geometry-in-ruby 0.0.1
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.
- 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
|