Is there a way to get information on a selected Polyline segment

Is there a way to get information on a selected Polyline segment

nshupeFMPE3
Advocate Advocate
1,974 Views
14 Replies
Message 1 of 15

Is there a way to get information on a selected Polyline segment

nshupeFMPE3
Advocate
Advocate

You can use CTRL + Click on a segment of a polyline in order to highlight it. But is there any way to get information about that highlighted segment? Even just being able to get the length of that line segment could be useful. 

Thanks for any help.


0 Likes
Accepted solutions (2)
1,975 Views
14 Replies
Replies (14)
Message 2 of 15

norman.yuan
Mentor
Mentor

With Polyline.GetArcSegment[2d]At()/GetSegment[2d]At() method in conjunction with Polyline.GetSegmentType(), you can get the information you need.

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 3 of 15

Ed__Jobe
Mentor
Mentor

@nshupeFMPE3 wrote:

You can use CTRL + Click on a segment of a polyline in order to highlight it. But is there any way to get information about that highlighted segment? Even just being able to get the length of that line segment could be useful.


What do you need this for? Are you using it as part of a program or just need to know the length? Once you have it selected as you noted, the Properties palette has all that info.

Ed


Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
How to post your code.

EESignature

0 Likes
Message 4 of 15

nshupeFMPE3
Advocate
Advocate

Thank you for the help, one question I still have though is how would I know which segment I am interested in? I see that I can iterate through all the segments that way, but if I'm trying to gather information from a particular segment that was selected? I'm unclear on that part

0 Likes
Message 5 of 15

nshupeFMPE3
Advocate
Advocate

@Ed__Jobe I need to be able to do more with the info, I just wanted to make as simple a question as to not get to far in the weeds. 

But what I'd like would be a user to be able to select a segement from a polyline, and then (and this is my problem to figure out next) keep track of that segment so that I can assign some data that pertains to that segment. For instance a use would select a segment, run the command, and that segments would be assigned "north" or some other piece of data that I need. 

When I select a single segment and then look at the properties palette, it still shows Length, Area, etc for the entire polyline, not just that segment

0 Likes
Message 6 of 15

norman.yuan
Mentor
Mentor

Your question is quite vague: why you do not know which segment is the target while you are writing code? You should explain under what circumstance you need to determine the target segment. For example, when your code ask user to select polyline y calling Editor.GetEntity() method, which user required user to pick a polyline and returns a PromptEntityResult object (if the PromptStatus is PromptStatus.OK), which is not only includes an ObjectId of the selected entity/polyline, but also includes a property "PickedPoint", indicating where the user is picked. You can use the point to determine which segment of the polyline is picked. Note the point is the center of the mouse cursor, which is not necessarily exactly on the polyline. You need to call Polyline.GetClosestPoint() method to decide where exactly the segment is picked.

 

 Again, if it is not your code to ask user to select a polyline, then you really need to explain VERY WELL your case as why/when/how a polyline is selected before you want to identify a segment of the polyline.

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 7 of 15

Ed__Jobe
Mentor
Mentor

That might be a problem. A pline stores vertices, not segments. There are no 'properties' for a segment. You would have to calculate the length as a vector vertices(0)-vertices(1). If you wanted to store xdata, I think you have to do it at the entity level. I don't think you can attach it to a vertex. If the first segment is from vertex 0 to vertex 1, then you could attach xdata to the pline as a dotted pair ("0-1" . 1050).

Ed


Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
How to post your code.

EESignature

0 Likes
Message 8 of 15

nshupeFMPE3
Advocate
Advocate

@norman.yuan 

Thank you for the insight. I had forgotten or did not know about the "PickedPoint" property. I think with that and the method you described I could determine which segment of the line the user was selecting. 

My apologies for the vagueness, it was not my intent. I wanted to keep the question simple as to not bore or complicate with implementation details. 

My goal is to have a user select a polyline (and hopefully thanks to the suggestion determine the segment that was selected); In order to determine the length of that segment and store that data along with other data for our use case. And getting the segment was simply the first step. 

0 Likes
Message 9 of 15

nshupeFMPE3
Advocate
Advocate

Using this code I was able to get the index for the segment that was clicked on by the user. Which in turn means I was able to get the LineSegment3d object and print out the length, a good start!

[CommandMethod("SegmentTest")]
public void SegmentTest()
{
    Document doc = Application.DocumentManager.MdiActiveDocument;
    Database db = doc.Database;
    Editor ed = doc.Editor;
    
    var selection = ed.GetEntity(new PromptEntityOptions($"\nSelect CFA line:")
    {
        AllowNone = false,
        AllowObjectOnLockedLayer = false,
    });

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

    using (Transaction tr = db.TransactionManager.StartOpenCloseTransaction())
    using(Polyline pline = tr.GetObject(selection.ObjectId, OpenMode.ForRead) as Polyline)
    {
        var nearest = pline.GetClosestPointTo(selection.PickedPoint, true);

        var segmentIndex = pline.FindSegmentIndex(nearest);

        if (segmentIndex < 0) return;

        var segmentType = pline.GetSegmentType(segmentIndex);

        switch (segmentType)
        {
            case SegmentType.Line:
                var segment = pline.GetLineSegmentAt(segmentIndex);
                Active.WriteMessage($"{segment.Length}");
                break;
            case SegmentType.Arc:
                break;
            case SegmentType.Coincident:
                break;
            case SegmentType.Point:
                break;
            case SegmentType.Empty:
                break;
            default:
                break;
        }
    }


}

 

public static int FindSegmentIndex(this Polyline polyline, Point3d point)
{
    for (int i = 0; i < polyline.NumberOfVertices - 1; i++)
    {
        // Get the start and end points of the current segment
        Point3d startPoint = polyline.GetPoint3dAt(i);
        Point3d endPoint = polyline.GetPoint3dAt(i + 1);

        // Check if the closest point lies on this segment
        if (point.IsPointBetween(startPoint, endPoint))
        {
            return i; // Return the index of the segment
        }
    }

    // If no segment is found (which shouldn't happen), return -1
    return -1;
}
public static bool IsPointBetween(this Point3d vertex, Point3d point1, Point3d point2)
{
    // Check if the vertex is collinear with point1 and point2
    Vector3d mainVector = point2 - point1;
    Vector3d vertexVector = vertex - point1;

    // Calculate the cross product to check collinearity
    double crossProduct = mainVector.CrossProduct(vertexVector).Length;
    if (crossProduct > 1e-6) // Allowing a small tolerance for floating-point precision
        return false;

    // Check if the vertex is within the bounds of the segment
    double dotProduct = mainVector.DotProduct(vertexVector);
    if (dotProduct < 0 || dotProduct > mainVector.LengthSqrd)
        return false;

    return true;
}



0 Likes
Message 10 of 15

norman.yuan
Mentor
Mentor
Accepted solution

The code for getting segment index according to the point on curve/polyline could be much simple (not necessarily use less computer power to compute):

 

var index=Convert.ToInt32(Math.Floor(pline.GetParamterAtPoint(ptOnPolyline)));

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 11 of 15

ActivistInvestor
Mentor
Mentor

All of that code to claim you solved the problem?

 

It only takes a single Line of code to find the index of a polyline segment given a point on it, as @norman.yuan showed.

0 Likes
Message 12 of 15

nshupeFMPE3
Advocate
Advocate

My apologies @ActivistInvestor and @norman.yuan 

I thought I had a solution so I shared it. Given I was unaware of the one liner that was shared, I was simply trying to share a solution that worked so that I didn't need to take up any more time from you guys.

0 Likes
Message 13 of 15

kerry_w_brown
Advisor
Advisor

@nshupeFMPE3 wrote:

. . .
I thought I had a solution so I shared it. Given I was unaware of the one liner that was shared, I was simply trying to share a solution that worked so that I didn't need to take up any more time from you guys.


 

don't be too sorry that you posted it ; be happy that you may have learned something from Tony and Norman.

at least your posting was in the spirit of peer to peer support.

 

consider posting your revised code incorporating your new knowledge, so that others may learn.

then mark that post as  your solution  🙂

 

Regards,

 

 

 


// Called Kerry or kdub in my other life.

Everything will work just as you expect it to, unless your expectations are incorrect. ~ kdub
Sometimes the question is more important than the answer. ~ kdub

NZST UTC+12 : class keyThumper<T> : Lazy<T>;      another  Swamper
0 Likes
Message 14 of 15

_gile
Consultant
Consultant
Accepted solution

Here's an example which works whatever the current UCS (PromptEntityResult.PickedPoint is returned in UCS coordinates) and whatever the current view (by using this overload of Curve.GetClosestPointTo which projects the curve onto the plane defined by the supplied Point3d and Vector3d).

public class Commands
{
    [CommandMethod("TEST")]
    public void Test()
    {
        var doc = Application.DocumentManager.MdiActiveDocument;
        var db = doc.Database;
        var ed = doc.Editor;

        var options = new PromptEntityOptions("\nSelect a polyline segment: ");
        options.SetRejectMessage("\nSelected object is not a polyline.");
        options.AddAllowedClass(typeof(Polyline), true);
        var result = ed.GetEntity(options);
        if (result.Status != PromptStatus.OK)
            return;
        var id = result.ObjectId;
        var pickedPoint = result.PickedPoint.TransformBy(ed.CurrentUserCoordinateSystem);

        using (var tr = new OpenCloseTransaction())
        {
            var pline = (Polyline)tr.GetObject(id, OpenMode.ForRead);

            using (var view = ed.GetCurrentView())
            {
                var pointOnPline = pline.GetClosestPointTo(pickedPoint, view.ViewDirection, false);
                int index = (int)pline.GetParameterAtPoint(pointOnPline);

                double GetArcLength(CircularArc2d arc) =>
                    arc.GetLength(arc.GetParameterOf(arc.StartPoint), arc.GetParameterOf(arc.EndPoint));

                string message;
                switch (pline.GetSegmentType(index))
                {
                    case SegmentType.Line:
                        message = $"\nLine segment Index: {index} Length: {pline.GetLineSegment2dAt(index).Length:0.00}";
                        break;
                    case SegmentType.Arc:
                        message = $"\nArc segment Index: {index} Length: {GetArcLength(pline.GetArcSegment2dAt(index)):0.00}";
                        break;
                    default:
                        message = "\nInvalid segment";
                        break;
                }
                ed.WriteMessage(message);
            }

            tr.Commit();
        }
    }

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 15 of 15

nshupeFMPE3
Advocate
Advocate

Thank you @kerry_w_brown  @norman.yuan @ActivistInvestor @_gile for the help. I've marked Giles as the solution, as it covers a wide range of scenarios and will be what I will be using. I really need to learn about using/manipulating the coordinate system!

0 Likes