We recently spotted a post on web and reviewed the code there.
Testing whether a point is inside or above an AutoCAD solid using .NET
But found the AutoCAD API used there was both overkill and error prone. Very likely, tricky issues would be introduced in by the BREP API usage, or even worse, random crashes might happen as covered by a few articles already. Here are two more relevant ones.
.NET Crash AutoCAD: #10 – Sooner If Explicitly Disposing of BRep Objects (Disposable)
.NET Crash AutoCAD: #11 – Later If Not Disposing of BRep Objects (Disposable)
Is there a reliable approach to make the same done then?
Yes, there is, and in fact, easier. The basic idea is to use the simple but functional Solid3d.ProjectOnToSolid method. Here we go.
public static class PointAndSolid3d
{
public enum Relation
{
Above,
Within,
Below,
Beside,
}
public static Relation RelateTo(this Solid3d solid, Point3d pt)
{
try
{
DBPoint dbPt = new DBPoint(pt);
Entity[] ents = solid.ProjectOnToSolid(dbPt, Vector3d.ZAxis);
bool hasEnts = ents != null && ents.Count() == 2;
Vector3d vec1 = (pt - ((DBPoint)ents[0]).Position).GetNormal();
Vector3d vec2 = (pt - ((DBPoint)ents[1]).Position).GetNormal();
return vec1 != vec2 ?
Relation.Within : vec1.IsEqualTo(Vector3d.ZAxis) ?
Relation.Above : Relation.Below;
}
catch (Autodesk.AutoCAD.Runtime.Exception ex)
{
if (ex.ErrorStatus == ErrorStatus.GeneralModelingFailure)
return Relation.Beside;
else
throw;
}
catch
{
throw;
}
}
[CommandMethod("TestPointAndSolid3dRelation")]
public static void TestPointAndSolid3dRelation_Method()
{
Editor editor = MgdAcApplication.DocumentManager.MdiActiveDocument.Editor;
Solid3d box = new Solid3d();
try
{
box.CreateBox(10, 20, 30);
Point3d pt1 = new Point3d(3, 5, 20);
Point3d pt2 = new Point3d(0, 0, 10);
Point3d pt3 = new Point3d(3, 5, -20);
Point3d pt4 = new Point3d(8, 12, 5);
editor.WriteMessage("Point {0} is {1} the box(10,20,30).\n", pt1.ToString(), box.RelateTo(pt1), box);
editor.WriteMessage("Point {0} is {1} the box(10,20,30).\n", pt2.ToString(), box.RelateTo(pt2), box);
editor.WriteMessage("Point {0} is {1} the box(10,20,30).\n", pt3.ToString(), box.RelateTo(pt3), box);
editor.WriteMessage("Point {0} is {1} the box(10,20,30).\n", pt4.ToString(), box.RelateTo(pt4), box);
}
catch (System.Exception ex)
{
editor.WriteMessage(ex.ToString());
}
finally
{
box.Dispose();
}
}
}
Here is the test result:
Command: TESTPOINTANDSOLID3DRELATION
Point (3,5,20) is Above the box(10,20,30).
Point (0,0,10) is Within the box(10,20,30).
Point (3,5,-20) is Below the box(10,20,30).
Point (8,12,5) is Beside the box(10,20,30).
As can be seen, this approach is pretty straightforward and the code is also much concise. Furthermore, two more relations (Below and Beside) are checked by the same code. The only matter was that the Solid3d.ProjectOnToSolid method threw out the GeneralModelingFailure exception in the fourth scenario, no projection entities being found. We expected null being simply returned or the entity array contained nothing in this situation. What about you?
Enjoy anyway!
By the way, the leading edge AutoCAD .NET Addin Wizard (AcadNetAddinWizard) helped create the test project and the test command automatically in only a moment.
Recent Comments