geometry-in-ruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/.gitignore +6 -0
  2. data/Gemfile +7 -0
  3. data/LICENSE +21 -0
  4. data/README.markdown +105 -0
  5. data/Rakefile +24 -0
  6. data/geometry-in-ruby.gemspec +23 -0
  7. data/lib/geometry/arc.rb +94 -0
  8. data/lib/geometry/circle.rb +122 -0
  9. data/lib/geometry/cluster_factory.rb +15 -0
  10. data/lib/geometry/edge.rb +140 -0
  11. data/lib/geometry/line.rb +154 -0
  12. data/lib/geometry/obround.rb +238 -0
  13. data/lib/geometry/path.rb +67 -0
  14. data/lib/geometry/point.rb +163 -0
  15. data/lib/geometry/point_zero.rb +107 -0
  16. data/lib/geometry/polygon.rb +368 -0
  17. data/lib/geometry/polyline.rb +318 -0
  18. data/lib/geometry/rectangle.rb +378 -0
  19. data/lib/geometry/regular_polygon.rb +136 -0
  20. data/lib/geometry/rotation.rb +190 -0
  21. data/lib/geometry/size.rb +75 -0
  22. data/lib/geometry/size_zero.rb +70 -0
  23. data/lib/geometry/square.rb +113 -0
  24. data/lib/geometry/text.rb +24 -0
  25. data/lib/geometry/transformation/composition.rb +39 -0
  26. data/lib/geometry/transformation.rb +171 -0
  27. data/lib/geometry/triangle.rb +78 -0
  28. data/lib/geometry/vector.rb +34 -0
  29. data/lib/geometry.rb +22 -0
  30. data/test/geometry/arc.rb +25 -0
  31. data/test/geometry/circle.rb +112 -0
  32. data/test/geometry/edge.rb +132 -0
  33. data/test/geometry/line.rb +132 -0
  34. data/test/geometry/obround.rb +25 -0
  35. data/test/geometry/path.rb +66 -0
  36. data/test/geometry/point.rb +258 -0
  37. data/test/geometry/point_zero.rb +177 -0
  38. data/test/geometry/polygon.rb +214 -0
  39. data/test/geometry/polyline.rb +266 -0
  40. data/test/geometry/rectangle.rb +154 -0
  41. data/test/geometry/regular_polygon.rb +120 -0
  42. data/test/geometry/rotation.rb +108 -0
  43. data/test/geometry/size.rb +97 -0
  44. data/test/geometry/size_zero.rb +153 -0
  45. data/test/geometry/square.rb +66 -0
  46. data/test/geometry/transformation/composition.rb +49 -0
  47. data/test/geometry/transformation.rb +169 -0
  48. data/test/geometry/triangle.rb +32 -0
  49. data/test/geometry/vector.rb +41 -0
  50. data/test/geometry.rb +5 -0
  51. 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