geometry 6.2 → 6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +4 -0
- data/README.markdown +58 -44
- data/geometry.gemspec +1 -1
- data/lib/geometry.rb +1 -0
- data/lib/geometry/annulus.rb +74 -0
- data/lib/geometry/circle.rb +6 -0
- data/lib/geometry/edge.rb +6 -3
- data/lib/geometry/obround.rb +6 -0
- data/lib/geometry/point.rb +40 -3
- data/lib/geometry/point_iso.rb +133 -0
- data/lib/geometry/point_one.rb +131 -0
- data/lib/geometry/point_zero.rb +19 -1
- data/lib/geometry/polygon.rb +6 -6
- data/lib/geometry/polyline.rb +4 -0
- data/lib/geometry/rectangle.rb +6 -0
- data/lib/geometry/regular_polygon.rb +59 -52
- data/lib/geometry/rotation.rb +1 -0
- data/lib/geometry/size.rb +41 -11
- data/lib/geometry/size_one.rb +85 -0
- data/lib/geometry/size_zero.rb +8 -0
- data/lib/geometry/square.rb +6 -0
- data/lib/geometry/triangle.rb +21 -0
- data/test/geometry/annulus.rb +69 -0
- data/test/geometry/circle.rb +36 -0
- data/test/geometry/obround.rb +5 -0
- data/test/geometry/point.rb +40 -5
- data/test/geometry/point_iso.rb +189 -0
- data/test/geometry/point_one.rb +199 -0
- data/test/geometry/point_zero.rb +23 -2
- data/test/geometry/polyline.rb +4 -0
- data/test/geometry/rectangle.rb +4 -0
- data/test/geometry/regular_polygon.rb +57 -11
- data/test/geometry/rotation.rb +6 -0
- data/test/geometry/size.rb +31 -10
- data/test/geometry/size_one.rb +155 -0
- data/test/geometry/size_zero.rb +8 -0
- data/test/geometry/square.rb +4 -0
- data/test/geometry/triangle.rb +16 -0
- metadata +15 -2
@@ -0,0 +1,199 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'geometry/point_one'
|
3
|
+
|
4
|
+
describe Geometry::PointOne do
|
5
|
+
subject { Geometry::PointOne.new }
|
6
|
+
let(:one) { Geometry::PointOne.new }
|
7
|
+
|
8
|
+
describe 'arithmetic' do
|
9
|
+
let(:left) { Point[1,2] }
|
10
|
+
let(:right) { Point[3,4] }
|
11
|
+
|
12
|
+
it 'must pretend to be a Point' do
|
13
|
+
subject.is_a?(Point).must_equal true
|
14
|
+
subject.kind_of?(Point).must_equal true
|
15
|
+
|
16
|
+
subject.is_a?(Geometry::PointOne).must_equal true
|
17
|
+
subject.kind_of?(Geometry::PointOne).must_equal true
|
18
|
+
|
19
|
+
subject.instance_of?(Point).must_equal false
|
20
|
+
subject.instance_of?(Geometry::PointOne).must_equal true
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'must have +@' do
|
24
|
+
(+one).must_be :eql?, 1
|
25
|
+
(+one).must_be_instance_of(Geometry::PointOne)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'must have unary negation' do
|
29
|
+
(-one).must_be :eql?, -1
|
30
|
+
# (-one).must_be_instance_of(Geometry::PointOne)
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'Accessors' do
|
34
|
+
it 'must return 1 for array access' do
|
35
|
+
one[3].must_equal 1
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'must return 1 for named element access' do
|
39
|
+
one.x.must_equal 1
|
40
|
+
one.y.must_equal 1
|
41
|
+
one.z.must_equal 1
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'must add a number' do
|
46
|
+
(one + 3).must_equal 4
|
47
|
+
(3 + one).must_equal 4
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'return a Point when adding two Points' do
|
51
|
+
(one + right).must_be_kind_of Point
|
52
|
+
(left + one).must_be_kind_of Point
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'must return an Array when adding an array' do
|
56
|
+
(one + [5,6]).must_equal [6, 7]
|
57
|
+
([5,6] + one).must_equal [5,6]
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'must return a Point when adding a Size' do
|
61
|
+
(one + Size[5,6]).must_be_instance_of(Point)
|
62
|
+
(one + Size[5,6]).must_equal Point[6,7]
|
63
|
+
end
|
64
|
+
|
65
|
+
describe 'when subtracting' do
|
66
|
+
it 'must subtract a number' do
|
67
|
+
(one - 3).must_equal -2
|
68
|
+
(3 - one).must_equal 2
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'return a Point when subtracting two Points' do
|
72
|
+
(one - right).must_equal Point[-2, -3]
|
73
|
+
(left - one).must_equal Point[0, 1]
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'must return a Point when subtracting an array' do
|
77
|
+
(one - [5,6]).must_equal [-4, -5]
|
78
|
+
# ([5,6] - one).must_equal [4,5]
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'must return a Point when subtracting a Size' do
|
82
|
+
(one - Size[5,6]).must_be_instance_of(Point)
|
83
|
+
(one - Size[5,6]).must_equal Point[-4,-5]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'must multiply by a scalar' do
|
88
|
+
(one * 3).must_equal 3
|
89
|
+
(one * 3.0).must_equal 3.0
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'must refuse to multiply by a Point' do
|
93
|
+
-> { one * Point[1, 2] }.must_raise Geometry::OperationNotDefined
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'must refuse to multiply by a Vector' do
|
97
|
+
-> { one * Vector[2, 3] }.must_raise Geometry::OperationNotDefined
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'must divide by a scalar' do
|
101
|
+
(one / 3).must_equal 1/3
|
102
|
+
(one / 4.0).must_equal 1/4.0
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'must raise an exception when divided by 0' do
|
106
|
+
-> { one / 0 }.must_raise ZeroDivisionError
|
107
|
+
end
|
108
|
+
|
109
|
+
describe 'division' do
|
110
|
+
it 'must raise an exception for Points' do
|
111
|
+
lambda { one / Point[1,2] }.must_raise Geometry::OperationNotDefined
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'must raise an exception for Vectors' do
|
115
|
+
lambda { one / Vector[1,2] }.must_raise Geometry::OperationNotDefined
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe 'coercion' do
|
121
|
+
it 'must coerce Arrays into Points' do
|
122
|
+
one.coerce([3,4]).must_equal [Point[3,4], Point[1, 1]]
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'must coerce Vectors into Vectors' do
|
126
|
+
one.coerce(Vector[3,4]).must_equal [Vector[3,4], Vector[1, 1]]
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'must coerce Points into Points' do
|
130
|
+
one.coerce(Point[5,6]).must_equal [Point[5,6], Point[1, 1]]
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe 'comparison' do
|
135
|
+
subject { Geometry::PointOne.new }
|
136
|
+
|
137
|
+
it 'must be equal to 1 and 1.0' do
|
138
|
+
one.must_be :eql?, 1
|
139
|
+
one.must_be :eql?, 1.0
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'must not be equal to a non-one number' do
|
143
|
+
0.wont_equal one
|
144
|
+
3.14.wont_equal one
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'must be equal to an Array of ones' do
|
148
|
+
one.must_be :==, [1,1]
|
149
|
+
one.must_be :eql?, [1,1]
|
150
|
+
one.must_be :===, [1,1]
|
151
|
+
[1, 1].must_equal one
|
152
|
+
one.must_equal [1, 1]
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'must not be equal to a non-one Array' do
|
156
|
+
one.wont_equal [3, 2, 1]
|
157
|
+
[3, 2, 1].wont_equal one
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'must not be equal to a Point at the origin' do
|
161
|
+
one.wont_be :==, Point[0,0]
|
162
|
+
one.wont_be :eql?, Point[0,0]
|
163
|
+
one.wont_be :===, Point[0,0]
|
164
|
+
Point[0,0].wont_equal one
|
165
|
+
subject.wont_equal Point[0,0]
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'must not be equal to a Point not at the origin' do
|
169
|
+
one.wont_equal Point[3,2]
|
170
|
+
Point[3,2].wont_equal one
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'must be equal to a Point of ones' do
|
174
|
+
one.must_be :==, Point[1,1]
|
175
|
+
one.must_be :eql?, Point[1,1]
|
176
|
+
one.must_be :===, Point[1,1]
|
177
|
+
Point[1,1].must_equal one
|
178
|
+
one.must_equal Point[1,1]
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'must be equal to an Vector of ones' do
|
182
|
+
one.must_be :eql?, Vector[1, 1]
|
183
|
+
Vector[1, 1].must_equal one
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'must not be equal to a non-one Vector' do
|
187
|
+
one.wont_equal Vector[3,2]
|
188
|
+
Vector[3,2].wont_equal one
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe 'when enumerating' do
|
193
|
+
it 'must have a first method' do
|
194
|
+
one.first.must_equal 1
|
195
|
+
one.first(1).must_equal [1]
|
196
|
+
one.first(5).must_equal [1,1,1,1,1]
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
data/test/geometry/point_zero.rb
CHANGED
@@ -2,12 +2,24 @@ require 'minitest/autorun'
|
|
2
2
|
require 'geometry/point_zero'
|
3
3
|
|
4
4
|
describe Geometry::PointZero do
|
5
|
+
subject { Geometry::PointZero.new }
|
5
6
|
let(:zero) { Geometry::PointZero.new }
|
6
7
|
|
7
8
|
describe "arithmetic" do
|
8
9
|
let(:left) { Point[1,2] }
|
9
10
|
let(:right) { Point[3,4] }
|
10
|
-
|
11
|
+
|
12
|
+
it 'must pretend to be a Point' do
|
13
|
+
subject.is_a?(Point).must_equal true
|
14
|
+
subject.kind_of?(Point).must_equal true
|
15
|
+
|
16
|
+
subject.is_a?(PointZero).must_equal true
|
17
|
+
subject.kind_of?(PointZero).must_equal true
|
18
|
+
|
19
|
+
subject.instance_of?(Point).must_equal false
|
20
|
+
subject.instance_of?(PointZero).must_equal true
|
21
|
+
end
|
22
|
+
|
11
23
|
it "must have +@" do
|
12
24
|
(+zero).must_be :eql?, 0
|
13
25
|
(+zero).must_be_instance_of(Geometry::PointZero)
|
@@ -31,8 +43,9 @@ describe Geometry::PointZero do
|
|
31
43
|
end
|
32
44
|
|
33
45
|
describe "when adding" do
|
34
|
-
it "must return a number" do
|
46
|
+
it "must return a PointIso when adding a number" do
|
35
47
|
(zero + 3).must_equal 3
|
48
|
+
(zero + 3).must_be_instance_of Geometry::PointIso
|
36
49
|
(3 + zero).must_equal 3
|
37
50
|
end
|
38
51
|
|
@@ -174,4 +187,12 @@ describe Geometry::PointZero do
|
|
174
187
|
Vector[3,2].wont_equal zero
|
175
188
|
end
|
176
189
|
end
|
190
|
+
|
191
|
+
describe 'when enumerating' do
|
192
|
+
it 'must have a first method' do
|
193
|
+
subject.first.must_equal 0
|
194
|
+
subject.first(1).must_equal [0]
|
195
|
+
subject.first(5).must_equal [0,0,0,0,0]
|
196
|
+
end
|
197
|
+
end
|
177
198
|
end
|
data/test/geometry/polyline.rb
CHANGED
@@ -22,6 +22,10 @@ describe Geometry::Polyline do
|
|
22
22
|
polyline.vertices.count.must_equal 4
|
23
23
|
end
|
24
24
|
|
25
|
+
it 'must have a points attribute' do
|
26
|
+
unit_square.points.must_equal [Point[0,0], Point[1,0], Point[1,1], Point[0,1]]
|
27
|
+
end
|
28
|
+
|
25
29
|
it 'must know the max' do
|
26
30
|
unit_square.max.must_equal Point[1,1]
|
27
31
|
end
|
data/test/geometry/rectangle.rb
CHANGED
@@ -111,6 +111,10 @@ describe Geometry::Rectangle do
|
|
111
111
|
rectangle.center.must_equal Point[2,3]
|
112
112
|
end
|
113
113
|
|
114
|
+
it 'must always be closed' do
|
115
|
+
subject.closed?.must_equal true
|
116
|
+
end
|
117
|
+
|
114
118
|
it "have a width property" do
|
115
119
|
assert_equal(2, rectangle.width)
|
116
120
|
end
|
@@ -4,7 +4,13 @@ require 'geometry/regular_polygon'
|
|
4
4
|
describe Geometry::RegularPolygon do
|
5
5
|
RegularPolygon = Geometry::RegularPolygon
|
6
6
|
|
7
|
-
|
7
|
+
subject { RegularPolygon.new sides:4, center:[1,2], radius:3 }
|
8
|
+
|
9
|
+
it 'must always be closed' do
|
10
|
+
subject.closed?.must_equal true
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'when constructed with a center and circumradius' do
|
8
14
|
let(:polygon) { RegularPolygon.new sides:4, center:[1,2], radius:3 }
|
9
15
|
subject { RegularPolygon.new sides:4, center:[1,2], radius:3 }
|
10
16
|
|
@@ -33,16 +39,19 @@ describe Geometry::RegularPolygon do
|
|
33
39
|
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
40
|
end
|
35
41
|
end
|
42
|
+
|
43
|
+
it 'must have an indiameter' do
|
44
|
+
subject.indiameter.must_be_close_to 4.242
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'must have an inradius' do
|
48
|
+
subject.inradius.must_be_close_to 2.121
|
49
|
+
end
|
36
50
|
end
|
37
51
|
|
38
52
|
describe "when constructed with a center and diameter" do
|
39
53
|
let(:polygon) { RegularPolygon.new sides:4, center:[1,2], diameter:4 }
|
40
54
|
|
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
55
|
it "must have the correct number of sides" do
|
47
56
|
polygon.edge_count.must_equal 4
|
48
57
|
end
|
@@ -67,11 +76,6 @@ describe Geometry::RegularPolygon do
|
|
67
76
|
describe "when constructed with a diameter and no center" do
|
68
77
|
let(:polygon) { RegularPolygon.new sides:4, diameter:4 }
|
69
78
|
|
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
79
|
it "must have the correct number of sides" do
|
76
80
|
polygon.edge_count.must_equal 4
|
77
81
|
end
|
@@ -89,6 +93,41 @@ describe Geometry::RegularPolygon do
|
|
89
93
|
end
|
90
94
|
end
|
91
95
|
|
96
|
+
describe 'when constructed with an indiameter and center' do
|
97
|
+
subject { RegularPolygon.new sides:6, indiameter:4 }
|
98
|
+
|
99
|
+
it 'must have a circumdiameter' do
|
100
|
+
subject.diameter.must_be_close_to 4.618
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'must have a circumradius' do
|
104
|
+
subject.circumradius.must_be_close_to 2.309
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'must have an indiameter' do
|
108
|
+
subject.indiameter.must_be_close_to 4
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'must have an inradius' do
|
112
|
+
subject.inradius.must_be_close_to 2
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe 'when constructed with an inradius and center' do
|
117
|
+
subject { RegularPolygon.new sides:6, inradius:4 }
|
118
|
+
|
119
|
+
it 'must have a circumradius' do
|
120
|
+
subject.circumradius.must_be_close_to 4.618
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'must have points' do
|
124
|
+
expected_points = [Point[4.618, 0], Point[2.309, 4], Point[-2.309, 4], Point[-4.618, 0], Point[-2.309, -4], Point[2.309, -4]]
|
125
|
+
subject.points.zip(expected_points) do |point0, point1|
|
126
|
+
point0.to_a.zip(point1.to_a) {|a, b| a.must_be_close_to b }
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
92
131
|
describe "properties" do
|
93
132
|
subject { RegularPolygon.new sides:6, diameter:4 }
|
94
133
|
|
@@ -101,6 +140,13 @@ describe Geometry::RegularPolygon do
|
|
101
140
|
end
|
102
141
|
end
|
103
142
|
|
143
|
+
it 'must have points' do
|
144
|
+
expected_points = [Point[2, 0], Point[1, 1.732], Point[-1, 1.732], Point[-2, 0], Point[-1, -1.732], Point[1, -1.732]]
|
145
|
+
subject.points.zip(expected_points) do |point0, point1|
|
146
|
+
point0.to_a.zip(point1.to_a) {|a, b| a.must_be_close_to b }
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
104
150
|
it "must have a bounds property that returns a Rectangle" do
|
105
151
|
subject.bounds.must_equal Rectangle.new([-2,-2], [2,2])
|
106
152
|
end
|
data/test/geometry/rotation.rb
CHANGED
@@ -93,6 +93,8 @@ describe Geometry::Rotation do
|
|
93
93
|
end
|
94
94
|
|
95
95
|
describe "when transforming a Point" do
|
96
|
+
subject { Rotation.new(angle:Math::PI/2) }
|
97
|
+
|
96
98
|
describe "when no rotation is set" do
|
97
99
|
it "must return the Point" do
|
98
100
|
Rotation.new.transform(Point[1,0]).must_equal Point[1,0]
|
@@ -104,5 +106,9 @@ describe Geometry::Rotation do
|
|
104
106
|
rotated_point.x.must_be_close_to 0
|
105
107
|
rotated_point.y.must_be_close_to 1
|
106
108
|
end
|
109
|
+
|
110
|
+
it 'must transform a PointZero' do
|
111
|
+
subject.transform(Point.zero).must_equal Point.zero
|
112
|
+
end
|
107
113
|
end
|
108
114
|
end
|
data/test/geometry/size.rb
CHANGED
@@ -41,12 +41,21 @@ describe Geometry::Size do
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
44
|
+
describe 'when array access' do
|
45
|
+
it 'must allow indexed access' do
|
46
|
+
size = Geometry::Size[5,6]
|
47
|
+
size.size.must_equal 2
|
48
|
+
size[0].must_equal 5
|
49
|
+
size[1].must_equal 6
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'must slize with a start index and a length' do
|
53
|
+
size = Geometry::Size[5, 6, 7]
|
54
|
+
slice = size[1,2]
|
55
|
+
slice.length.must_equal 2
|
56
|
+
end
|
49
57
|
end
|
58
|
+
|
50
59
|
it "allow named element access" do
|
51
60
|
size = Geometry::Size[5,6,7]
|
52
61
|
assert_equal(3, size.size)
|
@@ -99,9 +108,15 @@ describe Geometry::Size do
|
|
99
108
|
|
100
109
|
it 'must inset with horizontal and vertical insets' do
|
101
110
|
subject.inset(4).must_equal Geometry::Size[6, 6]
|
102
|
-
subject.inset(2,3).must_equal Geometry::Size[
|
103
|
-
subject.inset(x:2, y:3).must_equal Geometry::Size[
|
111
|
+
subject.inset(2,3).must_equal Geometry::Size[6, 4]
|
112
|
+
subject.inset(x:2, y:3).must_equal Geometry::Size[6, 4]
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'must inset with left and top' do
|
104
116
|
subject.inset(left:2, top:3).must_equal Geometry::Size[8, 7]
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'must inset with right and bottom' do
|
105
120
|
subject.inset(right:2, bottom:3).must_equal Geometry::Size[8, 7]
|
106
121
|
end
|
107
122
|
|
@@ -111,13 +126,19 @@ describe Geometry::Size do
|
|
111
126
|
|
112
127
|
it 'must outset' do
|
113
128
|
subject.outset(4).must_equal Geometry::Size[14, 14]
|
114
|
-
subject.outset(2,3).must_equal Geometry::Size[
|
115
|
-
subject.outset(x:2, y:3).must_equal Geometry::Size[
|
129
|
+
subject.outset(2,3).must_equal Geometry::Size[14, 16]
|
130
|
+
subject.outset(x:2, y:3).must_equal Geometry::Size[14, 16]
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'must outset with left and top' do
|
116
134
|
subject.outset(left:2, top:3).must_equal Geometry::Size[12, 13]
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'must outset with right and bottom' do
|
117
138
|
subject.outset(right:2, bottom:3).must_equal Geometry::Size[12, 13]
|
118
139
|
end
|
119
140
|
|
120
|
-
it 'must
|
141
|
+
it 'must outset with insets for top, left, bottom, right' do
|
121
142
|
subject.outset(top:1, left:2, bottom:3, right:4).must_equal Geometry::Size[16, 14]
|
122
143
|
end
|
123
144
|
end
|