class PerfectShape::Polygon
Constants
- WINDING_RULES
Attributes
winding_rule[R]
Public Class Methods
new(points: [], winding_rule: :wind_even_odd)
click to toggle source
Calls superclass method
PerfectShape::MultiPoint::new
# File lib/perfect_shape/polygon.rb, line 36 def initialize(points: [], winding_rule: :wind_even_odd) super(points: points) self.winding_rule = winding_rule end
Public Instance Methods
contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)
click to toggle source
Checks if polygon contains point (two-number Array or x, y args) using the Ray Casting Algorithm (aka Even-Odd Rule) or Winding Number Algorithm (aka Nonzero Rule) Details: en.wikipedia.org/wiki/Point_in_polygon
@param x The X coordinate of the point to test. @param y The Y coordinate of the point to test.
@return true if the point lies within the bound of the polygon, false if the point lies outside of the polygon’s bounds.
# File lib/perfect_shape/polygon.rb, line 57 def contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0) x, y = Point.normalize_point(x_or_point, y) return unless x && y if outline edges.any? { |edge| edge.contain?(x, y, distance_tolerance: distance_tolerance) } else if winding_rule == :wind_even_odd wind_even_odd_contain?(x, y) else path.contain?(x, y) end end end
edges()
click to toggle source
# File lib/perfect_shape/polygon.rb, line 71 def edges points.zip(points.rotate(1)).map do |point1, point2| Line.new(points: [[point1.first, point1.last], [point2.first, point2.last]]) end end
intersect?(rectangle)
click to toggle source
# File lib/perfect_shape/polygon.rb, line 84 def intersect?(rectangle) path.intersect?(rectangle) end
path()
click to toggle source
# File lib/perfect_shape/polygon.rb, line 77 def path path_shapes = [] path_shapes << PerfectShape::Point.new(points[0]) path_shapes += points[1..-1].map { |point| PerfectShape::Line.new(points: [point]) } PerfectShape::Path.new(shapes: path_shapes, closed: true, winding_rule: winding_rule) end
winding_rule=(value)
click to toggle source
# File lib/perfect_shape/polygon.rb, line 41 def winding_rule=(value) raise "Invalid winding rule: #{value} (must be one of #{WINDING_RULES})" unless WINDING_RULES.include?(value.to_s.to_sym) @winding_rule = value end
Private Instance Methods
wind_even_odd_contain?(x, y)
click to toggle source
optimized even-odd rule point in polygon algorithm (uses less memory than PerfectShape::Path
algorithms)
# File lib/perfect_shape/polygon.rb, line 91 def wind_even_odd_contain?(x, y) npoints = points.count xpoints = points.map(&:first) ypoints = points.map(&:last) return false if npoints <= 2 || !bounding_box.contain?(x, y) hits = 0 lastx = xpoints[npoints - 1] lasty = ypoints[npoints - 1] # Walk the edges of the polygon npoints.times do |i| curx = xpoints[i] cury = ypoints[i] if cury == lasty lastx = curx lasty = cury next end if curx < lastx if x >= lastx lastx = curx lasty = cury next end leftx = curx else if x >= curx lastx = curx lasty = cury next end leftx = lastx end if cury < lasty if y < cury || y >= lasty lastx = curx lasty = cury next end if x < leftx hits += 1 lastx = curx lasty = cury next end test1 = x - curx test2 = y - cury else if y < lasty || y >= cury lastx = curx lasty = cury next end if x < leftx hits += 1 lastx = curx lasty = cury next end test1 = x - lastx test2 = y - lasty end hits += 1 if (test1 < (test2 / (lasty - cury) * (lastx - curx))) end (hits & 1) != 0 end