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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/Gemfile +7 -0
  4. data/LICENSE +21 -0
  5. data/README.markdown +105 -0
  6. data/Rakefile +24 -0
  7. data/aurora-geometry.gemspec +23 -0
  8. data/lib/geometry.rb +22 -0
  9. data/lib/geometry/arc.rb +94 -0
  10. data/lib/geometry/circle.rb +122 -0
  11. data/lib/geometry/cluster_factory.rb +15 -0
  12. data/lib/geometry/edge.rb +140 -0
  13. data/lib/geometry/line.rb +154 -0
  14. data/lib/geometry/obround.rb +238 -0
  15. data/lib/geometry/path.rb +67 -0
  16. data/lib/geometry/point.rb +163 -0
  17. data/lib/geometry/point_zero.rb +107 -0
  18. data/lib/geometry/polygon.rb +368 -0
  19. data/lib/geometry/polyline.rb +318 -0
  20. data/lib/geometry/rectangle.rb +378 -0
  21. data/lib/geometry/regular_polygon.rb +136 -0
  22. data/lib/geometry/rotation.rb +190 -0
  23. data/lib/geometry/size.rb +75 -0
  24. data/lib/geometry/size_zero.rb +70 -0
  25. data/lib/geometry/square.rb +113 -0
  26. data/lib/geometry/text.rb +24 -0
  27. data/lib/geometry/transformation.rb +171 -0
  28. data/lib/geometry/transformation/composition.rb +39 -0
  29. data/lib/geometry/triangle.rb +78 -0
  30. data/lib/geometry/vector.rb +34 -0
  31. data/test/geometry.rb +5 -0
  32. data/test/geometry/arc.rb +25 -0
  33. data/test/geometry/circle.rb +112 -0
  34. data/test/geometry/edge.rb +132 -0
  35. data/test/geometry/line.rb +132 -0
  36. data/test/geometry/obround.rb +25 -0
  37. data/test/geometry/path.rb +66 -0
  38. data/test/geometry/point.rb +258 -0
  39. data/test/geometry/point_zero.rb +177 -0
  40. data/test/geometry/polygon.rb +214 -0
  41. data/test/geometry/polyline.rb +266 -0
  42. data/test/geometry/rectangle.rb +154 -0
  43. data/test/geometry/regular_polygon.rb +120 -0
  44. data/test/geometry/rotation.rb +108 -0
  45. data/test/geometry/size.rb +97 -0
  46. data/test/geometry/size_zero.rb +153 -0
  47. data/test/geometry/square.rb +66 -0
  48. data/test/geometry/transformation.rb +169 -0
  49. data/test/geometry/transformation/composition.rb +49 -0
  50. data/test/geometry/triangle.rb +32 -0
  51. data/test/geometry/vector.rb +41 -0
  52. metadata +115 -0
data/test/geometry.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'minitest/autorun'
2
+ require 'geometry'
3
+
4
+ describe Geometry do
5
+ end
@@ -0,0 +1,25 @@
1
+ require 'minitest/autorun'
2
+ require 'geometry/arc'
3
+
4
+ describe Geometry::Arc do
5
+ Arc = Geometry::Arc
6
+
7
+ describe "when constructed" do
8
+ it "must accept a center point, radius, start and end angles" do
9
+ arc = Geometry::Arc.new center:[1,2], radius:3, start:0, end:90
10
+ arc.must_be_kind_of Geometry::Arc
11
+ arc.center.must_equal Point[1,2]
12
+ arc.radius.must_equal 3
13
+ arc.start_angle.must_equal 0
14
+ arc.end_angle.must_equal 90
15
+ end
16
+
17
+ it "must create an Arc from center, start and end points" do
18
+ arc = Geometry::Arc.new center:[1,2], start:[3,4], end:[5,6]
19
+ arc.must_be_kind_of Geometry::Arc
20
+ arc.center.must_equal Point[1,2]
21
+ arc.first.must_equal Point[3,4]
22
+ arc.last.must_equal Point[5,6]
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,112 @@
1
+ require 'minitest/autorun'
2
+ require 'geometry/circle'
3
+
4
+ describe Geometry::Circle do
5
+ Circle = Geometry::Circle
6
+
7
+ describe "when constructed with center and radius arguments" do
8
+ let(:circle) { Circle.new [1,2], 3 }
9
+
10
+ it "must create a Circle" do
11
+ circle.must_be_instance_of(Circle)
12
+ end
13
+
14
+ it "must have a center point accessor" do
15
+ circle.center.must_equal Point[1,2]
16
+ end
17
+
18
+ it "must have a radius accessor" do
19
+ circle.radius.must_equal 3
20
+ end
21
+
22
+ it "must compare equal" do
23
+ circle.must_equal Circle.new([1,2], 3)
24
+ end
25
+ end
26
+
27
+ describe "when constructed with named center and radius arguments" do
28
+ let(:circle) { Circle.new :center => [1,2], :radius => 3 }
29
+
30
+ it "must create a Circle" do
31
+ circle.must_be_instance_of(Circle)
32
+ end
33
+
34
+ it "must have a center point accessor" do
35
+ circle.center.must_equal Point[1,2]
36
+ end
37
+
38
+ it "must have a radius accessor" do
39
+ circle.radius.must_equal 3
40
+ end
41
+
42
+ it "must compare equal" do
43
+ (circle == Circle.new(:center => [1,2], :radius => 3)).must_equal true
44
+ end
45
+ end
46
+
47
+ describe "when constructed with named center and diameter arguments" do
48
+ let(:circle) { Circle.new center:[1,2], diameter:4 }
49
+
50
+ it "must be a CenterDiameterCircle" do
51
+ circle.must_be_instance_of(Geometry::CenterDiameterCircle)
52
+ circle.must_be_kind_of(Circle)
53
+ end
54
+
55
+ it "must have a center" do
56
+ circle.center.must_equal Point[1,2]
57
+ end
58
+
59
+ it "must have a diameter" do
60
+ circle.diameter.must_equal 4
61
+ end
62
+
63
+ it "must calculate the correct radius" do
64
+ circle.radius.must_equal 2
65
+ end
66
+
67
+ it "must compare equal" do
68
+ circle.must_equal Circle.new([1,2], :diameter => 4)
69
+ end
70
+ end
71
+
72
+ describe "when constructed with a diameter and no center" do
73
+ let(:circle) { Circle.new :diameter => 4 }
74
+
75
+ it "must be a CenterDiameterCircle" do
76
+ circle.must_be_instance_of(Geometry::CenterDiameterCircle)
77
+ circle.must_be_kind_of(Circle)
78
+ end
79
+
80
+ it "must have a nil center" do
81
+ circle.center.must_be_kind_of Geometry::PointZero
82
+ end
83
+
84
+ it "must have a diameter" do
85
+ circle.diameter.must_equal 4
86
+ end
87
+
88
+ it "must calculate the correct radius" do
89
+ circle.radius.must_equal 2
90
+ end
91
+ end
92
+
93
+ describe "properties" do
94
+ subject { Circle.new center:[1,2], :diameter => 4 }
95
+
96
+ it "must have a bounds property that returns a Rectangle" do
97
+ subject.bounds.must_equal Rectangle.new([-1,0], [3,4])
98
+ end
99
+
100
+ it "must have a minmax property that returns the corners of the bounding rectangle" do
101
+ subject.minmax.must_equal [Point[-1,0], Point[3,4]]
102
+ end
103
+
104
+ it "must have a max property that returns the upper right corner of the bounding rectangle" do
105
+ subject.max.must_equal Point[3,4]
106
+ end
107
+
108
+ it "must have a min property that returns the lower left corner of the bounding rectangle" do
109
+ subject.min.must_equal Point[-1,0]
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,132 @@
1
+ require 'minitest/autorun'
2
+ require 'geometry/edge'
3
+
4
+ def Edge(*args)
5
+ Geometry::Edge.new(*args)
6
+ end
7
+
8
+ describe Geometry::Edge do
9
+ Edge = Geometry::Edge
10
+ subject { Geometry::Edge.new [0,0], [1,1] }
11
+
12
+ it "must create an Edge object" do
13
+ edge = Edge.new([0,0], [1,0])
14
+ assert_kind_of(Geometry::Edge, edge)
15
+ assert_equal(Geometry::Point[0,0], edge.first)
16
+ assert_equal(Geometry::Point[1,0], edge.last)
17
+ end
18
+
19
+ it "must handle equality" do
20
+ edge1 = Edge.new([1,0], [0,1])
21
+ edge2 = Edge.new([1,0], [0,1])
22
+ edge3 = Edge.new([1,1], [5,5])
23
+ assert_equal(edge1, edge2)
24
+ edge1.wont_equal edge3
25
+ end
26
+
27
+ it "must return the height of the edge" do
28
+ edge = Edge([0,0], [1,1])
29
+ assert_equal(1, edge.height)
30
+ end
31
+
32
+ it "must return the width of the edge" do
33
+ edge = Edge([0,0], [1,1])
34
+ assert_equal(1, edge.width)
35
+ end
36
+
37
+ it "must convert an Edge to a Vector" do
38
+ Edge.new([0,0], [1,0]).vector.must_equal Vector[1,0]
39
+ end
40
+
41
+ it "must return the normalized direction of a vector" do
42
+ Edge.new([0,0], [1,0]).direction.must_equal Vector[1,0]
43
+ end
44
+
45
+ it "must return true for parallel edges" do
46
+ Edge.new([0,0], [1,0]).parallel?(Edge.new([0,0], [1,0])).must_equal 1
47
+ Edge.new([0,0], [1,0]).parallel?(Edge.new([1,0], [2,0])).must_equal 1
48
+ Edge.new([0,0], [1,0]).parallel?(Edge.new([3,0], [4,0])).must_equal 1
49
+ Edge.new([0,0], [1,0]).parallel?(Edge.new([3,1], [4,1])).must_equal 1
50
+ end
51
+
52
+ it "must return false for non-parallel edges" do
53
+ Edge.new([0,0], [2,0]).parallel?(Edge.new([1,-1], [1,1])).must_equal false
54
+ end
55
+
56
+ it "must clone and reverse" do
57
+ reversed = subject.reverse
58
+ reversed.to_a.must_equal subject.to_a.reverse
59
+ reversed.wont_be_same_as subject
60
+ end
61
+
62
+ it "must reverse itself" do
63
+ original = subject.to_a
64
+ subject.reverse!
65
+ subject.to_a.must_equal original.reverse
66
+ end
67
+
68
+ describe "spaceship" do
69
+ it "ascending with a Point" do
70
+ edge = Edge.new [0,0], [1,1]
71
+ (edge <=> Point[0,0]).must_equal 0
72
+ (edge <=> Point[1,0]).must_equal -1
73
+ (edge <=> Point[0,1]).must_equal 1
74
+ (edge <=> Point[2,2]).must_equal nil
75
+ end
76
+
77
+ it "descending with a Point" do
78
+ edge = Edge.new [1,1], [0,0]
79
+ (edge <=> Point[0,0]).must_equal 0
80
+ (edge <=> Point[1,0]).must_equal 1
81
+ (edge <=> Point[0,1]).must_equal -1
82
+ (edge <=> Point[2,2]).must_equal nil
83
+ end
84
+ end
85
+
86
+ describe "when finding an intersection" do
87
+ it "must find the intersection of two end-intersecting Edges" do
88
+ intersection = Edge.new([0,0],[1,1]).intersection(Edge.new([0,1],[1,1]))
89
+ intersection.must_be_kind_of Geometry::Point
90
+ intersection.must_equal Geometry::Point[1,1]
91
+ end
92
+
93
+ it "must find the intersection of two collinear end-intersecting Edges" do
94
+ intersection = Edge.new([2,2], [0,2]).intersection(Edge.new([3,2], [2,2]))
95
+ intersection.must_be_kind_of Geometry::Point
96
+ intersection.must_equal Geometry::Point[2,2]
97
+
98
+ intersection = Edge.new([0,2], [2,2]).intersection(Edge.new([2,2], [3,2]))
99
+ intersection.must_be_kind_of Geometry::Point
100
+ intersection.must_equal Geometry::Point[2,2]
101
+ end
102
+
103
+ it "must find the itersection of two crossed Edges" do
104
+ edge1 = Edge.new [0.0, 0], [2.0, 2.0]
105
+ edge2 = Edge.new [2.0, 0], [0.0, 2.0]
106
+ intersection = edge1.intersection edge2
107
+ intersection.must_be_kind_of Geometry::Point
108
+ intersection.must_equal Geometry::Point[1,1]
109
+ end
110
+
111
+ it "must return nil for two edges that do not intersect" do
112
+ Edge.new([0,0],[1,0]).intersection(Edge.new([0,1],[1,1])).must_equal nil
113
+ end
114
+
115
+ it "must return true for two collinear and overlapping edges" do
116
+ Edge.new([0,0],[2,0]).intersection(Edge.new([1,0],[3,0])).must_equal true
117
+ end
118
+
119
+ it "must return false for collinear but non-overlapping edges" do
120
+ Edge.new([0,0],[2,0]).intersection(Edge.new([3,0],[4,0])).must_equal false
121
+ Edge.new([0,0],[0,2]).intersection(Edge.new([0,3],[0,4])).must_equal false
122
+ end
123
+
124
+ it "must return nil for two parallel but not collinear edges" do
125
+ Edge.new([0,0],[2,0]).intersection(Edge.new([1,1],[3,1])).must_equal nil
126
+ end
127
+
128
+ it "must return nil for two perpendicular but not interseting edges" do
129
+ Edge.new([0, 0], [2, 0]).intersection(Edge.new([3, 3], [3, 1])).must_equal nil
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,132 @@
1
+ require 'minitest/autorun'
2
+ require 'geometry/line'
3
+
4
+ describe Geometry::Line do
5
+ Line = Geometry::Line
6
+ Point = Geometry::Point
7
+
8
+ describe "when initializing" do
9
+ it "must accept two named points" do
10
+ line = Line.new(from:Point[0,0], to:Point[10,10])
11
+ line.must_be_kind_of(Line)
12
+ line.must_be_instance_of(Geometry::TwoPointLine)
13
+ line.first.must_equal Point[0,0]
14
+ line.last.must_equal Point[10,10]
15
+ end
16
+
17
+ it "must accept named start and end points" do
18
+ line = Line.new(start:Point[0,0], end:Point[10,10])
19
+ line.must_be_kind_of(Line)
20
+ line.must_be_instance_of(Geometry::TwoPointLine)
21
+ line.first.must_equal Point[0,0]
22
+ line.last.must_equal Point[10,10]
23
+ end
24
+
25
+ it "must raise an exception when no arguments are given" do
26
+ -> { Line.new }.must_raise ArgumentError
27
+ end
28
+ end
29
+
30
+ it "create a Line object from 2 Points" do
31
+ line = Geometry::Line[Geometry::Point[0,0], Geometry::Point[10,10]]
32
+ assert_kind_of(Geometry::Line, line)
33
+ assert_kind_of(Geometry::TwoPointLine, line)
34
+ end
35
+ it "create a Line object from two arrays" do
36
+ line = Geometry::Line[[0,0], [10,10]]
37
+ assert(line.is_a?(Geometry::Line))
38
+ assert_kind_of(Geometry::TwoPointLine, line)
39
+ assert_kind_of(Geometry::Point, line.first)
40
+ assert_kind_of(Geometry::Point, line.last)
41
+ end
42
+ it "create a Line object from two Vectors" do
43
+ line = Geometry::Line[Vector[0,0], Vector[10,10]]
44
+ assert(line.is_a?(Geometry::Line))
45
+ assert_kind_of(Geometry::TwoPointLine, line)
46
+ end
47
+
48
+ it "create a Line from a slope and y-intercept" do
49
+ line = Geometry::Line[0.75, 5]
50
+ assert(line.is_a?(Geometry::Line))
51
+ assert_kind_of(Geometry::SlopeInterceptLine, line)
52
+ assert_equal(5, line.intercept)
53
+ assert_equal(0.75, line.slope)
54
+ end
55
+
56
+ it "create a Line from a Rational slope and y-intercept" do
57
+ line = Geometry::Line[Rational(3,4), 5]
58
+ assert_kind_of(Geometry::SlopeInterceptLine, line)
59
+ assert(line.is_a?(Geometry::Line))
60
+ assert_equal(Rational(3,4), line.slope)
61
+ end
62
+
63
+ it "have a special constructor for horizontal lines" do
64
+ line = Geometry::Line.horizontal
65
+ assert(line.horizontal?)
66
+ end
67
+ it "have a special constructor for vertical lines" do
68
+ line = Geometry::Line.vertical
69
+ assert(line.vertical?)
70
+ end
71
+
72
+ it "have accessor for y-intercept" do
73
+ line = Geometry::Line[0.75, 5]
74
+ assert_equal(5, line.intercept)
75
+ assert_equal(5, line.intercept(:y))
76
+ end
77
+ it "have accessor for x-intercept" do
78
+ line = Geometry::Line.vertical(7)
79
+ assert_equal(7, line.intercept(:x))
80
+ end
81
+
82
+ it "return the correct x-intercept for vertical lines" do
83
+ line = Geometry::Line.vertical(7)
84
+ assert_equal(7, line.intercept(:x))
85
+ end
86
+ it "return the correct y-intercept for horizontal lines" do
87
+ line = Geometry::Line.horizontal(4)
88
+ assert_equal(4, line.intercept(:y))
89
+ end
90
+
91
+ it "return nil x-intercept for horizontal lines" do
92
+ line = Geometry::Line.horizontal
93
+ assert_nil(line.intercept(:x))
94
+ end
95
+ it "return nil y-intercept for vertical lines" do
96
+ line = Geometry::Line.vertical
97
+ assert_nil(line.intercept(:y))
98
+ end
99
+
100
+ it "implement inspect" do
101
+ line = Geometry::Line[[0,0], [10,10]]
102
+ assert_equal('Line(Point[0, 0], Point[10, 10])', line.inspect)
103
+ end
104
+ it "implement to_s" do
105
+ line = Geometry::Line[[0,0], [10,10]]
106
+ assert_equal('Line(Point[0, 0], Point[10, 10])', line.to_s)
107
+ end
108
+ end
109
+
110
+ describe Geometry::PointSlopeLine do
111
+ subject { Geometry::PointSlopeLine.new [1,2], 3 }
112
+
113
+ it "must have a slope attribute" do
114
+ subject.slope.must_equal 3
115
+ end
116
+ end
117
+
118
+ describe Geometry::SlopeInterceptLine do
119
+ subject { Geometry::SlopeInterceptLine.new 3, 2 }
120
+
121
+ it "must have a slope attribute" do
122
+ subject.slope.must_equal 3
123
+ end
124
+ end
125
+
126
+ describe Geometry::TwoPointLine do
127
+ subject { Geometry::TwoPointLine.new [1,2], [3,4] }
128
+
129
+ it "must have a slope attribute" do
130
+ subject.slope.must_equal 1
131
+ end
132
+ end
@@ -0,0 +1,25 @@
1
+ require 'minitest/autorun'
2
+ require 'geometry/obround'
3
+
4
+ describe Geometry::Obround do
5
+ Obround = Geometry::Obround
6
+
7
+ describe "when constructed" do
8
+ it "must accept two Points" do
9
+ obround = Geometry::Obround.new [1,2], [3,4]
10
+ obround.must_be_kind_of Geometry::Obround
11
+ end
12
+
13
+ it "must accept a width and height" do
14
+ obround = Geometry::Obround.new 2, 3
15
+ obround.must_be_kind_of Geometry::Obround
16
+ obround.height.must_equal 3
17
+ obround.width.must_equal 2
18
+ end
19
+
20
+ it "must compare equal" do
21
+ obround = Geometry::Obround.new [1,2], [3,4]
22
+ obround.must_equal Obround.new([1,2], [3,4])
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,66 @@
1
+ require 'minitest/autorun'
2
+ require 'geometry/path'
3
+
4
+ describe Geometry::Path do
5
+ describe "construction" do
6
+ it "must create a Path with no arguments" do
7
+ path = Geometry::Path.new
8
+ path.must_be_kind_of Geometry::Path
9
+ path.elements.wont_be_nil
10
+ path.elements.size.must_equal 0
11
+ end
12
+
13
+ it "must create a Path from Points" do
14
+ path = Geometry::Path.new Point[1,1], Point[2,2], Point[3,3]
15
+ path.elements.size.must_equal 2
16
+ path.elements.each {|a| a.must_be_kind_of Geometry::Edge }
17
+ end
18
+
19
+ it "with connected Edges" do
20
+ path = Geometry::Path.new Edge.new([1,1], [2,2]), Edge.new([2,2], [3,3])
21
+ path.elements.size.must_equal 2
22
+ path.elements.each {|a| a.must_be_kind_of Geometry::Edge }
23
+ end
24
+
25
+ it "with disjoint Edges" do
26
+ path = Geometry::Path.new Edge.new([1,1], [2,2]), Edge.new([3,3], [4,4])
27
+ path.elements.size.must_equal 3
28
+ path.elements.each {|a| a.must_be_kind_of Geometry::Edge }
29
+ end
30
+
31
+ it "with Points and Arcs" do
32
+ path = Geometry::Path.new [0,0], [1.0,0.0], Arc.new(center:[1,1], radius:1, start:-90*Math::PI/180, end:0), [2.0,1.0], [1,2]
33
+ path.elements.size.must_equal 3
34
+ path.elements[0].must_be_kind_of Geometry::Edge
35
+ path.elements[1].must_be_kind_of Geometry::Arc
36
+ path.elements[2].must_be_kind_of Geometry::Edge
37
+ end
38
+
39
+ it "with Edges and Arcs" do
40
+ path = Geometry::Path.new Edge.new([0,0], [1.0,0.0]), Arc.new(center:[1,1], radius:1, start:-90*Math::PI/180, end:0), Edge.new([2.0,1.0], [1,2])
41
+ path.elements.size.must_equal 3
42
+ path.elements[0].must_be_kind_of Geometry::Edge
43
+ path.elements[1].must_be_kind_of Geometry::Arc
44
+ path.elements[2].must_be_kind_of Geometry::Edge
45
+ end
46
+
47
+ it "with disjoint Edges and Arcs" do
48
+ path = Geometry::Path.new Edge.new([0,0], [1,0]), Arc.new(center:[2,1], radius:1, start:-90*Math::PI/180, end:0), Edge.new([3,1], [1,2])
49
+ path.elements.size.must_equal 4
50
+ path.elements[0].must_be_kind_of Geometry::Edge
51
+ path.elements[1].must_be_kind_of Geometry::Edge
52
+ path.elements[2].must_be_kind_of Geometry::Arc
53
+ path.elements[3].must_be_kind_of Geometry::Edge
54
+ end
55
+
56
+ it "with disjoint Arcs" do
57
+ path = Geometry::Path.new Arc.new(center:[2,1], radius:1, start:-90*Math::PI/180, end:0), Arc.new(center:[3,1], radius:1, start:-90*Math::PI/180, end:0)
58
+ path.elements.size.must_equal 3
59
+ path.elements[0].must_be_kind_of Geometry::Arc
60
+ path.elements[1].must_be_kind_of Geometry::Edge
61
+ path.elements[2].must_be_kind_of Geometry::Arc
62
+
63
+ path.elements[0].last.must_equal path.elements[1].first
64
+ end
65
+ end
66
+ end