easy_geometry 0.1.0

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.
@@ -0,0 +1,291 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe EasyGeometry::D2::Polygon do
4
+ let(:l1) { EasyGeometry::D2::Line.new([0, 0], [1, 1]) }
5
+ let(:poly1) { described_class.new([0, 0], [3, -1], [6, 0], [4, 5], [2, 3], [0, 3]) }
6
+ let(:poly2) { described_class.new([6, 0], [3, -1], [0, 0], [0, 3], [2, 3], [4, 5]) }
7
+ let(:poly3) { described_class.new([0, 0], [3, 0], [5, 2], [4, 4]) }
8
+ let(:poly4) { described_class.new([0, 2], [2, 2], [0, 0], [2, 0]) }
9
+ let(:poly5) { described_class.new([0, 0], [0, 1], [1, 1], [1, 0]) }
10
+ let(:poly6) { described_class.new([0, 0], [1, 0], [5, 1], [0, 1]) }
11
+
12
+
13
+ describe '.new' do
14
+ let(:polygon1) { described_class.new([-15, -15], [15, -15], [15, 15], [-15, 15]) }
15
+
16
+ it 'should raise type error if incorrect parameters' do
17
+ expect { described_class.new("1", 0) }.to raise_error(TypeError)
18
+ expect { described_class.new(nil, 0) }.to raise_error(TypeError)
19
+ expect { described_class.new([], 0) }.to raise_error(TypeError)
20
+ expect { described_class.new(l1) }.to raise_error(TypeError)
21
+ end
22
+
23
+ it 'should raise argument error if incorrect number of vertices' do
24
+ expect { described_class.new([0, 0], [0, 1]) }.to raise_error(ArgumentError)
25
+ expect { described_class.new([0, 0], [0, 1], [0, 1]) }.to raise_error(ArgumentError)
26
+ end
27
+
28
+ it 'should remove consecutive duplicates' do
29
+ expect(described_class.new([0, 0], [0, 1], [0, 1], [0, 1], [0, 1], [1, 1], [1, 1], [1, 0]) == poly5).to be true
30
+ end
31
+
32
+ it 'should remove collinear points' do
33
+ expect(described_class.new(
34
+ [-4, 15], [-11, 15], [-15, 15],
35
+ [-15, 33/5], [-15, -87/10], [-15, -15],
36
+ [-42/5, -15], [-2, -15], [7, -15], [15, -15],
37
+ [15, -3], [15, 10], [15, 15]) == polygon1).to be true
38
+ end
39
+ end
40
+
41
+ describe '.is_right?' do
42
+ let(:p1) { EasyGeometry::D2::Point.new(0, 0) }
43
+ let(:p2) { EasyGeometry::D2::Point.new(1, 1) }
44
+ let(:p3) { EasyGeometry::D2::Point.new(1, 0) }
45
+
46
+ it 'should raise type error if incorrect parameters' do
47
+ expect { described_class.is_right?("1", 0, nil) }.to raise_error(TypeError)
48
+ expect { described_class.is_right?(p1, 0, nil) }.to raise_error(TypeError)
49
+ expect { described_class.is_right?(p1, p2, nil) }.to raise_error(TypeError)
50
+ end
51
+
52
+ it 'should return true' do
53
+ expect(described_class.is_right?(p1, p2, p3)).to be true
54
+ end
55
+
56
+ it 'should return false' do
57
+ expect(described_class.is_right?(p1, p3, p2)).to be false
58
+ end
59
+ end
60
+
61
+ describe '#==' do
62
+ it 'should return false if argument is not a polygon' do
63
+ expect(poly1 == l1).to be false
64
+ expect(poly1 == '').to be false
65
+ expect(poly1 == 2).to be false
66
+ end
67
+
68
+ it 'should be equal' do
69
+ expect(poly1 == poly1).to be true
70
+ expect(poly1 == poly2).to be true
71
+ end
72
+
73
+ it 'should not be equal' do
74
+ expect(poly1 == poly3).to be false
75
+ expect(poly2 == poly3).to be false
76
+ end
77
+ end
78
+
79
+ describe '#area' do
80
+ it 'should return correct number' do
81
+ expect(poly1.area).to eq(22)
82
+ expect(poly4.area).to eq(0)
83
+ expect(poly5.area.abs).to eq(1)
84
+ end
85
+ end
86
+
87
+ describe '#perimeter' do
88
+ it 'should return correct number' do
89
+ expect(poly1.perimeter).to eq(5 + 2 * Math.sqrt(10) + Math.sqrt(29) + Math.sqrt(8))
90
+ expect(poly5.perimeter).to eq(4)
91
+ end
92
+ end
93
+
94
+ describe '#centroid' do
95
+ it 'should return correct number' do
96
+ expect(poly6.centroid).to eq(EasyGeometry::D2::Point.new(31/18r, 11/18r))
97
+ expect(poly5.centroid).to eq(EasyGeometry::D2::Point.new(0.5, 0.5))
98
+ end
99
+ end
100
+
101
+ describe '#sides' do
102
+ it 'should return correct number of sides' do
103
+ expect(poly1.sides.length).to eq(6)
104
+ expect(poly6.sides.length).to eq(4)
105
+ end
106
+
107
+ it 'should return correct array with sides' do
108
+ expect(poly6.sides).to eq([
109
+ EasyGeometry::D2::Segment.new([0, 0], [1, 0]),
110
+ EasyGeometry::D2::Segment.new([1, 0], [5, 1]),
111
+ EasyGeometry::D2::Segment.new([5, 1], [0, 1]),
112
+ EasyGeometry::D2::Segment.new([0, 1], [0, 0]),
113
+ ])
114
+ end
115
+ end
116
+
117
+ describe '#bounds' do
118
+ it 'should return correct number' do
119
+ expect(poly1.bounds).to eq([0, -1, 6, 5])
120
+ expect(poly5.bounds).to eq([0, 0, 1, 1])
121
+ end
122
+ end
123
+
124
+ describe '#is_convex?' do
125
+ let(:polygon1) { described_class.new([0, 0], [4, 4], [5, 2], [3, 0]) }
126
+ let(:polygon2) { described_class.new([0, 0], [5, 0], [0, 5]) }
127
+
128
+ it 'should return true' do
129
+ expect(poly3.is_convex?).to be true
130
+ expect(poly6.is_convex?).to be true
131
+ expect(polygon1.is_convex?).to be true
132
+ expect(polygon2.is_convex?).to be true
133
+ end
134
+
135
+ it 'should return false' do
136
+ expect(poly1.is_convex?).to be false
137
+ end
138
+ end
139
+
140
+ describe '#is_encloses_point?' do
141
+ let(:polygon1) { described_class.new([0, 0], [4, 4], [0, 4]) }
142
+ let(:polygon2) { described_class.new([0, 0], [0, 2], [4, 4], [8, 2], [8, 0], [4, 2])}
143
+
144
+ it 'should raise type error if incorrect parameters' do
145
+ expect { described_class.new("1") }.to raise_error(TypeError)
146
+ expect { described_class.new(nil) }.to raise_error(TypeError)
147
+ expect { described_class.new([]) }.to raise_error(TypeError)
148
+ expect { described_class.new(l1) }.to raise_error(TypeError)
149
+ end
150
+
151
+ it 'should return true' do
152
+ expect(polygon1.is_encloses_point?([1, 3])).to be true
153
+ expect(polygon2.is_encloses_point?([4, 3])).to be true
154
+ expect(polygon2.is_encloses_point?([4, 3.99999])).to be true
155
+ end
156
+
157
+ it 'should return false' do
158
+ expect(poly1.is_encloses_point?([0, 0])).to be false
159
+ expect(poly1.is_encloses_point?([6, 0])).to be false
160
+ expect(polygon1.is_encloses_point?([2, 2])).to be false
161
+ expect(polygon1.is_encloses_point?([2, 1])).to be false
162
+ expect(polygon1.is_encloses_point?([5, 5])).to be false
163
+ expect(polygon1.is_encloses_point?([0, 0])).to be false
164
+ expect(polygon1.is_encloses_point?([4, 0])).to be false
165
+ expect(polygon2.is_encloses_point?([2, 1])).to be false
166
+ expect(polygon2.is_encloses_point?([4, 4])).to be false
167
+ end
168
+ end
169
+
170
+ describe '#intersection' do
171
+ let(:polygon1) { described_class.new([0, 0], [1, 0], [0, 1]) }
172
+ let(:polygon2) { described_class.new([0, 1], [-5, 0], [0, -4], [0, 1/5r], [1/2r, -0.1], [1, 0], [0, 1])}
173
+
174
+ context 'with point' do
175
+ it 'intersect' do
176
+ expect(polygon1.intersection(EasyGeometry::D2::Point.new(0, 0))).to eq([EasyGeometry::D2::Point.new(0, 0)])
177
+ expect(polygon1.intersection(EasyGeometry::D2::Point.new(1, 0))).to eq([EasyGeometry::D2::Point.new(1, 0)])
178
+ expect(polygon1.intersection(EasyGeometry::D2::Point.new(0.5, 0))).to eq([EasyGeometry::D2::Point.new(0.5, 0)])
179
+ end
180
+
181
+ it 'not intersect' do
182
+ expect(polygon1.intersection(EasyGeometry::D2::Point.new(-12, -43))).to eq([])
183
+ expect(polygon1.intersection(EasyGeometry::D2::Point.new(0.1, 0.1))).to eq([])
184
+ end
185
+ end
186
+
187
+ context 'with linear entity' do
188
+ it 'intersect' do
189
+ expect(polygon2.intersection(EasyGeometry::D2::Line.new([-12, 0], [12, 0]))).to eq([
190
+ EasyGeometry::D2::Point.new(-5, 0),
191
+ EasyGeometry::D2::Point.new(0, 0),
192
+ EasyGeometry::D2::Point.new(1/3r, 0),
193
+ EasyGeometry::D2::Point.new(1, 0),
194
+ ])
195
+
196
+ expect(polygon2.intersection(EasyGeometry::D2::Line.new([-5, 0], [0, 1]))).to eq([
197
+ EasyGeometry::D2::Segment.new([-5, 0], [0, 1]),
198
+ ])
199
+
200
+ expect(polygon2.intersection(EasyGeometry::D2::Line.new([0, 0], [0, 1]))).to eq([
201
+ EasyGeometry::D2::Point.new(0, 1),
202
+ EasyGeometry::D2::Segment.new([0, -4], [0, 0.2]),
203
+ ])
204
+
205
+ expect(polygon2.intersection(EasyGeometry::D2::Ray.new([-3, 4], [1, 0]))).to eq([
206
+ EasyGeometry::D2::Segment.new([1, 0], [0, 1]),
207
+ ])
208
+ end
209
+
210
+ it 'not intersect' do
211
+ expect(polygon1.intersection(EasyGeometry::D2::Line.new([-12, 0], [12, 12]))).to eq([])
212
+ end
213
+ end
214
+
215
+ context 'with polygon' do
216
+ it 'intersect' do
217
+ expect(polygon1.intersection(polygon2)).to eq([
218
+ EasyGeometry::D2::Point.new(1/3r, 0),
219
+ EasyGeometry::D2::Segment.new([0, 1/5r], [0, 0]),
220
+ EasyGeometry::D2::Segment.new([1, 0], [0, 1]),
221
+ ])
222
+
223
+ expect(polygon2.intersection(polygon1)).to eq([
224
+ EasyGeometry::D2::Point.new(1/3r, 0),
225
+ EasyGeometry::D2::Segment.new([0, 0], [0, 1/5r]),
226
+ EasyGeometry::D2::Segment.new([1, 0], [0, 1]),
227
+ ])
228
+
229
+ expect(polygon1.intersection(polygon1)).to eq([
230
+ EasyGeometry::D2::Segment.new([0, 0], [1, 0]),
231
+ EasyGeometry::D2::Segment.new([0, 0], [0, 1]),
232
+ EasyGeometry::D2::Segment.new([1, 0], [0, 1]),
233
+ ])
234
+
235
+ expect(polygon2.intersection(polygon2)).to eq([
236
+ EasyGeometry::D2::Segment.new([-5, 0], [0, -4]),
237
+ EasyGeometry::D2::Segment.new([0, -4], [0, 1/5r]),
238
+ EasyGeometry::D2::Segment.new([0, 1/5r], [1/2r, -1/10r]),
239
+ EasyGeometry::D2::Segment.new([0, 1], [-5, 0]),
240
+ EasyGeometry::D2::Segment.new([1/2r, -1/10r], [1, 0]),
241
+ EasyGeometry::D2::Segment.new([1, 0], [0, 1]),
242
+ ])
243
+
244
+ expect(polygon2.intersection(described_class.new([0, 1], [1, 0], [-1, 1]) )).to eq([
245
+ EasyGeometry::D2::Point.new(-5/7r, 6/7r),
246
+ EasyGeometry::D2::Segment.new([0, 1], [1, 0]),
247
+ ])
248
+
249
+ expect(polygon1.intersection(described_class.new([3, 0], [1, 2], [1, 0]))).to eq([
250
+ EasyGeometry::D2::Point.new(1, 0),
251
+ ])
252
+
253
+ end
254
+
255
+ it 'not intersect' do
256
+ expect(polygon1.intersection(described_class.new([3, 0], [1, 2], [1.0004, 0]))).to eq([])
257
+ end
258
+ end
259
+ end
260
+
261
+ describe '#distance' do
262
+ let(:polygon1) { described_class.new([0, 0], [1, 0], [1, 1], [0, 1]) }
263
+ let(:polygon2) { described_class.new([0, 5/4r], [1, 5/4r], [1, 9/4r], [0, 9/4r]) }
264
+ let(:polygon3) { described_class.new([1, 2], [2, 2], [2, 1]) }
265
+ let(:polygon4) { described_class.new([1, 1], [6/5r, 1], [1, 6/5r]) }
266
+ let(:polygon5) { described_class.new([0, 0], [4, 4], [0, 4]) }
267
+
268
+
269
+
270
+ it 'should raise TypeError' do
271
+ expect{ poly1.distance(l1) }.to raise_error(TypeError)
272
+ expect{ poly1.distance("") }.to raise_error(TypeError)
273
+ expect{ poly1.distance(nil) }.to raise_error(TypeError)
274
+ end
275
+
276
+ it 'should return distance to point' do
277
+ expect(polygon1.distance([1/2r, 1/2r])).to eq(1/2r)
278
+ expect(polygon1.distance([1, 1])).to eq(0)
279
+ expect(polygon2.distance([1/2r, 1/2r])).to eq(3/4r)
280
+ expect(polygon3.distance([1, 1])).to eq(Math.sqrt(2)/2)
281
+ end
282
+
283
+ it 'should return distance to polygon' do
284
+ expect(polygon1.distance(polygon2)).to eq(1/4r)
285
+ expect(polygon1.distance(polygon3)).to eq(Math.sqrt(2)/2)
286
+ expect(polygon3.distance(polygon4)).to eq(2 * Math.sqrt(2)/5)
287
+ expect(polygon5.distance(described_class.new([10, 10], [14, 14], [10, 14]))).to eq((6 * Math.sqrt(2)).round(14))
288
+ expect(polygon5.distance(described_class.new([1, 8], [5, 8], [8, 12], [1, 12]))).to eq(4)
289
+ end
290
+ end
291
+ end
@@ -0,0 +1,439 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe EasyGeometry::D2::Ray do
4
+ let(:p1) { EasyGeometry::D2::Point.new(0, 0) }
5
+ let(:p2) { EasyGeometry::D2::Point.new(1, 1) }
6
+ let(:p3) { EasyGeometry::D2::Point.new(1, 0) }
7
+ let(:s1) { EasyGeometry::D2::Segment.new([0, 0], [1, 1]) }
8
+ let(:s2) { EasyGeometry::D2::Segment.new([0, 0], [-1, 1]) }
9
+ let(:s3) { EasyGeometry::D2::Segment.new([0, 0], [1, 0]) }
10
+ let(:l1) { EasyGeometry::D2::Line.new([0, 0], [1, 1]) }
11
+ let(:l2) { EasyGeometry::D2::Line.new([0, 0], [-1, 1]) }
12
+ let(:l3) { EasyGeometry::D2::Line.new([0, 0], [1, 0]) }
13
+ let(:r1) { described_class.new([0, 0], [1, 1]) }
14
+ let(:r2) { described_class.new([0, 0], [-1, 1]) }
15
+ let(:r3) { described_class.new([0, 0], [1, 0]) }
16
+
17
+ describe '.new' do
18
+ it 'should raise type error if incorrect parameters' do
19
+ expect { described_class.new("1", 0) }.to raise_error(TypeError)
20
+ expect { described_class.new(nil, 0) }.to raise_error(TypeError)
21
+ expect { described_class.new({}, 0) }.to raise_error(TypeError)
22
+ end
23
+
24
+ it 'should raise argument error if two points are equal' do
25
+ expect { described_class.new([0, 0], [0, 0]) }.to raise_error(ArgumentError)
26
+ expect { described_class.new([1, 1], [1, 1]) }.to raise_error(ArgumentError)
27
+ expect { described_class.new(EasyGeometry::D2::Point.new(2, 2), EasyGeometry::D2::Point.new(2, 2)) }.to raise_error(ArgumentError)
28
+ end
29
+
30
+ it 'should create ray' do
31
+ expect(described_class.new(p1, [1, 1])).to eq(r1)
32
+ expect(described_class.new([0, 0], p2)).to eq(r1)
33
+ expect(described_class.new(p1, p2)).to eq(r1)
34
+ expect(described_class.new([0, 0], [1, 1])).to eq(r1)
35
+ end
36
+ end
37
+
38
+ describe '#direction' do
39
+ it 'should return a correct vector' do
40
+ expect(r1.direction).to eq(EasyGeometry::D2::Vector.new(1, 1))
41
+ expect(r2.direction).to eq(EasyGeometry::D2::Vector.new(-1, 1))
42
+ end
43
+ end
44
+
45
+ describe '#angle_between' do
46
+ it 'should raise error if incorrect parameters' do
47
+ expect { r1.angle_between(1) }.to raise_error(TypeError)
48
+ expect { r1.angle_between('') }.to raise_error(TypeError)
49
+ expect { r1.angle_between({}) }.to raise_error(TypeError)
50
+ end
51
+
52
+ it 'should return a correct angle' do
53
+ expect(r1.angle_between(r2)).to eq(90 * Math::PI / 180)
54
+ expect(r1.angle_between(s2)).to eq(90 * Math::PI / 180)
55
+ expect(r1.angle_between(l2)).to eq(90 * Math::PI / 180)
56
+
57
+ expect(r1.angle_between(r1)).to eq(0)
58
+ expect(r1.angle_between(l1)).to eq(0)
59
+ expect(r1.angle_between(s1)).to eq(0)
60
+
61
+ expect(r1.angle_between(r3)).to eq((45 * Math::PI / 180))
62
+ expect(r1.angle_between(s3)).to eq((45 * Math::PI / 180))
63
+ expect(r1.angle_between(l3)).to eq((45 * Math::PI / 180))
64
+ end
65
+ end
66
+
67
+ describe '#parallel_to?' do
68
+ it 'should raise error if incorrect parameters' do
69
+ expect { r1.parallel_to?(1) }.to raise_error(TypeError)
70
+ expect { r1.parallel_to?('') }.to raise_error(TypeError)
71
+ expect { r1.parallel_to?({}) }.to raise_error(TypeError)
72
+ end
73
+
74
+ it 'should return true' do
75
+ expect(r1.parallel_to?(r1)).to be true
76
+ expect(r1.parallel_to?(s1)).to be true
77
+ expect(r1.parallel_to?(l1)).to be true
78
+ expect(r3.parallel_to?(described_class.new([6, 6], [12, 6]))).to be true
79
+ end
80
+
81
+ it 'should return false' do
82
+ expect(r1.parallel_to?(r2)).to be false
83
+ expect(r1.parallel_to?(l2)).to be false
84
+ expect(r1.parallel_to?(s2)).to be false
85
+ expect(r2.parallel_to?(r3)).to be false
86
+ expect(r3.parallel_to?(described_class.new([6, 6], [12, 6.00001]))).to be false
87
+ end
88
+ end
89
+
90
+ describe '#perpendicular_to?' do
91
+ it 'should raise error if incorrect parameters' do
92
+ expect { r1.perpendicular_to?(1) }.to raise_error(TypeError)
93
+ expect { r1.perpendicular_to?('') }.to raise_error(TypeError)
94
+ expect { r1.perpendicular_to?({}) }.to raise_error(TypeError)
95
+ end
96
+
97
+ it 'should return true' do
98
+ expect(r1.perpendicular_to?(r2)).to be true
99
+ expect(r1.perpendicular_to?(s2)).to be true
100
+ expect(r1.perpendicular_to?(l2)).to be true
101
+ expect(r3.perpendicular_to?(described_class.new(p1, [0, 1]))).to be true
102
+ end
103
+
104
+ it 'should return false' do
105
+ expect(s1.perpendicular_to?(s1)).to be false
106
+ expect(s1.perpendicular_to?(l1)).to be false
107
+ expect(s1.perpendicular_to?(r1)).to be false
108
+ expect(s1.perpendicular_to?(l3)).to be false
109
+ expect(s2.perpendicular_to?(l3)).to be false
110
+ end
111
+ end
112
+
113
+ describe '#similar_to?' do
114
+ it 'should raise error if incorrect parameters' do
115
+ expect { r1.similar_to?(1) }.to raise_error(TypeError)
116
+ expect { r1.similar_to?('') }.to raise_error(TypeError)
117
+ expect { r1.similar_to?({}) }.to raise_error(TypeError)
118
+ end
119
+
120
+ it 'should return true' do
121
+ expect(r1.similar_to?(described_class.new([2, 2], [4, 4]))).to be true
122
+ expect(r1.similar_to?(EasyGeometry::D2::Line.new([2, 2], [4, 4]))).to be true
123
+ expect(r1.similar_to?(EasyGeometry::D2::Segment.new([2, 2], [4, 4]))).to be true
124
+ expect(r3.similar_to?(described_class.new([10, 0], [40, 0]))).to be true
125
+ end
126
+
127
+ it 'should return false' do
128
+ expect(r1.similar_to?(r2)).to be false
129
+ expect(r1.similar_to?(s2)).to be false
130
+ expect(r1.similar_to?(l2)).to be false
131
+ expect(r1.similar_to?(r3)).to be false
132
+ expect(r2.similar_to?(r3)).to be false
133
+ end
134
+ end
135
+
136
+ describe '#intersection' do
137
+ it 'should raise error if incorrect parameters' do
138
+ expect { r1.intersection(1) }.to raise_error(TypeError)
139
+ expect { r1.intersection('') }.to raise_error(TypeError)
140
+ expect { r1.intersection({}) }.to raise_error(TypeError)
141
+ end
142
+
143
+ context 'intersection with a point' do
144
+ it 'should return array with our point' do
145
+ expect(r1.intersection(p1)).to eq([p1])
146
+ expect(r1.intersection(p2)).to eq([p2])
147
+ expect(r1.intersection([55, 55])).to eq([EasyGeometry::D2::Point.new(55, 55)])
148
+ end
149
+
150
+ it 'should return empty array' do
151
+ expect(r3.intersection(p2)).to eq([])
152
+ expect(r3.intersection(p2)).to eq([])
153
+ end
154
+ end
155
+
156
+ context 'intersection with a linear entity which lies on one line' do
157
+ it 'should return array with self when intersection with line' do
158
+ expect(r1.intersection(l1)).to eq([r1])
159
+ expect(r2.intersection(l2)).to eq([r2])
160
+ expect(r3.intersection(l3)).to eq([r3])
161
+ expect(r1.intersection(EasyGeometry::D2::Line.new([10, 10], [20, 20]))).to eq([r1])
162
+ end
163
+
164
+ it 'should return array with results when intersection with no line' do
165
+ expect(r1.intersection(r1)).to eq([r1])
166
+ expect(r1.intersection(described_class.new([0.5, 0.5], [2, 2]))).to eq([
167
+ described_class.new([0.5, 0.5], [2, 2])
168
+ ])
169
+ expect(r1.intersection(described_class.new([-1, -1], [2, 2]))).to eq([r1])
170
+ expect(r1.intersection(described_class.new([0, 0], [-2, -2]))).to eq([p1])
171
+ expect(r1.intersection(described_class.new([-1, -1], [-2, -2]))).to eq([])
172
+
173
+ expect(r1.intersection(EasyGeometry::D2::Segment.new([-1, -1], [0, 0]))).to eq([p1])
174
+ expect(described_class.new([0, 0], [-2, -2]).intersection(s1)).to eq([p1])
175
+ expect(r1.intersection(s1)).to eq([s1])
176
+ expect(described_class.new(p2, p1).intersection(s1)).to eq([s1])
177
+ expect(described_class.new([0.5, 0.5], p2).intersection(s1)).to eq([
178
+ EasyGeometry::D2::Segment.new([0.5, 0.5], p2)
179
+ ])
180
+ expect(described_class.new([0.5, 0.5], p1).intersection(s1)).to eq([
181
+ EasyGeometry::D2::Segment.new([0.5, 0.5], p1)
182
+ ])
183
+ expect(described_class.new([2, 2], [9, 9]).intersection(s1)).to eq([])
184
+ end
185
+ end
186
+
187
+ context 'intersection with a linear entity which does not lie on one line' do
188
+ context 'intersection with parallel linear entity' do
189
+ it 'should return empty array' do
190
+ expect(r1.intersection(described_class.new([1, 0], [2, 1]))).to eq([])
191
+ expect(r1.intersection(EasyGeometry::D2::Line.new([1, 0], [2, 1]))).to eq([])
192
+ expect(r3.intersection(described_class.new([0, 1], [1, 1]))).to eq([])
193
+ expect(r3.intersection(EasyGeometry::D2::Segment.new([0, 1], [1, 1]))).to eq([])
194
+ end
195
+ end
196
+
197
+ context 'intersection with not parallel linear entity' do
198
+ it 'should return array with point' do
199
+ expect(r1.intersection(s2)).to eq([p1])
200
+ expect(r1.intersection(l2)).to eq([p1])
201
+ expect(r1.intersection(r2)).to eq([p1])
202
+ expect(r1.intersection(s3)).to eq([p1])
203
+ expect(r1.intersection(l3)).to eq([p1])
204
+ expect(r1.intersection(r3)).to eq([p1])
205
+
206
+ expect(described_class.new([0, 0], [10, 0]).intersection(described_class.new([3, -1], [9, 2]))).to eq([
207
+ EasyGeometry::D2::Point.new(5, 0)
208
+ ])
209
+ expect(described_class.new([0, 0], [10, 0]).intersection(described_class.new([9, 2], [3, -1]))).to eq([
210
+ EasyGeometry::D2::Point.new(5, 0)
211
+ ])
212
+ expect(described_class.new([-10, 0], [10, 0]).intersection(described_class.new([-3, -1], [2, 9]))).to eq([
213
+ EasyGeometry::D2::Point.new(-2.5, 0)
214
+ ])
215
+
216
+ expect(s3.intersection(EasyGeometry::D2::Ray.new([0, -1], [1, 1]))).to eq([
217
+ EasyGeometry::D2::Point.new(0.5, 0)
218
+ ])
219
+ expect(EasyGeometry::D2::Segment.new([-10, 0], [10, 0]).intersection(described_class.new([-3, 0.9], [1, 0.3]))).to eq([
220
+ EasyGeometry::D2::Point.new(3, 0)
221
+ ])
222
+ expect(s3.intersection(EasyGeometry::D2::Ray.new([0.2, 0.2], [0.1, 0.1]))).to eq([p1])
223
+ end
224
+
225
+ it 'should return empty array' do
226
+ expect(r3.intersection(described_class.new([0, 0.001], [1, 1]))).to eq([])
227
+ expect(r3.intersection(described_class.new([-1, -1], [-1, 2]))).to eq([])
228
+
229
+ expect(r3.intersection(EasyGeometry::D2::Segment.new([-0.001, 0], [-0.001, 2]))).to eq([])
230
+ expect(r3.intersection(EasyGeometry::D2::Segment.new([1, 1], [4, 0.0001]))).to eq([])
231
+ end
232
+ end
233
+ end
234
+ end
235
+
236
+ describe '#parallel_line' do
237
+ it 'should raise error if incorrect parameters' do
238
+ expect { r1.parallel_line(1) }.to raise_error(TypeError)
239
+ expect { r1.parallel_line('') }.to raise_error(TypeError)
240
+ expect { r1.parallel_line({}) }.to raise_error(TypeError)
241
+ end
242
+
243
+ it 'should return a parallel line' do
244
+ expect(r3.parallel_line(p2).parallel_to?(r3)).to be true
245
+ end
246
+ end
247
+
248
+ describe '#perpendicular_line' do
249
+ it 'should raise error if incorrect parameters' do
250
+ expect { r1.perpendicular_line(1) }.to raise_error(TypeError)
251
+ expect { r1.perpendicular_line('') }.to raise_error(TypeError)
252
+ expect { r1.perpendicular_line({}) }.to raise_error(TypeError)
253
+ end
254
+
255
+ it 'should return a perpendicular line' do
256
+ expect(r3.perpendicular_line(p2).perpendicular_to?(r3)).to be true
257
+ end
258
+ end
259
+
260
+ describe '#perpendicular_segment' do
261
+ it 'should raise error if incorrect parameters' do
262
+ expect { r1.perpendicular_segment(1) }.to raise_error(TypeError)
263
+ expect { r1.perpendicular_segment('') }.to raise_error(TypeError)
264
+ expect { r1.perpendicular_segment({}) }.to raise_error(TypeError)
265
+ end
266
+
267
+ it 'should return the point if ray contains this point' do
268
+ expect(r1.perpendicular_segment(p1)).to eq(p1)
269
+ expect(r2.perpendicular_segment(p1)).to eq(p1)
270
+ expect(r3.perpendicular_segment(p1)).to eq(p1)
271
+ end
272
+
273
+ it 'should return a perpendicular segment' do
274
+ expect(r2.perpendicular_segment(p2)).to eq(EasyGeometry::D2::Segment.new(p2, p1))
275
+ expect(r3.perpendicular_segment(p2)).to eq(EasyGeometry::D2::Segment.new(p2, p3))
276
+ expect(r3.perpendicular_segment(EasyGeometry::D2::Point.new(2, 2))).to eq(
277
+ EasyGeometry::D2::Segment.new(
278
+ EasyGeometry::D2::Point.new(2, 2),
279
+ EasyGeometry::D2::Point.new(2, 0)
280
+ )
281
+ )
282
+ end
283
+ end
284
+
285
+ describe '#slope' do
286
+ it 'should return a number' do
287
+ expect(r1.slope).to eq(1)
288
+ expect(r3.slope).to eq(0)
289
+ expect(described_class.new(p1, [0, 2]).slope).to eq(BigDecimal('Infinity'))
290
+ end
291
+ end
292
+
293
+ describe '#span_test' do
294
+ it 'should raise error if incorrect parameters' do
295
+ expect { r1.span_test(1) }.to raise_error(TypeError)
296
+ expect { r1.span_test('') }.to raise_error(TypeError)
297
+ expect { r1.span_test({}) }.to raise_error(TypeError)
298
+ end
299
+
300
+ it 'should return correct number' do
301
+ expect(r1.span_test(p1)).to eq(0)
302
+ expect(r1.span_test(p2)).to eq(1)
303
+ expect(r1.span_test(EasyGeometry::D2::Point.new(-1, -1))).to eq(-1)
304
+ end
305
+ end
306
+
307
+ describe '#contains?' do
308
+ it 'should contains point' do
309
+ expect(r1.contains?(p1)).to be true
310
+ expect(r1.contains?(p2)).to be true
311
+ expect(r1.contains?([0.5, 0.5])).to be true
312
+ expect(r1.contains?([0.0123, 0.0123])).to be true
313
+ expect(r1.contains?([125, 125])).to be true
314
+ end
315
+
316
+ it 'shouldnt contains point' do
317
+ expect(r1.contains?(p3)).to be false
318
+ expect(r3.contains?(p2)).to be false
319
+ expect(r3.contains?([-0.000001, 0])).to be false
320
+ expect(r3.contains?([-1, 0])).to be false
321
+ expect(r3.contains?([20, 20])).to be false
322
+ end
323
+
324
+ it 'should contains ray' do
325
+ expect(r1.contains?(r1)).to be true
326
+ expect(r1.contains?(described_class.new([20, 20], [900, 900]))).to be true
327
+ expect(r1.contains?(described_class.new([0.1, 0.1], [0.3, 0.3]))).to be true
328
+ expect(described_class.new([-2, -2], [9, 9]).contains?(r1)).to be true
329
+ expect(described_class.new([0, 0], [0.1, 0.1]).contains?(r1)).to be true
330
+ end
331
+
332
+ it 'should not contains ray' do
333
+ expect(r1.contains?(r2)).to be false
334
+ expect(r1.contains?(r3)).to be false
335
+ expect(r1.contains?(described_class.new([0, 0], [1, 1.1]))).to be false
336
+ end
337
+
338
+ it 'should contains segment' do
339
+ expect(r1.contains?(s1)).to be true
340
+
341
+ expect(r1.contains?(EasyGeometry::D2::Segment.new(
342
+ [271, 271], [373, 373]
343
+ ))).to be true
344
+
345
+ expect(r1.contains?(EasyGeometry::D2::Segment.new(
346
+ [0.01, 0.01], [0.999, 0.999]
347
+ ))).to be true
348
+
349
+ expect(r1.contains?(EasyGeometry::D2::Segment.new(
350
+ [0.5, 0.5], [0.6, 0.6]
351
+ ))).to be true
352
+
353
+ expect(r1.contains?(EasyGeometry::D2::Segment.new(
354
+ [0.5555551, 0.5555551], [0.5555552, 0.5555552]
355
+ ))).to be true
356
+
357
+ expect(r1.contains?(EasyGeometry::D2::Segment.new(
358
+ [0.5555551, 0.5555551], [0.5555552, 0.5555552]
359
+ ))).to be true
360
+ end
361
+
362
+ it 'should not contains segment' do
363
+ expect(r1.contains?(s2)).to be false
364
+ expect(r1.contains?(s3)).to be false
365
+
366
+ expect(r1.contains?(EasyGeometry::D2::Segment.new(
367
+ [-1, -1], [2, 2]
368
+ ))).to be false
369
+
370
+ expect(r1.contains?(EasyGeometry::D2::Segment.new(
371
+ [0, 0], [1, 1.000001]
372
+ ))).to be false
373
+ end
374
+
375
+ it 'should return false' do
376
+ expect(r1.contains?(2)).to be false
377
+ expect(r1.contains?('')).to be false
378
+ end
379
+ end
380
+
381
+ describe '#distance' do
382
+ it 'should raise error if incorrect parameters' do
383
+ expect { r1.distance(1) }.to raise_error(TypeError)
384
+ expect { r1.distance('') }.to raise_error(TypeError)
385
+ expect { r1.distance({}) }.to raise_error(TypeError)
386
+ end
387
+
388
+ it 'should return 0' do
389
+ expect(r1.distance(p1)).to eq(0)
390
+ expect(r1.distance(p2)).to eq(0)
391
+ expect(r1.distance(EasyGeometry::D2::Point.new(1000, 1000))).to eq(0)
392
+ end
393
+
394
+ it 'should return correct number' do
395
+ expect(r1.distance(EasyGeometry::D2::Point.new(-1, -1))).to eq(Math.sqrt(2))
396
+ expect(r1.distance(EasyGeometry::D2::Point.new(-1, 1))).to eq(Math.sqrt(2))
397
+ end
398
+ end
399
+
400
+ describe '#==' do
401
+ it 'should return false if argument is not a ray' do
402
+ expect(r1 == p1).to be false
403
+ expect(r1 == '').to be false
404
+ expect(r1 == 2).to be false
405
+ expect(r1 == l1).to be false
406
+ expect(r1 == s1).to be false
407
+ end
408
+
409
+ it 'should not be equal' do
410
+ expect(r1 == r2).to be false
411
+ expect(r1 == r3).to be false
412
+ expect(r1 == EasyGeometry::D2::Ray.new(
413
+ [-1, -1], [1, 1]
414
+ )).to be false
415
+ end
416
+
417
+ it 'should be equal' do
418
+ expect(r1 == r1).to be true
419
+ expect(r1 == EasyGeometry::D2::Ray.new([0, 0], [100, 100])).to be true
420
+ expect(r3 == r3).to be true
421
+ end
422
+ end
423
+
424
+ describe '#xdirection' do
425
+ it 'should return a number' do
426
+ expect(described_class.new([0, 0], [0, 2]).xdirection).to eq (0)
427
+ expect(described_class.new([0, 0], [-1, 2]).xdirection).to eq (-BigDecimal('Infinity'))
428
+ expect(r3.xdirection).to eq (BigDecimal('Infinity'))
429
+ end
430
+ end
431
+
432
+ describe '#ydirection' do
433
+ it 'should return a number' do
434
+ expect(r3.ydirection).to eq (0)
435
+ expect(r1.ydirection).to eq (BigDecimal('Infinity'))
436
+ expect(described_class.new([0, 0], [-1, -2]).ydirection).to eq (-BigDecimal('Infinity'))
437
+ end
438
+ end
439
+ end