-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Robustify compare segments #13
Robustify compare segments #13
Conversation
CC @untoldwind (I assume you don't get notified by PRs since you are not among the Watchers, and for some reason I can't assign you as a reviewer this time). As a note to myself:
Probably this can be solved by introducing a flag for each segment with the semantics "second attempt" or rather "don't trust the left endpoint". If we encounter the case of an intersection on the left endpoint in the second stage, we could re-push the segment into the sweep line with the flag set to true. And in this second attempt The solution is still a bit more error prone, because when ordering a segment in a second attempt we still have to order the same segment properly with respect to other segments (where we have to use the left endpoint for the comparison to get a correct result), and only use the right endpoint in the particular case shown above. Clearly something for a future experiment. |
I think I have a reasonable bundle for another update (although there are still open issues...).
This PR fixes a few issues around ordering segments in the sweep line. The most challenging issue was the following problem, already alluded to here:
Normally when comparing two line segments it suffices to look at the left point, and if it is below or above the other segments, the segment is below/above. Special handling is only triggered when the left point falls perfectly on the line (according to the signed_area == 0 check). This leaves an ugly edge case:
My ideas to work-around this inconsistency were:
Solution 3 is most straightforward, so I went for that. Obviously this adds a bit in terms of run time. I made sure to compute the intersection lazily only if necessary to keep the impact small. Currently I see a 5% - 10% performance impact. However, I already have a few ideas how to optimize performance eventually (only really makes sense once the logic has fewer bugs), and the algorithm is crazy fast anyway -- less than 1 ms total run time even on somewhat complex polygons.
Other bug fixes / improvements:
compare_segments
: The comparison returned "equals" on equal values, which was messing up test cases with self-overlapping edges. I feel like it is easier to support self-overlapping edges properly by using "equals" only for identity. Fixes Incorrect union on small example #12 (the main reported issue).subdivide_segments
in the intersection with "next" branch) callcompute_fields
two times onevent
itself. It occurs to me that it should be called once forevent
and once fornext
, similar to how the branch looks like in the "prev" case. This is required to fix the other issue mentioned in Incorrect union on small example #12 and test casesoverlapping_segment2
andoverlapping_segment3
.op(A, B) == result
but alsoop(B, A) == result
. Currently there are still 2 test cases which are broken with swapped operands (marked as such in the PDFs), TODO for later.Rust specific changes:
possible_itersection
had a minor problem, because it didn't account for changes of the "other event" pointer. Fix is required foroverlapping_segment2
.std::panic::catch_unwind
. This means the tests will no longer fail/panic on the first failing test, but rather run through all the test cases and report a failure summary. This is super convenient for getting a better understanding of the algorithm, because one can add e.g. debug asserts and see how many / which test cases would be affected.Fixed / new test cases: test_cases.pdf