Coordinate of 2 vertices of a polyline segment

Coordinate of 2 vertices of a polyline segment

kinakira2013
Advocate Advocate
613 Views
4 Replies
Message 1 of 5

Coordinate of 2 vertices of a polyline segment

kinakira2013
Advocate
Advocate

Hi,

Are there any ways to get coordinates of 2 vertices of a polyline segment that was picked? (The polyline have more than 2 segments)

 

Thanks for your help!

Kin,

0 Likes
Accepted solutions (3)
614 Views
4 Replies
Replies (4)
Message 2 of 5

norman.yuan
Mentor
Mentor
Accepted solution

If you look at Polyline class in Object Browser window, it would be hard to miss something like GetPoint2[3]dAt(int). Quick example:

 

for (int i=0; i<myPolyline.NumberOfVertices; i++)

{

    var vetexPoint=myPolyline.GetPoint3d(i); //i is the vertex index!

}

 

That is, as long as you know the index of the segment, you can get its coordinates at 2 ends. Since you said the polyline is picked, you should know where the pick point is, thus the segment's index:

 

var para=myPolyline.GetParameterAtPoint(pickedPointOnPolyline);

var index=Convert.ToInt32(Math.Floor(para));

var segStartPt=myPolyline.GetPoint3d(index);

var segEndPt=myPolyline.GetPoint3d(index+1);

Norman Yuan

Drive CAD With Code

EESignature

Message 3 of 5

_gile
Consultant
Consultant
Accepted solution

Hi,

 

Yo can get the picked point from the PromptEntityResult, then compute the point on the polyline (GetClosestPointTo), the get the polyline parameter at this point.
The parameter of a polyline is a double value, its integer part is the index of the previous vertex (0 for the 1st segment, 1 for the 2nd, ...), the decimal part is the ratio of the segment length (e.g. .25 at the quarter of the segment, .5 at the middle, ...).

With the indices of the vertices enclosing the picked point, you can get the coordinates of these vertices with GetPointAtParameter.

        [CommandMethod("TEST")]
        public static void Test()
        {
            var doc = Application.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;
            var peo = new PromptEntityOptions("\nSelect Polyline: ");
            peo.SetRejectMessage("\nNot a polyline, try again.");
            peo.AddAllowedClass(typeof(Polyline), true);
            var per = ed.GetEntity(peo);
            if (per.Status != PromptStatus.OK) 
                return;
            var plineId = per.ObjectId;
            var pickedPt = per.PickedPoint.TransformBy(ed.CurrentUserCoordinateSystem);
            using (var tr = db.TransactionManager.StartTransaction())
            {
                var pline = (Polyline)tr.GetObject(plineId, OpenMode.ForRead);
                var pointOnPline = pline.GetClosestPointTo(pickedPt, false);
                double paramAtPoint = pline.GetParameterAtPoint(pointOnPline);
                int segmentStartParam = (int)paramAtPoint;
                int segmentEndParam = segmentStartParam + 1;
                var segmentStartPoint = pline.GetPointAtParameter(segmentStartParam);
                var segmentEndPoint = pline.GetPointAtParameter(segmentEndParam);

                double radius = segmentStartPoint.DistanceTo(segmentEndPoint) / 10.0;
                var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                var circle = new Circle(segmentStartPoint, Vector3d.ZAxis, radius);
                curSpace.AppendEntity(circle);
                tr.AddNewlyCreatedDBObject(circle, true);
                circle = new Circle(segmentEndPoint, Vector3d.ZAxis, radius);
                curSpace.AppendEntity(circle);
                tr.AddNewlyCreatedDBObject(circle, true);
                tr.Commit();
            }
        }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 4 of 5

kinakira2013
Advocate
Advocate

Hi,

Everything is fine when I picked a segment of the polyline. However, I have trouble with a close polyline inside a block. The parameter of the close polyline is wrong in this case.

Please advise me!

double paramAtPoint = pline.GetParameterAtPoint(pointOnPline);

 

       [CommandMethod("SSS")]
        public void cmd_SSS()
        {
            var doc = Application.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            using (var tr = db.TransactionManager.StartTransaction())
            {
                var nestedEntOpt = new PromptNestedEntityOptions("\nSelect segment");
                PromptNestedEntityResult nestedEntRes = ed.GetNestedEntity(nestedEntOpt);

                if (nestedEntRes.Status != PromptStatus.OK)
                    return;
                
                var ent = (Entity)tr.GetObject(nestedEntRes.ObjectId, OpenMode.ForRead);
                if(ent is Polyline)
                {
                    var pline = ent as Polyline;
                    var plineId = pline.ObjectId;
                    var pickedPt = nestedEntRes.PickedPoint.TransformBy(ed.CurrentUserCoordinateSystem);

                    var pointOnPline = pline.GetClosestPointTo(pickedPt, false);
                    double paramAtPoint = pline.GetParameterAtPoint(pointOnPline);

                    var para = pline.GetParameterAtPoint(pointOnPline);
                    ed.WriteMessage("\nPara = " + para.ToString());

                    tr.Commit();
                }                
            }
        }
0 Likes
Message 5 of 5

_gile
Consultant
Consultant
Accepted solution

Hi,

You have to keep in mind that block references do not contain entities, they're only references to a block definition (BlockTableRecord) which contains entities.

So the polyline you get from PromptNestedEntityResult.ObjectId is the one owned by the block definition. That means you have to compute the transformation matrix from the block definition coordinate system to WCS using the BlockTransform property of each container (possibly more then one) and use this matrix to get the parameter (reversed matrix) and to convert the points to WCS (not reversed matrix).

        [CommandMethod("SSS")]
        public void cmd_SSS()
        {
            var doc = Application.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

                var nestedEntOpt = new PromptNestedEntityOptions("\nSelect segment");
                PromptNestedEntityResult nestedEntRes = ed.GetNestedEntity(nestedEntOpt);

                if (nestedEntRes.Status != PromptStatus.OK)
                    return;

            using (var tr = db.TransactionManager.StartTransaction())
            {
                if (nestedEntRes.ObjectId.ObjectClass == RXObject.GetClass(typeof(Polyline)))
                {
                    var pline = (Polyline)tr.GetObject(nestedEntRes.ObjectId, OpenMode.ForRead);
                    var pickedPt = nestedEntRes.PickedPoint.TransformBy(ed.CurrentUserCoordinateSystem);

                    // compute the polyline transformation matrix
                    var xform = Matrix3d.Identity;
                    foreach (ObjectId id in nestedEntRes.GetContainers())
                    {
                        var br = (BlockReference)tr.GetObject(id, OpenMode.ForRead);
                        xform *= br.BlockTransform;
                    }

                    // convert the picked point in the block definition coordinate system
                    pickedPt = pickedPt.TransformBy(xform.Inverse());
                    var pointOnPline = pline.GetClosestPointTo(pickedPt, false);
                    double paramAtPoint = pline.GetParameterAtPoint(pointOnPline);
                    int segmentStartParam = (int)paramAtPoint;
                    int segmentEndParam = segmentStartParam + 1;
                    var segmentStartPoint = pline.GetPointAtParameter(segmentStartParam);
                    var segmentEndPoint = pline.GetPointAtParameter(segmentEndParam);

                    // convert the segment start and end points back to WCS
                    segmentStartPoint = segmentStartPoint.TransformBy(xform);
                    segmentEndPoint = segmentEndPoint.TransformBy(xform);

                    double radius = segmentStartPoint.DistanceTo(segmentEndPoint) / 10.0;
                    var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                    var circle = new Circle(segmentStartPoint, Vector3d.ZAxis, radius);
                    curSpace.AppendEntity(circle);
                    tr.AddNewlyCreatedDBObject(circle, true);
                    circle = new Circle(segmentEndPoint, Vector3d.ZAxis, radius);
                    curSpace.AppendEntity(circle);
                    tr.AddNewlyCreatedDBObject(circle, true);

                    tr.Commit();
                }
            }
        }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub