Class: PerfectShape::Polygon

Inherits:
Shape
  • Object
show all
Includes:
MultiPoint
Defined in:
lib/perfect_shape/polygon.rb

Overview

Instance Attribute Summary

Attributes included from MultiPoint

#points

Instance Method Summary collapse

Methods included from MultiPoint

#initialize, #max_x, #max_y, #min_x, #min_y

Methods inherited from Shape

#==, #bounding_box, #center_point, #center_x, #center_y, #height, #max_x, #max_y, #min_x, #min_y, #normalize_point, #width

Instance Method Details

#contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0) ⇒ @code true

Checks if polygon contains point (two-number Array or x, y args) using the Ray Casting Algorithm (aka Even-Odd Rule): en.wikipedia.org/wiki/Point_in_polygon

the polygon, false if the point lies outside of the polygon’s bounds.

Parameters:

  • x

    The X coordinate of the point to test.

  • y (defaults to: nil)

    The Y coordinate of the point to test.

Returns:

  • (@code true)

    if the point lies within the bound of



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/perfect_shape/polygon.rb', line 40

def contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)
  x, y = normalize_point(x_or_point, y)
  return unless x && y
  if outline
    edges.any? { |edge| edge.contain?(x, y, distance_tolerance: distance_tolerance) }
  else
    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
end

#edgesObject



119
120
121
122
123
# File 'lib/perfect_shape/polygon.rb', line 119

def edges
  points.zip(points.rotate(1)).map do |point1, point2|
    Line.new(points: [[point1.first, point1.last], [point2.first, point2.last]])
  end
end