User defined properties allows us to store additional information about a COGO point. In this post, I will demonstrate how you can define new properties that then can be assigned to a point and set their value. The process is simple and gives you great flexibility on the type of the properties you can create. Let’s start by looking at the “demo” command I created.
C#
[CommandMethod("CDS_UDPDemo")]
public void CDS_UDPDemo()
{
createDemoPointsRepresentingWells();
createDemoProperties();
createDemoPointGroup();
setDemoPointProperties();
}
VB.NET
<CommandMethod("CDS_UDPDemo")> _
Public Sub CDS_UDPDemo()
createDemoPointsRepresentingWells()
createDemoProperties()
createDemoPointGroup()
setDemoPointProperties()
End Sub
The command is very simple. We first create some points to represent “Wells”. Then, we create the custom properties (User Defined Properties/UDPs). Finally, we create a point group to include our points and show the properties, and we set their values in the point objects themselves. I will not spend time explaining how to create the points and point groups, since I already talk about it in Cogo Point Basics and Point Groups. But it is important to understand that UDP classifications, which group properties, are applied to point groups, and you need to specify the classification to use by calling the ‘UseCustomClassification()’ method of the point group object. As always, you can download the entire source code from the “Civilized Development” repository at Bitbucket.
Creating a UDP Classfication
The first thing that you need is a “classification” to group the properties. Maybe, there are already classifications available in the drawing you are working on, but in general, you will want to create your own classifications for your UDPs you create. It is also a good idea to create your own point groups to display the properties. Creating a classification is very simple, as you can see in the following code.
C#
private UDPClassification createClassification(string name)
{
UDPClassificationCollection classifications =
UDPClassificationCollection
.GetPointUDPClassifications(_database);
return classifications.Add(name);
}
VB.NET
Private Function createClassification(name As String) As UDPClassification
Dim classifications As UDPClassificationCollection =
UDPClassificationCollection.GetPointUDPClassifications(_database)
Return classifications.Add(name)
End Function
We access the classifications collection through the static method ‘GetPointUDPClassifications()’ in the UDPClassficationCollection class, which takes an instance of the ‘Database’. The UDPClassificationCollection exposes an interface to access and manipulate all the classifications in the drawing, as well as creating new ones. Classifications are created by name, and the ‘Add()’ method throws an exception if the specified name already exists. You can avoid the exception by calling ‘Contains()’ to check for the existence of a classification with the specified name.
Creating User Defined Properties
Creating a UDP involves two steps. First, we need to create a type information for the UDP, which defines the type and values that are accepted.Then, you create the UDP through the ‘UDPClassification’ object using the type information. The following examples demonstrate how to create the different type information objects that are supported by the API.
C#
private AttributeTypeInfoBool makeBoolDefinition(
string name, string description)
{
AttributeTypeInfoBool definition = new AttributeTypeInfoBool(name);
definition.Description = description;
definition.DefaultValue = false;
definition.UseDefaultValue = true;
return definition;
}
VB.NET
Private Function makeBoolDefinition(name As String, description As String) _
As AttributeTypeInfoBool
Dim definition As New AttributeTypeInfoBool(name)
definition.Description = description
definition.DefaultValue = False
definition.UseDefaultValue = True
Return definition
End Function
To define a boolean value, we use the ‘AttributeTypeInfoBool’ class. This class, like other type information classes, allows you to specify a “name” for the property and a description. It also allows you to specify the default value of the property (the value to which the property is set if it is not specified) and whether the value should be used or not. Most of the time, you will want to specify the default value and set the ‘UseDefaultValue’ to true to insure the property is properly initialized.
C#
private AttributeTypeInfoString makeStringDefinition(
string name, string description)
{
AttributeTypeInfoString definition =
new AttributeTypeInfoString(name);
definition.Description = description;
definition.DefaultValue = String.Empty;
definition.UseDefaultValue = true;
return definition;
}
VB.NET
Private Function makeStringDefinition(name As String,
description As String) As AttributeTypeInfoString
Dim definition As New AttributeTypeInfoString(name)
definition.Description = description
definition.DefaultValue = [String].Empty
definition.UseDefaultValue = True
Return definition
End Function
String properties are similar to booleans. You defined them through the ‘AttributeTypeInfoString’ class, and you must specify the “name”. You can also specify a description for the property. The string type information also allows you to set the default value and specify whether it should be used, which you should use it to insure proper initialization.
C#
private AttributeTypeInfoEnum makeEnumDefinition(
string name, string description)
{
EnumDefinition valueDefinitions = new EnumDefinition();
AttributeTypeInfoEnum definition =
new AttributeTypeInfoEnum(name, valueDefinitions.Values);
definition.Description = description;
definition.DefaultValue = valueDefinitions.DefaultValue;
definition.UseDefaultValue = true;
return definition;
}
VB.NET
Private Function makeEnumDefinition(name As String,
description As String) As AttributeTypeInfoEnum
Dim valueDefinitions As New EnumDefinition()
Dim definition As New AttributeTypeInfoEnum(name,valueDefinitions.Values)
definition.Description = description
definition.DefaultValue = valueDefinitions.DefaultValue
definition.UseDefaultValue = True
Return definition
End Function
You can create UDPs that work as enumerations (enums). The values supported by the enumeration are strings, and should be specified by an ‘IEnumerable<string>’. You can also set the its default, which must be one of the supported values and whether the default value should be used.
C#
private AttributeTypeInfoInt makeIntDefinition(
string name, string description)
{
AttributeTypeInfoInt definition = new AttributeTypeInfoInt(name);
definition.Description = description;
definition.DefaultValue = 0;
definition.LowerBoundValue = Int32.MinValue;
definition.LowerBoundInclusive = true;
definition.UpperBoundValue = Int32.MaxValue;
definition.UpperBoundInclusive = true;
definition.UseDefaultValue = true;
return definition;
}
VB.NET
Private Function makeIntDefinition(name As String, description As String) _
As AttributeTypeInfoInt
Dim definition As New AttributeTypeInfoInt(name)
definition.Description = description
definition.DefaultValue = 0
definition.LowerBoundValue = Int32.MinValue
definition.LowerBoundInclusive = True
definition.UpperBoundValue = Int32.MaxValue
definition.UpperBoundInclusive = True
definition.UseDefaultValue = True
Return definition
End Function
Integer properties are defined by the ‘AttributeTypeInfoInt’ class. You must specify a “name”, and you can specify a “description”, “default value”, and whether the default value should be used. But, it also allows you to specify a minimum and maximum value for the property, and whether those values are included (accepted). Basically, the ‘AttributeTypeInfoInt’ allows you to specified a valid range of values for the property.
C#
private AttributeTypeInfoDouble makeDoubleDefinition(
string name, string description)
{
AttributeTypeInfoDouble definition =
new AttributeTypeInfoDouble(name);
definition.Description = description;
definition.DefaultValue = 0.0;
definition.UseDefaultValue = true;
definition.LowerBoundValue = 0.0;
definition.LowerBoundInclusive = true;
definition.UpperBoundValue = Double.MaxValue;
definition.UpperBoundInclusive = true;
definition.UseDefaultValue = true;
definition.DataType = AttributeTypeInfoDoubleDataType.Percent;
return definition;
}
VB.NET
Private Function makeDoubleDefinition(name As String,
description As String) As AttributeTypeInfoDouble
Dim definition As New AttributeTypeInfoDouble(name)
definition.Description = description
definition.DefaultValue = 0.0
definition.UseDefaultValue = True
definition.LowerBoundValue = 0.0
definition.LowerBoundInclusive = True
definition.UpperBoundValue = [Double].MaxValue
definition.UpperBoundInclusive = True
definition.UseDefaultValue = True
definition.DataType = AttributeTypeInfoDoubleDataType.Percent
Return definition
End Function
You can also create properties that store a double value. You use the ‘AttributeTypeInfoDouble’ class to define the property, which exposes a similar interface to that of integers. Double properties, however, are more flexible because they also allow you to specify what the value represents. The ‘AttributeTypeInfoDouble’ class exposes a ‘DataType’ property, which takes a value from the ‘AttributeTypeInfoDoubleDataType’ enumeration, and it will represent the value according to the value set. If you don’t specify the ‘DataType’ property, the value will be interpreted as a plain double, but you can also represent it as any of the types in the enumeration (angle, direction, coordinate, rotation, among others). This give you a lot of flexibility to represent different properties of a point. In the example above, we represent the double as a percentage.
Once you created your UDP definition (type information), you can use it to add the property to a classification, as demonstrated in the following example.
C#
private void addUDPs(UDPClassification classification)
{
_potable = classification.CreateUDP(makeBoolDefinition("Potable",
"Indicates if water is suitable for consumption."));
_chloride = classification.CreateUDP(makeIntDefinition("Chloride",
"Amount of chloride (mg/l)."));
_laboratory = classification.CreateUDP(
makeStringDefinition("Laboratory",
"Name of the laboratory that performed analysis."));
_hardness = classification.CreateUDP(makeEnumDefinition("Hardness",
"Hardness with respect to anions in metallic cations."));
_alkalinity = classification.CreateUDP(
makeDoubleDefinition("Alkalinity",
"Ability to resist sudden changes in pH."));
}
VB.NET
Private Sub addUDPs(classification As UDPClassification)
_potable = classification.CreateUDP(
makeBoolDefinition("Potable",
"Indicates if water is suitable for consumption."))
_chloride = classification.CreateUDP(
makeIntDefinition("Chloride", "Amount of chloride (mg/l)."))
_laboratory = classification.CreateUDP(
makeStringDefinition("Laboratory",
"Name of the laboratory that performed analysis."))
_hardness = classification.CreateUDP(
makeEnumDefinition("Hardness",
"Hardness with respect to anions in metallic cations."))
_alkalinity = classification.CreateUDP(
makeDoubleDefinition("Alkalinity",
"Ability to resist sudden changes in pH."))
End Sub
Setting a UDP in a COGO Point
To set a property, you call the ‘SetUDPValue()’ method of ‘CogoPoint’, specifying the UDP you want to set and its value.The following example shows how to do this.
C#
private void customizePoint(ObjectId id)
{
CogoPoint point = id.GetObject(OpenMode.ForWrite) as CogoPoint;
point.SetUDPValue(_potable, true);
point.SetUDPValue(_chloride, 150);
point.SetUDPValue(_laboratory, "CivilDev Labs, Inc.");
point.SetUDPValue(_hardness, "Carbonate (Temporary)");
point.SetUDPValue(_alkalinity, 7.5);
}
VB.NET
Private Sub customizePoint(id As ObjectId)
Dim point As CogoPoint = TryCast(id.GetObject(OpenMode.ForWrite),
CogoPoint)
point.SetUDPValue(_potable, True)
point.SetUDPValue(_chloride, 150)
point.SetUDPValue(_laboratory, "CivilDev Labs, Inc.")
point.SetUDPValue(_hardness, "Carbonate (Temporary)")
point.SetUDPValue(_alkalinity, 7.5)
End Sub
The COM API has a “bug” where if the property you are trying to set is not part of a classification applied to a point group containing the point, the call will fail. I thought I blog about this issue in the past, but I cannot find the post, so maybe I didn’t. The problem was caused by some validation code that was added for the UI, and which does not apply to the API but was being reused.
Through the UI, you will only see properties in classifications that are applied to a point group. Your options are to apply all the classifications, none of them, or apply a specific one, and the UI will show properties from those classifications
However, the properties and their values apply to COGO Points, so you should be able to set an existing UDP to any point. You will not be able to see the property or its value in the UI if it doesn’t meet the requirements above, but you should be able to retrieve them and manipulate them through the API. We insured the correct behavior was implemented in the .NET API, so any workarounds you have used in the past with COM should not be necessary.
Comments
You can follow this conversation by subscribing to the comment feed for this post.