Profile.Difference() Exception 'Unable to clean up bad polygon resulting from a polygon boolean operation'
protoGenSoftware opened this issue · 2 comments
Describe the bug
Exception as stated in the title. The polygons are created using offsets from a polyline, then divided from extensions. The resulting divided polygons are then fed into the Difference() method with the intent to remove the middle portion of the polygon.
To Reproduce
Use the polygons in this code to reproduce the problem
var model = new Model();
var deserializedList = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Polygon>>("[{\"discriminator\":\"Elements.Geometry.Polygon\",\"Vertices\":[{\"X\":55.111379557489,\"Y\":-41.62452252843075,\"Z\":0.0},{\"X\":40.31819221050546,\"Y\":-56.41770987541429,\"Z\":0.0},{\"X\":81.7767669252342,\"Y\":-111.06787576729614,\"Z\":0.0},{\"X\":98.28933388079639,\"Y\":-98.54115275215467,\"Z\":0.0}]},{\"discriminator\":\"Elements.Geometry.Polygon\",\"Vertices\":[{\"X\":132.15718134116867,\"Y\":35.421279255248876,\"Z\":0.0},{\"X\":117.50140335158372,\"Y\":50.07705724483371,\"Z\":0.0},{\"X\":42.46720873704877,\"Y\":-24.95713736970123,\"Z\":0.0},{\"X\":55.111379557489,\"Y\":-41.62452252843075,\"Z\":0.0}]},{\"discriminator\":\"Elements.Geometry.Polygon\",\"Vertices\":[{\"X\":42.46720873704877,\"Y\":-24.95713736970123,\"Z\":0.0},{\"X\":27.674021390065235,\"Y\":-39.750324716684744,\"Z\":0.0},{\"X\":40.31819221050546,\"Y\":-56.41770987541429,\"Z\":0.0},{\"X\":55.111379557489,\"Y\":-41.62452252843075,\"Z\":0.0}]},{\"discriminator\":\"Elements.Geometry.Polygon\",\"Vertices\":[{\"X\":206.5874534112776,\"Y\":-39.008992814859354,\"Z\":0.0},{\"X\":221.2432314008624,\"Y\":-24.35321482527442,\"Z\":0.0},{\"X\":146.8129593307535,\"Y\":50.07705724483374,\"Z\":0.0},{\"X\":132.15718134116867,\"Y\":35.421279255248876,\"Z\":0.0}]},{\"discriminator\":\"Elements.Geometry.Polygon\",\"Vertices\":[{\"X\":146.8129593307535,\"Y\":50.07705724483374,\"Z\":0.0},{\"X\":132.15718134116858,\"Y\":64.73283523441854,\"Z\":0.0},{\"X\":117.50140335158372,\"Y\":50.07705724483371,\"Z\":0.0},{\"X\":132.15718134116867,\"Y\":35.421279255248876,\"Z\":0.0}]}]");
var deserializedPolygon = Newtonsoft.Json.JsonConvert.DeserializeObject<Polygon>(
"{\"discriminator\":\"Elements.Geometry.Polygon\",\"Vertices\":[{\"X\":91.00437787098954,\"Y\":-104.0676482000112,\"Z\":0.0},{\"X\":43.00666271891972,\"Y\":-40.7976705526605,\"Z\":0.0},{\"X\":132.1571813411686,\"Y\":48.35284806958845,\"Z\":0.0},{\"X\":213.0532378184474,\"Y\":-32.54320840768953,\"Z\":0.0},{\"X\":214.77744699369268,\"Y\":-30.818999232444238,\"Z\":0.0},{\"X\":132.1571813411686,\"Y\":51.801266420079,\"Z\":0.0},{\"X\":39.77873822863455,\"Y\":-40.577176692455055,\"Z\":0.0},{\"X\":89.06172293504105,\"Y\":-105.54138031943961,\"Z\":0.0}]}");
var floor1 = new Floor(deserializedPolygon, 0.1, new Transform(0,0,0.1), new Material("Red", Colors.Red));
model.AddElement(floor1);
foreach(var poly in deserializedList)
{
var floor = new Floor(poly, 0.1, new Transform(0,0,-0.1));
model.AddElement(floor);
model.AddElements(new ModelLines(poly.Segments()));
}
var booleanPolygons = new List<Profile>();
booleanPolygons.AddRange(Profile.Difference(deserializedList.Select(x=>new Profile(x)), new[] {new Profile(deserializedPolygon)}));
return model;
Expected behavior
The red polygon area should be removed from the gray polygons.
Screenshots
Polygons shown before the Difference()
Desktop (please complete the following information):
- OS: Windows 10
Additional context
Trying to remove the "corridor" portion of the polygon from the "unit" divisions. This code does work for other geometry produced from arbitrary polyline definitions, so it makes me think this is a tolerance issue. Though overriding the tolerance does not fix the problem.
I noticed that this does work if I take those red polygon ends and extend them past the edge. I believe that the bad geometry is produced at the shared edge of the inside and outside polygons.
@ikeough Difference produced single loop of points representing two polygons that should left after but connected by an edge. Polygon constructor considers this as self intersection and it leads to exception. There is Polygon.SplitInternalLoops that fixes this but it has no opportunity to be run since exception is thrown earlier than it's called in ToProfiles. Note that this issue can also happen for Polygon difference, not only for profiles.
I can fix this for Polyline and Profile in one of two ways:
- Move code around so split happens before Polygon construction.
- Change validation code, so this configuration is not considered as self intersection and can be fixed by downstream code.