winding-polygon 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f8c0df6f0765c7a2a1a8a060d1bb6c78510ecef9
4
- data.tar.gz: 6a0d538f3f4b56cf79c1445953da99f363130b27
3
+ metadata.gz: 7d8c4d4bd5532c0f315bfd93c56b2abeb83d71ba
4
+ data.tar.gz: 29690ff49b94f6005f0b3b4ab5d43f1467ee7f8a
5
5
  SHA512:
6
- metadata.gz: 77e7991c609942476f78bf67c2944ccdde34d88f99e17cbc51823f98634ce6000bae5aa47635dc811b24cc125da188b011fc2d2bef2b2f1bd1fd1aed8b9a656e
7
- data.tar.gz: 42958476e6918e4794eaa881c2c54624baf0aa41521865af4887341a36bdcb7d960c0abeaf326a0d54ba23614e87ebf4e2fc63c9d630b1ff09abc8de1d4410e1
6
+ metadata.gz: 3270fcf7ab126fb0aee8044905b9595fad6f17d54f47f4216941ccd365adc65bf838b43a3f2524fece01c3789655511271059628ab08bf4d0d0faddee437f30f
7
+ data.tar.gz: a6e3ea0045b182ae9b18d9f799b94a31ead92806b9d86b20e0a33430ab5005a8634795d345a288f5021bf5449638c2dd260acea6ed0ed4fe6bdbe8353ba08dc6
@@ -1,15 +1,79 @@
1
1
  require "winding-polygon/version"
2
+ require "winding-polygon/vector"
2
3
 
3
4
  module WindingPolygon
4
5
 
5
- def self.decompose(input_polygon, output_polygons)
6
- output_polygons = Array.new if output_polygons.nil?
7
- result = input_polygon.decompose
8
- if result.instance_of?(Array) && result.size==1 && !output_polygons.include?(input_polygon)
9
- output_polygons.concat(result)
10
- else
11
- decompose(result[0],output_polygons )
12
- decompose(result[1],output_polygons )
6
+ def self.decompose(input_polygon)
7
+
8
+ intersection_points = input_polygon.get_intersection_points
9
+ return input_polygon if intersection_points.nil? || intersection_points.size==0
10
+
11
+ input_polygon.simple_segments.sort_by!{|seg| [seg.left_point] }
12
+ simple_polygons = Array.new
13
+ while !input_polygon.simple_segments.nil? && input_polygon.simple_segments.size>=3
14
+ simple_polygons << get_one_simple_polygon(get_first_segment(input_polygon), input_polygon)
15
+ end
16
+ simple_polygons
17
+
18
+ end
19
+
20
+ def self.get_one_simple_polygon(first_segment, input_polygon)
21
+ current_simple_polygon = Array.new
22
+ current_simple_polygon_vertices = Array.new
23
+ current_simple_polygon << first_segment
24
+ current_simple_polygon_vertices << first_segment.left_point << first_segment.right_point
25
+ current_point = first_segment.right_point
26
+
27
+ while !input_polygon.simple_segments.nil? && input_polygon.simple_segments.size>=1
28
+ previous_edge = current_simple_polygon.last.edge
29
+ next_segment_candidates = input_polygon.simple_segments.select { |seg| seg.edge!=previous_edge && (seg.left_point == current_point ||seg.right_point == current_point) }.dup
30
+
31
+ if !next_segment_candidates.nil? && next_segment_candidates.size>=2
32
+ #determine previous segment vector
33
+ if current_point == current_simple_polygon.last.left_point
34
+ v0 = Vector.new(current_simple_polygon.last.right_point.x-current_point.x, current_simple_polygon.last.right_point.y-current_point.y)
35
+ else
36
+ v0 = Vector.new(current_simple_polygon.last.left_point.x-current_point.x, current_simple_polygon.last.left_point.y-current_point.y)
37
+ end
38
+
39
+ #determine next segment vector
40
+ if current_point == next_segment_candidates[0].left_point
41
+ v1 = Vector.new(next_segment_candidates[0].right_point.x-current_point.x, next_segment_candidates[0].right_point.y-current_point.y)
42
+ else
43
+ v1 = Vector.new(next_segment_candidates[0].left_point.x-current_point.x, next_segment_candidates[0].left_point.y-current_point.y)
44
+ end
45
+
46
+ if v1.cross_product(v0) > 0
47
+ current_simple_polygon << next_segment_candidates[0]
48
+ else
49
+ current_simple_polygon << next_segment_candidates[1]
50
+ end
51
+ else
52
+ current_simple_polygon << next_segment_candidates[0]
53
+ end
54
+
55
+ if current_simple_polygon.last.left_point == current_point
56
+ current_point = current_simple_polygon.last.right_point
57
+ else
58
+ current_point = current_simple_polygon.last.left_point
59
+ end
60
+
61
+ current_simple_polygon_vertices << current_point
62
+
63
+ input_polygon.simple_segments.delete_if { |seg| seg.left_point==current_simple_polygon.last.left_point && seg.right_point==current_simple_polygon.last.right_point }
64
+
65
+ return current_simple_polygon_vertices if current_simple_polygon.first.left_point == current_simple_polygon.last.left_point
66
+
13
67
  end
68
+ current_simple_polygon_vertices
69
+ end
70
+
71
+ def self.get_first_segment(input_polygon)
72
+ start_point = input_polygon.simple_segments[0].left_point
73
+ first_segment_candidates = input_polygon.simple_segments.select { |seg| seg.left_point == start_point }.dup
74
+ first_segment_candidates.sort!
75
+ input_polygon.simple_segments.delete_if { |seg| seg.left_point==first_segment_candidates[0].left_point && seg.right_point==first_segment_candidates[0].right_point }
76
+ first_segment_candidates[0]
14
77
  end
78
+
15
79
  end
@@ -46,6 +46,11 @@ module WindingPolygon
46
46
  d = search(v)
47
47
  return nil if d.nil?
48
48
 
49
+ if @root.height==1 && @root.value==v
50
+ @root = nil
51
+ return nil
52
+ end
53
+
49
54
  if d.left == nil or d.right == nil
50
55
  n = d
51
56
  else #both children exist
@@ -26,14 +26,29 @@ module WindingPolygon
26
26
  @events[a][:type] = 'right'
27
27
  @events[b][:type] = 'left'
28
28
  end
29
-
30
- @events[a][:other_y]=@events[b][:vertex].y
31
- @events[b][:other_y]=@events[a][:vertex].y
32
29
  end
33
30
 
34
31
  # sort events lexicographically
35
- @events.sort!{|a,b| a[:vertex].compare(b[:vertex]).nonzero? || a[:type]<=>b[:type] || a[:other_y]<=>b[:other_y] }
32
+ #@events.sort!{|a,b| [a[:vertex], b[:type], a[:other_endpoint]] <=> [b[:vertex], a[:type], b[:other_endpoint]] }
33
+ @events.sort!{|a,b| [a[:vertex], b[:type]] <=> [b[:vertex], a[:type]] }
34
+
35
+ end
36
+
37
+ def insert(point_hash)
38
+ for i in 0..@events.size-1
39
+ next if @events[i][:vertex].x < point_hash[:point].x
40
+ next if @events[i][:vertex].x == point_hash[:point].x && @events[i][:vertex].y<point_hash[:point].y
41
+ @events.insert(i,{:type=>'intersection_point',:vertex=>point_hash[:point],:edge1=>point_hash[:edge1],:edge2=>point_hash[:edge2]})
42
+ break
43
+ end
44
+ end
45
+
46
+ def exist(point)
47
+ for i in 0..@events.size-1
48
+ return true if @events[i][:vertex] ==point
49
+ end
36
50
 
51
+ return false
37
52
  end
38
53
 
39
54
  end
@@ -42,6 +42,18 @@ module WindingPolygon
42
42
  @x==other_point.x && @y==other_point.y
43
43
  end
44
44
 
45
+ def < (other_point)
46
+ return true if @x < other_point.x
47
+ return true if @x == other_point.x && @y < other_point.y
48
+ return false
49
+ end
50
+
51
+ def > (other_point)
52
+ return true if @x > other_point.x
53
+ return true if @x == other_point.x && @y > other_point.y
54
+ return false
55
+ end
56
+
45
57
  # tests if point is Left|On|Right of the line P0 to P1.
46
58
  #
47
59
  # returns:
@@ -2,10 +2,32 @@ module WindingPolygon
2
2
  class Polygon
3
3
  attr_reader :vertices
4
4
  attr_reader :intersection_points
5
+ attr_accessor :segments
6
+ attr_accessor :simple_segments
5
7
 
6
8
  def initialize(points)
7
9
  @vertices = points
8
10
  @intersection_points = Array.new
11
+
12
+ @simple_segments = Array.new
13
+
14
+ @segments = Array.new
15
+ for i in 0..@vertices.length-2
16
+
17
+ seg = Segment.new({:edge=>i})
18
+
19
+ if @vertices[i]<@vertices[i+1]
20
+ seg.left_point = @vertices[i]
21
+ seg.right_point = @vertices[i+1]
22
+ else
23
+ seg.left_point = @vertices[i+1]
24
+ seg.right_point = @vertices[i]
25
+ end
26
+
27
+ @segments << seg
28
+
29
+ end
30
+
9
31
  end
10
32
 
11
33
  def is_simple
@@ -45,14 +67,41 @@ module WindingPolygon
45
67
 
46
68
  if e[:type] == 'left'
47
69
  s = sweep_line.add(e)
70
+ find_intersection_point_between_segments(s,s.above, event_queue, sweep_line)
71
+ find_intersection_point_between_segments(s,s.below, event_queue, sweep_line)
72
+ end
48
73
 
49
- add_to_intersection_point_collection(sweep_line.intersect(s, s.above))
50
- add_to_intersection_point_collection(sweep_line.intersect(s, s.below))
51
-
52
- else
53
- s = sweep_line.find(e)
54
- add_to_intersection_point_collection(sweep_line.intersect(s.above, s.below))
74
+ if e[:type] == 'right'
75
+ s = sweep_line.find_segment(@segments[e[:edge]])
76
+ point = sweep_line.intersect(s.above, s.below)
77
+ event_queue.insert(point_hash_with_edge_info(point, s.above, s.below)) if !point.nil? && !event_queue.exist(point)
55
78
  sweep_line.remove(s)
79
+ @simple_segments << s
80
+ end
81
+
82
+ if e[:type] == 'intersection_point'
83
+ add_to_intersection_point_collection(e[:vertex])
84
+
85
+ s1 = sweep_line.find_segment(@segments[e[:edge1]])
86
+ sweep_line.remove(s1)
87
+ s11 = s1.dup
88
+ s11.right_point = e[:vertex]
89
+ @simple_segments << s11
90
+
91
+
92
+ s2 = sweep_line.find_segment(@segments[e[:edge2]])
93
+ sweep_line.remove(s2)
94
+ s22 = s2.dup
95
+ s22.right_point = e[:vertex]
96
+ @simple_segments << s22
97
+
98
+ @segments[e[:edge1]].left_point=e[:vertex]
99
+ s1 = sweep_line.add_segment(@segments[e[:edge1]])
100
+ find_intersection_point_between_segments(s1,s1.below, event_queue, sweep_line)
101
+
102
+ @segments[e[:edge2]].left_point=e[:vertex]
103
+ s2 = sweep_line.add_segment(@segments[e[:edge2]])
104
+ find_intersection_point_between_segments(s2,s2.above, event_queue, sweep_line)
56
105
  end
57
106
 
58
107
  e = event_queue.events.shift
@@ -62,6 +111,11 @@ module WindingPolygon
62
111
  @intersection_points
63
112
  end
64
113
 
114
+ def find_intersection_point_between_segments(s1,s2, event_queue, sweep_line)
115
+ point =sweep_line.intersect(s1, s2)
116
+ event_queue.insert(point_hash_with_edge_info(point, s1, s2)) if !point.nil? && !event_queue.exist(point)
117
+ end
118
+
65
119
  def add_to_intersection_point_collection(point)
66
120
  @intersection_points << point if !point.nil? && !@intersection_points.any?{|p| p.compare(point)==0}
67
121
  end
@@ -93,16 +147,12 @@ module WindingPolygon
93
147
  return nil
94
148
  end
95
149
 
96
- def decompose
97
- intersection_point = get_first_intersection_point_hash
98
- return [self] if intersection_point.nil?
99
- first_polygon = Polygon.new((@vertices[0..intersection_point[:edge1]]<<intersection_point[:point]).concat( @vertices[intersection_point[:edge2]+1,@vertices.length-intersection_point[:edge2]]))
100
- second_polygon = Polygon.new(@vertices[intersection_point[:edge1]+1..intersection_point[:edge2]].insert(0,intersection_point[:point])<<intersection_point[:point])
101
- return [first_polygon,second_polygon]
102
- end
103
-
104
150
  def point_hash_with_edge_info(point, s1, s2)
105
- edges=[s1.edge, s2.edge].sort!
151
+ if s1.right_point.y<s2.right_point.y
152
+ edges=[s1.edge, s2.edge]
153
+ else
154
+ edges=[s2.edge, s1.edge]
155
+ end
106
156
  {:point => point, :edge1 => edges[0], :edge2 => edges[1]}
107
157
  end
108
158
 
@@ -14,20 +14,38 @@ module WindingPolygon
14
14
  end
15
15
 
16
16
  def <(other_segment)
17
- return true if @left_point.y < other_segment.left_point.y
17
+ if @left_point == other_segment.left_point
18
+ return true if @right_point.is_left(other_segment.left_point,other_segment.right_point)<0
19
+ end
20
+
21
+ return true if @left_point.is_left(other_segment.left_point,other_segment.right_point)<0
22
+
18
23
  return false
19
24
  end
20
25
 
21
26
  def >(other_segment)
22
- return true if @left_point.y > other_segment.left_point.y
27
+ if @left_point == other_segment.left_point
28
+ return true if @right_point.is_left(other_segment.left_point,other_segment.right_point)>0
29
+ end
30
+
31
+ return true if @left_point.is_left(other_segment.left_point,other_segment.right_point)>0
32
+
23
33
  return false
24
34
  end
25
35
 
26
36
  def == (other_segment)
27
- return true if @left_point.y == other_segment.left_point.y
37
+ return true if @left_point == other_segment.left_point && @right_point == other_segment.right_point && @edge==other_segment.edge
28
38
  return false
29
39
  end
30
40
 
41
+ def <=> other_segment
42
+ raise Exception.new("Self is edge=#{@edge}, the other_segment is nil") if other_segment.nil?
43
+
44
+ return 1 if self > other_segment
45
+ return -1 if self < other_segment
46
+ return 0 if self == other_segment
47
+ end
48
+
31
49
  def to_s
32
50
  return "edge:#{@edge.to_s}"
33
51
  end
@@ -48,5 +66,35 @@ module WindingPolygon
48
66
 
49
67
  Point.new(x, y)
50
68
  end
69
+
70
+ def is_intersected_with(other_segment)
71
+ # no intersect if either segment doesn't existend
72
+ return false if other_segment.nil?
73
+
74
+ #test for existence of an intersect point
75
+ #other_segment left point sign
76
+ lsign = other_segment.left_point.is_left(@left_point, @right_point)
77
+ #other_segment right point sign
78
+ rsign = other_segment.right_point.is_left(@left_point, @right_point)
79
+
80
+ # other_segment endpoints have same sign relative to it => on same side => no intersect is possible
81
+ return false if (lsign * rsign > 0)
82
+
83
+ # its left point sign
84
+ lsign = @left_point.is_left(other_segment.left_point, other_segment.right_point)
85
+ #its right point sign
86
+ rsign = @right_point.is_left(other_segment.left_point, other_segment.right_point)
87
+
88
+ # its endpoints have same sign relative to other_segment => on same side => no intersect is possible
89
+ return false if (lsign * rsign > 0)
90
+
91
+ return true
92
+
93
+ end
94
+
95
+ def is_on_the_line(point)
96
+ return true if @left_point.x<point.x && point.x < @right_point.x && (@left_point.y<point.y && point.y < @right_point.y || @right_point.y<point.y && point.y < @left_point.y) && ((point.x - @left_point.x) / (@right_point.x - @left_point.x) - (point.y - @left_point.y) / (@right_point.y - @left_point.y)).abs<0.00000000001
97
+ false
98
+ end
51
99
  end
52
100
  end
@@ -45,6 +45,29 @@ module WindingPolygon
45
45
 
46
46
  end
47
47
 
48
+ def add_segment(seg)
49
+ seg.below=seg.above=nil
50
+
51
+ # Add node to tree and setup linkages to "above" and "below"
52
+ # edges as per algorithm
53
+ nd = @tree.insert(seg)
54
+
55
+ nx = nd.next
56
+ np = nd.prev
57
+
58
+ if !nx.nil?
59
+ seg.above = nx.value
60
+ seg.above.below = seg
61
+ end
62
+
63
+ if !np.nil?
64
+ seg.below = np.value
65
+ seg.below.above = seg
66
+ end
67
+ return seg
68
+
69
+ end
70
+
48
71
  def find(event)
49
72
  # need a segment to find it in the tree
50
73
  seg = Segment.new(event)
@@ -68,6 +91,12 @@ module WindingPolygon
68
91
  node.value
69
92
  end
70
93
 
94
+ def find_segment(seg)
95
+ node = @tree.search(seg)
96
+ return nil if node.nil?
97
+ node.value
98
+ end
99
+
71
100
  def remove(seg)
72
101
  nd = @tree.search(seg)
73
102
  return if nd.nil?
@@ -81,13 +110,14 @@ module WindingPolygon
81
110
  @tree.delete(seg)
82
111
  end
83
112
 
84
- def switch(s1,s2)
113
+ def swap(s1,s2)
85
114
  nd1 = @tree.search(s1)
86
115
  return if nd1.nil?
87
116
 
88
117
  nd2 = @tree.search(s2)
89
118
  return if nd2.nil?
90
119
 
120
+
91
121
  nx1 = nd1.next
92
122
  nx1.value.below = nd2.value if !nx1.nil?
93
123
 
@@ -100,6 +130,28 @@ module WindingPolygon
100
130
  np2 = nd2.prev
101
131
  np2.value.above = nd1.value if !np2.nil?
102
132
 
133
+
134
+ nd1.value = s2
135
+ nd2.value = s1
136
+
137
+ temp = s1
138
+ s1=s2
139
+ s2=temp
140
+
141
+
142
+
143
+ temp_above = s1.above
144
+ temp_below = s1.below
145
+
146
+ s1.above = s2.above
147
+ s1.below = s2.below
148
+
149
+ s2.above = temp_above
150
+ s2.below = temp_below
151
+
152
+
153
+ [s1,s2]
154
+
103
155
  end
104
156
 
105
157
  #test intersect of 2 segments and return: nil when none, point when intersecting
@@ -0,0 +1,50 @@
1
+ module WindingPolygon
2
+ class Vector < Struct.new(:x, :y)
3
+ def ==(vector)
4
+ x === vector.x && y === vector.y
5
+ end
6
+
7
+ # Modulus of vector. Also known as length, size or norm
8
+ def modulus
9
+ Math.hypot(x ,y)
10
+ end
11
+
12
+ # z-coordinate of cross product (also known as vector product or outer product)
13
+ # It is positive if other vector should be turned counter-clockwise in order to superpose them.
14
+ # It is negetive if other vector should be turned clockwise in order to superpose them.
15
+ # It is zero when vectors are collinear.
16
+ # Remark: x- and y- coordinates of plane vectors cross product are always zero
17
+ def cross_product(vector)
18
+ x * vector.y - y * vector.x
19
+ end
20
+
21
+ # Scalar product, also known as inner product or dot product
22
+ def scalar_product(vector)
23
+ x * vector.x + y * vector.y
24
+ end
25
+
26
+ def collinear_with?(vector)
27
+ cross_product(vector) === 0
28
+ end
29
+
30
+ def +(vector)
31
+ Vector.new(x + vector.x, y + vector.y)
32
+ end
33
+
34
+ def -(vector)
35
+ self + (-1) * vector
36
+ end
37
+
38
+ def *(scalar)
39
+ Vector.new(x * scalar, y * scalar)
40
+ end
41
+
42
+ def coerce(scalar)
43
+ if scalar.is_a?(Numeric)
44
+ [self, scalar]
45
+ else
46
+ raise ArgumentError, "Vector: cannot coerce #{scalar.inspect}"
47
+ end
48
+ end
49
+ end
50
+ end
@@ -1,3 +1,3 @@
1
1
  module WindingPolygon
2
- VERSION = "0.0.7"
2
+ VERSION = "0.0.8"
3
3
  end
data/spec/polygon_spec.rb CHANGED
@@ -174,25 +174,28 @@ describe "Polygon" do
174
174
  points = JSON.parse("[[-98.4609375000036,40.3051841980949],[-98.4609375000036,38.057277897745],[-96.0878906250017,40.1038062719331],[-96.6152343750031,37.9880405545487],[-98.4609375000036,40.3051841980949]]")
175
175
  polygon = WindingPolygon::Polygon.new(points.map{|item| WindingPolygon::Point.new(item[0],item[1])})
176
176
 
177
- polygon.get_first_intersection_point_hash.should == {:point=>WindingPolygon::Point.new(-97.39951856124108,38.97265129300353),:edge1=>1,:edge2=>3 }
177
+ polygon.get_first_intersection_point_hash.should == {:point=>WindingPolygon::Point.new(-97.39951856124108,38.97265129300353),:edge1=>3,:edge2=>1 }
178
178
 
179
179
  end
180
180
 
181
- it 'should decompose a practical complex polygon into two simple polygons' do
181
+ it 'get practical complex polygon 5 intersection points' do
182
182
 
183
- points = JSON.parse("[[-98.4609375000036,40.3051841980949],[-98.4609375000036,38.057277897745],[-96.0878906250017,40.1038062719331],[-96.6152343750031,37.9880405545487],[-98.4609375000036,40.3051841980949]]")
183
+ points = JSON.parse("[[-98.4609375000036,40.3051841980949],[-98.4609375000036,38.057277897745],[-96.0878906250017,40.1038062719331],[-96.6152343750031,37.9880405545487],[-97.6152343750031,40.9880405545487],[-98.0152343750031,37.9880405545487],[-98.4609375000036,40.3051841980949]]")
184
184
  polygon = WindingPolygon::Polygon.new(points.map{|item| WindingPolygon::Point.new(item[0],item[1])})
185
185
 
186
- multi_polygons = polygon.decompose
187
- multi_polygons.should_not be_nil
186
+ polygon.get_intersection_points.size.should == 3
187
+
188
+ end
189
+
190
+ it 'get practical complex polygon 6 intersection points' do
191
+
192
+ points = JSON.parse("[["+"-115.86328125000495 34.15328996737699,-119.818359375002 45.45290147989422,-81.4101562500034 35.021556836103684,-110.50195312500117 46.97322061018078,-92.66015625000608 43.38159203778072,-94.68164062500398 46.18790776409503,-115.07226562500733 41.63237589430056,-104.17382812500229 40.17099871188528,-100.3945312500027 32.46399995947513,-95.82421875000551 37.08201838643584,-88.52929687500257 35.95188058401679,-84.31054687500303 33.64262887366194,-83.16796875000327 34.51617009551454,-82.37695312500296 32.538125275571225,-84.31054687500303 39.36031127050692,-72.79687500000323 42.739443407624286,-115.86328125000495 34.15328996737699".gsub(',','],[').gsub(' ',',')+"]]")
193
+ polygon = WindingPolygon::Polygon.new(points.map{|item| WindingPolygon::Point.new(item[0],item[1])})
188
194
 
189
- points1 = JSON.parse("[[-98.4609375000036,40.3051841980949],[-98.4609375000036,38.057277897745],[-97.39951856124108,38.97265129300353],[-98.4609375000036,40.3051841980949]]")
190
- polygon1 = WindingPolygon::Polygon.new(points1.map{|item| WindingPolygon::Point.new(item[0],item[1])})
191
- multi_polygons[0].should ==polygon1
195
+ intersection_points = polygon.get_intersection_points
196
+ intersection_points.size.should == 8
197
+ polygon.simple_segments.size == 32
192
198
 
193
- points2 = JSON.parse("[[-97.39951856124108,38.97265129300353],[-96.0878906250017,40.1038062719331],[-96.6152343750031,37.9880405545487],[-97.39951856124108,38.97265129300353]]")
194
- polygon2 = WindingPolygon::Polygon.new(points2.map{|item| WindingPolygon::Point.new(item[0],item[1])})
195
- multi_polygons[1].should ==polygon2
196
199
 
197
200
  end
198
201
 
data/spec/segment_spec.rb CHANGED
@@ -17,4 +17,16 @@ describe "Segment" do
17
17
  intersection_point.y.should ==2
18
18
 
19
19
  end
20
+
21
+ it "point is on the line segment" do
22
+
23
+ segment1 = WindingPolygon::Segment.new({:edge=>0})
24
+ segment1.left_point = WindingPolygon::Point.new(0,0)
25
+ segment1.right_point = WindingPolygon::Point.new(3,3)
26
+
27
+ segment1.is_on_the_line(WindingPolygon::Point.new(1.5,1.5)).should == true
28
+ segment1.is_on_the_line(WindingPolygon::Point.new(1.5,2.5)).should == false
29
+ segment1.is_on_the_line(WindingPolygon::Point.new(3.5,3.5)).should == false
30
+
31
+ end
20
32
  end
@@ -8,14 +8,17 @@ describe "SweepLine" do
8
8
  sweep_line = WindingPolygon::SweepLine.new(polygon)
9
9
  event_queue = WindingPolygon::EventQueue.new(polygon)
10
10
 
11
- event = event_queue.events.pop
11
+ event = event_queue.events.shift
12
12
  while !event.nil?
13
- sweep_line.add(event) if event[:type]=='left'
14
- event = event_queue.events.pop
15
- end
16
-
17
- for i in 0..3 do
18
- sweep_line.find({:edge=>i}).should_not be_nil
13
+ if event[:type]=='left'
14
+ sweep_line.add(event)
15
+ sweep_line.find(event).should_not be_nil
16
+ else
17
+ seg = sweep_line.find(event)
18
+ seg.should_not be_nil
19
+ sweep_line.remove(seg)
20
+ end
21
+ event = event_queue.events.shift
19
22
  end
20
23
 
21
24
  end
@@ -5,13 +5,18 @@ describe WindingPolygon do
5
5
  WindingPolygon::VERSION.should_not be_nil
6
6
  end
7
7
 
8
- it 'should decompose a practical complex polygon into two simple polygons' do
9
8
 
9
+ =begin
10
+ it 'should decompose a practical complex polygon into two simple polygons' do
11
+ puts 'should decompose a practical complex polygon into two simple polygons'
10
12
  points = JSON.parse("[[-98.4609375000036,40.3051841980949],[-98.4609375000036,38.057277897745],[-96.0878906250017,40.1038062719331],[-96.6152343750031,37.9880405545487],[-98.4609375000036,40.3051841980949]]")
11
13
  polygon = WindingPolygon::Polygon.new(points.map{|item| WindingPolygon::Point.new(item[0],item[1])})
12
14
 
13
15
  multi_polygons = []
16
+ t1 = Time.now
14
17
  WindingPolygon.decompose(polygon,multi_polygons)
18
+ t2 = Time.now
19
+ puts "elapsed time: #{(t2-t1)*1000.to_i} ms"
15
20
  multi_polygons.should_not be_nil
16
21
 
17
22
  points1 = JSON.parse("[[-98.4609375000036,40.3051841980949],[-98.4609375000036,38.057277897745],[-97.39951856124108,38.97265129300353],[-98.4609375000036,40.3051841980949]]")
@@ -26,12 +31,15 @@ describe WindingPolygon do
26
31
 
27
32
 
28
33
  it 'should decompose a practical complex polygon into four simple polygons' do
29
-
34
+ puts 'should decompose a practical complex polygon into four simple polygons'
30
35
  points = JSON.parse("[[-98.4609375000036,40.3051841980949],[-98.4609375000036,38.057277897745],[-96.0878906250017,40.1038062719331],[-96.6152343750031,37.9880405545487],[-97.6152343750031,40.9880405545487],[-98.0152343750031,37.9880405545487],[-98.4609375000036,40.3051841980949]]")
31
36
  polygon = WindingPolygon::Polygon.new(points.map{|item| WindingPolygon::Point.new(item[0],item[1])})
32
37
 
33
38
  multi_polygons = []
39
+ t1 = Time.now
34
40
  WindingPolygon.decompose(polygon,multi_polygons)
41
+ t2 = Time.now
42
+ puts "elapsed time: #{(t2-t1)*1000.to_i} ms"
35
43
  multi_polygons.should_not be_nil
36
44
 
37
45
  multi_polygons.size.should == 4
@@ -39,12 +47,15 @@ describe WindingPolygon do
39
47
  end
40
48
 
41
49
  it 'should decompose a production complex polygon 2 into two simple polygons' do
42
-
50
+ puts 'should decompose a production complex polygon 2 into two simple polygons'
43
51
  points = JSON.parse("[[-95.6968,29.93101],[-95.6992,29.93101],[-95.7016,29.9319],[-95.70401,29.93309],[-95.7071,29.93428],[-95.7095,29.93488],[-95.7119,29.93547],[-95.71431,29.93607],[-95.7174,29.93666],[-95.72014,29.93726],[-95.72255,29.93785],[-95.72564,29.93875],[-95.72804,29.93994],[-95.72598,29.95094],[-95.72358,29.95303],[-95.72152,29.95481],[-95.71877,29.95659],[-95.71637,29.95778],[-95.71362,29.95838],[-95.71122,29.95838],[-95.70847,29.95838],[-95.70538,29.95808],[-95.70195,29.95778],[-95.69851,29.95719],[-95.69405,29.956],[-95.69165,29.9554],[-95.6889,29.95451],[-95.68615,29.95332],[-95.68307,29.95184],[-95.68066,29.95124],[-95.67723,29.94856],[-95.67483,29.94648],[-95.67242,29.9438],[-95.67448,29.93607],[-95.67689,29.93339],[-95.67895,29.93161],[-95.68101,29.93131],[-95.68341,29.93131],[-95.68615,29.93131],[-95.6889,29.93101],[-95.69165,29.93101],[-95.69439,29.93101],[-95.69748,29.93161],[-95.70023,29.9322],[-95.70435,29.93339],[-95.70641,29.93428],[-95.70984,29.93458],[-95.6968,29.93101]]")
44
52
  polygon = WindingPolygon::Polygon.new(points.map{|item| WindingPolygon::Point.new(item[0].to_f,item[1].to_f)})
45
53
 
46
54
  multi_polygons = []
55
+ t1 = Time.now
47
56
  WindingPolygon.decompose(polygon,multi_polygons)
57
+ t2 = Time.now
58
+ puts "elapsed time: #{(t2-t1)*1000.to_i} ms"
48
59
  multi_polygons.should_not be_nil
49
60
 
50
61
  multi_polygons.size.should == 3
@@ -53,11 +64,15 @@ describe WindingPolygon do
53
64
 
54
65
  it 'should decompose a production complex polygon 3 into two simple polygons' do
55
66
 
67
+ puts 'should decompose a production complex polygon 3 into two simple polygons'
56
68
  points = JSON.parse("[[-95.6968,29.93101],[-95.6992,29.93101],[-95.7016,29.9319],[-95.70401,29.93309],[-95.7071,29.93428],[-95.70747130044843,29.934372825112106],[-95.70984,29.93458],[-95.6968,29.93101]]")
57
69
  polygon = WindingPolygon::Polygon.new(points.map{|item| WindingPolygon::Point.new(item[0].to_f,item[1].to_f)})
58
70
 
59
71
  multi_polygons = []
72
+ t1 = Time.now
60
73
  WindingPolygon.decompose(polygon,multi_polygons)
74
+ t2 = Time.now
75
+ puts "elapsed time: #{(t2-t1)*1000.to_i} ms"
61
76
  multi_polygons.should_not be_nil
62
77
 
63
78
  multi_polygons.size.should == 2
@@ -65,18 +80,102 @@ describe WindingPolygon do
65
80
  end
66
81
 
67
82
  it 'should decompose a production complex polygon 4 into two simple polygons' do
68
-
83
+ puts 'should decompose a production complex polygon 4 into two simple polygons'
69
84
  points = JSON.parse("[[-87.80356,41.96514],[-87.80115,41.96182],[-87.79909,41.96156],[-87.79635,41.96131],[-87.79394,41.96105],[-87.79188,41.9608],[-87.78914,41.95978],[-87.78708,41.95876],[-87.78467,41.95722],[-87.78193,41.95544],[-87.77987,41.95339],[-87.77781,41.9511],[-87.77541,41.94803],[-87.773,41.94446],[-87.7706,41.94063],[-87.76785,41.9368],[-87.76545,41.93271],[-87.76339,41.92658],[-87.76133,41.91687],[-87.76373,41.87522],[-87.76579,41.87445],[-87.76854,41.87394],[-87.7706,41.87368],[-87.77335,41.87343],[-87.77575,41.87266],[-87.77815,41.8724],[-87.78021,41.87215],[-87.78296,41.87164],[-87.78536,41.87113],[-87.78776,41.87113],[-87.78982,41.87113],[-87.79223,41.87113],[-87.79463,41.87113],[-87.79703,41.87113],[-87.79978,41.87138],[-87.80184,41.87189],[-87.8039,41.8724],[-87.8063,41.87317],[-87.80871,41.87419],[-87.81077,41.87471],[-87.81283,41.87547],[-87.81523,41.87649],[-87.81729,41.87726],[-87.81935,41.87752],[-87.82141,41.87777],[-87.82347,41.87803],[-87.82622,41.87828],[-87.82862,41.87854],[-87.83171,41.87854],[-87.83377,41.8788],[-87.83652,41.87931],[-87.83926,41.88007],[-87.84132,41.88058],[-87.84373,41.88135],[-87.84613,41.88237],[-87.84888,41.88365],[-87.85094,41.88493],[-87.85334,41.88697],[-87.8554,41.89055],[-87.85746,41.89515],[-87.85952,41.90026],[-87.86158,41.90435],[-87.85952,41.92913],[-87.85746,41.93373],[-87.8554,41.94139],[-87.85334,41.94573],[-87.85094,41.94778],[-87.84888,41.94905],[-87.84647,41.95059],[-87.84304,41.95263],[-87.84098,41.95365],[-87.83892,41.95442],[-87.83514,41.95671],[-87.83308,41.95773],[-87.83102,41.95901],[-87.82862,41.96003],[-87.82484,41.96207],[-87.82107,41.9631],[-87.81901,41.9631],[-87.81695,41.9631],[-87.81351,41.9631],[-87.81042,41.96284],[-87.80699,41.96233],[-87.80424,41.96207],[-87.80184,41.96156],[-87.79978,41.96105],[-87.79703,41.95901],[-87.80356,41.96514]]")
70
85
  polygon = WindingPolygon::Polygon.new(points.map{|item| WindingPolygon::Point.new(item[0].to_f,item[1].to_f)})
71
86
 
72
87
  multi_polygons = []
88
+ t1 = Time.now
73
89
  WindingPolygon.decompose(polygon,multi_polygons)
90
+ t2 = Time.now
91
+ puts "elapsed time: #{(t2-t1)*1000.to_i} ms"
74
92
  multi_polygons.should_not be_nil
75
93
 
76
94
  multi_polygons.size.should == 2
77
95
 
78
96
  end
79
97
 
98
+ it 'should decompose a production complex polygon 5 into two simple polygons' do
99
+ puts 'should decompose a production complex polygon 5 into two simple polygons'
100
+ points = JSON.parse("[[153.4229,-28.0902],[153.42346,-28.09104],[153.42395,-28.09178],[153.42435,-28.09254],[153.42487,-28.09328],[153.4229,-28.0902]]")
101
+ polygon = WindingPolygon::Polygon.new(points.map{|item| WindingPolygon::Point.new(item[0].to_f,item[1].to_f)})
102
+
103
+ multi_polygons = []
104
+ t1 = Time.now
105
+ WindingPolygon.decompose(polygon,multi_polygons)
106
+ t2 = Time.now
107
+ puts "elapsed time: #{(t2-t1)*1000.to_i} ms"
108
+ multi_polygons.should_not be_nil
109
+
110
+ multi_polygons.size.should == 2
111
+
112
+ end
113
+
114
+ it 'should decompose a production complex polygon 6 into three simple polygons' do
115
+ puts 'should decompose a production complex polygon 6 into three simple polygons'
116
+ points = JSON.parse("[["+"-78.17273 38.94346,-78.17685 38.93652,-78.18097 38.93171,-78.18578 38.92637,-78.1899 38.91836,-78.19196 38.91622,-78.17273 38.94346".gsub(',','],[').gsub(' ',',')+"]]")
117
+ polygon = WindingPolygon::Polygon.new(points.map{|item| WindingPolygon::Point.new(item[0].to_f,item[1].to_f)})
118
+
119
+ multi_polygons = []
120
+ t1 = Time.now
121
+ WindingPolygon.decompose(polygon,multi_polygons)
122
+ t2 = Time.now
123
+ puts "elapsed time: #{(t2-t1)*1000.to_i} ms"
124
+ multi_polygons.should_not be_nil
125
+
126
+ multi_polygons.size.should == 3
127
+
128
+ end
129
+
130
+ it 'should decompose a production complex polygon 7 into two simple polygons' do
131
+ puts 'should decompose a production complex polygon 7 into two simple polygons'
132
+ points = JSON.parse("[["+"-71.77812 41.42488,-71.774 41.42024,-71.76782 41.41818,-71.76301 41.41818,-71.75546 41.41818,-71.74859 41.41818,-71.74172 41.41818,-71.73486 41.41818,-71.7273 41.41818,-71.71906 41.41818,-71.71288 41.41818,-71.70739 41.41818,-71.70327 41.41818,-71.69778 41.41818,-71.69366 41.41612,-71.77812 41.42488".gsub(',','],[').gsub(' ',',')+"]]")
133
+ polygon = WindingPolygon::Polygon.new(points.map{|item| WindingPolygon::Point.new(item[0].to_f,item[1].to_f)})
134
+
135
+ multi_polygons = []
136
+ t1 = Time.now
137
+ WindingPolygon.decompose(polygon,multi_polygons)
138
+ t2 = Time.now
139
+ puts "elapsed time: #{(t2-t1)*1000.to_i} ms"
140
+ multi_polygons.should_not be_nil
141
+
142
+ multi_polygons.size.should == 2
143
+
144
+ end
145
+
146
+ it 'should decompose a production complex polygon 8 into four simple polygons' do
147
+ puts 'should decompose a production complex polygon 8 into four simple polygons'
148
+ points = JSON.parse("[["+"-88.69626 32.36626,-88.69697 32.36713,-88.69706 32.36722,-88.69713 32.3673,-88.69719 32.36738,-88.69729 32.36747,-88.69743 32.36758,-88.69749 32.36765,-88.69759 32.36777,-88.69767 32.36791,-88.69769 32.36798,-88.69626 32.36626".gsub(',','],[').gsub(' ',',')+"]]")
149
+ polygon = WindingPolygon::Polygon.new(points.map{|item| WindingPolygon::Point.new(item[0].to_f,item[1].to_f)})
150
+
151
+ multi_polygons = []
152
+ t1 = Time.now
153
+ WindingPolygon.decompose(polygon,multi_polygons)
154
+ t2 = Time.now
155
+ puts "elapsed time: #{(t2-t1)*1000.to_i} ms"
156
+ multi_polygons.should_not be_nil
157
+
158
+ multi_polygons.size.should == 4
159
+
160
+ end
161
+ =end
162
+
163
+
164
+ it 'should decompose Andy complex polygon into 7 simple polygons' do
165
+ puts 'should decompose Andy complex polygon into four simple polygons'
166
+ points = JSON.parse("[["+"-115.86328125000495 34.15328996737699,-119.818359375002 45.45290147989422,-81.4101562500034 35.021556836103684,-110.50195312500117 46.97322061018078,-92.66015625000608 43.38159203778072,-94.68164062500398 46.18790776409503,-115.07226562500733 41.63237589430056,-104.17382812500229 40.17099871188528,-100.3945312500027 32.46399995947513,-95.82421875000551 37.08201838643584,-88.52929687500257 35.95188058401679,-84.31054687500303 33.64262887366194,-83.16796875000327 34.51617009551454,-82.37695312500296 32.538125275571225,-84.31054687500303 39.36031127050692,-72.79687500000323 42.739443407624286,-115.86328125000495 34.15328996737699".gsub(',','],[').gsub(' ',',')+"]]")
167
+ polygon = WindingPolygon::Polygon.new(points.map{|item| WindingPolygon::Point.new(item[0].to_f,item[1].to_f)})
168
+
169
+ t1 = Time.now
170
+ multi_polygons = WindingPolygon.decompose(polygon)
171
+ t2 = Time.now
172
+ puts "elapsed time: #{(t2-t1)*1000.to_i} ms"
173
+
174
+
175
+ multi_polygons.size.should == 7
176
+
177
+ end
178
+
80
179
 
81
180
 
82
181
  end
data/test/test_avltree.rb CHANGED
@@ -65,6 +65,8 @@ class TestAVLTree < Test::Unit::TestCase
65
65
  assert_equal "[1, 5]", @tree.sort.inspect
66
66
  @tree.delete 1
67
67
  assert_equal "[5]", @tree.sort.inspect
68
+ @tree.delete 5
69
+ assert_equal nil, @tree.root
68
70
 
69
71
  @rot_tree.delete 1
70
72
  assert_equal 4.to_s, @rot_tree.root.to_s
@@ -0,0 +1,22 @@
1
+ require 'test/unit'
2
+ require 'winding-polygon/vector'
3
+
4
+ class ArithmeticsTest < Test::Unit::TestCase
5
+ include WindingPolygon
6
+
7
+ def test_summation
8
+ assert_equal Vector.new(4, 6), Vector.new(1, 2) + Vector.new(3, 4)
9
+ end
10
+
11
+ def test_subtraction
12
+ assert_equal Vector.new(-2, -4), Vector.new(1, 0) - Vector.new(3, 4)
13
+ end
14
+
15
+ def test_vector_multiplied_by_scalar
16
+ assert_equal Vector.new(-2, -4), Vector.new(1, 2) * -2
17
+ end
18
+
19
+ def test_scalar_multiplied_by_vector
20
+ assert_equal Vector.new(-2, -4), -2 * Vector.new(1, 2)
21
+ end
22
+ end
@@ -0,0 +1,27 @@
1
+ require 'test/unit'
2
+ require 'winding-polygon/vector'
3
+
4
+ class CollinearWithTest < Test::Unit::TestCase
5
+ include WindingPolygon
6
+
7
+ def test_vectors_are_collinear
8
+ vector1 = Vector.new(1, 2)
9
+ vector2 = Vector.new(2, 4)
10
+
11
+ assert vector1.collinear_with?(vector2)
12
+ end
13
+
14
+ def test_vectors_are_not_collinear
15
+ vector1 = Vector.new(1, 2)
16
+ vector2 = Vector.new(1, 1)
17
+
18
+ assert ! vector1.collinear_with?(vector2)
19
+ end
20
+
21
+ def test_vectors_are_oppositely_directed
22
+ vector1 = Vector.new(2, 2)
23
+ vector2 = Vector.new(-2, -2)
24
+
25
+ assert vector1.collinear_with?(vector2)
26
+ end
27
+ end
@@ -0,0 +1,86 @@
1
+ require 'test/unit'
2
+ require 'winding-polygon/vector'
3
+ require 'winding-polygon/point'
4
+
5
+ class CrossProductTest < Test::Unit::TestCase
6
+ include WindingPolygon
7
+
8
+ def test_positive
9
+ assert 1 === Vector.new(1, 0).cross_product(Vector.new(0, 1))
10
+ assert 1 === Vector.new(-1, 0).cross_product(Vector.new(0, -1))
11
+ assert 0 === Vector.new(-1, 0).cross_product(Vector.new(1, 0))
12
+ assert 0 === Vector.new(-1, 0).cross_product(Vector.new(2, 0))
13
+ end
14
+
15
+ def test_positive_for_latlon
16
+ #current vertex
17
+ p0= Point.new(-102.52676351947564,36.81219275411459)
18
+ #previous vertex
19
+ p1=Point.new(-115.86328125000495,34.15328996737699)
20
+ #current edge
21
+ v0 = Vector.new(p1.x-p0.x, p1.y-p0.y)
22
+
23
+ #next vertex
24
+ p2= Point.new(-104.17382812500229,40.17099871188528)
25
+ #next edge
26
+ v1 = Vector.new(p2.x-p0.x, p2.y-p0.y)
27
+
28
+ assert_true v1.cross_product(v0)>0
29
+
30
+ end
31
+
32
+ def test_positive_for_latlon2
33
+ #current vertex
34
+ p0=Point.new(-103.69099150583577,44.1751011402773)
35
+ #previous vertex
36
+ p1= Point.new(-110.50195312500117,46.97322061018078)
37
+ #current edge
38
+ v0 = Vector.new(p1.x-p0.x, p1.y-p0.y)
39
+
40
+ #next vertex
41
+ p2= Point.new(-100.33100481371673,44.925766039368476)
42
+ #next edge
43
+ v1 = Vector.new(p2.x-p0.x, p2.y-p0.y)
44
+
45
+ assert_true v1.cross_product(v0)>0
46
+ end
47
+
48
+ def test_negative
49
+ assert(-1 === Vector.new(0, 1).cross_product(Vector.new(1, 0)))
50
+ end
51
+
52
+ def test_negative_for_latlon
53
+ p0= Point.new(-81.4101562500034,35.021556836103684)
54
+ p1=Point.new(-115.86328125000495,34.15328996737699)
55
+ v0 = Vector.new(p1.x-p0.x, p1.y-p0.y)
56
+
57
+ p2= Point.new(-100.3945312500027,32.46399995947513)
58
+ v1 = Vector.new(p2.x-p0.x, p2.y-p0.y)
59
+
60
+ assert_true v1.cross_product(v0)<0
61
+ end
62
+
63
+ def test_negative_for_latlon_2
64
+ #current vertex
65
+ p0=Point.new(-103.69099150583577,44.1751011402773)
66
+ #previous vertex
67
+ p1= Point.new(-110.50195312500117,46.97322061018078)
68
+ #current edge
69
+ v0 = Vector.new(p1.x-p0.x, p1.y-p0.y)
70
+
71
+ #next vertex
72
+ p2= Point.new(-109.95811865270818,42.77494310443354)
73
+ #next edge
74
+ v1 = Vector.new(p2.x-p0.x, p2.y-p0.y)
75
+
76
+ assert_true v1.cross_product(v0)<0
77
+ end
78
+
79
+ def test_zero
80
+ assert 0 === Vector.new(1, 1).cross_product(Vector.new(-2, -2))
81
+ end
82
+
83
+ def test_unnormalized
84
+ assert 4 === Vector.new(1, 1).cross_product(Vector.new(-2, 2))
85
+ end
86
+ end
@@ -0,0 +1,15 @@
1
+ require 'test/unit'
2
+ require 'winding-polygon/vector'
3
+
4
+ class EqualsTest < Test::Unit::TestCase
5
+ include WindingPolygon
6
+
7
+ def test_equal
8
+ assert_equal Vector.new(1, 3), Vector.new(1, 3)
9
+ end
10
+
11
+ def test_not_equal
12
+ assert_not_equal Vector.new(1, 3), Vector.new(1, 2)
13
+ assert_not_equal Vector.new(1, 2), Vector.new(0, 2)
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'test/unit'
2
+ require 'winding-polygon/vector'
3
+
4
+ class ModulusTest < Test::Unit::TestCase
5
+ include WindingPolygon
6
+
7
+ def test_parallel_to_axis
8
+ assert 1 === Vector.new(1, 0).modulus
9
+ assert 1 === Vector.new(0, 1).modulus
10
+ end
11
+
12
+ def test_inclined
13
+ assert Math.sqrt(2) === Vector.new(1, 1).modulus
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ require 'test/unit'
2
+ require 'winding-polygon/vector'
3
+
4
+ class ScalarProductTest < Test::Unit::TestCase
5
+ include WindingPolygon
6
+
7
+ def test_vectors_are_perpendicular
8
+ assert 0 === Vector.new(1, 1).scalar_product(Vector.new(-1, 1))
9
+ end
10
+
11
+ def test_vectors_are_collinear
12
+ assert(-4 === Vector.new(1, 1).scalar_product(Vector.new(-2, -2)))
13
+ end
14
+
15
+ def test_vectors_are_inclined
16
+ assert 1 === Vector.new(1, 1).scalar_product(Vector.new(0, 1))
17
+ end
18
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: winding-polygon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Xu
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-05-16 00:00:00.000000000 Z
11
+ date: 2013-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -28,31 +28,31 @@ dependencies:
28
28
  name: test-unit
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ! '>='
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ! '>='
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ! '>='
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ! '>='
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
- description: 'Use Bentley-Ottmann algorithm to solve self-intersecting polygon issue '
55
+ description: ! 'Use Bentley-Ottmann algorithm to solve self-intersecting polygon issue '
56
56
  email:
57
57
  - mxu2008@gmail.com
58
58
  executables: []
@@ -72,6 +72,7 @@ files:
72
72
  - lib/winding-polygon/polygon.rb
73
73
  - lib/winding-polygon/segment.rb
74
74
  - lib/winding-polygon/sweep_line.rb
75
+ - lib/winding-polygon/vector.rb
75
76
  - lib/winding-polygon/version.rb
76
77
  - spec/event_queue_spec.rb
77
78
  - spec/point_spec.rb
@@ -81,6 +82,12 @@ files:
81
82
  - spec/sweep_line_spec.rb
82
83
  - spec/winding-polygon_spec.rb
83
84
  - test/test_avltree.rb
85
+ - test/vector/arithmetics_test.rb
86
+ - test/vector/collinear_with_test.rb
87
+ - test/vector/cross_product_test.rb
88
+ - test/vector/equals_test.rb
89
+ - test/vector/modulus_test.rb
90
+ - test/vector/scalar_product_test.rb
84
91
  - winding-polygon.gemspec
85
92
  homepage: ''
86
93
  licenses:
@@ -92,17 +99,17 @@ require_paths:
92
99
  - lib
93
100
  required_ruby_version: !ruby/object:Gem::Requirement
94
101
  requirements:
95
- - - '>='
102
+ - - ! '>='
96
103
  - !ruby/object:Gem::Version
97
104
  version: '0'
98
105
  required_rubygems_version: !ruby/object:Gem::Requirement
99
106
  requirements:
100
- - - '>='
107
+ - - ! '>='
101
108
  - !ruby/object:Gem::Version
102
109
  version: '0'
103
110
  requirements: []
104
111
  rubyforge_project:
105
- rubygems_version: 2.0.0
112
+ rubygems_version: 2.0.3
106
113
  signing_key:
107
114
  specification_version: 4
108
115
  summary: Detect intersecting points and decompose it into multi-polygons
@@ -115,3 +122,9 @@ test_files:
115
122
  - spec/sweep_line_spec.rb
116
123
  - spec/winding-polygon_spec.rb
117
124
  - test/test_avltree.rb
125
+ - test/vector/arithmetics_test.rb
126
+ - test/vector/collinear_with_test.rb
127
+ - test/vector/cross_product_test.rb
128
+ - test/vector/equals_test.rb
129
+ - test/vector/modulus_test.rb
130
+ - test/vector/scalar_product_test.rb