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,108 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'geometry/rotation'
|
3
|
+
|
4
|
+
describe Geometry::Rotation do
|
5
|
+
Point = Geometry::Point
|
6
|
+
Rotation = Geometry::Rotation
|
7
|
+
RotationAngle = Geometry::RotationAngle
|
8
|
+
|
9
|
+
describe "when constructed" do
|
10
|
+
it "must accept a rotation angle" do
|
11
|
+
rotation = Rotation.new angle:Math::PI/2
|
12
|
+
rotation.must_be_instance_of(RotationAngle)
|
13
|
+
rotation.angle.must_equal Math::PI/2
|
14
|
+
rotation.x.x.must_be_close_to 0
|
15
|
+
rotation.x.y.must_be_close_to 1
|
16
|
+
rotation.y.x.must_be_close_to -1
|
17
|
+
rotation.y.y.must_be_close_to 0
|
18
|
+
end
|
19
|
+
|
20
|
+
it "must accept an X axis" do
|
21
|
+
rotation = Rotation.new x:[1,0]
|
22
|
+
rotation.must_be_instance_of(RotationAngle)
|
23
|
+
rotation.angle.must_equal 0
|
24
|
+
rotation.x.must_equal Point[1,0]
|
25
|
+
rotation.y.must_equal Point[0,1]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it "must accept x and y axes" do
|
30
|
+
rotation = Geometry::Rotation.new :x => [1,2,3], :y => [4,5,6]
|
31
|
+
rotation.x.must_equal [1,2,3]
|
32
|
+
rotation.y.must_equal [4,5,6]
|
33
|
+
end
|
34
|
+
|
35
|
+
it "must accept 3-element x and y axes and a dimensionality of 3" do
|
36
|
+
rotation = Geometry::Rotation.new(:dimensions => 3, :x => [1,2,3], :y => [4,5,6])
|
37
|
+
rotation.dimensions.must_equal 3
|
38
|
+
end
|
39
|
+
|
40
|
+
it "must reject 3-element x and y axes and a dimensionality of 2" do
|
41
|
+
lambda { Geometry::Rotation.new(:dimensions => 2, :x => [1,2,3], :y => [4,5,6]) }.must_raise ArgumentError
|
42
|
+
end
|
43
|
+
|
44
|
+
it "must promote 2-element Vectors to dimensionality of 3" do
|
45
|
+
rotation = Geometry::Rotation.new(:dimensions => 3, :x => [1,2], :y => [4,5])
|
46
|
+
rotation.dimensions.must_equal 3
|
47
|
+
rotation.x.must_equal [1,2,0]
|
48
|
+
rotation.y.must_equal [4,5,0]
|
49
|
+
end
|
50
|
+
|
51
|
+
it "must be the identity rotation if no axes are given" do
|
52
|
+
Geometry::Rotation.new.identity?.must_equal true
|
53
|
+
Geometry::Rotation.new(:dimensions => 3).identity?.must_equal true
|
54
|
+
end
|
55
|
+
|
56
|
+
it "must be the identity rotation when identity axes are given" do
|
57
|
+
Geometry::Rotation.new(:x => [1,0,0], :y => [0,1,0])
|
58
|
+
end
|
59
|
+
|
60
|
+
it "must have a matrix accessor" do
|
61
|
+
r = Geometry::Rotation.new(:x => [1,0,0], :y => [0,1,0])
|
62
|
+
r.matrix.must_equal Matrix[[1,0,0],[0,1,0],[0,0,1]]
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "when comparing" do
|
66
|
+
it "must equate equal objects" do
|
67
|
+
Rotation.new(x:[1,2,3], y:[4,5,6]).must_equal Rotation.new(x:[1,2,3], y:[4,5,6])
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "comparison" do
|
72
|
+
it "must equate equal angles" do
|
73
|
+
Rotation.new(angle:45).must_equal Rotation.new(angle:45)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "must not equate unequal angles" do
|
77
|
+
Rotation.new(angle:10).wont_equal Rotation.new(angle:45)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "composition" do
|
82
|
+
it "must add angles" do
|
83
|
+
(Rotation.new(angle:45) + Rotation.new(angle:45)).must_equal Rotation.new(angle:90)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "must subtract angles" do
|
87
|
+
(Rotation.new(angle:45) - Rotation.new(angle:45)).must_equal Rotation.new(angle:0)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "must negate angles" do
|
91
|
+
(-Rotation.new(angle:45)).must_equal Rotation.new(angle:-45)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "when transforming a Point" do
|
96
|
+
describe "when no rotation is set" do
|
97
|
+
it "must return the Point" do
|
98
|
+
Rotation.new.transform(Point[1,0]).must_equal Point[1,0]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
it "must rotate" do
|
103
|
+
rotated_point = Rotation.new(angle:Math::PI/2).transform(Point[1,0])
|
104
|
+
rotated_point.x.must_be_close_to 0
|
105
|
+
rotated_point.y.must_be_close_to 1
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'geometry/size'
|
3
|
+
|
4
|
+
describe Geometry::Size do
|
5
|
+
describe "when constructed" do
|
6
|
+
it "create a Size object using list syntax" do
|
7
|
+
size = Geometry::Size[2,1]
|
8
|
+
assert_equal(2, size.size)
|
9
|
+
assert_equal(2, size.x)
|
10
|
+
assert_equal(1, size.y)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "create a Size object from an array" do
|
14
|
+
size = Geometry::Size[[3,4]]
|
15
|
+
assert_equal(2, size.size)
|
16
|
+
assert_equal(3, size.x)
|
17
|
+
assert_equal(4, size.y)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "create a Size object from individual parameters" do
|
21
|
+
size = Geometry::Size[3,4]
|
22
|
+
assert_equal(2, size.size)
|
23
|
+
assert_equal(3, size.x)
|
24
|
+
assert_equal(4, size.y)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "create a Size object from a Size" do
|
28
|
+
size = Geometry::Size[Geometry::Size[3,4]]
|
29
|
+
assert_equal(2, size.size)
|
30
|
+
assert_equal(3, size.x)
|
31
|
+
assert_equal(4, size.y)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "create a Size object from a Vector" do
|
35
|
+
size = Geometry::Size[Vector[3,4]]
|
36
|
+
assert_equal(2, size.size)
|
37
|
+
assert_equal(3, size.x)
|
38
|
+
assert_equal(4, size.y)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it "allow indexed element access" do
|
43
|
+
size = Geometry::Size[5,6]
|
44
|
+
assert_equal(2, size.size)
|
45
|
+
assert_equal(5, size[0])
|
46
|
+
assert_equal(6, size[1])
|
47
|
+
end
|
48
|
+
it "allow named element access" do
|
49
|
+
size = Geometry::Size[5,6,7]
|
50
|
+
assert_equal(3, size.size)
|
51
|
+
assert_equal(5, size.x)
|
52
|
+
assert_equal(6, size.y)
|
53
|
+
assert_equal(7, size.z)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "have a width accessor" do
|
57
|
+
size = Geometry::Size[5,6,7]
|
58
|
+
assert_equal(5, size.width)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "have a height accessor" do
|
62
|
+
size = Geometry::Size[5,6,7]
|
63
|
+
assert_equal(6, size.height)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "have a depth accessor" do
|
67
|
+
size = Geometry::Size[5,6,7]
|
68
|
+
assert_equal(7, size.depth)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "compare equal" do
|
72
|
+
size1 = Geometry::Size[1,2]
|
73
|
+
size2 = Geometry::Size[1,2]
|
74
|
+
size3 = Geometry::Size[3,4]
|
75
|
+
assert_equal(size1, size2)
|
76
|
+
size2.wont_equal size3
|
77
|
+
end
|
78
|
+
|
79
|
+
it "compare equal to an array with equal elements" do
|
80
|
+
size1 = Size[1,2]
|
81
|
+
assert_equal(size1, [1,2])
|
82
|
+
end
|
83
|
+
|
84
|
+
it "not compare equal to an array with unequal elements" do
|
85
|
+
size1 = Size[1,2]
|
86
|
+
size1.wont_equal [3,2]
|
87
|
+
end
|
88
|
+
|
89
|
+
it "implement inspect" do
|
90
|
+
size = Geometry::Size[8,9]
|
91
|
+
assert_equal('Size[8, 9]', size.inspect)
|
92
|
+
end
|
93
|
+
it "implement to_s" do
|
94
|
+
size = Geometry::Size[10,11]
|
95
|
+
assert_equal('Size[10, 11]', size.to_s)
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'geometry/size_zero'
|
3
|
+
|
4
|
+
describe Geometry::SizeZero do
|
5
|
+
Size = Geometry::Size
|
6
|
+
|
7
|
+
let(:zero) { Geometry::SizeZero.new }
|
8
|
+
|
9
|
+
describe "arithmetic" do
|
10
|
+
let(:left) { Size[1,2] }
|
11
|
+
let(:right) { Size[3,4] }
|
12
|
+
|
13
|
+
it "must have +@" do
|
14
|
+
(+zero).must_be :eql?, 0
|
15
|
+
(+zero).must_be_instance_of(Geometry::SizeZero)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "must have unary negation" do
|
19
|
+
(-zero).must_be :eql?, 0
|
20
|
+
(-zero).must_be_instance_of(Geometry::SizeZero)
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "when adding" do
|
24
|
+
it "must return a number" do
|
25
|
+
(zero + 3).must_equal 3
|
26
|
+
(3 + zero).must_equal 3
|
27
|
+
end
|
28
|
+
|
29
|
+
it "return a Size when adding two Sizes" do
|
30
|
+
(zero + right).must_be_kind_of Size
|
31
|
+
# (left + zero).must_be_kind_of Size
|
32
|
+
end
|
33
|
+
|
34
|
+
it "must return a Size when adding an array" do
|
35
|
+
(zero + [5,6]).must_equal [5,6]
|
36
|
+
# ([5,6] + zero).must_equal [5,6]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "when subtracting" do
|
41
|
+
it "must return a number" do
|
42
|
+
(zero - 3).must_equal -3
|
43
|
+
(3 - zero).must_equal 3
|
44
|
+
end
|
45
|
+
|
46
|
+
it "return a Size when subtracting two Size" do
|
47
|
+
(zero - right).must_equal Size[-3,-4]
|
48
|
+
(left - zero).must_equal Size[1,2]
|
49
|
+
end
|
50
|
+
|
51
|
+
it "must return a Size when subtracting an array" do
|
52
|
+
(zero - [5,6]).must_equal [-5, -6]
|
53
|
+
# ([5,6] - zero).must_equal [5,6]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "multiplication" do
|
58
|
+
it "must return 0 for scalars" do
|
59
|
+
(zero * 3).must_equal 0
|
60
|
+
(zero * 3.0).must_equal 0.0
|
61
|
+
end
|
62
|
+
|
63
|
+
it "must return 0 for Sizes" do
|
64
|
+
(zero * Size[1,2]).must_equal 0
|
65
|
+
end
|
66
|
+
|
67
|
+
it "must return 0 for Vectors" do
|
68
|
+
(zero * Vector[2,3]).must_equal 0
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "division" do
|
73
|
+
it "must return 0 for non-zero scalars" do
|
74
|
+
(zero / 3).must_equal 0
|
75
|
+
(zero / 4.0).must_equal 0
|
76
|
+
end
|
77
|
+
|
78
|
+
it "must raise an exception when divided by 0" do
|
79
|
+
lambda { zero / 0 }.must_raise ZeroDivisionError
|
80
|
+
end
|
81
|
+
|
82
|
+
it "must raise an exception for Sizes" do
|
83
|
+
lambda { zero / Size[1,2] }.must_raise Geometry::OperationNotDefined
|
84
|
+
end
|
85
|
+
|
86
|
+
it "must raise an exception for Vectors" do
|
87
|
+
lambda { zero / Vector[1,2] }.must_raise Geometry::OperationNotDefined
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "coercion" do
|
95
|
+
it "must coerce Arrays into Sizes" do
|
96
|
+
zero.coerce([3,4]).must_equal [Size[3,4], Size[0,0]]
|
97
|
+
end
|
98
|
+
|
99
|
+
it "must coerce Vectors into Vectors" do
|
100
|
+
zero.coerce(Vector[3,4]).must_equal [Vector[3,4], Vector[0,0]]
|
101
|
+
end
|
102
|
+
|
103
|
+
it "must coerce Size into Size" do
|
104
|
+
zero.coerce(Size[5,6]).must_equal [Size[5,6], Size[0,0]]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "comparison" do
|
109
|
+
let(:zero) { Geometry::PointZero.new }
|
110
|
+
|
111
|
+
it "must be equal to 0 and 0.0" do
|
112
|
+
zero.must_be :eql?, 0
|
113
|
+
zero.must_be :eql?, 0.0
|
114
|
+
end
|
115
|
+
|
116
|
+
it "must not be equal to a non-zero number" do
|
117
|
+
1.wont_equal zero
|
118
|
+
3.14.wont_equal zero
|
119
|
+
end
|
120
|
+
|
121
|
+
it "must be equal to an Array of zeros" do
|
122
|
+
zero.must_be :==, [0,0]
|
123
|
+
zero.must_be :eql?, [0,0]
|
124
|
+
[0,0].must_equal zero
|
125
|
+
end
|
126
|
+
|
127
|
+
it "must not be equal to a non-zero Array" do
|
128
|
+
zero.wont_equal [3,2]
|
129
|
+
[3,2].wont_equal zero
|
130
|
+
end
|
131
|
+
|
132
|
+
it "must be equal to a zero Size" do
|
133
|
+
zero.must_be :==, Size[0,0]
|
134
|
+
zero.must_be :eql?, Size[0,0]
|
135
|
+
Size[0,0].must_equal zero
|
136
|
+
end
|
137
|
+
|
138
|
+
it "must not be equal to a non-zero Size" do
|
139
|
+
zero.wont_equal Size[3,2]
|
140
|
+
Size[3,2].wont_equal zero
|
141
|
+
end
|
142
|
+
|
143
|
+
it "must be equal to an Vector of zeroes" do
|
144
|
+
zero.must_be :eql?, Vector[0,0]
|
145
|
+
Vector[0,0].must_equal zero
|
146
|
+
end
|
147
|
+
|
148
|
+
it "must not be equal to a non-zero Vector" do
|
149
|
+
zero.wont_equal Vector[3,2]
|
150
|
+
Vector[3,2].wont_equal zero
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'geometry/square'
|
3
|
+
|
4
|
+
describe Geometry::Square do
|
5
|
+
Square = Geometry::Square
|
6
|
+
|
7
|
+
describe "when constructed" do
|
8
|
+
it "must create a Square from two Points" do
|
9
|
+
square = Square.new from:[1,2], to:[3,4]
|
10
|
+
square.must_be_kind_of Geometry::Square
|
11
|
+
end
|
12
|
+
|
13
|
+
it "must reorder swapped points when constructed from two Points" do
|
14
|
+
square = Geometry::Square.new from:[3,4], to:[1,2]
|
15
|
+
square.must_be_kind_of Geometry::Square
|
16
|
+
square.instance_eval('@points[0]').must_equal Point[1,2]
|
17
|
+
square.instance_eval('@points[1]').must_equal Point[3,4]
|
18
|
+
end
|
19
|
+
|
20
|
+
it "must accept an origin Point and a size" do
|
21
|
+
square = Square.new origin:[1,2], size:5
|
22
|
+
square.must_be_kind_of Geometry::Square
|
23
|
+
square.origin.must_equal Point[1,2]
|
24
|
+
square.height.must_equal 5
|
25
|
+
square.width.must_equal 5
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "properties" do
|
30
|
+
subject { Square.new from:[2,3], to:[3,4] }
|
31
|
+
|
32
|
+
it "must have an origin accessor" do
|
33
|
+
subject.origin.must_equal Point[2,3]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe Geometry::CenteredSquare do
|
39
|
+
describe "when constructed" do
|
40
|
+
it "must create a CenteredSquare from a center point and a size" do
|
41
|
+
square = Geometry::CenteredSquare.new [2,3], 5
|
42
|
+
square.must_be_instance_of Geometry::CenteredSquare
|
43
|
+
square.must_be_kind_of Geometry::Square
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "properties" do
|
48
|
+
let(:square) { Geometry::CenteredSquare.new [2,3], 4 }
|
49
|
+
|
50
|
+
it "must have a center property" do
|
51
|
+
square.center.must_equal Point[2,3]
|
52
|
+
end
|
53
|
+
|
54
|
+
it "must have a points property" do
|
55
|
+
square.points.must_equal [Point[0,1], Point[4,1], Point[4,5], Point[0,5]]
|
56
|
+
end
|
57
|
+
|
58
|
+
it "must have a height property" do
|
59
|
+
square.height.must_equal 4
|
60
|
+
end
|
61
|
+
|
62
|
+
it "must have a width property" do
|
63
|
+
square.width.must_equal 4
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'geometry/point'
|
3
|
+
require 'geometry/transformation'
|
4
|
+
|
5
|
+
describe Geometry::Transformation do
|
6
|
+
Transformation = Geometry::Transformation
|
7
|
+
|
8
|
+
describe "when constructed" do
|
9
|
+
it "must accept nothing and become an identity transformation" do
|
10
|
+
Transformation.new.identity?.must_equal true
|
11
|
+
end
|
12
|
+
|
13
|
+
it "must accept a translate parameter" do
|
14
|
+
Transformation.new([4,2]).translation.must_equal Point[4,2]
|
15
|
+
end
|
16
|
+
|
17
|
+
it "must accept a translate Array" do
|
18
|
+
translate = Transformation.new(:translate => [4,2])
|
19
|
+
translate.translation.must_equal Point[4,2]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "must accept a translate Point" do
|
23
|
+
translate = Transformation.new(:translate => Point[4,2])
|
24
|
+
translate.translation.must_equal Point[4,2]
|
25
|
+
end
|
26
|
+
|
27
|
+
it "must accept a translate Point equal to zero" do
|
28
|
+
translate = Transformation.new(:translate => [0,0])
|
29
|
+
translate.translation.must_equal nil
|
30
|
+
end
|
31
|
+
|
32
|
+
it "must accept a translate Vector" do
|
33
|
+
translate = Transformation.new(:translate => Vector[4,2])
|
34
|
+
translate.translation.must_equal Point[4,2]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "must accept an origin option" do
|
38
|
+
translate = Transformation.new(:origin => [4,2])
|
39
|
+
translate.translation.must_equal Point[4,2]
|
40
|
+
end
|
41
|
+
|
42
|
+
it "must raise an exception when given too many translation options" do
|
43
|
+
lambda { Transformation.new :translate => [1,2], :origin => [3,4] }.must_raise ArgumentError
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "when given a dimensions option" do
|
47
|
+
it "must raise an exception if the other arguments are too big" do
|
48
|
+
lambda { Transformation.new :dimensions => 2, :origin => [1,2,3] }.must_raise ArgumentError
|
49
|
+
end
|
50
|
+
|
51
|
+
it "must raise an exception if the other arguments are too small" do
|
52
|
+
lambda { Transformation.new :dimensions => 3, :origin => [1,2] }.must_raise ArgumentError
|
53
|
+
end
|
54
|
+
|
55
|
+
it "must not complain when given only a dimensions option" do
|
56
|
+
Transformation.new(:dimensions => 3).dimensions.must_equal 3
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "rotation" do
|
61
|
+
it "must accept a y axis option" do
|
62
|
+
t = Transformation.new :y => [1,0]
|
63
|
+
t.rotation.y.must_equal [1,0]
|
64
|
+
t.identity?.wont_equal true
|
65
|
+
end
|
66
|
+
|
67
|
+
it "must accept a rotation angle" do
|
68
|
+
transformation = Transformation.new angle:90
|
69
|
+
transformation.identity?.wont_equal true
|
70
|
+
transformation.rotation.wont_be_nil
|
71
|
+
transformation.rotation.angle.must_equal 90
|
72
|
+
end
|
73
|
+
|
74
|
+
it "must accept a rotation angle specified by an X-axis" do
|
75
|
+
transformation = Transformation.new x:[0,1]
|
76
|
+
rotation = transformation.rotation
|
77
|
+
rotation.must_be_instance_of(RotationAngle)
|
78
|
+
rotation.angle.must_equal Math::PI/2
|
79
|
+
rotation.x.x.must_be_close_to 0
|
80
|
+
rotation.x.y.must_be_close_to 1
|
81
|
+
rotation.y.x.must_be_close_to -1
|
82
|
+
rotation.y.y.must_be_close_to 0
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "comparison" do
|
88
|
+
subject { Transformation.new(origin:[1,2]) }
|
89
|
+
|
90
|
+
it "must equate equal transformations" do
|
91
|
+
subject.must_equal Transformation.new(origin:[1,2])
|
92
|
+
end
|
93
|
+
|
94
|
+
it "must not equal nil" do
|
95
|
+
subject.eql?(nil).wont_equal true
|
96
|
+
end
|
97
|
+
|
98
|
+
it "must not equate a translation with a rotation" do
|
99
|
+
subject.wont_equal Transformation.new(x:[0,1,0], y:[1,0,0])
|
100
|
+
end
|
101
|
+
|
102
|
+
it "must equate empty transformations" do
|
103
|
+
Transformation.new.must_equal Transformation.new
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "attributes" do
|
108
|
+
describe "has_rotation?" do
|
109
|
+
it "must properly be true" do
|
110
|
+
Transformation.new(angle:90).has_rotation?.must_equal true
|
111
|
+
end
|
112
|
+
|
113
|
+
it "must properly be false" do
|
114
|
+
Transformation.new.has_rotation?.must_equal false
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "composition" do
|
120
|
+
let(:translate_left) { Geometry::Transformation.new origin:[-2,-2] }
|
121
|
+
let(:translate_right) { Geometry::Transformation.new origin:[1,1] }
|
122
|
+
let(:transformation) { Geometry::Transformation.new }
|
123
|
+
|
124
|
+
it "must add pure translation" do
|
125
|
+
(translate_left + translate_right).must_equal Geometry::Transformation.new origin:[-1,-1]
|
126
|
+
end
|
127
|
+
|
128
|
+
it "must add translation and no translation" do
|
129
|
+
(transformation + translate_left).must_equal translate_left
|
130
|
+
(translate_left + transformation).must_equal translate_left
|
131
|
+
end
|
132
|
+
|
133
|
+
it "array addition" do
|
134
|
+
(transformation + [1,2]).translation.must_equal Point[1,2]
|
135
|
+
((transformation + [1,2]) + [2,3]).translation.must_equal Point[3,5]
|
136
|
+
(transformation + [1,2]).rotation.must_be_nil
|
137
|
+
end
|
138
|
+
|
139
|
+
it "must update the translation when an array is subtracted" do
|
140
|
+
(transformation - [1,2]).translation.must_equal Point[-1,-2]
|
141
|
+
((transformation - [1,2]) - [2,3]).translation.must_equal Point[-3,-5]
|
142
|
+
(transformation - [1,2,3]).rotation.must_be_nil
|
143
|
+
end
|
144
|
+
|
145
|
+
it "must subtract translation and no translation" do
|
146
|
+
(transformation - translate_left).must_equal translate_left
|
147
|
+
(translate_left - transformation).must_equal translate_left
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe "when transforming a Point" do
|
152
|
+
describe "when no transformation is set" do
|
153
|
+
it "must return the Point" do
|
154
|
+
Transformation.new.transform(Point[1,2]).must_equal Point[1,2];
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
it "must translate" do
|
159
|
+
Geometry::Transformation.new(origin:[0,1]).transform([1,0]).must_equal Point[1,1]
|
160
|
+
end
|
161
|
+
|
162
|
+
it "must rotate" do
|
163
|
+
rotated_point = Transformation.new(angle:Math::PI/2).transform([1,0])
|
164
|
+
rotated_point.x.must_be_close_to 0
|
165
|
+
rotated_point.y.must_be_close_to 1
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
end
|