.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Numbering closed polyline clockwise or counter clock wise

10 REPLIES 10
SOLVED
Reply
Message 1 of 11
mzakiralam
3104 Views, 10 Replies

Numbering closed polyline clockwise or counter clock wise

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

10 REPLIES 10
Message 2 of 11
hgasty1001
in reply to: mzakiralam

Hi,

 

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

 

Gaston Nunez

Message 3 of 11
mzakiralam
in reply to: hgasty1001

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
Message 4 of 11
hgasty1001
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

 

 

Message 5 of 11
mzakiralam
in reply to: hgasty1001

Hi,

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

Regards
Zakir
Message 6 of 11
fieldguy
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? 

 

 

Message 7 of 11
mzakiralam
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.
Message 8 of 11
Hallex
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
Message 9 of 11
_gile
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
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 10 of 11
mzakiralam
in reply to: Hallex

Hi Hallex,
Thanks a lot for your code. It is very helpful for me.
Message 11 of 11
mzakiralam
in reply to: _gile

Hi gile,
Thanks a lot for your code. I am learning lot of things from this example 🙂

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost