We discussed and demonstrated previously about getting the ‘length’ of Curve like entities such as Line, Arc, and Polyline using the Curve.GetDistanceAtParameter API. The ‘length’ is quoted here because for some entities that are also derived from the Curve class the whole length is officially called something else such as circumference for Circle and Ellipse.
Let’s put aside all these concept stuffs here and focus on code.
Jeff H raised a couple of good points in the comments about the code that was presented in the last post.
public static double GetLength(Curve ent)
{
if (ent == null) return -1;
return ent.GetDistanceAtParameter(ent.EndParam)
- ent.GetDistanceAtParameter(ent.StartParam);
}
[CommandMethod("GetLength_Test")]
public static void GetLength_Test_Method()
{
Editor ed = MgdAcApplication.DocumentManager.MdiActiveDocument.Editor;
Database db = HostApplicationServices.WorkingDatabase;
try
{
PromptEntityResult selRes = ed.GetEntity("\nPick a Curve entity:");
if (selRes.Status == PromptStatus.OK)
{
using(Transaction tr = db.TransactionManager.StartTransaction())
{
Entity ent = (Entity)tr.GetObject(selRes.ObjectId, OpenMode.ForRead);
ed.WriteMessage("\nThe length of the {0} is: {1}", ent.GetType().Name, GetLength(ent as Curve));
tr.Commit();
}
}
}
catch (System.Exception ex)
{
ed.WriteMessage(ex.ToString());
}
}
“Any reason for not testing if Entity is a Curve before passing to GetLength function? Could you see problems arise if it was a Curve Type that was null?”
These apply to the test code, I think. Yes, checking the ‘ent’ variable is null or not obviously will make the code more reliable; checking if the ‘ent’ is ‘Curve’ or not before passing it to the GetLength call is another good idea. Fortunately, the first case rarely happens and even if it does, it will be gotcha! Whether the ‘ent’ is not a Curve or it is a Curve null has already been addressed inside the GetLength() function. As mentioned previously, it simply “returns -1 indicating something wrong”.
In terms of the version from Tony Tanzillo, it is good too.
public static double GetLength(this Curve curve)
{
try
{
return Math.Abs(curve.GetDistanceAtParameter(curve.EndParam) - curve.GetDistanceAtParameter(curve.StartParam));
}
catch
{
return double.PositiveInfinity;
}
}
It has quite different design though. First, it is designed as an extension method to the Curve class. Second, it tries to address the case of that the end distance is less than the start distance. Third, it assumes whenever an exception occurs the ‘length’ must be positive infinity.
All these sound reasonable enough, I would say. His concise code should work reliably judging from pure coding perspective and cover almost all possible senarios both existing and future (as expected or not).
However, there might still be something deserving to think about again. Not to appear picky or to offend anybody. If the ‘curve’ were null, what would happen? Was it really necessary to absolute the distance difference in this particular case? Was it good enough to assume the length was always positive infinity even if the AutoCAD API itself might think ‘eNotApplicable’ sometimes? Wasn't try/catch expensive? Would not the Extension Method confuse people on Circle or Ellipse entities for their Circumference property?
With these said, what about the following version?
public static double GetLength2(Curve ent)
{
if (ent == null)
throw new ArgumentNullException("Curve is null");
if (ent is Ray || ent is Xline)
return double.PositiveInfinity;
return ent.GetDistanceAtParameter(ent.EndParam) - ent.GetDistanceAtParameter(ent.StartParam);
}
It addresses the null argument problem and the Ray and Xline cases particularly, in which the length makes sense to be positive infinity. For all other cases, it returns the distance difference from start to end. In case the StartParam, EndParam, or GetDistanceAtParameter does not apply to the particular Cuve, the default exception from the API itself will be relayed instead of being digested silently. If the end distance is less than the start distance, the negative value will be returned indicating the API design or implementation issue. Of course, the method can be refined further with more testing being done and more findings coming out of surface.
As also mentioned previously, it does not seem a good idea to get the Curve length this way due to the simple fact that the ‘length’ concept does not apply well to Circles for example and the start or end parameter does not apply to Xline for another example. Have been wondering why there was such a need! May I know?
The good use case for the Curve.GetDistanceAtParameter API should be to calculate a partial length out from two points on a complex Curve (e.g. an Ellipse or a Spline) since there are no straightforward properties or methods in this case and the equation here is not that clear as the distance between two points or the circle circumference.
Thanks to Jeff H again for helping to make these clearer. Once again, let’s all strive to DO better!
The leading edge AutoCAD .NET Addin Wizard (AcadNetAddinWizard) provides various project wizards, item wizards, coders and widgets to help program AutoCAD .NET addins.
I modified that code and was not Tonys original version, your post about Eulers constant was what sparked the idea and seemed to make sense to return Infinity for a infinite length.
I actully thought about doing something similar to what you have but could not decide and thought just post as is and wait since you would have better insight.
Thanks again!
Posted by: JeffH | 10/16/2012 at 01:05 AM