.NET

Reply
Mentor
mzakiralam
Posts: 231
Registered: ‎11-09-2012
Message 1 of 11 (750 Views)
Accepted Solution

Numbering closed polyline clockwise or counter clock wise

750 Views, 10 Replies
11-29-2013 02:54 AM

Hi All,

I have some closed polyline in a rectangular area like below screen shot. I want numbering these polylines counter clockwise or clockwise by selecting a reference polyline. In the below screen shot , I have highlighted a polyline (red marked). So , first I select that polyline and ask to numbering other polylines in couter clockwise.

Capture.JPG

 

The result of my requirement should be like below screen shot. Can anybody give me hint regarding this matter how to do that? sample code in VB will be appreciated.

 

Capture1.JPG

 

Thanks.

Zakir

Not sure about if this helps, here is just a part of code

from working project of mine:

 Public Function Rtd(ByVal radian As Double) As Double
Return radian * (180 / Math.PI)
End Function
<CommandMethod("PolarInc")> _
Public Sub TestLablelPolar()
Try
Dim stack As Dictionary(Of ObjectId, Point3d) = New Dictionary(Of ObjectId, Point3d)
Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
Dim ed As Editor = doc.Editor
Dim ucs As CoordinateSystem3d = ed.CurrentUserCoordinateSystem.CoordinateSystem3d
'Dim plan As New Plane(Point3d.Origin, ucs.Zaxis)
Dim ppo As New PromptPointOptions(vbLf & "Lower left corner: ")
Dim ppr As PromptPointResult = ed.GetPoint(ppo)
If ppr.Status <> PromptStatus.OK Then
Return
End If
Dim pco As New PromptCornerOptions(vbLf & "Other corner: ", ppr.Value)
Dim pcr As PromptPointResult = ed.GetCorner(pco)
If pcr.Status <> PromptStatus.OK Then
Return
End If
Dim p1 As Point3d = ppr.Value
Dim p2 As Point3d = pcr.Value
If p1.X = p2.X OrElse p1.Y = p2.Y Then
ed.WriteMessage(vbLf & "Invalid coordinate specification")
Return
End If
' Calculate the middle point of the box
Dim center As Point3d = p1.Add(p1.GetVectorTo(p2).DivideBy(2))
Dim filter As TypedValue() = {New TypedValue(0, "lwpolyline"), New TypedValue(70, 1)}
Using tr = doc.TransactionManager.StartTransaction()
'' Create a crossing window from p1 to p2
Dim setRes As PromptSelectionResult = ed.SelectCrossingWindow(p1, p2, New SelectionFilter(filter))
'' If the prompt status is OK, objects were selected
If setRes.Status <> PromptStatus.OK Then Return
Dim selSet As SelectionSet = setRes.Value
Dim peo As New PromptEntityOptions(vbLf & "Select a lwpolyline to start (if CW order, select one before start): ")
peo.SetRejectMessage(vbLf & "Not a polyline...")
peo.AddAllowedClass(GetType(Polyline), True)
Dim per As PromptEntityResult = ed.GetEntity(peo)
If per.Status <> PromptStatus.OK Then
Return
End If
Dim spoly As Polyline = DirectCast(tr.GetObject(per.ObjectId, OpenMode.ForRead), Polyline)
Dim sext As Extents3d = spoly.GeometricExtents
Dim sminp As Point3d = sext.MinPoint
Dim smaxp As Point3d = sext.MaxPoint
Dim scp As Point3d = New Point3d((smaxp.X + sminp.X) / 2, (smaxp.Y + sminp.Y) / 2, sminp.Z)
Dim vec As Vector3d
vec = center.GetVectorTo(scp)
' Dim ang As Double = Rtd(vec.GetAngleTo(Vector3d.XAxis, Vector3d.ZAxis.Negate()))
For Each selObj As SelectedObject In selSet
Dim ent As Entity = DirectCast(tr.GetObject(selObj.ObjectId, OpenMode.ForRead), Entity)
Dim ext As Extents3d = ent.GeometricExtents
Dim minp As Point3d = ext.MinPoint
Dim maxp As Point3d = ext.MaxPoint
Dim cp As Point3d = New Point3d((maxp.X + minp.X) / 2, (maxp.Y + minp.Y) / 2, minp.Z)
stack(selObj.ObjectId) = cp
Next
If stack.Count = 0 Then Return
Dim pko As New PromptKeywordOptions(vbLf & "Choose an order of CW or CCW " & "[CW/CCW]: ")
' Add keywords
pko.Keywords.Add("CW")
pko.Keywords.Add("CCW")
' The default depends on our current settings
pko.Keywords.Default = "CCW"
'To get default setting
pko.AllowNone = True
Dim pkr As PromptResult = ed.GetKeywords(pko)
Dim rev As String = pkr.StringResult
If pkr.Status <> PromptStatus.OK Then
Return
End If
Dim asc As IEnumerable(Of KeyValuePair(Of ObjectId, Point3d))
If rev.ToUpper = "CCW" Then
asc = stack.OrderBy(Function(x) Rtd(center.GetVectorTo(x.Value).GetAngleTo(vec, ucs.Zaxis.Negate())))
Else
asc = stack.OrderByDescending(Function(x) Rtd(center.GetVectorTo(x.Value).GetAngleTo(vec, ucs.Zaxis.Negate())))
End If
' Set increment start
Dim i As Integer = 1
If asc IsNot Nothing Then
Dim db As Database = doc.Database
Dim btr As BlockTableRecord = DirectCast(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite), BlockTableRecord)
For Each kvp As KeyValuePair(Of ObjectId, Point3d) In asc
Dim pt As Point3d = New Point3d(kvp.Value.X, kvp.Value.Y, kvp.Value.Z)
Dim txt As DBText = New DBText()
txt.SetDatabaseDefaults()
txt.TextString = i.ToString()
txt.Height = 100
txt.TextStyleId = db.Textstyle
txt.HorizontalMode = TextHorizontalMode.TextCenter
txt.VerticalMode = TextVerticalMode.TextVerticalMid
txt.Position = pt
txt.AlignmentPoint = pt
txt.AdjustAlignment(db)
btr.AppendEntity(txt)
tr.AddNewlyCreatedDBObject(txt, True)
i += 1
Next
End If
tr.Commit()
End Using
Catch ex As Autodesk.AutoCAD.Runtime.Exception
Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog(ex.Message + vbLf + ex.StackTrace)
Finally
End Try
End Sub

 

Hi,

 

Here's an example using Linq extension methods.

Assuming polylines are rectangular, the barycenter is used to calculate polylines centers.

Assuming polylines are organized in a rectangular area, the center point is calculated using the extents ot all polylines.

If a polyline center is on the center point, it is sorted as the last item (as the 13 polyline in your example).

 

C# code

[CommandMethod("Test", CommandFlags.Modal)]
public void Test()
{
Document doc = AcAp.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
TypedValue[] filter = { new TypedValue(0, "LWPOLYLINE") };
PromptSelectionResult psr = ed.GetSelection(new SelectionFilter(filter));
if (psr.Status != PromptStatus.OK) return;
HashSet<ObjectId> ids = new HashSet<ObjectId>(psr.Value.GetObjectIds());
PromptEntityOptions peo = new PromptEntityOptions("\nSelect the start polyline: ");
peo.SetRejectMessage("Only a polyline.");
peo.AddAllowedClass(typeof(Polyline), true);
PromptEntityResult per;
while (true)
{
per = ed.GetEntity(peo);
if (per.Status != PromptStatus.OK) return;
if (ids.Contains(per.ObjectId)) break;
ed.WriteMessage("\nThe start polyline must belong to the previous selection.");
}
ObjectId startId = per.ObjectId;
PromptResult pr = ed.GetKeywords("\nChoose an option: ", "CW", "CCW");
if (pr.Status != PromptStatus.OK) return;
bool clockwise = pr.StringResult == "CW";
Vector3d normal = clockwise ? Vector3d.ZAxis.Negate() : Vector3d.ZAxis;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
var pts = psr.Value.GetObjectIds()
.ToDictionary(id => id, id => GetBarycenter(id));
Point3d center = GetExtentsCenter(pts.Values);
Vector3d org = center.GetVectorTo(pts[startId]);
int i = 1;
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
foreach (Point3d pt in pts.Values.OrderBy(p =>
p.IsEqualTo(center) ? double.MaxValue : org.GetAngleTo(p - center, normal)))
{
DBText text = new DBText();
text.Justify = AttachmentPoint.MiddleCenter;
text.AlignmentPoint = pt;
text.TextString = i.ToString();
btr.AppendEntity(text);
tr.AddNewlyCreatedDBObject(text, true);
i++;
}
tr.Commit();
}
}
private Point3d GetBarycenter(ObjectId id)
{
Polyline pline =
(Polyline)id.Database.TransactionManager.GetObject(id, OpenMode.ForRead);
Vector3d vector = new Vector3d();
int i = 0;
for (; i < pline.NumberOfVertices; i++) vector += pline.GetPoint3dAt(i).GetAsVector();
return Point3d.Origin + vector / i;
}
private Point3d GetExtentsCenter(IEnumerable<Point3d> pts)
{
Extents3d ext = pts.Aggregate(new Extents3d(), (e, p) => { e.AddPoint(p); return e; });
return ext.MinPoint + ext.MinPoint.GetVectorTo(ext.MaxPoint) / 2.0;
}

 

VB conversion

<CommandMethod("Test", CommandFlags.Modal)> _
Public Sub Test()
Dim doc As Document = Application.DocumentManager.MdiActiveDocument
Dim db As Database = doc.Database
Dim ed As Editor = doc.Editor
Dim filter As TypedValue() = {New TypedValue(0, "LWPOLYLINE")}
Dim psr As PromptSelectionResult = ed.GetSelection(New SelectionFilter(filter))
If psr.Status <> PromptStatus.OK Then
Return
End If
Dim ids As New HashSet(Of ObjectId)(psr.Value.GetObjectIds())
Dim peo As New PromptEntityOptions(vbLf & "Select the start polyline: ")
peo.SetRejectMessage("Only a polyline.")
peo.AddAllowedClass(GetType(Polyline), True)
Dim per As PromptEntityResult = ed.GetEntity(peo)
While True
If per.Status <> PromptStatus.OK Then
Return
End If
If ids.Contains(per.ObjectId) Then
Exit While
End If
ed.WriteMessage(vbLf & "The start polyline must belong to the previous selection.")
per = ed.GetEntity(peo)
End While
Dim startId As ObjectId = per.ObjectId
Dim pr As PromptResult = ed.GetKeywords(vbLf & "Choose an option: ", "CW", "CCW")
If pr.Status <> PromptStatus.OK Then
Return
End If
Dim clockwise As Boolean = pr.StringResult = "CW"
Dim normal As Vector3d = If(clockwise, Vector3d.ZAxis.Negate(), Vector3d.ZAxis)
Using tr As Transaction = db.TransactionManager.StartTransaction()
Dim pts = psr.Value.GetObjectIds() _
.ToDictionary(Function(id) id, Function(id) GetBarycenter(id))
Dim center As Point3d = GetExtentsCenter(pts.Values)
Dim org As Vector3d = pts(startId) - center
Dim i As Integer = 1
Dim btr As BlockTableRecord = _
DirectCast(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite), BlockTableRecord)
For Each pt As Point3d In pts.Values _
.OrderBy(Function(p) _
If(p.IsEqualTo(center), Double.MaxValue, org.GetAngleTo(p - center, normal)))
Dim text As New DBText()
text.Justify = AttachmentPoint.MiddleCenter
text.AlignmentPoint = pt
text.TextString = i.ToString()
btr.AppendEntity(text)
tr.AddNewlyCreatedDBObject(text, True)
i += 1
Next
tr.Commit()
End Using
End Sub
Private Function GetBarycenter(id As ObjectId) As Point3d
Dim pline As Polyline = _
DirectCast(id.Database.TransactionManager.GetObject(id, OpenMode.ForRead), Polyline)
Dim vector As New Vector3d()
Dim i As Integer = 0
While i < pline.NumberOfVertices
vector += pline.GetPoint3dAt(i).GetAsVector()
i += 1
End While
Return Point3d.Origin + vector / i
End Function
Private Function GetExtentsCenter(pts As IEnumerable(Of Point3d)) As Point3d
Dim extents As Extents3d = _
pts.Aggregate(New Extents3d(), Function(ext, pt)
ext.AddPoint(pt)
Return ext
End Function)
Return extents.MinPoint + extents.MinPoint.GetVectorTo(extents.MaxPoint) / 2.0
End Function

 

Distinguished Mentor
gasty1001
Posts: 533
Registered: ‎04-11-2010
Message 2 of 11 (737 Views)

Re: Numbering closed polyline clockwise or counter clock wise

11-29-2013 05:20 AM in reply to: mzakiralam

Hi,

 

Just search for "clockwise" in this forum, this has been asked several times before.

 

Gaston Nunez

Mentor
mzakiralam
Posts: 231
Registered: ‎11-09-2012
Message 3 of 11 (733 Views)

Re: Numbering closed polyline clockwise or counter clock wise

11-29-2013 05:31 AM in reply to: gasty1001
I have searched before posted this Topic. Most of the case I have found to get the direction of a poline. Here I want find a entity in ClockWise or anticlockise. I do not want whether a polyline is created ClockWise or anticlockwise direction
Distinguished Mentor
gasty1001
Posts: 533
Registered: ‎04-11-2010
Message 4 of 11 (724 Views)

Re: Numbering closed polyline clockwise or counter clock wise

11-29-2013 05:54 AM in reply to: mzakiralam

Hi,

 

It seems i misread your post, if i understand, you need to "sort" the polylines in a cw/ccw fashion, is that true, then you can try finding the angle to any point on the polyline (or to the centroid) from the "center" of the rectangle in the picture, and then sort on this angle. You need to find the angles in the [0,2pi] range, to do that you may try something like:

 

dim v as vector3D ' The vector from cp to p

dim cp as point3D ' Center point

dim p as point3D   ' Some point on a polyline (or the centroid of the polyline)

dim theta as double 'The angle

 

v= cp.GetVectorTo(p)

theta= v.GetAngleTo(Vector3d.XAxis, Vector3d.ZAxis.Negate())

 

now, do that for each polyline, put theta in some data structure( a dictionary should be my first choice) and sort them.

 

Gaston Nunez

 

 

Mentor
mzakiralam
Posts: 231
Registered: ‎11-09-2012
Message 5 of 11 (720 Views)

Re: Numbering closed polyline clockwise or counter clock wise

11-29-2013 06:17 AM in reply to: gasty1001
Hi,

Thanks for your kind reply. It seems promising. I will try with the method you have recommended.

Regards
Zakir
Valued Mentor
fieldguy
Posts: 376
Registered: ‎03-31-2005
Message 6 of 11 (707 Views)

Re: Numbering closed polyline clockwise or counter clock wise

11-29-2013 07:31 AM in reply to: mzakiralam

I would try coordinates of the centre points.  But, you would need some rules and tolerances.  Is it always the same pattern?  Is there always 3 polygons on the right, 3 on the left, 5 across the top, 12 total, etc?  Is there a chance the coordinates could be negative?  Is the x value of the 3 on the right / left exactly the same - also the y value of the 5 at the top / bottom? 

 

 

Mentor
mzakiralam
Posts: 231
Registered: ‎11-09-2012
Message 7 of 11 (699 Views)

Re: Numbering closed polyline clockwise or counter clock wise

11-29-2013 07:52 AM in reply to: fieldguy
Hi fieldguy,
Thanks for the concern in this topic.
>> Is it always the same pattern? --> pattern will not be same
>> Is there always 3 polygons on the right, 3 on the left, 5 across the top, 12 total, etc? --> No, no of polygon could be different. As an example on right side there could be 5 and left 2.
>>Is there a chance the coordinates could be negative? Is the x value of the 3 on the right / left exactly the same - also the y value of the 5 at the top / bottom? --> yes there is Chance that coordinate could be negative. x value of the right and left is not same always.
*Expert Elite*
Hallex
Posts: 1,569
Registered: ‎10-08-2008
Message 8 of 11 (664 Views)

Re: Numbering closed polyline clockwise or counter clock wise

12-01-2013 12:01 AM in reply to: mzakiralam

Not sure about if this helps, here is just a part of code

from working project of mine:

  Public Function Rtd(ByVal radian As Double) As Double
            Return radian * (180 / Math.PI)
        End Function
        <CommandMethod("PolarInc")> _
        Public Sub TestLablelPolar()

            Try
                Dim stack As Dictionary(Of ObjectId, Point3d) = New Dictionary(Of ObjectId, Point3d)

                Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
                Dim ed As Editor = doc.Editor

                Dim ucs As CoordinateSystem3d = ed.CurrentUserCoordinateSystem.CoordinateSystem3d

                'Dim plan As New Plane(Point3d.Origin, ucs.Zaxis)
                Dim ppo As New PromptPointOptions(vbLf & "Lower left corner: ")
                Dim ppr As PromptPointResult = ed.GetPoint(ppo)
                If ppr.Status <> PromptStatus.OK Then
                    Return
                End If
                Dim pco As New PromptCornerOptions(vbLf & "Other corner: ", ppr.Value)
                Dim pcr As PromptPointResult = ed.GetCorner(pco)
                If pcr.Status <> PromptStatus.OK Then
                    Return
                End If
                Dim p1 As Point3d = ppr.Value
                Dim p2 As Point3d = pcr.Value
                If p1.X = p2.X OrElse p1.Y = p2.Y Then
                    ed.WriteMessage(vbLf & "Invalid coordinate specification")
                    Return
                End If
                ' Calculate the middle point of the box
                Dim center As Point3d = p1.Add(p1.GetVectorTo(p2).DivideBy(2))
                Dim filter As TypedValue() = {New TypedValue(0, "lwpolyline"), New TypedValue(70, 1)}


                Using tr = doc.TransactionManager.StartTransaction()
                    '' Create a crossing window from p1 to p2
                    Dim setRes As PromptSelectionResult = ed.SelectCrossingWindow(p1, p2, New SelectionFilter(filter))
                    '' If the prompt status is OK, objects were selected
                    If setRes.Status <> PromptStatus.OK Then Return
                    Dim selSet As SelectionSet = setRes.Value
                    Dim peo As New PromptEntityOptions(vbLf & "Select a lwpolyline to start (if CW order, select one before start): ")
                    peo.SetRejectMessage(vbLf & "Not a polyline...")
                    peo.AddAllowedClass(GetType(Polyline), True)
                    Dim per As PromptEntityResult = ed.GetEntity(peo)
                    If per.Status <> PromptStatus.OK Then
                        Return
                    End If
                    Dim spoly As Polyline = DirectCast(tr.GetObject(per.ObjectId, OpenMode.ForRead), Polyline)
                    Dim sext As Extents3d = spoly.GeometricExtents
                    Dim sminp As Point3d = sext.MinPoint
                    Dim smaxp As Point3d = sext.MaxPoint
                    Dim scp As Point3d = New Point3d((smaxp.X + sminp.X) / 2, (smaxp.Y + sminp.Y) / 2, sminp.Z)
                    Dim vec As Vector3d
                    vec = center.GetVectorTo(scp)
                    ' Dim ang As Double = Rtd(vec.GetAngleTo(Vector3d.XAxis, Vector3d.ZAxis.Negate()))

                    For Each selObj As SelectedObject In selSet
                        Dim ent As Entity = DirectCast(tr.GetObject(selObj.ObjectId, OpenMode.ForRead), Entity)
                        Dim ext As Extents3d = ent.GeometricExtents
                        Dim minp As Point3d = ext.MinPoint
                        Dim maxp As Point3d = ext.MaxPoint
                        Dim cp As Point3d = New Point3d((maxp.X + minp.X) / 2, (maxp.Y + minp.Y) / 2, minp.Z)
                        stack(selObj.ObjectId) = cp
                    Next
                    If stack.Count = 0 Then Return

                    Dim pko As New PromptKeywordOptions(vbLf & "Choose an order of CW or CCW " & "[CW/CCW]: ")

                    ' Add keywords
                    pko.Keywords.Add("CW")
                    pko.Keywords.Add("CCW")
                    ' The default depends on our current settings
                    pko.Keywords.Default = "CCW"
                    'To get default setting
                    pko.AllowNone = True
                    Dim pkr As PromptResult = ed.GetKeywords(pko)
                    Dim rev As String = pkr.StringResult
                    If pkr.Status <> PromptStatus.OK Then
                        Return
                    End If
                    Dim asc As IEnumerable(Of KeyValuePair(Of ObjectId, Point3d))
                    If rev.ToUpper = "CCW" Then

                        asc = stack.OrderBy(Function(x) Rtd(center.GetVectorTo(x.Value).GetAngleTo(vec, ucs.Zaxis.Negate())))

                    Else

                        asc = stack.OrderByDescending(Function(x) Rtd(center.GetVectorTo(x.Value).GetAngleTo(vec, ucs.Zaxis.Negate())))

                    End If
                    ' Set increment start
                    Dim i As Integer = 1


                    If asc IsNot Nothing Then
                        Dim db As Database = doc.Database
                        Dim btr As BlockTableRecord = DirectCast(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite), BlockTableRecord)

                        For Each kvp As KeyValuePair(Of ObjectId, Point3d) In asc
                            Dim pt As Point3d = New Point3d(kvp.Value.X, kvp.Value.Y, kvp.Value.Z)
                            Dim txt As DBText = New DBText()
                            txt.SetDatabaseDefaults()
                            txt.TextString = i.ToString()
                            txt.Height = 100
                            txt.TextStyleId = db.Textstyle
                            txt.HorizontalMode = TextHorizontalMode.TextCenter
                            txt.VerticalMode = TextVerticalMode.TextVerticalMid
                            txt.Position = pt
                            txt.AlignmentPoint = pt
                            txt.AdjustAlignment(db)
                            btr.AppendEntity(txt)
                            tr.AddNewlyCreatedDBObject(txt, True)
                            i += 1
                        Next
                    End If

                    tr.Commit()
                End Using
            Catch ex As Autodesk.AutoCAD.Runtime.Exception
                Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog(ex.Message + vbLf + ex.StackTrace)
            Finally

            End Try
        End Sub

 

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
*Expert Elite*
_gile
Posts: 2,106
Registered: ‎04-29-2006
Message 9 of 11 (641 Views)

Re : Numbering closed polyline clockwise or counter clock wise

12-01-2013 09:27 AM in reply to: mzakiralam

Hi,

 

Here's an example using Linq extension methods.

Assuming polylines are rectangular, the barycenter is used to calculate polylines centers.

Assuming polylines are organized in a rectangular area, the center point is calculated using the extents ot all polylines.

If a polyline center is on the center point, it is sorted as the last item (as the 13 polyline in your example).

 

C# code

[CommandMethod("Test", CommandFlags.Modal)]
public void Test()
{
    Document doc = AcAp.DocumentManager.MdiActiveDocument;
    Database db = doc.Database;
    Editor ed = doc.Editor;

    TypedValue[] filter = { new TypedValue(0, "LWPOLYLINE") };
    PromptSelectionResult psr = ed.GetSelection(new SelectionFilter(filter));
    if (psr.Status != PromptStatus.OK) return;
    HashSet<ObjectId> ids = new HashSet<ObjectId>(psr.Value.GetObjectIds());

    PromptEntityOptions peo = new PromptEntityOptions("\nSelect the start polyline: ");
    peo.SetRejectMessage("Only a polyline.");
    peo.AddAllowedClass(typeof(Polyline), true);
    PromptEntityResult per;
    while (true)
    {
        per = ed.GetEntity(peo);
        if (per.Status != PromptStatus.OK) return;
        if (ids.Contains(per.ObjectId)) break;
        ed.WriteMessage("\nThe start polyline must belong to the previous selection.");
    }
    ObjectId startId = per.ObjectId;

    PromptResult pr = ed.GetKeywords("\nChoose an option: ", "CW", "CCW");
    if (pr.Status != PromptStatus.OK) return;
    bool clockwise = pr.StringResult == "CW";
    Vector3d normal = clockwise ? Vector3d.ZAxis.Negate() : Vector3d.ZAxis;

    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        var pts = psr.Value.GetObjectIds()
            .ToDictionary(id => id, id => GetBarycenter(id));
        Point3d center = GetExtentsCenter(pts.Values);
        Vector3d org = center.GetVectorTo(pts[startId]);
        int i = 1;
        BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
        foreach (Point3d pt in pts.Values.OrderBy(p =>
            p.IsEqualTo(center) ? double.MaxValue : org.GetAngleTo(p - center, normal)))
        {
            DBText text = new DBText();
            text.Justify = AttachmentPoint.MiddleCenter;
            text.AlignmentPoint = pt;
            text.TextString = i.ToString();
            btr.AppendEntity(text);
            tr.AddNewlyCreatedDBObject(text, true);
            i++;
        }
        tr.Commit();
    }
}

private Point3d GetBarycenter(ObjectId id)
{
    Polyline pline =
        (Polyline)id.Database.TransactionManager.GetObject(id, OpenMode.ForRead);
    Vector3d vector = new Vector3d();
    int i = 0;
    for (; i < pline.NumberOfVertices; i++) vector += pline.GetPoint3dAt(i).GetAsVector();
    return Point3d.Origin + vector / i;
}

private Point3d GetExtentsCenter(IEnumerable<Point3d> pts)
{
    Extents3d ext = pts.Aggregate(new Extents3d(), (e, p) => { e.AddPoint(p); return e; });
    return ext.MinPoint + ext.MinPoint.GetVectorTo(ext.MaxPoint) / 2.0;
}

 

VB conversion

<CommandMethod("Test", CommandFlags.Modal)> _
Public Sub Test()
    Dim doc As Document = Application.DocumentManager.MdiActiveDocument
    Dim db As Database = doc.Database
    Dim ed As Editor = doc.Editor

    Dim filter As TypedValue() = {New TypedValue(0, "LWPOLYLINE")}
    Dim psr As PromptSelectionResult = ed.GetSelection(New SelectionFilter(filter))
    If psr.Status <> PromptStatus.OK Then
        Return
    End If
    Dim ids As New HashSet(Of ObjectId)(psr.Value.GetObjectIds())

    Dim peo As New PromptEntityOptions(vbLf & "Select the start polyline: ")
    peo.SetRejectMessage("Only a polyline.")
    peo.AddAllowedClass(GetType(Polyline), True)
    Dim per As PromptEntityResult = ed.GetEntity(peo)
    While True
        If per.Status <> PromptStatus.OK Then
            Return
        End If
        If ids.Contains(per.ObjectId) Then
            Exit While
        End If
        ed.WriteMessage(vbLf & "The start polyline must belong to the previous selection.")
        per = ed.GetEntity(peo)
    End While
    Dim startId As ObjectId = per.ObjectId

    Dim pr As PromptResult = ed.GetKeywords(vbLf & "Choose an option: ", "CW", "CCW")
    If pr.Status <> PromptStatus.OK Then
        Return
    End If
    Dim clockwise As Boolean = pr.StringResult = "CW"
    Dim normal As Vector3d = If(clockwise, Vector3d.ZAxis.Negate(), Vector3d.ZAxis)

    Using tr As Transaction = db.TransactionManager.StartTransaction()
        Dim pts = psr.Value.GetObjectIds() _
                  .ToDictionary(Function(id) id, Function(id) GetBarycenter(id))
        Dim center As Point3d = GetExtentsCenter(pts.Values)
        Dim org As Vector3d = pts(startId) - center
        Dim i As Integer = 1
        Dim btr As BlockTableRecord = _
            DirectCast(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite), BlockTableRecord)
        For Each pt As Point3d In pts.Values _
            .OrderBy(Function(p) _
                         If(p.IsEqualTo(center), Double.MaxValue, org.GetAngleTo(p - center, normal)))
            Dim text As New DBText()
            text.Justify = AttachmentPoint.MiddleCenter
            text.AlignmentPoint = pt
            text.TextString = i.ToString()
            btr.AppendEntity(text)
            tr.AddNewlyCreatedDBObject(text, True)
            i += 1
        Next
        tr.Commit()
    End Using
End Sub

Private Function GetBarycenter(id As ObjectId) As Point3d
    Dim pline As Polyline = _
        DirectCast(id.Database.TransactionManager.GetObject(id, OpenMode.ForRead), Polyline)
    Dim vector As New Vector3d()
    Dim i As Integer = 0
    While i < pline.NumberOfVertices
        vector += pline.GetPoint3dAt(i).GetAsVector()
        i += 1
    End While
    Return Point3d.Origin + vector / i
End Function

Private Function GetExtentsCenter(pts As IEnumerable(Of Point3d)) As Point3d
    Dim extents As Extents3d = _
        pts.Aggregate(New Extents3d(), Function(ext, pt)
                                           ext.AddPoint(pt)
                                           Return ext
                                       End Function)
    Return extents.MinPoint + extents.MinPoint.GetVectorTo(extents.MaxPoint) / 2.0
End Function

 

Gilles Chanteau
Mentor
mzakiralam
Posts: 231
Registered: ‎11-09-2012
Message 10 of 11 (634 Views)

Re: Numbering closed polyline clockwise or counter clock wise

12-01-2013 11:56 AM in reply to: Hallex
Hi Hallex,
Thanks a lot for your code. It is very helpful for me.
Post to the Community

Have questions about Autodesk products? Ask the community.

New Post
Need installation help?

Start with some of our most frequented solutions or visit the Installation and Licensing Forum to get help installing your software.