aurora-geometry 0.0.2
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/.gitignore +6 -0
- data/Gemfile +7 -0
- data/LICENSE +21 -0
- data/README.markdown +105 -0
- data/Rakefile +24 -0
- data/aurora-geometry.gemspec +23 -0
- data/lib/geometry.rb +22 -0
- data/lib/geometry/arc.rb +94 -0
- data/lib/geometry/circle.rb +122 -0
- data/lib/geometry/cluster_factory.rb +15 -0
- data/lib/geometry/edge.rb +140 -0
- data/lib/geometry/line.rb +154 -0
- data/lib/geometry/obround.rb +238 -0
- data/lib/geometry/path.rb +67 -0
- data/lib/geometry/point.rb +163 -0
- data/lib/geometry/point_zero.rb +107 -0
- data/lib/geometry/polygon.rb +368 -0
- data/lib/geometry/polyline.rb +318 -0
- data/lib/geometry/rectangle.rb +378 -0
- data/lib/geometry/regular_polygon.rb +136 -0
- data/lib/geometry/rotation.rb +190 -0
- data/lib/geometry/size.rb +75 -0
- data/lib/geometry/size_zero.rb +70 -0
- data/lib/geometry/square.rb +113 -0
- data/lib/geometry/text.rb +24 -0
- data/lib/geometry/transformation.rb +171 -0
- data/lib/geometry/transformation/composition.rb +39 -0
- data/lib/geometry/triangle.rb +78 -0
- data/lib/geometry/vector.rb +34 -0
- data/test/geometry.rb +5 -0
- data/test/geometry/arc.rb +25 -0
- data/test/geometry/circle.rb +112 -0
- data/test/geometry/edge.rb +132 -0
- data/test/geometry/line.rb +132 -0
- data/test/geometry/obround.rb +25 -0
- data/test/geometry/path.rb +66 -0
- data/test/geometry/point.rb +258 -0
- data/test/geometry/point_zero.rb +177 -0
- data/test/geometry/polygon.rb +214 -0
- data/test/geometry/polyline.rb +266 -0
- data/test/geometry/rectangle.rb +154 -0
- data/test/geometry/regular_polygon.rb +120 -0
- data/test/geometry/rotation.rb +108 -0
- data/test/geometry/size.rb +97 -0
- data/test/geometry/size_zero.rb +153 -0
- data/test/geometry/square.rb +66 -0
- data/test/geometry/transformation.rb +169 -0
- data/test/geometry/transformation/composition.rb +49 -0
- data/test/geometry/triangle.rb +32 -0
- data/test/geometry/vector.rb +41 -0
- metadata +115 -0
@@ -0,0 +1,266 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'geometry/polyline'
|
3
|
+
|
4
|
+
describe Geometry::Polyline do
|
5
|
+
Polyline = Geometry::Polyline
|
6
|
+
|
7
|
+
let(:closed_unit_square) { Polyline.new [0,0], [1,0], [1,1], [0,1], [0,0] }
|
8
|
+
let(:unit_square) { Polyline.new [0,0], [1,0], [1,1], [0,1] }
|
9
|
+
let(:reverse_unit_square) { Polyline.new [0,1], [1,1], [1,0], [0,0] }
|
10
|
+
|
11
|
+
it "must create a Polyline object with no arguments" do
|
12
|
+
polyline = Geometry::Polyline.new
|
13
|
+
polyline.must_be_kind_of Polyline
|
14
|
+
polyline.edges.count.must_equal 0
|
15
|
+
polyline.vertices.count.must_equal 0
|
16
|
+
end
|
17
|
+
|
18
|
+
it "must create a Polyline object from array arguments" do
|
19
|
+
polyline = Geometry::Polyline.new([0,0], [1,0], [1,1], [0,1])
|
20
|
+
polyline.must_be_kind_of Polyline
|
21
|
+
polyline.edges.count.must_equal 3
|
22
|
+
polyline.vertices.count.must_equal 4
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "when the Polyline is closed" do
|
26
|
+
let(:closed_concave_polyline) { Polyline.new [-2,0], [0,0], [0,-2], [2,-2], [2,2], [-2,2], [-2,0] }
|
27
|
+
subject { closed_concave_polyline }
|
28
|
+
|
29
|
+
it "must be closed" do
|
30
|
+
closed_unit_square.closed?.must_equal true
|
31
|
+
end
|
32
|
+
|
33
|
+
it "must clone and close" do
|
34
|
+
closed = subject.close
|
35
|
+
closed.closed?.must_equal true
|
36
|
+
closed.must_equal subject
|
37
|
+
closed.wont_be_same_as subject
|
38
|
+
end
|
39
|
+
|
40
|
+
it "must be able to close itself" do
|
41
|
+
subject.close!
|
42
|
+
subject.closed?.must_equal true
|
43
|
+
subject.must_equal subject
|
44
|
+
end
|
45
|
+
|
46
|
+
it "must clone and reverse" do
|
47
|
+
vertices = subject.vertices
|
48
|
+
vertices.push vertices.shift
|
49
|
+
reversed = subject.reverse
|
50
|
+
reversed.vertices.must_equal vertices.reverse
|
51
|
+
reversed.wont_be_same_as subject
|
52
|
+
reversed.closed?.must_equal true
|
53
|
+
end
|
54
|
+
|
55
|
+
it "must reverse itself" do
|
56
|
+
original = subject.vertices.dup
|
57
|
+
subject.reverse!
|
58
|
+
subject.vertices.to_a.must_equal original.reverse
|
59
|
+
subject.closed?.must_equal true
|
60
|
+
end
|
61
|
+
|
62
|
+
it "must generate bisectors" do
|
63
|
+
closed_unit_square.bisectors.must_equal [Vector[1, 1], Vector[-1, 1], Vector[-1, -1], Vector[1, -1]]
|
64
|
+
end
|
65
|
+
|
66
|
+
it "must generate bisectors with an inside corner" do
|
67
|
+
closed_concave_polyline.bisectors.must_equal [Vector[1,1], Vector[-1,-1], Vector[1,1], Vector[-1,1], Vector[-1,-1], Vector[1,-1]]
|
68
|
+
end
|
69
|
+
|
70
|
+
it "must generate left bisectors" do
|
71
|
+
closed_unit_square.left_bisectors.must_equal [Vector[1, 1], Vector[-1, 1], Vector[-1, -1], Vector[1, -1]]
|
72
|
+
end
|
73
|
+
|
74
|
+
it "must generate left bisectors with an inside corner" do
|
75
|
+
closed_concave_polyline.left_bisectors.must_equal [Vector[1,1], Vector[1,1], Vector[1,1], Vector[-1,1], Vector[-1,-1], Vector[1,-1]]
|
76
|
+
end
|
77
|
+
|
78
|
+
it "must generate right bisectors" do
|
79
|
+
closed_unit_square.right_bisectors.must_equal [Vector[-1,-1], Vector[1,-1], Vector[1,1], Vector[-1,1]]
|
80
|
+
end
|
81
|
+
|
82
|
+
it "must generate right bisectors with an inside corner" do
|
83
|
+
closed_concave_polyline.right_bisectors.must_equal [Vector[-1,-1], Vector[-1,-1], Vector[-1,-1], Vector[1,-1], Vector[1,1], Vector[-1,1]]
|
84
|
+
end
|
85
|
+
|
86
|
+
it "must generate spokes" do
|
87
|
+
closed_unit_square.spokes.must_equal [Vector[-1,-1], Vector[1,-1], Vector[1,1], Vector[-1,1]]
|
88
|
+
end
|
89
|
+
|
90
|
+
it "must rightset a closed concave polyline where the first outset edge intersects with the last outset edge" do
|
91
|
+
skip
|
92
|
+
polyline = Polyline.new [0,0], [0,1], [2,1], [2,2], [-1,2], [-1,-1], [2,-1], [2,0], [0,0]
|
93
|
+
polyline.offset(-1).must_equal Polyline.new [1, 0], [3, 0], [3, 3], [-2, 3], [-2, -2], [3, -2]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "when the Polyline is open" do
|
98
|
+
let(:concave_polyline) { Polyline.new [-2,0], [0,0], [0,-2], [2,-2], [2,2], [-2,2] }
|
99
|
+
subject { concave_polyline }
|
100
|
+
|
101
|
+
it "must not be closed" do
|
102
|
+
unit_square.closed?.must_equal false
|
103
|
+
end
|
104
|
+
|
105
|
+
it "must clone and close" do
|
106
|
+
closed = subject.close
|
107
|
+
closed.closed?.must_equal true
|
108
|
+
closed.must_equal subject
|
109
|
+
closed.wont_be_same_as subject
|
110
|
+
end
|
111
|
+
|
112
|
+
it "must be able to close it" do
|
113
|
+
closed = subject.close!
|
114
|
+
closed.closed?.must_equal true
|
115
|
+
closed.must_equal subject
|
116
|
+
closed.must_be_same_as subject
|
117
|
+
end
|
118
|
+
|
119
|
+
it "must clone and reverse" do
|
120
|
+
reversed = subject.reverse
|
121
|
+
reversed.vertices.must_equal subject.vertices.reverse
|
122
|
+
reversed.wont_be_same_as subject
|
123
|
+
reversed.closed?.wont_equal true
|
124
|
+
end
|
125
|
+
|
126
|
+
it "must reverse itself" do
|
127
|
+
original = subject.vertices.dup
|
128
|
+
subject.reverse!
|
129
|
+
subject.vertices.to_a.must_equal original.reverse
|
130
|
+
subject.closed?.wont_equal true
|
131
|
+
end
|
132
|
+
|
133
|
+
it "must generate bisectors" do
|
134
|
+
unit_square.bisectors.must_equal [Vector[0, 1], Vector[-1, 1], Vector[-1, -1], Vector[0, -1]]
|
135
|
+
end
|
136
|
+
|
137
|
+
it "must generate bisectors with an inside corner" do
|
138
|
+
concave_polyline.bisectors.must_equal [Vector[0,1], Vector[-1,-1], Vector[1,1], Vector[-1,1], Vector[-1,-1], Vector[0,-1]]
|
139
|
+
end
|
140
|
+
|
141
|
+
it "must generate left bisectors" do
|
142
|
+
unit_square.left_bisectors.must_equal [Vector[0, 1], Vector[-1, 1], Vector[-1, -1], Vector[0, -1]]
|
143
|
+
reverse_unit_square.left_bisectors.must_equal [Vector[0, 1], Vector[1, 1], Vector[1, -1], Vector[0, -1]]
|
144
|
+
end
|
145
|
+
|
146
|
+
it "must generate right bisectors" do
|
147
|
+
unit_square.right_bisectors.must_equal [Vector[0,-1], Vector[1,-1], Vector[1,1], Vector[0,1]]
|
148
|
+
end
|
149
|
+
|
150
|
+
it "must generate right bisectors with an inside corner" do
|
151
|
+
concave_polyline.right_bisectors.must_equal [Vector[0,-1], Vector[-1,-1], Vector[-1,-1], Vector[1,-1], Vector[1,1], Vector[0,1]]
|
152
|
+
end
|
153
|
+
|
154
|
+
it "must generate left bisectors with an inside corner" do
|
155
|
+
concave_polyline.left_bisectors.must_equal [Vector[0,1], Vector[1,1], Vector[1,1], Vector[-1,1], Vector[-1,-1], Vector[0,-1]]
|
156
|
+
end
|
157
|
+
|
158
|
+
it "must generate spokes" do
|
159
|
+
unit_square.spokes.must_equal [Vector[0,-1], Vector[1,-1], Vector[1,1], Vector[0,1]]
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
describe "when checking for closedness" do
|
164
|
+
it "must be closed when it is closed" do
|
165
|
+
closed_unit_square.closed?.must_equal true
|
166
|
+
end
|
167
|
+
|
168
|
+
it "must not be closed when it is not closed" do
|
169
|
+
unit_square.closed?.must_equal false
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "when creating a Polyline from an array of Points" do
|
174
|
+
it "must ignore repeated Points" do
|
175
|
+
polyline = Geometry::Polyline.new([0,0], [1,0], [1,1], [1,1], [0,1])
|
176
|
+
polyline.must_be_kind_of Geometry::Polyline
|
177
|
+
polyline.must_equal Geometry::Polyline.new([0,0], [1,0], [1,1], [0,1])
|
178
|
+
end
|
179
|
+
|
180
|
+
it "must collapse collinear Edges" do
|
181
|
+
polyline = Geometry::Polyline.new([0,0], [1,0], [1,1], [0.5,1], [0,1])
|
182
|
+
polyline.must_equal Geometry::Polyline.new([0,0], [1,0], [1,1], [0,1])
|
183
|
+
end
|
184
|
+
|
185
|
+
it "must collapse backtracking Edges" do
|
186
|
+
polyline = Geometry::Polyline.new [0,0], [2,0], [2,2], [1,2], [1,1], [1,2], [0,2]
|
187
|
+
polyline.must_equal Geometry::Polyline.new([0,0], [2,0], [2,2], [0,2])
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
it "must compare identical polylines as equal" do
|
192
|
+
(unit_square.eql? unit_square).must_equal true
|
193
|
+
end
|
194
|
+
|
195
|
+
it "must rightset a closed concave polyline where the first outset edge intersects with the last outset edge" do
|
196
|
+
skip
|
197
|
+
polyline = Polyline.new [0,0], [0,1], [2,1], [2,2], [-1,2], [-1,-1], [2,-1], [2,0], [0,0]
|
198
|
+
polyline.offset(-1).must_equal Polyline.new [1, 0], [3, 0], [3, 3], [-2, 3], [-2, -2], [3, -2]
|
199
|
+
end
|
200
|
+
|
201
|
+
describe "when offsetting" do
|
202
|
+
describe "with a positive offset" do
|
203
|
+
it "must leftset a unit square" do
|
204
|
+
expected_polyline = Polyline.new [0,0.1], [0.9,0.1], [0.9,0.9], [0,0.9]
|
205
|
+
unit_square.offset(0.1).must_equal expected_polyline
|
206
|
+
end
|
207
|
+
|
208
|
+
it "must leftset a simple concave polyline" do
|
209
|
+
concave_polyline = Polyline.new [0,0], [4,0], [4,4], [3,4], [3,3], [1,3], [1,4], [0,4]
|
210
|
+
offset_polyline = concave_polyline.offset(1)
|
211
|
+
offset_polyline.must_equal Polyline.new [0,1], [3,1], [3,2], [0,2], [0,3]
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
describe "with a negative offset" do
|
216
|
+
it "must rightset a unit square" do
|
217
|
+
expected_polyline = Polyline.new [0,-1.0], [2.0,-1.0], [2.0,2.0], [0,2.0]
|
218
|
+
unit_square.offset(-1).must_equal expected_polyline
|
219
|
+
end
|
220
|
+
|
221
|
+
it "must rightset a simple concave polyline" do
|
222
|
+
concave_polyline = Polyline.new [0,0], [4,0], [4,2], [3,2], [3,1], [1,1], [1,2], [0,2]
|
223
|
+
offset_polyline = concave_polyline.offset(-1)
|
224
|
+
offset_polyline.must_equal Polyline.new [0,-1], [5,-1], [5,3], [0,3]
|
225
|
+
end
|
226
|
+
|
227
|
+
it "must rightset a concave polyline" do
|
228
|
+
concave_polyline = Polyline.new [0,0], [4,0], [4,2], [3,2], [3,1], [1,1], [1,2], [0,2]
|
229
|
+
offset_polyline = concave_polyline.offset(-2)
|
230
|
+
offset_polyline.must_equal Polyline.new [0,-2], [6,-2], [6,4], [0,4]
|
231
|
+
end
|
232
|
+
|
233
|
+
it "must rightset an asymetric concave polyline" do
|
234
|
+
concave_polyline = Polyline.new [0,0], [4,0], [4,3], [3,3], [3,1], [1,1], [1,2], [0,2]
|
235
|
+
offset_polyline = concave_polyline.offset(-2)
|
236
|
+
offset_polyline.must_equal Polyline.new [0,-2], [6,-2], [6,5], [1,5], [1,4], [0,4]
|
237
|
+
end
|
238
|
+
|
239
|
+
it "must rightset a concave polyline with multiply-intersecting edges" do
|
240
|
+
concave_polyline = Polyline.new [0,0], [5,0], [5,2], [4,2], [4,1], [3,1], [3,2], [2,2], [2,1], [1,1], [1,2], [0,2]
|
241
|
+
offset_polyline = concave_polyline.offset(-2)
|
242
|
+
offset_polyline.must_equal Polyline.new [0,-2], [7,-2], [7,4], [0,4]
|
243
|
+
end
|
244
|
+
|
245
|
+
it "must rightset a closed concave polyline with multiply-intersecting edges" do
|
246
|
+
concave_polyline = Polyline.new [0,0], [5,0], [5,2], [4,2], [4,1], [3,1], [3,2], [2,2], [2,1], [1,1], [1,2], [0,2], [0,0]
|
247
|
+
offset_polyline = concave_polyline.offset(-2)
|
248
|
+
offset_polyline.must_equal Polyline.new [-2,-2], [7,-2], [7,4], [-2,4]
|
249
|
+
end
|
250
|
+
|
251
|
+
it "must rightset a concave polyline where the first outset edge intersects with the last outset edge" do
|
252
|
+
polyline = Polyline.new [0,0], [0,1], [2,1], [2,2], [-1,2], [-1,-1], [2,-1], [2,0]
|
253
|
+
polyline.offset(-1).must_equal Polyline.new [1, 0], [3, 0], [3, 3], [-2, 3], [-2, -2], [3, -2]
|
254
|
+
end
|
255
|
+
|
256
|
+
# Naturally, this test is very sensitive to the input coordinate values. This is a painfully contrived example that
|
257
|
+
# checks for sensitivity to edges that are very close to horizontal, but not quite.
|
258
|
+
# When the test fails, the first point of the offset polyline is at [0,-1]
|
259
|
+
it "must not be sensitive to floating point rounding errors" do
|
260
|
+
polyline = Polyline.new [0, 0], [0, -2], [10, -2], [10, 10], [-100, 10], [-100, -22], [-69, -22], [-69, 3.552713678800501e-15], [0,0]
|
261
|
+
outset = polyline.offset(-1)
|
262
|
+
outset.edges.first.first.must_equal Geometry::Point[-1,-1]
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'geometry/rectangle'
|
3
|
+
|
4
|
+
def Rectangle(*args)
|
5
|
+
Geometry::Rectangle.new(*args)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe Geometry::Rectangle do
|
9
|
+
Rectangle = Geometry::Rectangle
|
10
|
+
|
11
|
+
describe "when initializing" do
|
12
|
+
it "must accept two corners as Arrays" do
|
13
|
+
rectangle = Rectangle.new [1,2], [2,3]
|
14
|
+
rectangle.must_be_kind_of Geometry::Rectangle
|
15
|
+
rectangle.height.must_equal 1
|
16
|
+
rectangle.width.must_equal 1
|
17
|
+
rectangle.origin.must_equal Point[1,2]
|
18
|
+
end
|
19
|
+
|
20
|
+
it "must accept two named corners as Arrays" do
|
21
|
+
rectangle = Rectangle.new from:[1,2], to:[2,3]
|
22
|
+
rectangle.must_be_kind_of Geometry::Rectangle
|
23
|
+
rectangle.height.must_equal 1
|
24
|
+
rectangle.width.must_equal 1
|
25
|
+
rectangle.origin.must_equal Point[1,2]
|
26
|
+
end
|
27
|
+
|
28
|
+
it "must accept named center point and size arguments" do
|
29
|
+
rectangle = Rectangle.new center:[1,2], size:[3,4]
|
30
|
+
rectangle.must_be_kind_of Geometry::Rectangle
|
31
|
+
rectangle.height.must_equal 4
|
32
|
+
rectangle.width.must_equal 3
|
33
|
+
rectangle.center.must_equal Point[1,2]
|
34
|
+
end
|
35
|
+
|
36
|
+
it "must reject a named center argument with no size argument" do
|
37
|
+
-> { Rectangle.new center:[1,2] }.must_raise ArgumentError
|
38
|
+
end
|
39
|
+
|
40
|
+
it "must accept named origin point and size arguments" do
|
41
|
+
rectangle = Rectangle.new origin:[1,2], size:[3,4]
|
42
|
+
rectangle.must_be_kind_of Geometry::Rectangle
|
43
|
+
rectangle.height.must_equal 4
|
44
|
+
rectangle.width.must_equal 3
|
45
|
+
rectangle.origin.must_equal Point[1,2]
|
46
|
+
end
|
47
|
+
|
48
|
+
it "must reject a named origin argument with no size argument" do
|
49
|
+
-> { Rectangle.new origin:[1,2] }.must_raise ArgumentError
|
50
|
+
end
|
51
|
+
|
52
|
+
it "must accept a sole named size argument that is an Array" do
|
53
|
+
rectangle = Rectangle.new size:[1,2]
|
54
|
+
rectangle.must_be_kind_of Geometry::Rectangle
|
55
|
+
rectangle.origin.must_equal Point[0,0]
|
56
|
+
rectangle.height.must_equal 2
|
57
|
+
rectangle.width.must_equal 1
|
58
|
+
end
|
59
|
+
|
60
|
+
it "must accept a sole named size argument that is a Size" do
|
61
|
+
rectangle = Rectangle.new size:Size[1,2]
|
62
|
+
rectangle.must_be_kind_of Geometry::Rectangle
|
63
|
+
rectangle.origin.must_equal Point[0,0]
|
64
|
+
rectangle.height.must_equal 2
|
65
|
+
rectangle.width.must_equal 1
|
66
|
+
end
|
67
|
+
|
68
|
+
it "must accept named width and height arguments" do
|
69
|
+
rectangle = Rectangle.new width:1, height:3
|
70
|
+
rectangle.must_be_kind_of Geometry::Rectangle
|
71
|
+
rectangle.height.must_equal 3
|
72
|
+
rectangle.width.must_equal 1
|
73
|
+
end
|
74
|
+
|
75
|
+
it "must reject width or height by themselves" do
|
76
|
+
-> { Rectangle.new height:1 }.must_raise ArgumentError
|
77
|
+
-> { Rectangle.new width:1 }.must_raise ArgumentError
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "comparison" do
|
82
|
+
it "must compare equal" do
|
83
|
+
rectangle = Rectangle [1,2], [3,4]
|
84
|
+
rectangle.must_equal Rectangle([1,2], [3, 4])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "inset" do
|
89
|
+
subject { Rectangle.new [0,0], [10,10] }
|
90
|
+
|
91
|
+
it "must inset equally" do
|
92
|
+
subject.inset(1).must_equal Rectangle.new [1,1], [9,9]
|
93
|
+
end
|
94
|
+
|
95
|
+
it "must inset vertically and horizontally" do
|
96
|
+
subject.inset(1,2).must_equal Rectangle.new [1,2], [9,8]
|
97
|
+
subject.inset(x:1, y:2).must_equal Rectangle.new [1,2], [9,8]
|
98
|
+
end
|
99
|
+
|
100
|
+
it "must inset from individual sides" do
|
101
|
+
subject.inset(1,2,3,4).must_equal Rectangle.new [2,3], [6,9]
|
102
|
+
subject.inset(top:1, left:2, bottom:3, right:4).must_equal Rectangle.new [2,3], [6,9]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "properties" do
|
107
|
+
subject { Rectangle.new [1,2], [3,4] }
|
108
|
+
let(:rectangle) { Rectangle [1,2], [3,4] }
|
109
|
+
|
110
|
+
it "have a center point property" do
|
111
|
+
rectangle.center.must_equal Point[2,3]
|
112
|
+
end
|
113
|
+
|
114
|
+
it "have a width property" do
|
115
|
+
assert_equal(2, rectangle.width)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "have a height property" do
|
119
|
+
assert_equal(2, rectangle.height)
|
120
|
+
end
|
121
|
+
|
122
|
+
it "have an origin property" do
|
123
|
+
assert_equal(Point[1,2], rectangle.origin)
|
124
|
+
end
|
125
|
+
|
126
|
+
it "have an edges property that returns 4 edges" do
|
127
|
+
edges = rectangle.edges
|
128
|
+
assert_equal(4, edges.size)
|
129
|
+
edges.each {|edge| assert_kind_of(Geometry::Edge, edge)}
|
130
|
+
end
|
131
|
+
|
132
|
+
it "have a points property that returns 4 points" do
|
133
|
+
points = rectangle.points
|
134
|
+
assert_equal(4, points.size)
|
135
|
+
points.each {|point| assert_kind_of(Geometry::Point, point)}
|
136
|
+
end
|
137
|
+
|
138
|
+
it "must have a bounds property that returns a Rectangle" do
|
139
|
+
subject.bounds.must_equal Rectangle.new([1,2], [3,4])
|
140
|
+
end
|
141
|
+
|
142
|
+
it "must have a minmax property that returns the corners of the bounding rectangle" do
|
143
|
+
subject.minmax.must_equal [Point[1,2], Point[3,4]]
|
144
|
+
end
|
145
|
+
|
146
|
+
it "must have a max property that returns the upper right corner of the bounding rectangle" do
|
147
|
+
subject.max.must_equal Point[3,4]
|
148
|
+
end
|
149
|
+
|
150
|
+
it "must have a min property that returns the lower left corner of the bounding rectangle" do
|
151
|
+
subject.min.must_equal Point[1,2]
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'geometry/regular_polygon'
|
3
|
+
|
4
|
+
describe Geometry::RegularPolygon do
|
5
|
+
RegularPolygon = Geometry::RegularPolygon
|
6
|
+
|
7
|
+
describe "when constructed with named center and radius arguments" do
|
8
|
+
let(:polygon) { RegularPolygon.new sides:4, center:[1,2], radius:3 }
|
9
|
+
subject { RegularPolygon.new sides:4, center:[1,2], radius:3 }
|
10
|
+
|
11
|
+
it "must create a RegularPolygon" do
|
12
|
+
polygon.must_be_instance_of(RegularPolygon)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "must have the correct number of sides" do
|
16
|
+
polygon.edge_count.must_equal 4
|
17
|
+
end
|
18
|
+
|
19
|
+
it "must have a center point accessor" do
|
20
|
+
polygon.center.must_equal Point[1,2]
|
21
|
+
end
|
22
|
+
|
23
|
+
it "must have a radius accessor" do
|
24
|
+
polygon.radius.must_equal 3
|
25
|
+
end
|
26
|
+
|
27
|
+
it "must compare equal" do
|
28
|
+
polygon.must_equal RegularPolygon.new(sides:4, center:[1,2], radius:3)
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "properties" do
|
32
|
+
it "must have vertices" do
|
33
|
+
subject.vertices.must_equal [Point[4.0, 2.0], Point[1.0000000000000002, 5.0], Point[-2.0, 2.0000000000000004], Point[0.9999999999999994, -1.0]]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "when constructed with a center and diameter" do
|
39
|
+
let(:polygon) { RegularPolygon.new sides:4, center:[1,2], diameter:4 }
|
40
|
+
|
41
|
+
it "must be a DiameterRegularPolygon" do
|
42
|
+
polygon.must_be_instance_of(Geometry::DiameterRegularPolygon)
|
43
|
+
polygon.must_be_kind_of(RegularPolygon)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "must have the correct number of sides" do
|
47
|
+
polygon.edge_count.must_equal 4
|
48
|
+
end
|
49
|
+
|
50
|
+
it "must have a center" do
|
51
|
+
polygon.center.must_equal Point[1,2]
|
52
|
+
end
|
53
|
+
|
54
|
+
it "must have a diameter" do
|
55
|
+
polygon.diameter.must_equal 4
|
56
|
+
end
|
57
|
+
|
58
|
+
it "must calculate the correct radius" do
|
59
|
+
polygon.radius.must_equal 2
|
60
|
+
end
|
61
|
+
|
62
|
+
it "must compare equal" do
|
63
|
+
polygon.must_equal RegularPolygon.new(sides:4, center:[1,2], diameter:4)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "when constructed with a diameter and no center" do
|
68
|
+
let(:polygon) { RegularPolygon.new sides:4, diameter:4 }
|
69
|
+
|
70
|
+
it "must be a DiameterRegularPolygon" do
|
71
|
+
polygon.must_be_instance_of(Geometry::DiameterRegularPolygon)
|
72
|
+
polygon.must_be_kind_of(RegularPolygon)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "must have the correct number of sides" do
|
76
|
+
polygon.edge_count.must_equal 4
|
77
|
+
end
|
78
|
+
|
79
|
+
it "must be at the origin" do
|
80
|
+
polygon.center.must_equal Point.zero
|
81
|
+
end
|
82
|
+
|
83
|
+
it "must have a diameter" do
|
84
|
+
polygon.diameter.must_equal 4
|
85
|
+
end
|
86
|
+
|
87
|
+
it "must calculate the correct radius" do
|
88
|
+
polygon.radius.must_equal 2
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "properties" do
|
93
|
+
subject { RegularPolygon.new sides:6, diameter:4 }
|
94
|
+
|
95
|
+
it "must have edges" do
|
96
|
+
expected_edges = [Edge(Point[2, 0], Point[1, 1.732]), Edge(Point[1, 1.732], Point[-1, 1.732]), Edge(Point[-1, 1.732], Point[-2, 0]), Edge(Point[-2, 0], Point[-1, -1.732]), Edge(Point[-1, -1.732], Point[1, -1.732]), Edge(Point[1, -1.732], Point[2, 0])]
|
97
|
+
subject.edges.zip(expected_edges) do |edge1, edge2|
|
98
|
+
edge1.to_a.zip(edge2.to_a) do |point1, point2|
|
99
|
+
point1.to_a.zip(point2.to_a) {|a, b| a.must_be_close_to b }
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it "must have a bounds property that returns a Rectangle" do
|
105
|
+
subject.bounds.must_equal Rectangle.new([-2,-2], [2,2])
|
106
|
+
end
|
107
|
+
|
108
|
+
it "must have a minmax property that returns the corners of the bounding rectangle" do
|
109
|
+
subject.minmax.must_equal [Point[-2,-2], Point[2,2]]
|
110
|
+
end
|
111
|
+
|
112
|
+
it "must have a max property that returns the upper right corner of the bounding rectangle" do
|
113
|
+
subject.max.must_equal Point[2,2]
|
114
|
+
end
|
115
|
+
|
116
|
+
it "must have a min property that returns the lower left corner of the bounding rectangle" do
|
117
|
+
subject.min.must_equal Point[-2,-2]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|