-
Notifications
You must be signed in to change notification settings - Fork 90
Add Bentley-Ottman Algorithm #1168
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
base: master
Are you sure you want to change the base?
Conversation
…uts a dictionary of vertex keys with segment values
…ntersections and ultimately calculates all intersections
@souma4 please let me know when the PR is ready for review. I have some review comments already, just waiting for your green light. |
@juliohm Thanks for reminding me! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @souma4 for working on this. It is really nice to see the amazing progress you've made already ❤️
Attached is my first round of review with a couple of suggestions to improve the PR. Let's work on it together slowly, possibly improving the BinaryTrees.jl dependency before coming back here.
Looking forward to the next round. It looks very promising!
…tests. Edited test to be more intensive. updated entire script to meet style and Julia best practices. Removed unneded functions. Shifted BinaryTrees relevant materials to PR JuliaGeometry#12 in BinaryTrees and adjusted code as needed. Reordered point processing to reduce the likelihood of a bug when processing start and intersection segments.
…d function. removed println calls used for debugging
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Attaching a few minor comments. Tomorrow I will try to find some time to run tests locally.
The good news is that the output of @code_warntype
is all green.
Tests are failing because the utility function is not exported. We can either export it or qualify the calls in the test suite with the |
Co-authored-by: Júlio Hoffimann <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More basic fixes before the actual review of the algorithm.
…eaner enum handling, and shifted the final dictionary to be unique values
…hes.jl into JRC_add_BentleyOttman
… that connect to the point
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests are failing due to the latest review changes.
So this works, which is awesome. Problem, doing some performance testing shows its n^2. Most of the time spent (according to profview) is occurring in the intersection checks from the |
Really nice progress. How are you checking the n^2 performance? Some tests are failing with Float32. |
I checked time complexity with the REPL off hand. created Yeah, some tests are failing with Float32, I'm not sure why, and I'll deal with it tomorrow haha. |
…ght it would so I'm just hard coding the Float32 tolerance.
…e removal of ending segments from the status structure. My local tests suggest roughly logarithmic time, although caching from garbage collection makes it sort of stepwise
@souma4 I will try to review tomorrow or over the weekend. Thank you for looking into it! :) |
In the meantime, I have a question regarding the overall structure of the algorithm. I noticed that the pseudo-code by Bentley-Ottman in their original paper has a different structure: It can be read as for p in ...
if s is a segment with p in the left
# do something
elseif s is a segment with p in the right
# do somethine else
else # p is some intersection
# do something else
end
end In this PR the structure is a bit different: for p in ...
for s in left segments
# do something
end
for s in right segments
# do something else
end
for s in middle segments
# do something else
end
end I understand that the latter structure is explicitly "greedy" and loops over all segments related to point p. The former structure in the paper seems incomplete in terms of these details. Just double checking if we are not missing something. Did you have a chance to think about it? Are these two structures equivalent? |
Yeah I've wracked my head over this a good bit. From my testing and thinking, the structures are equivalent when segments are expected to be completely independent (ie no corners) and there aren't more than two lines intersecting. But when corners and more segments are involved, the former algorithm will "skip" line segments and/or not capture intersections. This is because the earlier segments for a given point may intersect with later segments, but due to handling, this intersection may not be captured because there are segments "in between" the two focal segments within the status structure. |
Co-authored-by: Elias Carvalho <[email protected]>
I introduced a helper |
The heuristic for the number of digits worked well. Assuming a tolerance of I noticed that the output of the algorithm is including the original points besides the intersections. For instance, here is what I get in the second test: viz(segs)
viz!(points, color="red") Could you please take a look to make sure we are only returning intersection points? |
Oh if we only want intersections (not all points) then this is an easy change. I'll commit fixes and update tests to reflect. Although I am finding some variance in tests, so I'll need to debug and see if it's real or not. Outside of that, the facetgrid test returns nothing because the facet generator only generates cornerintersections, which are start/endpoints and not included. |
Very good point. I think we need to refactor this test by constructing segments manually in a grid-like arrangement. We could do the following instead: horizontal = [Segment((1, i), (n, i)) for i in 1:n]
vertical = [Segment((i, 1), (i, n)) for i in 1:n]
segs = [horizontal; vertical] |
…. EVENTS ARENT BEING HANDLED PROPERLY. I DONT HAVE TIME TO ADDRESS PROMPTLY
Thank you @souma4 for looking into it ❤️ Tests with random segments show that the algorithm is not there yet. Perhaps we could try to follow the algorithmic structure in Chapter 2 of Berg et al. Computational Geometry - Applications and Algorithms instead. This structure is discussed step-by-step in the video I linked in the issue. More specifically, it is discussed in this second video: https://www.youtube.com/watch?v=qkhUNzCGDt0 (If you need access to the book, I have the PDF and can send it to you directly) We are almost there! |
agreed. My plan was to pull up De Berg to see exactly what they do. I'm fairly busy this week, but, it'll keep moving haha. I think we are pretty close though. |
…s far as I got with De Berg implementation. All tests fail. I think this is occuring between the status structure isn't reflecting the order where the plane crosses, but the total order in x and y (so a line with a low x will always be the minimum even if where it intersects the plane is the maximum). I tried having a sort method to maybe get it but that didn't work. I'm sort of at a loss outside of computing intersections to the plane, which I can't think of an efficient way of doing that right now. Maybe y'all will have some ideas
see issue #1126 and PR #1125
I needed to refactor and I messed up with the last draft #1143.
This produces a dictionary of vertices with a vector of segment values. Future needs: A test that the outputs are correct, and general method for rebuilding polygons with this structure.
@juliohm sorry about messing up the prior draft. Live and learn. I'll let you look this over. I think a polygon build method for this output is a new PR. This outputs vertices with segment info. If someone just wants the vertices they can grab the keys. If someone wants a polygon they can use a build method.