Sha256: 372dd76dca64866ef0fc73b1bebfa9f6845de7bde8936cbc141fa86493018b12

Contents?: true

Size: 1.43 KB

Versions: 1

Compression:

Stored size: 1.43 KB

Contents

class GeometricPointInPolygon < Struct.new(:point, :polygon)
  extend Memoist

  def inside?
    point_location == :inside
  end

  def outside?
    point_location == :outside
  end

  def on_the_boundary?
    point_location == :on_the_boundary
  end

  def point_location
    return :outside unless bounding_box.contains?(point)
    return :on_the_boundary if point_is_vertex? || point_on_edge?

    intersection_count(choose_good_ray).odd? ? :inside : :outside
  end

  delegate :vertices, :edges, :bounding_box, to: :polygon
  memoize  :point_location, :edges, :bounding_box

  private

  def choose_good_ray
    ray = random_ray
    while ! good_ray?(ray) do
      ray = random_ray
    end
    ray
  end

  def good_ray?(ray)
    edges.none? { |edge| edge.parallel_to?(ray) } && vertices.none? { |vertex| ray.contains_point?(vertex) }
  end

  def intersection_count(ray)
    edges.select { |edge| edge.intersects_with?(ray) }.size
  end

  def point_is_vertex?
    vertices.any? { |vertex| vertex == point }
  end

  def point_on_edge?
    edges.any? { |edge| edge.contains_point?(point) }
  end

  def random_ray
    random_direction = rand * (2 * Math::PI)

    ray_endpoint = GeometricPoint.new(sufficient_ray_radius * Math.cos(random_direction), sufficient_ray_radius * Math.sin(random_direction))
    GeometricSegment.new(point, ray_endpoint)
  end

  def sufficient_ray_radius
    @sufficient_ray_radius ||= bounding_box.diagonal.length * 2
  end

end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
flash_math-0.0.1 lib/flash_math/modules/geometry/geometric_point_in_polygon.rb