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

Polyline3d GetClosestPointTo, GetObjectSnapPoints

9 REPLIES 9
Reply
Message 1 of 10
absStructural
2178 Views, 9 Replies

Polyline3d GetClosestPointTo, GetObjectSnapPoints

I am trying to get a point on (or possibly extended from the end of) a 3D polyline closest to a specified point.  In the attached drawing, there is a 3D Polyline, and two nodes. 

 

In AutoCAD, if I draw a line from the node at 1239.817,994.9588,91.7498 perpendicular to the polyline, it snaps to (1239.8705, 999.9583, 91.6499) - which is the desired result.

 

The code below shows 3 methods of trying to obtain this result, but without success.  The output of this is:

 

pickedPt: (1239.8717322503,994.958757180007,91.7498303566326)
testPt1: (1234.21981294827,999.958333333333,91.7210574435876)
testPt2: (1239.87317003466,999.958333333333,92.2930159035884)
testPt3: (1234.21981294827,999.958333333333,91.7210574435876)
Snap Point Count: 503

 

So, the issue with Method 1 is that it does not extend the polyline.  Which led me to Method 2.

 

The issue with Method 2 is that it is not using the end of the polyline to determine the direction it should extend.

 

The issue with Method 3 is that it doesn't extend the polyline (the result is the same as Method 1).

 

Any suggestions?

 

public static void ClosestPl3dTest()
        {
            Document acDoc = Application.DocumentManager.MdiActiveDocument;
            Editor acEd = acDoc.Editor;

            PromptEntityResult per  = acEd.GetEntity("Select Polyline3d");
            if (per.Status == PromptStatus.OK)
            {
                Polyline3d pl = null;
                using (Transaction acTrans = acDoc.TransactionManager.StartTransaction())
                {
                    DBObject obj = acTrans.GetObject(per.ObjectId, OpenMode.ForRead);
                    if (obj is Polyline3d)
                    {
                        pl = (Polyline3d)obj;
                    }
                    acTrans.Commit();
                }
                if (pl != null)
                {
                    PromptPointResult ppr = acEd.GetPoint("Select point");
                    if (ppr.Status == PromptStatus.OK)
                    {
                        Point3d pickedPt = ppr.Value;

                        // Method 1
                        Point3d testPt1 = pl.GetClosestPointTo(pickedPt, false);

                        // Method 2
                        Point3d testPt2 = pl.GetClosestPointTo(pickedPt, true);
                        
                        // Method 3
                        Point3dCollection ptColl = new Point3dCollection();
                        IntegerCollection intColl = new IntegerCollection();
                        Matrix3d identity = Matrix3d.Identity;
                        pl.GetObjectSnapPoints(ObjectSnapModes.ModePerpendicular, 1, pickedPt, pickedPt, identity, ptColl, intColl);
                        
                        Point3d[] array = new Point3d[ptColl.Count];
                        ptColl.CopyTo(array, 0);

                        // return the closest result
                        Point3d testPt3 = array.OrderBy(pt => pt.DistanceTo(pickedPt)).First();

                        acEd.WriteMessage("\npickedPt: " + pickedPt.ToString() + "\n");
                        acEd.WriteMessage("testPt1: " + testPt1.ToString() + "\n");
                        acEd.WriteMessage("testPt2: " + testPt2.ToString() + "\n");
                        acEd.WriteMessage("testPt3: " + testPt3.ToString() + "\n");
                        acEd.WriteMessage("Snap Point Count: " + ptColl.Count + "\n");
                    }
                }
            }
        }

 

9 REPLIES 9
Message 2 of 10
Hallex
in reply to: absStructural

Have not tested your code, just a guess, maybe you need to

convert the retrieved point to UCS

 

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 3 of 10
absStructural
in reply to: Hallex

This was just written as a small test - and it is assumed the UCS is World (which it was when I tested it).  Agreed, though, in a complete solution - this would be done.

Message 4 of 10

Any other thoughts?

Message 5 of 10

It would also appear that all of the 503 points that are populated in GetObjectSnapPoints are just vertices of the Polyline3d.  This doesn't seem right.

Message 6 of 10
Hallex
in reply to: absStructural

Not sure about what is your goal,

try to change snap mode like this

pl.GetObjectSnapPoints(ObjectSnapModes.ModeNear, 1, pickedPt, pickedPt, identity, ptColl, intColl);

 

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 7 of 10
absStructural
in reply to: Hallex

As stated in my original post:

 

In AutoCAD, if I draw a line from the node at 1239.817,994.9588,91.7498 perpendicular to the polyline, it snaps to (1239.8705, 999.9583, 91.6499) - which is the desired result.

 

So, that's the goal.

 

This point is off the end of the Polyline - which is what I want.  Using OSnap near would not make any sense.

Message 8 of 10
fenton.webb
in reply to: absStructural

It looks like the API version doesn't extend the Pline to gain the perp point like the Ui does. I suggest you either extend the ends of the in memory polyline and then carry out the GetObjectSnapPoints(), or used acedComand() to emulate the UI.




Fenton Webb
AutoCAD Engineering
Autodesk

Message 9 of 10

GetOsnapPoints() wasn't really intended to be used directly, it was designed to be called by AutoCAD in the process of interactively acquiring an object snap point. While it's possible to set up the parameters to those required to use the method, that isn't as simple as it may appear.

 

For your objective, this should be all you need:

 

   Autodesk.AutoCAD.EditorInput.Editor.Snap( string modes, Point3d point );

 

It is the managed wrapper for the LISP (osnap) function. For PERP and TAN osnap modes, you need to first set the LASTPOINT system variable to the point that those two modes use as a parameter.

Message 10 of 10

That method works; but with two issues I can see. 

 

1. The polyline has to be in the database (not just in memory) - though I'm okay with that.

2. This method doesn't guaranty that the desired polyline will be snapped to.  If there is another entity close by, it could very well snap to it.

 

What I ended up doing is getting a point using polyline.GetClosestPointTo(point, false).  If that point is the start point or end point of the polyline, then I create a line (in memory) from the start or end using the first derivative vector.  I then use line.GetClosestPointTo(point, true).

 

Is it clean?  No.  Do I like it?  Not really.  But, it works.

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