Update: All good. Indeed Clipper2Lib works now for the "union of tiles" case described above. The glitches I saw where related to a minor bug in the tessellation library I use (fixed now). Combination of those glitches and the fact that Clipper2Lib does (not yet) merge touching polygons in the solution threw me off. Congrats: that is a major improvement to Clipper1! Bold red outline in the attached picture indicates the union solution polygon.
Update: All good. Indeed Clipper2Lib works now for the "union of tiles" case described above. The glitches I saw where related to a minor bug in the tessellation library I use (fixed now). Combination of those glitches and the fact that Clipper2Lib does (not yet) merge touching polygons in the solution threw me off. Congrats: that is a major improvement to Clipper1!
EDITED (red outline was not result union but rather later process step clipping against earth features) Hmm...you might be right that it is technically correct. GREAT work! Clipping against the earth polygon features is a bit glitchy (see bottom left corner in Clipper2Lib picture)...need to investigate this further. See attachment. This is really difficult to reproduce and provide you samples with as the individual tiles are randomly "unified". A difficult situation is e.g. when 8 tiles have been...
Hmm...you might be right that it is technically "sort of" correct (there are some weird "spike-lines" instead of rectangles). See attachment. This is really difficult to reproduce and provide you samples with as the individual tiles are randomly "unified". A difficult situation is e.g. when 8 tiles have been merged in 3x3 tiles, and the last tile fills a hole in the middle vs top right corner tile missing. If you see in the attached picture something unexpected, maybe you are able to synthesize a...
Hmm...you might be right that it is technically "sort of" correct (there are some weird "spike-lines" instead of rectangles). See attachment. This is really difficult to reproduce and provide you samples with as the individual tiles are randomly "unified". A difficult situation is e.g. when 8 tiles have been merged in 3x3 tiles, and the last tile fills a hole in the middle vs top right corner tile missing. If you see in the attached picture something unexpected, maybe you are able to synthesize a...
Hmm...you might be right that it is technically "sort of" correct (there are some weird "spike-lines" instead of rectangles). See attachment. This is really difficult to reproduce and provide you samples with as the individual tiles are randomly "unified". A difficult situation is e.g. when 8 tiles have been merged in 3x3 tiles, and the last tile fills a hole in the middle vs top right corner tile missing. If you see in the attached picture something unexpected, maybe you are able to synthesize a...
However, I'm not sure if the line if (cnt < 3) return 0.0; is needed. It looks safe to remove (though I'm yet to test this). Indeed, in my framework the area function looks like this: public static double AreaNew(PathD path) { double a = default; for (int i = 0, cnt = path.Count; i < cnt; j = i++) a += (path[j].y + path[i].y) * (path[j].x - path[i].x) * 0.5; return a; } While the double version does not need any type casting, the integer version does need it and looks like this: public static double...
However, I'm not sure if the line if (cnt < 3) return 0.0; is needed. It looks safe to remove (though I'm yet to test this). Indeed, in my framework the area function looks like this: public static double AreaNew(PathD path) { double a = default; for (int i = 0, cnt = path.Count; i < cnt; j = i++) a += (path[j].y + path[i].y) * (path[j].x - path[i].x) * 0.5; return a; } While the double version does not need any type casting, the integer version does need it and looks like this: public static double...
However, I'm not sure if the line if (cnt < 3) return 0.0; is needed. It looks safe to remove (though I'm yet to test this). Indeed, in my framework the area function looks like this: public static double AreaNew(PathD path) { double a = default; for (int i = 0, cnt = path.Count; i < cnt; j = i++) a += (path[j].y + path[i].y) * (path[j].x - path[i].x) * 0.5; return a; } For for the integer version it would look like this: public static double AreaNew(Path64 path) { double a = default; for (int i...
Hi Angus, I got a use case where I need to create the union of individual quadratic tiles perfectly overlapping in their vertices. In my quest for a clipping algorithm that can do that perfectly without any glitches and edge cases, only Polybool worked so far. Hormann & Martinez & Clipper1 all work "sort off", but got plenty of edge cases rendering them unusable. Just tried if ClipperLib2 can do it...no luck. Is this something you would expect Clipper2Lib to ultimately be able to do, or is this a...
Hi Angus, I got a use case where I need to create the union of individual quadratic tiles perfectly overlapping in their vertices. In my quest for a clipping algorithm that can do that perfectly without any glitches and edge cases, only Polybool worked so far. Hormann & Martinez & Clippe1 all work "sort off", but got plenty of edge cases rendering them unusable. Just tried if ClipperLib2 can do it...no luck. Is this something you would expect Clipper2Lib to ultimately be able to do, or is this a...
However, I'm not sure if the line if (cnt < 3) return 0.0; is needed. It looks safe to remove (though I'm yet to test this). Indeed, in my framework the area function looks like this: public static double AreaNew(PathD path) { double a = default; for (int i = 0; i < cnt; j = i++) a += (path[j].y + path[i].y) * (path[j].x - path[i].x) * 0.5; return a; } For for the integer version it would look like this: public static double AreaNew(Path64 path) { double a = default; for (int i = 0; i < cnt; j =...
Hi Angus, I got a use case where I need create the union of individual quadratic tiles perfectly overlapping in their vertices. In my quest for a clipping algorithm that can do that perfectly without any glitches and edge cases, only Polybool worked so far. Hormann & Martinez & Clippe1 all work "sort off", but got plenty of edge cases rendering them unusable. Just tried if ClipperLib2 can do it...no luck. Is this something you would expect Clipper2Lib to ultimately be able to do, or is this a limitation...
Hi Angus, I got a use case where I need create the union of individual quadratic tiles perfectly overlapping in their vertices. In my quest for an clipping algorithm that can do that perfectly without any glitches and edge cases, onlyPolybool worked so far. Hormann & Martinez both work "sort off", but got edge cases. Just tried without if ClipperLib2 can do it...no luck. Is this something you would expect Clipper2Lib to ultimately be able to do, or is this a limitation that cannot be easily overcome?...
Dear Angus, The area formula used in clipper continues to confuse me as it is different than all my other polygon manipulation libraries. In cartesian coordinates (0,0 is bottom left) positive areas indicate CCW, and negative CW orientation. The area formula in clipper does that, but only by reversing the final result because it is using ((1/2 (Xi + Xi+1)(Yi-Yi+1), which is neither the Trapezoid formula (1/2 (Yi + Yi+1)(Xi-Xi+1) nor the Triangle/Shoelace Formula (1/2 (Xi * Yi+1) - (Xi+1 * Yi). To...
Dear Angus, The area formula used in clipper continues to confuse me as it is different than all my other polygon manipulation libraries. In Cartesian coordinates (0,0 is bottom left) positive areas indicate CCW, and negative CW orientation. The area formula in clipper does that, but only by reversing the final result because it is using ((1/2 (Xi + Xi+1)(Yi-Yi+1), which is neither the Trapezoid formula (1/2 (Yi + Yi+1)(Xi-Xi+1) nor the Triangle/Shoelace Formula (1/2 (Xi Yi+1) - (Xi+1 Yi). To that...
Dear Angus, The area formula used in clipper continues to confuse me as it is different than all my other polygon manipulation libraries. In Cartesian coordinates (0,0 is bottom left) positive areas indicate CCW, and negative CW orientation. The area formula in clipper does that, but only by reversing the final result because it is using ((1/2 (Xi + Xi+1)(Yi-Yi+1), which is neither the Trapezoid formula (1/2 (Yi + Yi+1)(Xi-Xi+1) nor the Triangle/Shoelace Formula (1/2 (Xi Yi+1) - (Xi+1 Yi). To that...
As we talk about perfection, how about this to ensure equality test works for small AND large numbers? "The absolute tolerance test fails when x and y become large, and the relative tolerance test fails when they become small. " https://realtimecollisiondetection.net/blog/?p=89 const double absTol = *desired tolerance*; const double relTol = *desired tolerance*; public static bool operator ==(PointD a, PointD b) { return (Math.Abs(a.x - b.x) <= Math.Max(absTol, relTol * Math.Max(math.abs(a.x), Math.Abs(b.x))))...
As we talk about perfection, how about this to ensure equality test works for small AND large numbers? "The absolute tolerance test fails when x and y become large, and the relative tolerance test fails when they become small. " https://realtimecollisiondetection.net/blog/?p=89 const double absTol = *desired tolerance*; const double relTol = *desired tolerance*; public static bool operator ==(PointD a, PointD b) { return (Math.Abs(a.x - b.x) <= Math.Max(absTol, relTol * Math.Max(math.abs(a.x), Math.Abs(b.x))))...
As we talk about perfection, how about this to ensure equality test works for small AND large numbers? "The absolute tolerance test fails when x and y become large, and the relative tolerance test fails when they become small. " https://realtimecollisiondetection.net/blog/?p=89 const double absTol = *desired tolerance*; const double relTol = *desired tolerance*; public static bool operator ==(PointD a, PointD b) { return (Math.Abs(a.x - b.x) <= Math.Max(absTol, relTol * Math.Max(math.abs(a.x), Math.Abs(b.x))))...
As we talk about perfection, how about this to ensure equality test works for small AND large numbers? : https://realtimecollisiondetection.net/blog/?p=89 const double absTol = *desired tolerance*; const double relTol = *desired tolerance*; public static bool operator ==(PointD a, PointD b) { return (Math.Abs(a.x - b.x) <= Math.Max(absTol, relTol * Math.Max(math.abs(a.x), Math.Abs(b.x)))) && (Math.Abs(a.y - b.y) <= Math.Max(absTol, relTol * Math.Max(math.abs(a.y), Math.Abs(b.y)))); }
You got degenerate points between subject and object (=fully overlapping points). Apparently clipper and clipper2 cannot really deal very well with that. See also "bug report" I field here and response from Angus. Greiner-Hormann can easily deal with degeneracies, but got some minor other issues (e.g. you have to implement sweepline intersection search yourself if your are interested in similar performance to clipper, reference implementation is only available in C++, and you got to add UNION, DIFF...
You got degenerate points between subject and object (=fully overlapping points). Apparently clipper and clipper2 cannot really deal very well with that. See also "bug report" I field here and response from Angus. Greiner-Hormann can easily deal with degeneracies, but got some minor other issues (e.g. you have to implement sweepline intersection search yourself if your are interested in similar performance to clipper, reference implementation is only available in C++, and you got to add UNION, DIFF...
You got degenerate points between subject and object (=fully overlapping points). Apparently clipper and clipper2 cannot really deal very well with that. See also "bug report" I field here and response from Angus. Greiner-Hormann can easily deal with degeneracies, but got some minor other issues (e.g. you have to implement sweepline intersection search yourself if your are interested in similar performance to clipper, reference implementation is only available in C++, and you got to add UNION, DIFF...
You got degenerate points between subject and object (=fully overlapping points). Apparently clipper and clipper2 cannot really deal very well with that. See also "bug report" I field here and response from Angus. Greiner-Hormann can easily deal with degeneracies, but got some minor other issues (e.g. you have to implement sweepline intersection search yourself if your are interested in similar performance to clipper, reference implementation is only available in C++, and you got to add UNION, DIFF...
Workaround for anybody interested: the algorithm published by Foster 2019 works perfectly for creating a UNION of degenerate polygons (touching edges). Code is was a bit slow due to brute force intersection search (which I resolved for my own use by using a sweepline approach to find the intersections). There is another issue with that algorithm, which is why I am using now a hybrid of that code (for a union of touching map outlines) and then Clipper2 for clipping that outcome against earth. Angus:...
Workaround for anybody interested: the algorthm publiushed by Foster 2019 works perfectly for creating a UNION of degenerate polygons (touching edges). Code is was a bit slow due to brute force intersection search (which I resolved for my own use by using a sweepline approach to find the intersections). There is another issue with that algorithm, which is why I am using now a hybrid of that code (for a union of touching map outlines) and then Clipper2 for clipping that outcome against earth. Angus:...
OK, thanks for the swift response and clarification. Did not think it had anything to do with micro-self intersection issue as the polygons I have (navigational S57 map coverage outlines) are by design mostly (perfectly) touching in identical common integer points. Spends days in the debugger to compare where clipper1 and clipper2 are starting to diverge, and thought it had something to do with the ordering of the active edges in the AEL, and some decisions taking in DoHorizontals() that affect it....
Union fails
[...]fixes that[...] Scratch that, nothing is fixed: Clipper and Clipper2 give completely different results when doing the union of the attached files. Using the unmodified C++ version of the respective libraries. Clipper correctly merges them all into one path, Clipper2 gives multiple path solution that is just wrong. Still suspect the culprit is somewhere in the DoHorizontals() method, but it's over my head to find a fix for that . Any advice?
Subject: -766833267 345833282, -652833328 345833282, -766833267 397166709, Clipper: -816666717 296772308, -671666717 345833282, -766833267 345833282, -766833267 353333282, -816666717 353333282, -816666717 296772308, UNION using clipper2 results in two solution paths instead of one, which would be correct and expected. The following replacement of ">=" and "<=" by ">" and "<", respectively, in DoHorizontal() fixes that. However, not sure if this the the correct way of addressing the issue? //or if...