Jeff H raised another good point about using the Curve.GetDistanceAtParameter and Curve.GetParameterAtPoint. Should we check whether the point is on the Curve or not inside the GetLength help method or outside of it?
It is obvious that we have to do so. Otherwise, there is no way for the Curve.GetDistanceAtParameter and Curve.GetParameterAtPoint methods to behave as expected. In worse scenarios, it will throw out exceptions.
In terms of doing so inside the GetLength or outside of it, it’s more like a preference for each person. For me, I’d like to do it outside. Did not mention last time that the points picked through the Editor.GetPoint calls are in UCS instead of WCS, thus we also need to do transformations for those points before passing them to the GetLength method.
In this post, however, I’d like to point out something about the possible inconsistencies among the ‘IsOn’ point which might be returned by any help methods, the ‘ClosestPoint’ returned by the Curve.GetClosestPointTo() call, and the really acceptable point by the Curve.GetParameterAtPoint method.
If a loose tolerance such as 10e-6 is used in a method such as Curve.IsOn(Point3d ) to check whether a point is on a curve or not, and the same point is used (if the method returns true) in the Curve.GetParameterAtPoint call, it will most likely fail. That might just explain why the Leader entity did not work with the code/command last time though the ‘Nearest’ object snap mode was used to make sure the point was on the curve from AutoCAD point of view. It’s likely that the AutoCAD ‘Nearest’ snapping feature returned a loose point particularly for that Leader at that moment but the point was not accepted by the Curve.GetParameterAtPoint call.
It does seem that the Curve.GetParameterAtPoint method likes the points that are returned by the Curve.GetClosestPointTo call and would think those points are really on the Curve itself. So, to make the ‘IsOn’ check and even the AutoCAD 'Nearest' object snapping consistent with the GetParameterAtPoint call, the following improved version looks better.
// Make sure the pt1 and pt2 are on the Curve before calling this method.
public static double GetLength2(Curve ent, Point3d pt1, Point3d pt2)
{
if (ent == null)
throw new ArgumentNullException("The passed in Curve is null.");
double dist1 = ent.GetDistanceAtParameter(ent.GetParameterAtPoint(ent.GetClosestPointTo(pt1, false)));
double dist2 = ent.GetDistanceAtParameter(ent.GetParameterAtPoint(ent.GetClosestPointTo(pt2, false)));
return Math.Abs(dist1 - dist2);
}
[CommandMethod("GetLengthGoodUseCase_Test")]
public static void GetLengthGoodUseCase_Test_Method()
{
Editor ed = MgdAcApplication.DocumentManager.MdiActiveDocument.Editor;
Database db = HostApplicationServices.WorkingDatabase;
Matrix3d ucs = ed.CurrentUserCoordinateSystem;
try
{
PromptEntityResult selRes = ed.GetEntity("\nPick a Curve entity");
PromptPointResult prPntRes1 = ed.GetPoint("\nPick a point on the Curve");
PromptPointResult prPntRes2 = ed.GetPoint("\nPick another point on the same Curve");
if (selRes.Status == PromptStatus.OK && prPntRes1.Status == PromptStatus.OK && prPntRes2.Status == PromptStatus.OK)
{
using (Transaction tr = db.TransactionManager.StartTransaction())
{
Entity ent = (Entity)tr.GetObject(selRes.ObjectId, OpenMode.ForRead);
ed.WriteMessage("\nThe length between the point {0} and the point {1}\n on the {2} is: {3}",
prPntRes1.Value.ToString(), prPntRes2.Value.ToString(),
ent.GetType().Name,
GetLength2(ent as Curve, prPntRes1.Value.TransformBy(ucs), prPntRes2.Value.TransformBy(ucs)));
tr.Commit();
}
}
}
catch (System.Exception ex)
{
ed.WriteMessage(ex.ToString());
}
}
The test command works with curves in UCS too this time. Here is the output of the various tests on a Leader.
Command: <Osnap on>
Command:
GETLENGTHGOODUSECASE_TEST
Pick a Curve entity:
Pick a point on the Curve:
Pick another point on the same Curve:
The length between the point
(371.019567729215,-309.111982835449,1.4210854715202E-14) and the point
(388.955611856188,-76.7055125236963,2.66453525910038E-15)
on the Leader is: 329.975459399009
Command: GETLENGTHGOODUSECASE_TEST
Pick a Curve entity:
Pick a point on the Curve:
Pick another point on the same Curve:
The length between the point
(394.423085665832,-234.385762120615,-1.4210854715202E-14) and the point
(455.177991950867,-131.561754539638,1.77635683940025E-14)
on the Leader is: 160.495665038296
Command: GETLENGTHGOODUSECASE_TEST
Pick a Curve entity:
Pick a point on the Curve:
Pick another point on the same Curve:
The length between the point
(362.987807793588,-334.756976348974,2.8421709430404E-14) and the point
(346.224188664124,-56.0500177294368,-2.0122792321331E-15)
on the Leader is: 404.308244636207
Command: GETLENGTHGOODUSECASE_TEST
Pick a Curve entity:
Pick a point on the Curve:
Pick another point on the same Curve:
The length between the point
(374.52095511761,-297.932234239449,2.8421709430404E-14) and the point
(442.794235969151,-102.730000757964,5.32907051820075E-15)
on the Leader is: 258.464595052049
The code/command works well with the Leader Curve too this time. The problem that was previously experienced has gone away!
The leading edge AutoCAD .NET Addin Wizard (AcadNetAddinWizard) provides project wizards in C#, VB.NET and CLI/Managed C++, and various item wizards such as Event Handlers, Command/LispFunction Definers, and Entity/Draw Jiggers in both C# and VB.NET, to help program AutoCAD addins.
Posted by: |