Skip to content
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

Deterministic algorithm to determine whether a point is in a polygon #17

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

seangransee
Copy link

I haven't gotten a chance to spend much time with this, but I've dropped in the algorithm I'm using in my application to replace Polygon.contains?.

There's one failing test, which is the check for a point being on the edge of a convex polygon. As stated in the section Point on a (Boundary) Edge from the algorithm's source page, this algorithm isn't able to predict when a point is exactly on the edge of a polygon. Perhaps a hybrid of this new algorithm with your current algorithm will do the trick.

Feel free to mess around with this and push commits to my branch.

@seangransee
Copy link
Author

seangransee commented May 6, 2017

I made an additional change to go back to the way you were originally checking whether a point was on a boundary. When a point is not on a boundary, it uses the deterministic algorithm I found as a replacement for intersection_count(choose_good_ray).odd?.

All tests in contains_point_test.rb pass now.

vertices.each_with_index do |vertex, i|
previous_vertex = vertices[i - 1] || vertex.last
if ((vertex.y > point.y) != (previous_vertex.y > point.y)) &&
(point.x < (previous_vertex.x - vertex.x) * (point.y - vertex.y) / (previous_vertex.y - vertex.y) + vertex.x)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Align the operands of a condition in an if statement spanning multiple lines.
Line is too long. [121/80]


vertices.each_with_index do |vertex, i|
previous_vertex = vertices[i - 1] || vertex.last
if ((vertex.y > point.y) != (previous_vertex.y > point.y)) &&
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use next to skip iteration.

@DanielVartanov
Copy link
Owner

Thanks @seangransee! Will look into it tomorrow 👍

@DanielVartanov
Copy link
Owner

Status update: still trying to figure out the idea of the algo author.

From the description, I conclude that it is the same algorithm as the current one in this gem, but instead of a random ray they choose a horizontal positively-oriented ray, the rest is the same (they just calculate whether the number of intersections with edges is odd or even).

If I understood everything correctly, why would it work well with edge-cases when the semi-infinite ray contains a vertex or a whole edge? @seangransee, can you please help me to understand? I'd really appreciate assistance as it would save me a lot of time digging/drawing/testing/thinking.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants