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.
- checksums.yaml +7 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +26 -0
- data/README +2 -0
- data/easy_geometry.gemspec +17 -0
- data/lib/.ruby-version +1 -0
- data/lib/easy_geometry.rb +12 -0
- data/lib/easy_geometry/d2/line.rb +73 -0
- data/lib/easy_geometry/d2/linear_entity.rb +355 -0
- data/lib/easy_geometry/d2/point.rb +193 -0
- data/lib/easy_geometry/d2/polygon.rb +638 -0
- data/lib/easy_geometry/d2/ray.rb +111 -0
- data/lib/easy_geometry/d2/segment.rb +119 -0
- data/lib/easy_geometry/d2/triangle.rb +375 -0
- data/lib/easy_geometry/d2/vector.rb +71 -0
- data/spec/d2/line_spec.rb +339 -0
- data/spec/d2/point_spec.rb +211 -0
- data/spec/d2/polygon_spec.rb +291 -0
- data/spec/d2/ray_spec.rb +439 -0
- data/spec/d2/segment_spec.rb +453 -0
- data/spec/d2/triangle_spec.rb +224 -0
- data/spec/d2/vector_spec.rb +91 -0
- data/spec/spec_helper.rb +101 -0
- metadata +88 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module EasyGeometry
|
|
2
|
+
module D2
|
|
3
|
+
# A vector in a 2-dimensional Euclidean space.
|
|
4
|
+
class Vector
|
|
5
|
+
attr_reader :x, :y
|
|
6
|
+
|
|
7
|
+
EQUITY_TOLERANCE = 0.0000000000001
|
|
8
|
+
|
|
9
|
+
def initialize(x, y)
|
|
10
|
+
@x = x; @y = y
|
|
11
|
+
|
|
12
|
+
validate!
|
|
13
|
+
converting_to_rational!
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Compare self and other Vector.
|
|
17
|
+
def ==(other)
|
|
18
|
+
return false unless other.is_a?(Vector)
|
|
19
|
+
(x - other.x).abs < EQUITY_TOLERANCE && (y - other.y).abs < EQUITY_TOLERANCE
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Subtract two vectors.
|
|
23
|
+
def -(other)
|
|
24
|
+
raise TypeError, "Subtract between Vector and #{ other.class } is not defined" unless other.is_a?(Vector)
|
|
25
|
+
Vector.new(self.x - other.x, self.y - other.y)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Returns a non-zero vector that is orthogonal to the
|
|
29
|
+
# line containing `self` and the origin.
|
|
30
|
+
def orthogonal_direction
|
|
31
|
+
# if a coordinate is zero, we can put a 1 there and zeros elsewhere
|
|
32
|
+
return Vector.new(1, 0) if x.zero?
|
|
33
|
+
return Vector.new(0, 1) if y.zero?
|
|
34
|
+
|
|
35
|
+
# if the first two coordinates aren't zero, we can create a non-zero
|
|
36
|
+
# orthogonal vector by swapping them, negating one, and padding with zeros
|
|
37
|
+
Vector.new(-y, x)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# It is positive if other vector should be turned counter-clockwise in order to superpose them.
|
|
41
|
+
# It is negetive if other vector should be turned clockwise in order to superpose them.
|
|
42
|
+
# It is zero when vectors are collinear.
|
|
43
|
+
def cross_product(other)
|
|
44
|
+
raise TypeError, "Cross product between Vector and #{ other.class } is not defined" unless other.is_a?(Vector)
|
|
45
|
+
x * other.y - y * other.x
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Dot product, also known as inner product or scalar product.
|
|
49
|
+
def dot(other)
|
|
50
|
+
raise TypeError, "Scalar (dot) product between Vector and #{ other.class } is not defined" unless other.is_a?(Vector)
|
|
51
|
+
x * other.x + y * other.y
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Converts the vector to a point
|
|
55
|
+
def to_point
|
|
56
|
+
Point.new(x, y)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def validate!
|
|
62
|
+
raise TypeError, 'Coords should be numbers' if !x.is_a?(Numeric) || !y.is_a?(Numeric)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def converting_to_rational!
|
|
66
|
+
@x = Rational(x.to_s) unless x.is_a?(Rational)
|
|
67
|
+
@y = Rational(y.to_s) unless y.is_a?(Rational)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe EasyGeometry::D2::Line do
|
|
4
|
+
let(:p1) { EasyGeometry::D2::Point.new(0, 0) }
|
|
5
|
+
let(:p2) { EasyGeometry::D2::Point.new(1, 1) }
|
|
6
|
+
let(:l1) { described_class.new([0, 0], [1, 1]) }
|
|
7
|
+
let(:l2) { described_class.new([0, 0], [-1, 1]) }
|
|
8
|
+
let(:l3) { described_class.new([0, 0], [1, 0]) }
|
|
9
|
+
let(:s1) { EasyGeometry::D2::Segment.new([0, 0], [1, 1]) }
|
|
10
|
+
let(:s2) { EasyGeometry::D2::Segment.new([0, 0], [-1, 1]) }
|
|
11
|
+
let(:s3) { EasyGeometry::D2::Segment.new([0, 0], [1, 0]) }
|
|
12
|
+
let(:r1) { EasyGeometry::D2::Ray.new([0, 0], [1, 1]) }
|
|
13
|
+
let(:r2) { EasyGeometry::D2::Ray.new([0, 0], [-1, 1]) }
|
|
14
|
+
let(:r3) { EasyGeometry::D2::Ray.new([0, 0], [1, 0]) }
|
|
15
|
+
|
|
16
|
+
describe '.new' do
|
|
17
|
+
it 'should raise type error if incorrect parameters' do
|
|
18
|
+
expect { described_class.new("1", 0) }.to raise_error(TypeError)
|
|
19
|
+
expect { described_class.new(nil, 0) }.to raise_error(TypeError)
|
|
20
|
+
expect { described_class.new({}, 0) }.to raise_error(TypeError)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'should raise argument error if two points are equal' do
|
|
24
|
+
expect { described_class.new([0, 0], [0, 0]) }.to raise_error(ArgumentError)
|
|
25
|
+
expect { described_class.new([1, 1], [1, 1]) }.to raise_error(ArgumentError)
|
|
26
|
+
expect { described_class.new(EasyGeometry::D2::Point.new(2, 2), EasyGeometry::D2::Point.new(2, 2)) }.to raise_error(ArgumentError)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'should create line' do
|
|
30
|
+
expect(described_class.new(p1, [1, 1])).to eq(l1)
|
|
31
|
+
expect(described_class.new([0, 0], p2)).to eq(l1)
|
|
32
|
+
expect(described_class.new(p1, p2)).to eq(l1)
|
|
33
|
+
expect(described_class.new([0, 0], [1, 1])).to eq(l1)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
describe '#direction' do
|
|
38
|
+
it 'should return a correct vector' do
|
|
39
|
+
expect(l1.direction).to eq(EasyGeometry::D2::Vector.new(1, 1))
|
|
40
|
+
expect(l2.direction).to eq(EasyGeometry::D2::Vector.new(-1, 1))
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
describe '#angle_between' do
|
|
45
|
+
it 'should raise error if incorrect parameters' do
|
|
46
|
+
expect { l1.angle_between(1) }.to raise_error(TypeError)
|
|
47
|
+
expect { l1.angle_between("") }.to raise_error(TypeError)
|
|
48
|
+
expect { l1.angle_between({}) }.to raise_error(TypeError)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'should return a correct angle' do
|
|
52
|
+
expect(l1.angle_between(l2)).to eq(90 * Math::PI / 180)
|
|
53
|
+
expect(l1.angle_between(s2)).to eq(90 * Math::PI / 180)
|
|
54
|
+
expect(l1.angle_between(r2)).to eq(90 * Math::PI / 180)
|
|
55
|
+
|
|
56
|
+
expect(l1.angle_between(l1)).to eq(0)
|
|
57
|
+
expect(l1.angle_between(s1)).to eq(0)
|
|
58
|
+
expect(l1.angle_between(r1)).to eq(0)
|
|
59
|
+
|
|
60
|
+
expect(l1.angle_between(l3)).to eq((45 * Math::PI / 180))
|
|
61
|
+
expect(l1.angle_between(s3)).to eq((45 * Math::PI / 180))
|
|
62
|
+
expect(l1.angle_between(r3)).to eq((45 * Math::PI / 180))
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe '#parallel_to?' do
|
|
67
|
+
it 'should raise error if incorrect parameters' do
|
|
68
|
+
expect { l1.parallel_to?(1) }.to raise_error(TypeError)
|
|
69
|
+
expect { l1.parallel_to?("") }.to raise_error(TypeError)
|
|
70
|
+
expect { l1.parallel_to?({}) }.to raise_error(TypeError)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it 'should return true' do
|
|
74
|
+
expect(l1.parallel_to?(l1)).to be true
|
|
75
|
+
expect(l1.parallel_to?(s1)).to be true
|
|
76
|
+
expect(l1.parallel_to?(r1)).to be true
|
|
77
|
+
expect(l3.parallel_to?(described_class.new([6, 6], [12, 6]))).to be true
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it 'should return false' do
|
|
81
|
+
expect(l1.parallel_to?(l2)).to be false
|
|
82
|
+
expect(l1.parallel_to?(s2)).to be false
|
|
83
|
+
expect(l1.parallel_to?(r2)).to be false
|
|
84
|
+
expect(l2.parallel_to?(l3)).to be false
|
|
85
|
+
expect(l3.parallel_to?(described_class.new([6, 6], [12, 6.00001]))).to be false
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
describe '#perpendicular_to?' do
|
|
90
|
+
it 'should raise error if incorrect parameters' do
|
|
91
|
+
expect { l1.perpendicular_to?(1) }.to raise_error(TypeError)
|
|
92
|
+
expect { l1.perpendicular_to?("") }.to raise_error(TypeError)
|
|
93
|
+
expect { l1.perpendicular_to?({}) }.to raise_error(TypeError)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it 'should return true' do
|
|
97
|
+
expect(l1.perpendicular_to?(l2)).to be true
|
|
98
|
+
expect(l1.perpendicular_to?(s2)).to be true
|
|
99
|
+
expect(l1.perpendicular_to?(r2)).to be true
|
|
100
|
+
expect(l3.perpendicular_to?(described_class.new(p1, [0, 1]))).to be true
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it 'should return false' do
|
|
104
|
+
expect(l1.perpendicular_to?(l1)).to be false
|
|
105
|
+
expect(l1.perpendicular_to?(s1)).to be false
|
|
106
|
+
expect(l1.perpendicular_to?(r1)).to be false
|
|
107
|
+
expect(l1.perpendicular_to?(l3)).to be false
|
|
108
|
+
expect(l2.perpendicular_to?(l3)).to be false
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
describe '#similar_to?' do
|
|
113
|
+
it 'should raise error if incorrect parameters' do
|
|
114
|
+
expect { l1.similar_to?(1) }.to raise_error(TypeError)
|
|
115
|
+
expect { l1.similar_to?("") }.to raise_error(TypeError)
|
|
116
|
+
expect { l1.similar_to?({}) }.to raise_error(TypeError)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it 'should return true' do
|
|
120
|
+
expect(l1.similar_to?(described_class.new([2, 2], [4, 4]))).to be true
|
|
121
|
+
expect(l1.similar_to?(EasyGeometry::D2::Segment.new([2, 2], [4, 4]))).to be true
|
|
122
|
+
expect(l1.similar_to?(EasyGeometry::D2::Ray.new([2, 2], [4, 4]))).to be true
|
|
123
|
+
expect(l3.similar_to?(described_class.new([10, 0], [40, 0]))).to be true
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it 'should return false' do
|
|
127
|
+
expect(l1.similar_to?(l2)).to be false
|
|
128
|
+
expect(l1.similar_to?(s2)).to be false
|
|
129
|
+
expect(l1.similar_to?(r2)).to be false
|
|
130
|
+
expect(l1.similar_to?(l3)).to be false
|
|
131
|
+
expect(l2.similar_to?(l3)).to be false
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
describe '#intersection' do
|
|
136
|
+
it 'should raise error if incorrect parameters' do
|
|
137
|
+
expect { l1.intersection(1) }.to raise_error(TypeError)
|
|
138
|
+
expect { l1.intersection("") }.to raise_error(TypeError)
|
|
139
|
+
expect { l1.intersection({}) }.to raise_error(TypeError)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
context 'intersection with a point' do
|
|
143
|
+
it 'should return array with our point' do
|
|
144
|
+
expect(l1.intersection(p1)).to eq([p1])
|
|
145
|
+
expect(l1.intersection(p2)).to eq([p2])
|
|
146
|
+
expect(l1.intersection(EasyGeometry::D2::Point.new(2, 2))).to eq([EasyGeometry::D2::Point.new(2, 2)])
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it 'should return empty array' do
|
|
150
|
+
expect(l2.intersection(p2)).to eq([])
|
|
151
|
+
expect(l3.intersection(p2)).to eq([])
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
context 'intersection with a linear entity which lies on our line' do
|
|
156
|
+
let(:s1) { EasyGeometry::D2::Segment.new([10, 10], [20, 20]) }
|
|
157
|
+
let(:r1) { EasyGeometry::D2::Ray.new([10, 10], [20, 20]) }
|
|
158
|
+
|
|
159
|
+
it 'should return array with self when intersection with line' do
|
|
160
|
+
expect(l1.intersection(l1)).to eq([l1])
|
|
161
|
+
expect(l2.intersection(l2)).to eq([l2])
|
|
162
|
+
expect(l3.intersection(l3)).to eq([l3])
|
|
163
|
+
expect(l1.intersection(described_class.new([10, 10], [20, 20]))).to eq([l1])
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
it 'should return array with linear entity when intersection with no line' do
|
|
168
|
+
expect(l1.intersection(s1)).to eq([s1])
|
|
169
|
+
expect(l1.intersection(r1)).to eq([r1])
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
context 'intersection with a linear entity which does not lie on our line' do
|
|
174
|
+
context 'intersection with parallel linear entity' do
|
|
175
|
+
it 'should return empty array' do
|
|
176
|
+
expect(l1.intersection(described_class.new([1, 0], [2, 1]))).to eq([])
|
|
177
|
+
expect(l1.intersection(EasyGeometry::D2::Segment.new([1, 0], [2, 1]))).to eq([])
|
|
178
|
+
expect(l3.intersection(described_class.new([0, 1], [1, 1]))).to eq([])
|
|
179
|
+
expect(l3.intersection(EasyGeometry::D2::Ray.new([0, 1], [1, 1]))).to eq([])
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
context 'intersection with not parallel linear entity' do
|
|
184
|
+
it 'should return array with point' do
|
|
185
|
+
expect(l1.intersection(l2)).to eq([p1])
|
|
186
|
+
expect(l1.intersection(l3)).to eq([p1])
|
|
187
|
+
expect(l3.intersection(described_class.new([7, 1], [9, 2]))).to eq([
|
|
188
|
+
EasyGeometry::D2::Point.new(5, 0)
|
|
189
|
+
])
|
|
190
|
+
expect(l3.intersection(described_class.new([1, 7], [2, 9]))).to eq([
|
|
191
|
+
EasyGeometry::D2::Point.new(-2.5, 0)
|
|
192
|
+
])
|
|
193
|
+
expect(l3.intersection(EasyGeometry::D2::Segment.new([0, 0], [1, 1]))).to eq([p1])
|
|
194
|
+
expect(l3.intersection(EasyGeometry::D2::Segment.new([-1, -1], [1, 1]))).to eq([p1])
|
|
195
|
+
expect(l3.intersection(EasyGeometry::D2::Ray.new([0, 0], [1, 1]))).to eq([p1])
|
|
196
|
+
expect(l3.intersection(EasyGeometry::D2::Ray.new([-1, -1], [1, 1]))).to eq([p1])
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
it 'should return empty array' do
|
|
200
|
+
expect(l3.intersection(EasyGeometry::D2::Segment.new([2, 2], [1, 1]))).to eq([])
|
|
201
|
+
expect(l3.intersection(EasyGeometry::D2::Segment.new([-2, -2], [-1, -1]))).to eq([])
|
|
202
|
+
|
|
203
|
+
expect(l3.intersection(EasyGeometry::D2::Ray.new([0, 0.001], [1, 1]))).to eq([])
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
describe '#parallel_line' do
|
|
210
|
+
it 'should raise error if incorrect parameters' do
|
|
211
|
+
expect { l1.parallel_line(1) }.to raise_error(TypeError)
|
|
212
|
+
expect { l1.parallel_line("") }.to raise_error(TypeError)
|
|
213
|
+
expect { l1.parallel_line({}) }.to raise_error(TypeError)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
it 'should return a parallel line' do
|
|
217
|
+
expect(l3.parallel_line(p2).parallel_to?(l3)).to be true
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
describe '#perpendicular_line' do
|
|
222
|
+
it 'should raise error if incorrect parameters' do
|
|
223
|
+
expect { l1.perpendicular_line(1) }.to raise_error(TypeError)
|
|
224
|
+
expect { l1.perpendicular_line("") }.to raise_error(TypeError)
|
|
225
|
+
expect { l1.perpendicular_line({}) }.to raise_error(TypeError)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
it 'should return a perpendicular line' do
|
|
229
|
+
expect(l3.perpendicular_line(p2).perpendicular_to?(l3)).to be true
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
describe '#perpendicular_segment' do
|
|
234
|
+
it 'should raise error if incorrect parameters' do
|
|
235
|
+
expect { l1.perpendicular_segment(1) }.to raise_error(TypeError)
|
|
236
|
+
expect { l1.perpendicular_segment("") }.to raise_error(TypeError)
|
|
237
|
+
expect { l1.perpendicular_segment({}) }.to raise_error(TypeError)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
it 'should return the point if line contains this point' do
|
|
241
|
+
expect(l1.perpendicular_segment(p1)).to eq(p1)
|
|
242
|
+
expect(l2.perpendicular_segment(p1)).to eq(p1)
|
|
243
|
+
expect(l3.perpendicular_segment(p1)).to eq(p1)
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
it 'should return a perpendicular segment' do
|
|
247
|
+
expect(l2.perpendicular_segment(p2)).to eq(EasyGeometry::D2::Segment.new(p2, p1))
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
describe '#slope' do
|
|
252
|
+
it 'should return a number' do
|
|
253
|
+
expect(l1.slope).to eq(1)
|
|
254
|
+
expect(l3.slope).to eq(0)
|
|
255
|
+
expect(described_class.new(p1, [0, 2]).slope).to eq(BigDecimal('Infinity'))
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
describe '#span_test' do
|
|
260
|
+
it 'should raise error if incorrect parameters' do
|
|
261
|
+
expect { l1.span_test(1) }.to raise_error(TypeError)
|
|
262
|
+
expect { l1.span_test("") }.to raise_error(TypeError)
|
|
263
|
+
expect { l1.span_test({}) }.to raise_error(TypeError)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
it 'should return correct number' do
|
|
267
|
+
expect(l1.span_test(p1)).to eq(0)
|
|
268
|
+
expect(l1.span_test(p2)).to eq(1)
|
|
269
|
+
expect(l1.span_test(EasyGeometry::D2::Point.new(-1, -1))).to eq(-1)
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
describe '#contains?' do
|
|
274
|
+
it 'should return true' do
|
|
275
|
+
expect(l1.contains?(p1)).to be true
|
|
276
|
+
expect(l1.contains?(p2)).to be true
|
|
277
|
+
expect(l1.contains?(EasyGeometry::D2::Point.new(100, 100))).to be true
|
|
278
|
+
expect(l1.contains?(EasyGeometry::D2::Segment.new(
|
|
279
|
+
[1000, 1000], [2000, 2000]
|
|
280
|
+
))).to be true
|
|
281
|
+
expect(l1.contains?(EasyGeometry::D2::Ray.new(
|
|
282
|
+
[-1000, -1000], [2000, 2000]
|
|
283
|
+
))).to be true
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
it 'should return false' do
|
|
287
|
+
expect(l1.contains?(EasyGeometry::D2::Point.new(2, 3))).to be false
|
|
288
|
+
expect(l1.contains?(EasyGeometry::D2::Point.new(0, 0.1))).to be false
|
|
289
|
+
expect(l1.contains?(EasyGeometry::D2::Segment.new(
|
|
290
|
+
[1000.1, 1000], [2000, 2000]
|
|
291
|
+
))).to be false
|
|
292
|
+
expect(l1.contains?(EasyGeometry::D2::Ray.new(
|
|
293
|
+
[-1000, -1001], [2000, 2000]
|
|
294
|
+
))).to be false
|
|
295
|
+
expect(l1.contains?(2)).to be false
|
|
296
|
+
expect(l1.contains?("")).to be false
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
describe '#distance' do
|
|
301
|
+
it 'should raise error if incorrect parameters' do
|
|
302
|
+
expect { l1.distance(1) }.to raise_error(TypeError)
|
|
303
|
+
expect { l1.distance("") }.to raise_error(TypeError)
|
|
304
|
+
expect { l1.distance({}) }.to raise_error(TypeError)
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
it 'should return zero if line contains point' do
|
|
308
|
+
expect(l1.distance(p1)).to eq(0)
|
|
309
|
+
expect(l1.distance(p2)).to eq(0)
|
|
310
|
+
expect(l2.distance(p1)).to eq(0)
|
|
311
|
+
expect(l3.distance(p1)).to eq(0)
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
it 'should return correct number' do
|
|
315
|
+
expect(l1.distance([-1, 1])).to eq(Math.sqrt(2))
|
|
316
|
+
expect(l1.distance([1, -1])).to eq(Math.sqrt(2))
|
|
317
|
+
expect(l3.distance([10, 10])).to eq(10)
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
describe '#==' do
|
|
322
|
+
it 'should return false if argument is not line' do
|
|
323
|
+
expect(l1 == p1).to be false
|
|
324
|
+
expect(l1 == '').to be false
|
|
325
|
+
expect(l1 == 2).to be false
|
|
326
|
+
expect(l1 == EasyGeometry::D2::Segment.new([0, 0], [1, 1])).to be false
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
it 'should return false if not equal' do
|
|
330
|
+
expect(l1 == l2).to be false
|
|
331
|
+
expect(l1 == l3).to be false
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
it 'should return false if equal' do
|
|
335
|
+
expect(l1 == l1).to be true
|
|
336
|
+
expect(l1 == EasyGeometry::D2::Line.new([-1, -1], [100, 100])).to be true
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
end
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe EasyGeometry::D2::Point do
|
|
4
|
+
let(:p1) { described_class.new(0, 0) }
|
|
5
|
+
let(:p2) { described_class.new(1, 1) }
|
|
6
|
+
let(:p3) { described_class.new(3, 0) }
|
|
7
|
+
let(:p4) { described_class.new(2, 2) }
|
|
8
|
+
let(:p5) { described_class.new(-2, 2) }
|
|
9
|
+
let(:l1) { EasyGeometry::D2::Line.new(p1, p2) }
|
|
10
|
+
|
|
11
|
+
describe '.new' do
|
|
12
|
+
it 'should raise error if incorrect parameters' do
|
|
13
|
+
expect { described_class.new("1", 0) }.to raise_error(TypeError)
|
|
14
|
+
expect { described_class.new(nil, 0) }.to raise_error(TypeError)
|
|
15
|
+
expect { described_class.new({}, 0) }.to raise_error(TypeError)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'should convert coords to big decimal' do
|
|
19
|
+
expect(p2.x).to be_kind_of(Rational)
|
|
20
|
+
expect(p2.y).to be_kind_of(Rational)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe '.project' do
|
|
25
|
+
it 'should raise error if incorrect parameters' do
|
|
26
|
+
expect { described_class.project(1, 0) }.to raise_error(TypeError)
|
|
27
|
+
expect { described_class.project(nil, "qwe") }.to raise_error(TypeError)
|
|
28
|
+
expect { described_class.project(p2, p1) }.to raise_error(ArgumentError)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'should be equal' do
|
|
32
|
+
expect(described_class.project(p2, p2)).to eq(p2)
|
|
33
|
+
expect(described_class.project(p2, p3)).to eq(described_class.new(1, 0))
|
|
34
|
+
expect(described_class.project(p3, p2)).to eq(described_class.new(1.5, 1.5))
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe '.is_collinear?' do
|
|
39
|
+
it 'should raise error if incorrect parameters' do
|
|
40
|
+
expect { described_class.is_collinear?(1, 2) }.to raise_error(TypeError)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'should return true' do
|
|
44
|
+
expect(described_class.is_collinear?()).to be true
|
|
45
|
+
expect(described_class.is_collinear?(p1)).to be true
|
|
46
|
+
expect(described_class.is_collinear?(p1, p2)).to be true
|
|
47
|
+
expect(described_class.is_collinear?(p1, p2, p2, p2)).to be true
|
|
48
|
+
expect(described_class.is_collinear?(p1, p2, p4)).to be true
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'should return false' do
|
|
52
|
+
expect(described_class.is_collinear?(p1, p2, p3, p4)).to be false
|
|
53
|
+
expect(described_class.is_collinear?(p1, p2, p3)).to be false
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
describe '.affine_rank' do
|
|
58
|
+
it 'should raise error if incorrect parameters' do
|
|
59
|
+
expect { described_class.affine_rank(1, 2) }.to raise_error(TypeError)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'should return -1' do
|
|
63
|
+
expect(described_class.affine_rank()).to eq(-1)
|
|
64
|
+
end
|
|
65
|
+
# Other tests are meaningless because they test the Matrix class
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
describe '#dot' do
|
|
69
|
+
it 'should raise error if incorrect parameters' do
|
|
70
|
+
expect { p1.dot(1) }.to raise_error(TypeError)
|
|
71
|
+
expect { p1.dot("sd") }.to raise_error(TypeError)
|
|
72
|
+
expect { p1.dot(l1) }.to raise_error(TypeError)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'should be equal' do
|
|
76
|
+
expect(p1.dot(p2)).to eq(0)
|
|
77
|
+
expect(p2.dot(p4)).to eq(4)
|
|
78
|
+
expect(p2.dot(p5)).to eq(0)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
describe '#zero?' do
|
|
83
|
+
it 'should return true' do
|
|
84
|
+
expect(p1.zero?).to be true
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'should return false' do
|
|
88
|
+
expect(p2.zero?).to be false
|
|
89
|
+
expect(p3.zero?).to be false
|
|
90
|
+
expect(p5.zero?).to be false
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
describe '#==' do
|
|
95
|
+
it 'should return true' do
|
|
96
|
+
expect(p1 == p1).to be true
|
|
97
|
+
expect(p2 == p2).to be true
|
|
98
|
+
expect(p3 == p3).to be true
|
|
99
|
+
expect(p4 == p4).to be true
|
|
100
|
+
expect(p5 == p5).to be true
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it 'should return false' do
|
|
104
|
+
expect(p1 == p2).to be false
|
|
105
|
+
expect(p3 == p2).to be false
|
|
106
|
+
expect(p4 == p1).to be false
|
|
107
|
+
expect(p1 == 2).to be false
|
|
108
|
+
expect(p1 == '').to be false
|
|
109
|
+
expect(p1 == {}).to be false
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
describe '#-' do
|
|
114
|
+
it 'should raise error if incorrect parameters' do
|
|
115
|
+
expect { p1 - 1 }.to raise_error(TypeError)
|
|
116
|
+
expect { p2 - '' }.to raise_error(TypeError)
|
|
117
|
+
expect { p2 - l1 }.to raise_error(TypeError)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it 'should be equal' do
|
|
121
|
+
expect(p1 - p2).to eq(described_class.new(-1, -1))
|
|
122
|
+
expect(p5 - p3).to eq(described_class.new(-5, 2))
|
|
123
|
+
expect(p5 - p5).to eq(described_class.new(0, 0))
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
describe '#+' do
|
|
128
|
+
it 'should raise error if incorrect parameters' do
|
|
129
|
+
expect { p1 + 1 }.to raise_error(TypeError)
|
|
130
|
+
expect { p2 + '' }.to raise_error(TypeError)
|
|
131
|
+
expect { p2 + l1 }.to raise_error(TypeError)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it 'should be equal' do
|
|
135
|
+
expect(p1 + p2).to eq(described_class.new(1, 1))
|
|
136
|
+
expect(p5 + p3).to eq(described_class.new(1, 2))
|
|
137
|
+
expect(p5 + p5).to eq(described_class.new(-4, 4))
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
describe '#*' do
|
|
142
|
+
it 'should raise error if incorrect parameters' do
|
|
143
|
+
expect { p1 * p1 }.to raise_error(TypeError)
|
|
144
|
+
expect { p2 * '' }.to raise_error(TypeError)
|
|
145
|
+
expect { p1 * l1 }.to raise_error(TypeError)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it 'should be equal' do
|
|
149
|
+
expect(p1 * 10).to eq(described_class.new(0, 0))
|
|
150
|
+
expect(p2 * 10).to eq(described_class.new(10, 10))
|
|
151
|
+
expect(p5 * -2).to eq(described_class.new(4, -4))
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
describe '#/' do
|
|
156
|
+
it 'should raise error if incorrect parameters' do
|
|
157
|
+
expect { p1 / p1 }.to raise_error(TypeError)
|
|
158
|
+
expect { p2 / '' }.to raise_error(TypeError)
|
|
159
|
+
expect { p1 / l1 }.to raise_error(TypeError)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
it 'should be equal' do
|
|
163
|
+
expect(p1 / 10).to eq(described_class.new(0, 0))
|
|
164
|
+
expect(p2 / 10).to eq(described_class.new(0.1, 0.1))
|
|
165
|
+
expect(p5 / -2).to eq(described_class.new(1, -1))
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
describe '#distance' do
|
|
170
|
+
it 'should raise error if incorrect parameters' do
|
|
171
|
+
expect { p1.distance(1) }.to raise_error(TypeError)
|
|
172
|
+
expect { p1.distance('') }.to raise_error(TypeError)
|
|
173
|
+
expect { p1.distance(nil) }.to raise_error(TypeError)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
it 'should be equal' do
|
|
177
|
+
expect(p1.distance(p2)).to eq(Math.sqrt(2))
|
|
178
|
+
expect(p1.distance(p4)).to eq(Math.sqrt(8))
|
|
179
|
+
expect(p3.distance(p5)).to eq(Math.sqrt(29))
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
describe '#intersection' do
|
|
184
|
+
it 'should raise error if incorrect parameters' do
|
|
185
|
+
expect { p1.intersection(1) }.to raise_error(TypeError)
|
|
186
|
+
expect { p1.intersection('') }.to raise_error(TypeError)
|
|
187
|
+
expect { p1.intersection(nil) }.to raise_error(TypeError)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
it 'should be equal' do
|
|
191
|
+
expect(p1.intersection(described_class.new(0, 0))).to eq([p1])
|
|
192
|
+
expect(p1.intersection(p2)).to eq([])
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
describe '#midpoint' do
|
|
197
|
+
it 'should raise error if incorrect parameters' do
|
|
198
|
+
expect { p1.midpoint(1) }.to raise_error(TypeError)
|
|
199
|
+
expect { p1.midpoint('') }.to raise_error(TypeError)
|
|
200
|
+
expect { p1.midpoint(nil) }.to raise_error(TypeError)
|
|
201
|
+
expect { p1.midpoint(l1) }.to raise_error(TypeError)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
it 'should be equal' do
|
|
205
|
+
expect(p1.midpoint(p1)).to eq(p1)
|
|
206
|
+
expect(p1.midpoint(p2)).to eq(described_class.new(0.5, 0.5))
|
|
207
|
+
expect(p1.midpoint(p3)).to eq(described_class.new(1.5, 0))
|
|
208
|
+
expect(p2.midpoint(p5)).to eq(described_class.new(-0.5, 1.5))
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|