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