11module Geometry
22 class PointInPolygon < Struct . new ( :point , :polygon )
33 extend Memoist
4-
4+
55 def inside?
66 point_location == :inside
77 end
@@ -18,7 +18,7 @@ def point_location
1818 return :outside unless bounding_box . contains? ( point )
1919 return :on_the_boundary if point_is_vertex? || point_on_edge?
2020
21- intersection_count ( choose_good_ray ) . odd ? ? :inside : :outside
21+ point_inside_polygon ? ? :inside : :outside
2222 end
2323
2424 delegate :vertices , :edges , :bounding_box , :to => :polygon
@@ -34,31 +34,21 @@ def point_on_edge?
3434 edges . any? { |edge | edge . contains_point? ( point ) }
3535 end
3636
37- def choose_good_ray
38- ray = random_ray
39- while ! good_ray? ( ray ) do
40- ray = random_ray
41- end
42- ray
43- end
37+ def point_inside_polygon?
38+ # Algorithm source:
39+ # https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html
4440
45- def good_ray? ( ray )
46- edges . none? { |edge | !edge . length . zero? && edge . parallel_to? ( ray ) } && vertices . none? { |vertex | ray . contains_point? ( vertex ) }
47- end
48-
49- def intersection_count ( ray )
50- edges . select { |edge | edge . intersects_with? ( ray ) } . size
51- end
52-
53- def random_ray
54- random_direction = rand * ( 2 * Math ::PI )
55-
56- ray_endpoint = Point sufficient_ray_radius * Math . cos ( random_direction ) , sufficient_ray_radius * Math . sin ( random_direction )
57- Segment point , ray_endpoint
58- end
41+ result = false
42+
43+ vertices . each_with_index do |vertex , i |
44+ previous_vertex = vertices [ i - 1 ] || vertex . last
45+ if ( ( vertex . y > point . y ) != ( previous_vertex . y > point . y ) ) &&
46+ ( point . x < ( previous_vertex . x - vertex . x ) * ( point . y - vertex . y ) / ( previous_vertex . y - vertex . y ) + vertex . x )
47+ result = !result
48+ end
49+ end
5950
60- def sufficient_ray_radius
61- @sufficient_ray_radius ||= bounding_box . diagonal . length * 2
51+ result
6252 end
6353 end
6454end
0 commit comments