Class: Geospatial::Polygon

Inherits:
Object
  • Object
show all
Defined in:
lib/geospatial/polygon.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(points) ⇒ Polygon



29
30
31
32
# File 'lib/geospatial/polygon.rb', line 29

def initialize(points)
  @points = points
  @box = nil
end

Class Method Details

.[](*points) ⇒ Object



25
26
27
# File 'lib/geospatial/polygon.rb', line 25

def self.[] *points
  self.new(points)
end

.is_left(p0, p1, p2) ⇒ Object



59
60
61
62
63
64
# File 'lib/geospatial/polygon.rb', line 59

def self.is_left(p0, p1, p2)
  a = p1 - p0
  b = p2 - p0
  
  return (a[0] * b[1]) - (b[0] * a[1])
end

Instance Method Details

#bounding_boxObject



38
39
40
# File 'lib/geospatial/polygon.rb', line 38

def bounding_box
  @bounding_box ||= Box.enclosing_points(@points)
end

#edgesObject



49
50
51
52
53
54
55
56
57
# File 'lib/geospatial/polygon.rb', line 49

def edges
  return to_enum(:edges) unless block_given?
  
  previous = @points.last
  @points.each do |point|
    yield previous, point
    previous = point
  end
end

#freezeObject



42
43
44
45
46
47
# File 'lib/geospatial/polygon.rb', line 42

def freeze
  @points.freeze
  bounding_box.freeze
  
  super
end

#include?(other) ⇒ Boolean



111
112
113
# File 'lib/geospatial/polygon.rb', line 111

def include?(other)
  other.corners.all?{|corner| self.include_point?(corner)}
end

#include_point?(point) ⇒ Boolean



88
89
90
91
92
# File 'lib/geospatial/polygon.rb', line 88

def include_point?(point)
  return false unless bounding_box.include_point?(point)
  
  self.winding_number(point) == 1
end

#intersect?(other) ⇒ Boolean



102
103
104
105
106
107
108
109
# File 'lib/geospatial/polygon.rb', line 102

def intersect?(other)
  case other
  when Box
    intersect_with_box?(other)
  when Circle
    intersect_with_circle?(other)
  end
end

#intersect_with_box?(other) ⇒ Boolean



94
95
96
97
98
99
100
# File 'lib/geospatial/polygon.rb', line 94

def intersect_with_box?(other)
  return true if @points.any?{|point| other.include_point?(point)}
  
  return true if other.corners.any?{|corner| self.include_point?(corner)}
  
  return false
end

#to_sObject



34
35
36
# File 'lib/geospatial/polygon.rb', line 34

def to_s
  "#{self.class}#{@points.inspect}"
end

#winding_number(p) ⇒ Number

Test a 2D point for inclusion in the polygon.



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/geospatial/polygon.rb', line 69

def winding_number(p)
  count = 0
  
  edges.each do |pa, pb|
    if pa[1] <= p[1] 
      if pb[1] >= p[1] and Polygon.is_left(pa, pb, p) > 0
        count += 1
      end
    else
      if pb[1] <= p[1] and Polygon.is_left(pa, pb, p) < 0
        count -= 1
      end
    end
    
  end
  
  return count
end