Point groups is an important, powerful feature of Civil 3D. In Jay Peak, we have exposed an API that allows you to work with the point groups in a drawing. You can create them, modify them, and delete them as you please, and in this post, we will look at the basics of working with point groups.
Creating Point Groups
The point groups in a drawing are exposed through the ‘PointGroups’ property in the ‘CivilDocument’ class, which returns a ‘PointGroupCollection’ object. Creating a point group is a simple as invoking the ‘Add’ method in the ‘PointGroupCollection’ class passing it the name of the new point group. Of course, you want to insure the point group doesn’t already exists. The following command creates a couple of point groups.
C#
[CommandMethod("CDS_CreateCivilDevPointGroups")]
public void CDS_CreateCivilDevPointGroups()
{
using (Transaction tr = startTransaction())
{
createPointGroup("Trees", "TREE*");
createPointGroup("Wells", "WELL*");
tr.Commit();
}
}
private void createPointGroup(string name,
string includeRawDescription)
{
if (_pointGroups.Contains(name))
{
return;
}
ObjectId groupId = _pointGroups.Add(name);
StandardPointGroupQuery query = new StandardPointGroupQuery();
query.IncludeRawDescriptions = includeRawDescription;
PointGroup group = groupId.GetObject(OpenMode.ForWrite)
as PointGroup;
group.SetQuery(query);
// NOTE: Setting a description throws an exception. The
// issue is being researched by the API team.
// group.Description = "Set a description";
}
private PointGroupCollection _pointGroups
{
get
{
return _civildoc.PointGroups;
}
}
VB.NET
<CommandMethod("CDS_CreateCivilDevPointGroups")> _
Public Sub CDS_CreateCivilDevPointGroups()
Using tr As Transaction = startTransaction()
createPointGroup("Trees", "TREE*")
createPointGroup("Wells", "WELL*")
tr.Commit()
End Using
End Sub
Private Sub createPointGroup(name As String,
includeRawDescription As String)
If _pointGroups.Contains(name) Then
Return
End If
Dim groupId As ObjectId = _pointGroups.Add(name)
Dim query As New StandardPointGroupQuery()
query.IncludeRawDescriptions = includeRawDescription
Dim group As PointGroup =
TryCast(groupId.GetObject(OpenMode.ForRead), PointGroup)
group.SetQuery(query)
' NOTE: Setting a description throws an exception. The
' issue is being researched by the API team.
' group.Description = "Set a description";
End Sub
Private ReadOnly Property _pointGroups() As PointGroupCollection
Get
Return _civildoc.PointGroups
End Get
End Property
The code checks for the existence of a point group with the specified name. If it doesn’t exist, it creates the point group. Creating a point group doesn’t do much; you will at least want to set a query that selects some points to be included in the point group. We will take a closer look at point group queries in a future post; for now, we will just use a ‘StandardPointGroupQuery’, and we will set its ‘IncludeRawDescriptions’ property to a specified value.
Note: Robert Zrnc has reported an issue setting the ‘Description’ property of the ‘PointGroup’ class.We are currently investigating the issue, and we will try to provide a fix as soon as possible. In the meantime, there is a workaround using the COM API. Of course, you will have to reference the COM API interops in your project.
C#
AeccPointGroup comPointGroup = group.AcadObject as AeccPointGroup;
comPointGroup.Description = "Set a description";
VB.NET
Dim comPointGroup As AeccPointGroup = TryCast(group.AcadObject, AeccPointGroup)
comPointGroup.Description = "Set a description"
The ‘AcadObject’ property of the ‘PointGroup’ returns the COM instance of the object. This allows you to set the description property.
Controlling Draw Order
We saw how the ‘PointDescriptionKeySetCollection’ exposes a ‘SearchOrder’ property that allows us to control the search order in which description keys will be applied. Point groups allow us to override certain properties of the contained points, which affect how points are drawn, and since a point may belong to several point groups, we need to control the draw order of the point groups. This is done through the ‘DrawOrder’ property of the ‘PointGroupCollection’ class. The following command reverses the order in which point groups are drawn.
C#
[CommandMethod("CDS_ReversPointGroupDrawOrder")]
public void CDS_ReversPointGroupDrawOrder()
{
ObjectIdCollection drawPriority = _pointGroups.DrawOrder;
ObjectIdCollection reversed = new ObjectIdCollection();
for (int i = drawPriority.Count - 1; i >= 0; i-- )
{
ObjectId current = drawPriority[i];
reversed.Add(current);
}
_pointGroups.DrawOrder = reversed;
}
VB.NET
<CommandMethod("CDS_ReversPointGroupDrawOrder")> _
Public Sub CDS_ReversPointGroupDrawOrder()
Dim drawPriority As ObjectIdCollection = _pointGroups.DrawOrder
Dim reversed As New ObjectIdCollection()
For i As Integer = drawPriority.Count - 1 To 0 Step -1
Dim current As ObjectId = drawPriority(i)
reversed.Add(current)
Next
_pointGroups.DrawOrder = reversed
End Sub
Like the ‘SearchOrder’ property of the ‘DescriptionKeySetCollection’, the ‘DrawOrder’ property returns a “disconnected” collection, which means that you cannot manipulate the collection directly. You either need to get it first, make the changes, and set it; or create a new ‘ObjectIdCollection’ that sets the desired order and set it in the ‘PointGroupCollection’.
Accessing Points in a Point Group
The ‘PointGroup’ object exposes a ‘GetPointNumbers()’ method that returns an array of ‘uint’ values representing the points in a point group. When working with the points in a point group (especially, if we want to use them for bulk operations), we will want to get the object id of a point instead of its number. The ‘CogoPointCollection’ class exposes a ‘GetPointByPointNumber()’ method that returns the object id for a specified point number. The following command renumbers the points in a point group.
C#
[CommandMethod("CDS_RenumberPointsForGroup")]
public void CDS_RenumberPointsForGroup()
{
string pointGroupName = getPointGroupName();
if (pointGroupName == String.Empty)
{
return;
}
int baseNumber = getNewBaseNumber();
if (baseNumber == _kNoNumber)
{
return;
}
renumberPointsForGroup(pointGroupName, baseNumber);
}
private void renumberPointsForGroup(string groupName, int baseNumber)
{
using (Transaction tr = startTransaction())
{
ObjectId pointGroupId = getPointGroupIdByName(groupName);
PointGroup group = pointGroupId.GetObject(OpenMode.ForRead)
as PointGroup;
renumberPoints(group, baseNumber);
tr.Commit();
}
}
private ObjectId getPointGroupIdByName(string groupName)
{
return _pointGroups[groupName];
}
private void renumberPoints(PointGroup group, int baseNumber)
{
uint[] pointNumbers = group.GetPointNumbers();
int firstNumber = (int)pointNumbers[0];
int factor = baseNumber - firstNumber;
_civildoc.CogoPoints.SetPointNumber(
ToEnumerableObjectId(group.GetPointNumbers()), factor);
group.Update();
}
private IEnumerable<ObjectId> ToEnumerableObjectId(uint[] numbers)
{
foreach(uint number in numbers)
{
yield return _civildoc.CogoPoints
.GetPointByPointNumber(number);
}
}
VB.NET
<CommandMethod("CDS_RenumberPointsForGroup")> _
Public Sub CDS_RenumberPointsForGroup()
Dim pointGroupName As String = getPointGroupName()
If pointGroupName = [String].Empty Then
Return
End If
Dim baseNumber As Integer = getNewBaseNumber()
If baseNumber = _kNoNumber Then
Return
End If
renumberPointsForGroup(pointGroupName, baseNumber)
End Sub
Private Sub renumberPointsForGroup(groupName As String,
baseNumber As Integer)
Using tr As Transaction = startTransaction()
Dim pointGroupId As ObjectId = getPointGroupIdByName(groupName)
Dim group As PointGroup =
TryCast(pointGroupId.GetObject(OpenMode.ForRead), PointGroup)
renumberPoints(group, baseNumber)
tr.Commit()
End Using
End Sub
Private Function getPointGroupIdByName(groupName As String) _As ObjectId
Return _pointGroups(groupName)
End Function
Private Sub renumberPoints(group As PointGroup, baseNumber As Integer)
Dim pointNumbers As UInteger() = group.GetPointNumbers()
Dim firstNumber As Integer = CInt(pointNumbers(0))
Dim factor As Integer = baseNumber - firstNumber
_civildoc.CogoPoints.SetPointNumber(
ToEnumerableObjectId(group.GetPointNumbers()), factor)
group.Update()
End Sub
Private Function ToEnumerableObjectId(numbers As UInteger()) _
As IEnumerable(Of ObjectId)
Dim points As List(Of ObjectId) = New List(Of ObjectId)
For Each number As UInteger In numbers
Dim id = _civildoc.CogoPoints.GetPointByPointNumber(number)
points.Add(id)
Next
Return points
End Function
The command converts the point numbers to object ids, so it can use the ‘SetPointNumbers()’ method in the ‘CogoPointsCollection’ to renumber the points. Notice how we need to call ‘Update()’ in the point group after we renumber the points. This is because the points are renumbered through the points node (‘CogoPointCollection’) in the drawing and not through the point group itself.
Comments
You can follow this conversation by subscribing to the comment feed for this post.