geometry-in-ruby 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/Gemfile +7 -0
- data/LICENSE +21 -0
- data/README.markdown +105 -0
- data/Rakefile +24 -0
- data/geometry-in-ruby.gemspec +23 -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/composition.rb +39 -0
- data/lib/geometry/transformation.rb +171 -0
- data/lib/geometry/triangle.rb +78 -0
- data/lib/geometry/vector.rb +34 -0
- data/lib/geometry.rb +22 -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/composition.rb +49 -0
- data/test/geometry/transformation.rb +169 -0
- data/test/geometry/triangle.rb +32 -0
- data/test/geometry/vector.rb +41 -0
- data/test/geometry.rb +5 -0
- metadata +117 -0
@@ -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
|
@@ -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,49 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'geometry/transformation/composition'
|
3
|
+
|
4
|
+
describe Geometry::Transformation::Composition do
|
5
|
+
Composition = Geometry::Transformation::Composition
|
6
|
+
Transformation = Geometry::Transformation
|
7
|
+
|
8
|
+
subject { Composition.new }
|
9
|
+
|
10
|
+
describe "when constructed" do
|
11
|
+
it "must accept multiple transformations" do
|
12
|
+
composition = Composition.new(Transformation.new, Transformation.new)
|
13
|
+
composition.size.must_equal 2
|
14
|
+
end
|
15
|
+
|
16
|
+
it "must reject anything that isn't a Transformation" do
|
17
|
+
-> { Composition.new :foo }.must_raise TypeError
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "attributes" do
|
22
|
+
describe "has_rotation?" do
|
23
|
+
it "must properly be true" do
|
24
|
+
Composition.new(Transformation.new angle:90).has_rotation?.must_equal true
|
25
|
+
end
|
26
|
+
|
27
|
+
it "must properly be false" do
|
28
|
+
subject.has_rotation?.must_equal false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "when composing" do
|
34
|
+
it "must append a Transformation" do
|
35
|
+
(Composition.new(Transformation.new) + Transformation.new).size.must_equal 2
|
36
|
+
end
|
37
|
+
|
38
|
+
it "must merge with a Composition" do
|
39
|
+
(Composition.new(Transformation.new) + Composition.new(Transformation.new)).size.must_equal 2
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "when transforming a Point" do
|
44
|
+
it "must handle composed translations" do
|
45
|
+
composition = Composition.new(Transformation.new origin:[1,2]) + Composition.new(Transformation.new [3,4])
|
46
|
+
composition.transform(Point[5,6]).must_equal Point[9, 12]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|