Analyzing the BUG in IntersectWith() - AutoCAD .Net API
One of the common tasks while solving
geometric problems in CAD environment is to find the intersection of two
geometric entities such as Lines, Polylines, Polygons (Closed Polyline in CAD),
Circle, Ellipse, Regions etc. Natural problems exist where a solution may solely
depend upon the intersection and the count of intersections.
A practical example where
intersection of geometric entities matters is Cutting a polygon into two parts. Another fundamental
problem in computational geometry, CAD, GIS, motion planning and Computer
Vision is to detect whether a given point lies inside or outside the given
polygon or plane. The simple solution to this problem is to test how many times
a ray starting from the given point extends towards the edges of a polygon. An
even number of intersections implies that the point is outside of the polygon
and vice versa.
Intersections are sometimes also referred when testing to detect overlap of two polygons. In such a case, the region of intersection may be computed instead of a point or points.
The AutoCAD .NET API enables programmers to manipulate
the application and drawing files programmatically with the assemblies or
libraries that are exposed. With these objects exposed, they can be accessed by
many different programming languages such as C# VB.Net and environments such as
visual studio.
Autodesk.AutoCAD.DatabaseServices
Namespace implements
IntersectWith method to populate a
Point3dCollection object with intersection points.
IntersectWith() method
plays a vital role to trim the geometric objects as there is NO trim()
like method in API. The geometry of the object to be trimmed is needed to be
modified using intersection points. Similarly, IntersectWith() method is
also used to extend the linear geometric objects. However, Extend() method is
provided in API, but there are some situations where IntersectWith() method is highly
useful and only solution to extend the
linear geometric objects.
The second argument of IntersectWith()
method provides the type of the intersection as ExtendBoth, ExtendArgument,
ExtendThis
and OnBothOperands.
With the significance of intersection
in computational geometry and its use in CAD automation explained, it may also
be realized that a programmer may have to call IntersectWith() method
whenever needed.
Recently, I was working on an
algorithm to divide a polygon into multiple parts using AutoCAD .Net API. The
algorithm was using sort of SweepLine technique calling IntersectWith()
method frequently in iterations. Apparently the algorithm was simple, free from
any logical error and well implemented but it was failing in most cases. Interestingly, there was no exception raised
but rather the program entered into an infinite loop and ultimately the AutoCAD
application had to be forcefully ended from the Windows Task Manager. Debugging
the code was hectic and a quite frustrating effort which took more than a
month. The BUG was revealed in IntersectWith() method of Autodesk.AutoCAD.DatabaseServices
Namespace. As shocking as it may seem, the code below demonstrates the bug.
[CommandMethod("IntersectionTest")]
public static void IntersectionTest()
{
Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
// First Polyline
Polyline pl1 = new Polyline();
pl1.AddVertexAt(0, new Point2d(600097.3438, 494820.3637), 0, 0, 0);
pl1.AddVertexAt(0, new Point2d(600101.7191, 494825.6028), 0, 0, 0);
pl1.AddVertexAt(0, new Point2d(600107.4447, 494835.9176), 0, 0, 0);
// 2nd Polyline
Polyline pl2 = new Polyline();
pl2.AddVertexAt(0, new Point2d(600110.2043, 494822.9429), 0, 0, 0);
pl2.AddVertexAt(0, new Point2d(600096.5547, 494827.2256), 0, 0, 0);
// Intersection Points Collection
Point3dCollection intPoints = new Point3dCollection();
pl1.IntersectWith(pl2, Intersect.OnBothOperands, intPoints, IntPtr.Zero, IntPtr.Zero);
ed.WriteMessage("\nNo. Of Intersection Points: {0}", intPoints.Count);
for (int i=0; i < intPoints.Count; i++)
{
ed.WriteMessage("\n Point No. {0} X:{1} Y:{2}", i.ToString(), intPoints[i].X, intPoints[i].Y);
}
}
The coordinates of two polyline objects (pl1 and pl2) when plotted in CAD seems as below:
The code given above, when compiled, computes
the intersection points and stores them in intPoints Points3DCollection. It is
evident from the given geometry of both polylines that there should be a single
point of intersection. On the contrary, the output returns two intersection
points as shown below.
The only explanation for this second
point computed using the AutoCAD API is due to presence of a bug in it. Some interesting observations from trials are
as follows:
· It returns one additional fake
intersection point
· The additional fake intersection
point is NOT any vertex of intersecting objects.
· The code may return different output by
moving the polylines to any other location.
Significance
of the issue:
Recall the starting paragraphs of
this blog. The redundant fake intersection point may create serious issues in
case of detecting whether a point is inside a polygon or not. Similarly, in
case of computing region of intersection (overlaps) between two polygons, the
IntersectWith method in AutoCAD .Net API will yield undesired results.
The Way Forward:
It is quite surprising that this bug
exists in all versions of AutoCAD .Net API (from v2007 to v2021). It is quite mandatory for Autodesk to notice
this bug and fix it. Until, the release of any update or patch, the programmer
may have to handle it by writing extra lines of the code to check the number of
intersections whenever IntersectWith method is called.
Open Design Alliance (ODA) offers
other convenient object oriented .Net API for processing DWG and DXF. Many
industry driven CAD packages such as BricsCAD,
ZwSoft ZWCAD, ProgeCAD, CADMATE, NanoCAD
etc expose functionality for use by managed code built on the .NET Common
Language Runtime (CLR) platform. The Teigha library by ODA implements IntersectWith method via Teigha.DatabaseServices Namespace with the same number of arguments and data types to populate
a Point3dCollection object with intersection points.
The same code was implemented using
BricsCAD .Net API. It returned a single point of intersection as below.
The objective of this blog is not to
discriminate or defame any product rather it aims to help
programmers/developers to handle run time errors while writing code for geometric
intersections using AutoCAD .Net API.
Same thing happens when using coordinates 500 000,6 000 000 and use returned point from IntersectWith to GetClosestPointTo: solution is to transform objects to 0,0.
ReplyDelete
DeleteThanks for your comment.
The best option is to check for the Duplicate Points (within some tolerance) in 3D Point Collection populated by IntersectWith method and remove the duplicates.