winding-polygon 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/winding-polygon/avltree.rb +228 -226
- data/lib/winding-polygon/event_queue.rb +30 -28
- data/lib/winding-polygon/point.rb +39 -37
- data/lib/winding-polygon/polygon.rb +88 -86
- data/lib/winding-polygon/segment.rb +38 -37
- data/lib/winding-polygon/sweep_line.rb +109 -107
- data/lib/winding-polygon/version.rb +1 -1
- data/spec/event_queue_spec.rb +2 -2
- data/spec/point_spec.rb +14 -14
- data/spec/polygon_spec.rb +24 -24
- data/spec/segment_spec.rb +6 -6
- data/spec/sweep_line_spec.rb +3 -3
- data/spec/winding-polygon_spec.rb +3 -3
- data/test/test_avltree.rb +2 -2
- metadata +9 -9
@@ -1,34 +1,36 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
module WindingPolygon
|
2
|
+
class EventQueue
|
3
|
+
attr_reader :number_of_events
|
4
|
+
attr_reader :events
|
5
|
+
attr_reader :individual_vertices
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
def initialize(polygon)
|
8
|
+
#last vertex in geojson is equal to first vertex
|
9
|
+
@individual_vertices = polygon.vertices.length - 1
|
10
|
+
#2 per edge - last event looping back to 0 is handled by +1 below
|
11
|
+
@number_of_events = 2 * (@individual_vertices)
|
12
|
+
@events = []
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
14
|
+
#build up 2 'events' per edge. One for left vertex, one for right.
|
15
|
+
for i in 0..@individual_vertices-1
|
16
|
+
a = 2*i
|
17
|
+
b = 2*i+1
|
18
|
+
@events[a] = {:edge=>i}
|
19
|
+
@events[b] = {:edge=>i}
|
20
|
+
@events[a][:vertex] = polygon.vertices[i]
|
21
|
+
@events[b][:vertex] = polygon.vertices[i+1]
|
22
|
+
if @events[a][:vertex].compare(@events[b][:vertex]) < 0
|
23
|
+
@events[a][:type] = 'left'
|
24
|
+
@events[b][:type] = 'right'
|
25
|
+
else
|
26
|
+
@events[a][:type] = 'right'
|
27
|
+
@events[b][:type] = 'left'
|
28
|
+
end
|
27
29
|
end
|
30
|
+
|
31
|
+
# sort events lexicographically
|
32
|
+
@events.sort!{|a,b| a[:vertex].compare(b[:vertex])}
|
28
33
|
end
|
29
34
|
|
30
|
-
# sort events lexicographically
|
31
|
-
@events.sort!{|a,b| a[:vertex].compare(b[:vertex])}
|
32
35
|
end
|
33
|
-
|
34
|
-
end
|
36
|
+
end
|
@@ -1,40 +1,42 @@
|
|
1
|
-
|
1
|
+
module WindingPolygon
|
2
|
+
class Point
|
3
|
+
|
4
|
+
attr_reader :x
|
5
|
+
attr_reader :y
|
6
|
+
|
7
|
+
def initialize(x,y)
|
8
|
+
@x=x
|
9
|
+
@y=y
|
10
|
+
end
|
11
|
+
|
12
|
+
# Determines the xy lexicographical order of two points
|
13
|
+
def compare other_point
|
14
|
+
raise Exception.new("Self is x=#{@x},y=#{@y}, the other_point is nil") if other_point.nil?
|
15
|
+
# x-coord first
|
16
|
+
return 1 if @x > other_point.x
|
17
|
+
return -1 if @x < other_point.x
|
18
|
+
|
19
|
+
# y-coord second
|
20
|
+
return 1 if @y > other_point.y
|
21
|
+
return -1 if @y < other_point.y
|
22
|
+
|
23
|
+
# they are the same point
|
24
|
+
return 0
|
25
|
+
end
|
26
|
+
|
27
|
+
def == (other_point)
|
28
|
+
@x==other_point.x && @y==other_point.y
|
29
|
+
end
|
30
|
+
|
31
|
+
# tests if point is Left|On|Right of the line P0 to P1.
|
32
|
+
#
|
33
|
+
# returns:
|
34
|
+
# >0 for left of the line
|
35
|
+
# 0 for on the line
|
36
|
+
# <0 for right of the line
|
37
|
+
def is_left p0, p1
|
38
|
+
return (p1.x - p0.x) * (@y - p0.y) - (@x - p0.x) * (p1.y - p0.y)
|
39
|
+
end
|
2
40
|
|
3
|
-
attr_reader :x
|
4
|
-
attr_reader :y
|
5
|
-
|
6
|
-
def initialize(x,y)
|
7
|
-
@x=x
|
8
|
-
@y=y
|
9
|
-
end
|
10
|
-
|
11
|
-
# Determines the xy lexicographical order of two points
|
12
|
-
def compare other_point
|
13
|
-
raise Exception.new("Self is x=#{@x},y=#{@y}, the other_point is nil") if other_point.nil?
|
14
|
-
# x-coord first
|
15
|
-
return 1 if @x > other_point.x
|
16
|
-
return -1 if @x < other_point.x
|
17
|
-
|
18
|
-
# y-coord second
|
19
|
-
return 1 if @y > other_point.y
|
20
|
-
return -1 if @y < other_point.y
|
21
|
-
|
22
|
-
# they are the same point
|
23
|
-
return 0
|
24
41
|
end
|
25
|
-
|
26
|
-
def == (other_point)
|
27
|
-
@x==other_point.x && @y==other_point.y
|
28
|
-
end
|
29
|
-
|
30
|
-
# tests if point is Left|On|Right of the line P0 to P1.
|
31
|
-
#
|
32
|
-
# returns:
|
33
|
-
# >0 for left of the line
|
34
|
-
# 0 for on the line
|
35
|
-
# <0 for right of the line
|
36
|
-
def is_left p0, p1
|
37
|
-
return (p1.x - p0.x) * (@y - p0.y) - (@x - p0.x) * (p1.y - p0.y)
|
38
|
-
end
|
39
|
-
|
40
42
|
end
|
@@ -1,114 +1,116 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
module WindingPolygon
|
2
|
+
class Polygon
|
3
|
+
attr_reader :vertices
|
4
|
+
attr_reader :intersection_points
|
5
|
+
|
6
|
+
def initialize(points)
|
7
|
+
@vertices = points
|
8
|
+
@intersection_points = Array.new
|
9
|
+
end
|
4
10
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
end
|
11
|
+
def is_simple
|
12
|
+
event_queue = EventQueue.new(self)
|
13
|
+
sweep_line = SweepLine.new(self)
|
9
14
|
|
10
|
-
|
11
|
-
|
12
|
-
|
15
|
+
# This loop processes all events in the sorted queue
|
16
|
+
# Events are only left or right vertices
|
17
|
+
e = event_queue.events.shift
|
18
|
+
while !e.nil? do
|
13
19
|
|
14
|
-
|
15
|
-
|
16
|
-
e = event_queue.events.shift
|
17
|
-
while !e.nil? do
|
20
|
+
if e[:type] == 'left'
|
21
|
+
s = sweep_line.add(e)
|
18
22
|
|
19
|
-
|
20
|
-
|
23
|
+
return false if !sweep_line.intersect(s, s.above).nil?
|
24
|
+
return false if !sweep_line.intersect(s, s.below).nil?
|
25
|
+
else
|
26
|
+
s = sweep_line.find(e)
|
27
|
+
return false if !sweep_line.intersect(s.above, s.below).nil?
|
28
|
+
sweep_line.remove(s)
|
29
|
+
end
|
21
30
|
|
22
|
-
|
23
|
-
return false if !sweep_line.intersect(s, s.below).nil?
|
24
|
-
else
|
25
|
-
s = sweep_line.find(e)
|
26
|
-
return false if !sweep_line.intersect(s.above, s.below).nil?
|
27
|
-
sweep_line.remove(s)
|
31
|
+
e = event_queue.events.shift
|
28
32
|
end
|
29
33
|
|
30
|
-
|
34
|
+
return true
|
31
35
|
end
|
32
36
|
|
33
|
-
|
34
|
-
|
37
|
+
def get_intersection_points
|
38
|
+
event_queue = EventQueue.new(self)
|
39
|
+
sweep_line = SweepLine.new(self)
|
35
40
|
|
36
|
-
|
37
|
-
|
38
|
-
|
41
|
+
# This loop processes all events in the sorted queue
|
42
|
+
# Events are only left or right vertices
|
43
|
+
e = event_queue.events.shift
|
44
|
+
while !e.nil? do
|
39
45
|
|
40
|
-
|
41
|
-
|
42
|
-
e = event_queue.events.shift
|
43
|
-
while !e.nil? do
|
46
|
+
if e[:type] == 'left'
|
47
|
+
s = sweep_line.add(e)
|
44
48
|
|
45
|
-
|
46
|
-
|
49
|
+
add_to_intersection_point_collection(sweep_line.intersect(s, s.above))
|
50
|
+
add_to_intersection_point_collection(sweep_line.intersect(s, s.below))
|
47
51
|
|
48
|
-
|
49
|
-
|
52
|
+
else
|
53
|
+
s = sweep_line.find(e)
|
54
|
+
add_to_intersection_point_collection(sweep_line.intersect(s.above, s.below))
|
55
|
+
sweep_line.remove(s)
|
56
|
+
end
|
50
57
|
|
51
|
-
|
52
|
-
s = sweep_line.find(e)
|
53
|
-
add_to_intersection_point_collection(sweep_line.intersect(s.above, s.below))
|
54
|
-
sweep_line.remove(s)
|
58
|
+
e = event_queue.events.shift
|
55
59
|
end
|
56
60
|
|
57
|
-
|
61
|
+
return nil if intersection_points.size==0
|
62
|
+
@intersection_points
|
58
63
|
end
|
59
64
|
|
60
|
-
|
61
|
-
|
62
|
-
|
65
|
+
def add_to_intersection_point_collection(point)
|
66
|
+
@intersection_points << point if !point.nil? && !@intersection_points.any?{|p| p.compare(point)==0}
|
67
|
+
end
|
63
68
|
|
64
|
-
|
65
|
-
|
66
|
-
|
69
|
+
def get_first_intersection_point_hash
|
70
|
+
event_queue = EventQueue.new(self)
|
71
|
+
sweep_line = SweepLine.new(self)
|
67
72
|
|
68
|
-
|
69
|
-
|
70
|
-
sweep_line = SweepLine.new(self)
|
71
|
-
|
72
|
-
# This loop processes all events in the sorted queue
|
73
|
-
# Events are only left or right vertices
|
74
|
-
e = event_queue.events.shift
|
75
|
-
while !e.nil? do
|
76
|
-
if e[:type] == 'left'
|
77
|
-
s = sweep_line.add(e)
|
78
|
-
|
79
|
-
point = sweep_line.intersect(s, s.above)
|
80
|
-
return point_hash_with_edge_info(point, s, s.above) if !point.nil?
|
81
|
-
|
82
|
-
point = sweep_line.intersect(s, s.below)
|
83
|
-
return point_hash_with_edge_info(point, s, s.below) if !point.nil?
|
84
|
-
else
|
85
|
-
s = sweep_line.find(e)
|
86
|
-
point = sweep_line.intersect(s.above, s.below)
|
87
|
-
return point_hash_with_edge_info(point, s.above, s.below) if !point.nil?
|
88
|
-
sweep_line.remove(s)
|
89
|
-
end
|
73
|
+
# This loop processes all events in the sorted queue
|
74
|
+
# Events are only left or right vertices
|
90
75
|
e = event_queue.events.shift
|
76
|
+
while !e.nil? do
|
77
|
+
if e[:type] == 'left'
|
78
|
+
s = sweep_line.add(e)
|
79
|
+
|
80
|
+
point = sweep_line.intersect(s, s.above)
|
81
|
+
return point_hash_with_edge_info(point, s, s.above) if !point.nil?
|
82
|
+
|
83
|
+
point = sweep_line.intersect(s, s.below)
|
84
|
+
return point_hash_with_edge_info(point, s, s.below) if !point.nil?
|
85
|
+
else
|
86
|
+
s = sweep_line.find(e)
|
87
|
+
point = sweep_line.intersect(s.above, s.below)
|
88
|
+
return point_hash_with_edge_info(point, s.above, s.below) if !point.nil?
|
89
|
+
sweep_line.remove(s)
|
90
|
+
end
|
91
|
+
e = event_queue.events.shift
|
92
|
+
end
|
93
|
+
return nil
|
91
94
|
end
|
92
|
-
return nil
|
93
|
-
end
|
94
95
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
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
|
102
103
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
104
|
+
def point_hash_with_edge_info(point, s1, s2)
|
105
|
+
edges=[s1.edge, s2.edge].sort!
|
106
|
+
{:point => point, :edge1 => edges[0], :edge2 => edges[1]}
|
107
|
+
end
|
107
108
|
|
108
|
-
|
109
|
-
|
110
|
-
|
109
|
+
def ==(other_polygon)
|
110
|
+
for i in 0..@vertices.size-1
|
111
|
+
return false if @vertices[i] != other_polygon.vertices[i]
|
112
|
+
end
|
113
|
+
return true
|
111
114
|
end
|
112
|
-
return true
|
113
115
|
end
|
114
116
|
end
|
@@ -1,48 +1,49 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
def initialize(event)
|
12
|
-
@edge = event[:edge]
|
13
|
-
end
|
1
|
+
module WindingPolygon
|
2
|
+
#A container class for segments (or edges) of the polygon to test
|
3
|
+
#Allows storage and retrieval from the Balanced Binary Tree
|
4
|
+
class Segment
|
5
|
+
attr_reader :edge
|
6
|
+
attr_accessor :left_point
|
7
|
+
attr_accessor :right_point
|
8
|
+
attr_accessor :above
|
9
|
+
attr_accessor :below
|
14
10
|
|
15
|
-
def <(other_segment)
|
16
|
-
return true if @edge<other_segment.edge
|
17
|
-
return false
|
18
|
-
end
|
19
11
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
12
|
+
def initialize(event)
|
13
|
+
@edge = event[:edge]
|
14
|
+
end
|
24
15
|
|
25
|
-
|
26
|
-
|
27
|
-
|
16
|
+
def <(other_segment)
|
17
|
+
return true if @edge<other_segment.edge
|
18
|
+
return false
|
19
|
+
end
|
28
20
|
|
29
|
-
|
30
|
-
|
31
|
-
|
21
|
+
def >(other_segment)
|
22
|
+
return true if @edge>other_segment.edge
|
23
|
+
return false
|
24
|
+
end
|
32
25
|
|
33
|
-
|
34
|
-
|
35
|
-
|
26
|
+
def == (other_segment)
|
27
|
+
@edge == other_segment.edge && @left_point == other_segment.left_point && @right_point == other_segment.right_point
|
28
|
+
end
|
36
29
|
|
37
|
-
|
38
|
-
|
30
|
+
def to_s
|
31
|
+
return "edge:#{@edge.to_s}"
|
32
|
+
end
|
39
33
|
|
40
|
-
|
34
|
+
def intersection_point_with(other_segment)
|
35
|
+
numerator = (other_segment.left_point.y - @left_point.y) * (other_segment.left_point.x - other_segment.right_point.x) -
|
36
|
+
(other_segment.left_point.y - other_segment.right_point.y) * (other_segment.left_point.x - @left_point.x)
|
41
37
|
|
42
|
-
|
43
|
-
|
38
|
+
denominator = (@right_point.y - @left_point.y) * (other_segment.left_point.x - other_segment.right_point.x) -
|
39
|
+
(other_segment.left_point.y - other_segment.right_point.y) * (@right_point.x - @left_point.x)
|
44
40
|
|
45
|
-
|
46
|
-
end
|
41
|
+
t = numerator.to_f / denominator
|
47
42
|
|
43
|
+
x = @left_point.x + t * (@right_point.x - @left_point.x)
|
44
|
+
y = @left_point.y + t * (@right_point.y - @left_point.y)
|
45
|
+
|
46
|
+
Point.new(x, y)
|
47
|
+
end
|
48
|
+
end
|
48
49
|
end
|
@@ -1,138 +1,140 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
def add(event)
|
11
|
-
# build up segment data
|
12
|
-
seg = Segment.new(event)
|
13
|
-
p1 = @polygon.vertices[seg.edge]
|
14
|
-
p2 = @polygon.vertices[seg.edge + 1]
|
15
|
-
|
16
|
-
# if it is being added, then it must be a LEFT edge event
|
17
|
-
# but need to determine which endpoint is the left one first
|
18
|
-
|
19
|
-
if p1.compare(p2) < 0
|
20
|
-
seg.left_point = p1
|
21
|
-
seg.right_point = p2
|
22
|
-
else
|
23
|
-
seg.left_point = p2
|
24
|
-
seg.right_point = p1
|
1
|
+
module WindingPolygon
|
2
|
+
class SweepLine
|
3
|
+
attr_reader :tree
|
4
|
+
attr_reader :polygon
|
5
|
+
|
6
|
+
def initialize(polygon)
|
7
|
+
@tree = AVLTree.new
|
8
|
+
@polygon = polygon
|
25
9
|
end
|
26
10
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
11
|
+
def add(event)
|
12
|
+
# build up segment data
|
13
|
+
seg = Segment.new(event)
|
14
|
+
p1 = @polygon.vertices[seg.edge]
|
15
|
+
p2 = @polygon.vertices[seg.edge + 1]
|
16
|
+
|
17
|
+
# if it is being added, then it must be a LEFT edge event
|
18
|
+
# but need to determine which endpoint is the left one first
|
19
|
+
|
20
|
+
if p1.compare(p2) < 0
|
21
|
+
seg.left_point = p1
|
22
|
+
seg.right_point = p2
|
23
|
+
else
|
24
|
+
seg.left_point = p2
|
25
|
+
seg.right_point = p1
|
26
|
+
end
|
27
|
+
|
28
|
+
# Add node to tree and setup linkages to "above" and "below"
|
29
|
+
# edges as per algorithm
|
30
|
+
nd = @tree.insert(seg)
|
31
|
+
|
32
|
+
nx = nd.next
|
33
|
+
np = nd.prev
|
34
|
+
|
35
|
+
if !nx.nil?
|
36
|
+
seg.above = nx.value
|
37
|
+
seg.above.below = seg
|
38
|
+
end
|
39
|
+
|
40
|
+
if !np.nil?
|
41
|
+
seg.below = np.value
|
42
|
+
seg.below.above = seg
|
43
|
+
end
|
44
|
+
return seg
|
33
45
|
|
34
|
-
if !nx.nil?
|
35
|
-
seg.above = nx.value
|
36
|
-
seg.above.below = seg
|
37
46
|
end
|
38
47
|
|
39
|
-
|
40
|
-
|
41
|
-
seg
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
48
|
+
def find(event)
|
49
|
+
# need a segment to find it in the tree
|
50
|
+
seg = Segment.new(event)
|
51
|
+
p1 = @polygon.vertices[seg.edge]
|
52
|
+
p2 = @polygon.vertices[seg.edge + 1]
|
46
53
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
seg.left_point = p1
|
57
|
-
seg.right_point = p2
|
58
|
-
else
|
59
|
-
seg.left_point = p2
|
60
|
-
seg.right_point = p1
|
61
|
-
end
|
54
|
+
# if it is being added, then it must be a LEFT edge event
|
55
|
+
# but need to determine which endpoint is the left one first
|
56
|
+
if p1.compare(p2) < 0
|
57
|
+
seg.left_point = p1
|
58
|
+
seg.right_point = p2
|
59
|
+
else
|
60
|
+
seg.left_point = p2
|
61
|
+
seg.right_point = p1
|
62
|
+
end
|
62
63
|
|
63
|
-
|
64
|
+
node = @tree.search(seg)
|
64
65
|
|
65
|
-
|
66
|
+
return nil if node.nil?
|
66
67
|
|
67
|
-
|
68
|
-
|
68
|
+
node.value
|
69
|
+
end
|
69
70
|
|
70
|
-
|
71
|
-
|
72
|
-
|
71
|
+
def remove(seg)
|
72
|
+
nd = @tree.search(seg)
|
73
|
+
return if nd.nil?
|
73
74
|
|
74
|
-
|
75
|
-
|
75
|
+
nx = nd.next
|
76
|
+
nx.value.below = seg.below if !nx.nil?
|
76
77
|
|
77
|
-
|
78
|
-
|
78
|
+
np = nd.prev
|
79
|
+
np.value.above = seg.above if !np.nil?
|
79
80
|
|
80
|
-
|
81
|
-
|
81
|
+
@tree.delete(seg)
|
82
|
+
end
|
82
83
|
|
83
|
-
|
84
|
-
|
85
|
-
|
84
|
+
def switch(s1,s2)
|
85
|
+
nd1 = @tree.search(s1)
|
86
|
+
return if nd1.nil?
|
86
87
|
|
87
|
-
|
88
|
-
|
88
|
+
nd2 = @tree.search(s2)
|
89
|
+
return if nd2.nil?
|
89
90
|
|
90
|
-
|
91
|
-
|
91
|
+
nx1 = nd1.next
|
92
|
+
nx1.value.below = nd2.value if !nx1.nil?
|
92
93
|
|
93
|
-
|
94
|
-
|
94
|
+
np1 = nd1.prev
|
95
|
+
np1.value.above = nd2.value if !np1.nil?
|
95
96
|
|
96
|
-
|
97
|
-
|
97
|
+
nx2 = nd2.next
|
98
|
+
nx2.value.below = nd1.value if !nx2.nil?
|
98
99
|
|
99
|
-
|
100
|
-
|
100
|
+
np2 = nd2.prev
|
101
|
+
np2.value.above = nd1.value if !np2.nil?
|
101
102
|
|
102
|
-
|
103
|
+
end
|
103
104
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
105
|
+
#test intersect of 2 segments and return: nil when none, point when intersecting
|
106
|
+
def intersect(s1,s2)
|
107
|
+
# no intersect if either segment doesn't existend
|
108
|
+
return nil if s1.nil? || s2.nil?
|
108
109
|
|
109
|
-
|
110
|
-
|
111
|
-
|
110
|
+
# check for consecutive edges in polygon
|
111
|
+
e1 = s1.edge
|
112
|
+
e2 = s2.edge
|
112
113
|
|
113
|
-
|
114
|
-
|
115
|
-
|
114
|
+
# no non-simple intersect since consecutive
|
115
|
+
polygon_edges = @polygon.vertices.length-1
|
116
|
+
return nil if (((e1+1)%polygon_edges === e2) || (e1 === (e2+1)%polygon_edges))
|
116
117
|
|
117
118
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
119
|
+
#test for existence of an intersect point
|
120
|
+
#s2 left point sign
|
121
|
+
lsign = s2.left_point.is_left(s1.left_point, s1.right_point)
|
122
|
+
#s2 right point sign
|
123
|
+
rsign = s2.right_point.is_left(s1.left_point, s1.right_point)
|
123
124
|
|
124
|
-
|
125
|
-
|
125
|
+
# s2 endpoints have same sign relative to s1 => on same side => no intersect is possible
|
126
|
+
return nil if (lsign * rsign > 0)
|
126
127
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
128
|
+
# s1 left point sign
|
129
|
+
lsign = s1.left_point.is_left(s2.left_point, s2.right_point)
|
130
|
+
#s1 right point sign
|
131
|
+
rsign = s1.right_point.is_left(s2.left_point, s2.right_point)
|
131
132
|
|
132
|
-
|
133
|
-
|
133
|
+
# s1 endpoints have same sign relative to s2 => on same side => no intersect is possible
|
134
|
+
return nil if (lsign * rsign > 0)
|
134
135
|
|
135
|
-
|
136
|
-
|
136
|
+
#segments s1 and s2 straddle. Intersect exists.
|
137
|
+
s1.intersection_point_with(s2)
|
138
|
+
end
|
137
139
|
end
|
138
140
|
end
|