winding-polygon 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|