geometry 6.3 → 6.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8d541e7a304b060e2bc7bd392a4530fbfca3040b
4
- data.tar.gz: 9f4bfc263c8c735ed3d28a6f32f676e0fe3606c4
3
+ metadata.gz: 2071223ccd3ab40dc84675595b6b204aa0d7df10
4
+ data.tar.gz: ed6b83fe034a5734ca9938c7ab54f4a4fcdda736
5
5
  SHA512:
6
- metadata.gz: e9e952e9d9c66085aa7fc2852605467b8456ab30ac05d6106f5593b183d6ff865ec812d47d63f32f01b280838b51d93ec58811542b1adfc5b6632b9c57cfc7fc
7
- data.tar.gz: 53f91b55768b360e9f07026228b150d7f250dc866098eba904b01ad0ee4d2cf9eb693399ec95a44b1a5ab6640ec8898ce68690e9971e5500456ad06db6a84b7d
6
+ metadata.gz: d78e31275dd418edf77a9067157213b63690bb7139ccf8c8561b228bb51e7be9e8b72e3a9187f02beb8d77ddc95427f882454f49c4827196f832acadec131e3c
7
+ data.tar.gz: ba61dfc2b8d83090d59fe4d5348d3b184edeca188bf59c604d6888644a7392b943f8979ac4ea82392b1d8a026b53873128bab58c64702af149c3be68c1852057
@@ -1,4 +1,12 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.0.0
4
- - 2.1.1
3
+ - 2.0.0
4
+ - 2.1.1
5
+ deploy:
6
+ provider: rubygems
7
+ api_key:
8
+ secure: aCCrqOZ4pR5ACbPHfsurZbY2KOT3Qs5DZ7cJEG6Haa3sJXoMQ2srCtE2hsH1VO8idmrkHvl3wCEO9zNLOdx2x40xlaLVQ+wixtFKW1u9nnxjw4zszyyaxDIc8qnFsRNh6j997wyT2Sqx1YuQ8I82DnTh2I28mnxS51O33KeB0is=
9
+ gem: geometry
10
+ on:
11
+ tags: true
12
+ repo: bfoz/geometry
@@ -26,6 +26,7 @@ Primitives
26
26
  - Edge
27
27
  - [Annulus](http://en.wikipedia.org/wiki/Annulus_(mathematics))
28
28
  - [Arc](http://en.wikipedia.org/wiki/Arc_(geometry)), Circle
29
+ - [Bézier Curves](http://en.wikipedia.org/wiki/Bézier_curve)
29
30
  - Rectangle, Square
30
31
  - Path, [Polyline](http://en.wikipedia.org/wiki/Polyline), [Polygon](http://en.wikipedia.org/wiki/Polygon), [RegularPolygon](http://en.wikipedia.org/wiki/Regular_polygon)
31
32
  - Transformation
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "geometry"
6
- s.version = '6.3'
6
+ s.version = '6.4'
7
7
  s.authors = ["Brandon Fosdick"]
8
8
  s.email = ["bfoz@bfoz.net"]
9
9
  s.homepage = "http://github.com/bfoz/geometry"
@@ -17,7 +17,5 @@ Gem::Specification.new do |s|
17
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
18
  s.require_paths = ["lib"]
19
19
 
20
- # specify any dependencies here; for example:
21
- # s.add_development_dependency "rspec"
22
- # s.add_runtime_dependency "rest-client"
20
+ s.required_ruby_version = '>= 2.0'
23
21
  end
@@ -0,0 +1,48 @@
1
+ module Geometry
2
+ =begin
3
+ Bézier curves are like lines, but curvier.
4
+
5
+ http://en.wikipedia.org/wiki/Bézier_curve
6
+
7
+ == Constructors
8
+
9
+ Bezier.new [0,0], [1,1], [2,2] # From control points
10
+
11
+ == Usage
12
+
13
+ To get a point on the curve for a particular value of t, you can use the subscript operator
14
+
15
+ bezier[0.5] # => [1,1]
16
+ =end
17
+ class Bezier
18
+ # @!attribute degree
19
+ # @return [Number] The degree of the curve
20
+ def degree
21
+ points.length - 1
22
+ end
23
+
24
+ # @!attribute points
25
+ # @return [Array<Point>] The control points for the Bézier curve
26
+ attr_reader :points
27
+
28
+ def initialize(*points)
29
+ @points = points.map {|v| Point[v]}
30
+ end
31
+
32
+ # http://en.wikipedia.org/wiki/Binomial_coefficient
33
+ # http://rosettacode.org/wiki/Evaluate_binomial_coefficients#Ruby
34
+ def binomial_coefficient(k)
35
+ (0...k).inject(1) {|m,i| (m * (degree - i)) / (i + 1) }
36
+ end
37
+
38
+ # @param t [Float] the input parameter
39
+ def [](t)
40
+ return nil unless (0..1).include?(t)
41
+ result = Point.zero(points.first.size)
42
+ points.each_with_index do |v, i|
43
+ result += v * binomial_coefficient(i) * ((1 - t) ** (degree - i)) * (t ** i)
44
+ end
45
+ result
46
+ end
47
+ end
48
+ end
@@ -8,8 +8,8 @@ module Geometry
8
8
  An edge. It's a line segment between 2 points. Generally part of a {Polygon}.
9
9
 
10
10
  == Usage
11
+ edge = Geometry::Edge.new([1,1], [2,2])
11
12
  edge = Geometry::Edge([1,1], [2,2])
12
-
13
13
  =end
14
14
 
15
15
  class Edge
@@ -44,7 +44,7 @@ An edge. It's a line segment between 2 points. Generally part of a {Polygon}.
44
44
 
45
45
  # Return a new {Edge} with swapped endpoints
46
46
  def reverse
47
- Edge.new(@last, @first)
47
+ self.class.new(@last, @first)
48
48
  end
49
49
 
50
50
  # In-place swap the endpoints
@@ -53,6 +53,11 @@ An edge. It's a line segment between 2 points. Generally part of a {Polygon}.
53
53
  self
54
54
  end
55
55
 
56
+ # @return [Number] the length of the {Edge}
57
+ def length
58
+ @length ||= vector.magnitude
59
+ end
60
+
56
61
  # Return the {Edge}'s length along the Y axis
57
62
  def height
58
63
  (@first.y - @last.y).abs
@@ -140,4 +145,12 @@ An edge. It's a line segment between 2 points. Generally part of a {Polygon}.
140
145
  [@first, @last]
141
146
  end
142
147
  end
148
+
149
+ # Convenience initializer for {Edge} that tries to coerce its arguments into
150
+ # something useful
151
+ # @param first [Point, Array] the starting point of the {Edge}
152
+ # @param last [Point, Array] the endpoint of the {Edge}
153
+ def Edge(first, last)
154
+ Edge.new(first, last)
155
+ end
143
156
  end
@@ -87,13 +87,42 @@ Supports two-point, slope-intercept, and point-slope initializer forms
87
87
 
88
88
  # @private
89
89
  class PointSlopeLine < Line
90
+ # @!attribute point
91
+ # @return [Point] the stating point
92
+ attr_reader :point
93
+
90
94
  # @return [Number] the slope of the {Line}
91
95
  attr_reader :slope
92
96
 
97
+ # @param point [Point] a {Point} that lies on the {Line}
98
+ # @param slope [Number] the slope of the {Line}
93
99
  def initialize(point, slope)
94
100
  @point = Point[point]
95
101
  @slope = slope
96
102
  end
103
+
104
+ # Two {PointSlopeLine}s are equal if both have equal slope and origin
105
+ def ==(other)
106
+ case other
107
+ when SlopeInterceptLine
108
+ # Check that the slopes are equal and that the starting point will solve the slope-intercept equation
109
+ (slope == other.slope) && (point.y == other.slope * point.x + other.intercept)
110
+ when TwoPointLine
111
+ # Plug both of other's endpoints into the line equation and check that they solve it
112
+ first_diff = other.first - point
113
+ last_diff = other.last - point
114
+ (first_diff.y == slope*first_diff.x) && (last_diff.y == slope*last_diff.x)
115
+ else
116
+ self.eql? other
117
+ end
118
+ end
119
+
120
+ # Two {PointSlopeLine}s are equal if both have equal slopes and origins
121
+ # @note eql? does not check for equivalence between cluster subclases
122
+ def eql?(other)
123
+ (point == other.point) && (slope == other.slope)
124
+ end
125
+
97
126
  def to_s
98
127
  'Line(' + @slope.to_s + ',' + @point.to_s + ')'
99
128
  end
@@ -104,11 +133,33 @@ Supports two-point, slope-intercept, and point-slope initializer forms
104
133
  # @return [Number] the slope of the {Line}
105
134
  attr_reader :slope
106
135
 
136
+ # @param slope [Number] the slope
137
+ # @param intercept [Number] the location of the y-axis intercept
107
138
  def initialize(slope, intercept)
108
139
  @slope = slope
109
140
  @intercept = intercept
110
141
  end
111
142
 
143
+ # Two {SlopeInterceptLine}s are equal if both have equal slope and intercept
144
+ def ==(other)
145
+ case other
146
+ when PointSlopeLine
147
+ # Check that the slopes are equal and that the starting point will solve the slope-intercept equation
148
+ (slope == other.slope) && (other.point.y == slope * other.point.x + intercept)
149
+ when TwoPointLine
150
+ # Check that both endpoints solve the line equation
151
+ ((other.first.y == slope * other.first.x + intercept)) && (other.last.y == (slope * other.last.x + intercept))
152
+ else
153
+ self.eql? other
154
+ end
155
+ end
156
+
157
+ # Two {SlopeInterceptLine}s are equal if both have equal slopes and intercepts
158
+ # @note eql? does not check for equivalence between cluster subclases
159
+ def eql?(other)
160
+ (intercept == other.intercept) && (slope == other.slope)
161
+ end
162
+
112
163
  def horizontal?
113
164
  0 == @slope
114
165
  end
@@ -142,6 +193,28 @@ Supports two-point, slope-intercept, and point-slope initializer forms
142
193
  end
143
194
  alias :to_s :inspect
144
195
 
196
+ # Two {TwoPointLine}s are equal if both have equal {Point}s in the same order
197
+ def ==(other)
198
+ case other
199
+ when PointSlopeLine
200
+ # Plug both endpoints into the line equation and check that they solve it
201
+ first_diff = first - other.point
202
+ last_diff = last - other.point
203
+ (first_diff.y == other.slope*first_diff.x) && (last_diff.y == other.slope*last_diff.x)
204
+ when SlopeInterceptLine
205
+ # Check that both endpoints solve the line equation
206
+ ((first.y == other.slope * first.x + other.intercept)) && (last.y == (other.slope * last.x + other.intercept))
207
+ else
208
+ self.eql?(other) || ((first == other.last) && (last == other.first))
209
+ end
210
+ end
211
+
212
+ # Two {TwoPointLine}s are equal if both have equal endpoints
213
+ # @note eql? does not check for equivalence between cluster subclases
214
+ def eql?(other)
215
+ (first == other.first) && (last == other.last)
216
+ end
217
+
145
218
  # @group Accessors
146
219
  # !@attribute [r[ slope
147
220
  # @return [Number] the slope of the {Line}
@@ -119,6 +119,44 @@ geometry class (x, y, z).
119
119
  'Point' + @elements.to_s
120
120
  end
121
121
 
122
+ # @override max()
123
+ # @return [Number] The maximum value of the {Point}'s elements
124
+ # @override max(point)
125
+ # @return [Point] The element-wise maximum values of the receiver and the given {Point}
126
+ def max(*args)
127
+ if args.empty?
128
+ @elements.max
129
+ else
130
+ args = args.first if 1 == args.size
131
+ self.class[@elements.zip(args).map(&:max)]
132
+ end
133
+ end
134
+
135
+ # @override min()
136
+ # @return [Number] The minimum value of the {Point}'s elements
137
+ # @override min(point)
138
+ # @return [Point] The element-wise minimum values of the receiver and the given {Point}
139
+ def min(*args)
140
+ if args.empty?
141
+ @elements.min
142
+ else
143
+ args = args.first if 1 == args.size
144
+ self.class[@elements.zip(args).map(&:min)]
145
+ end
146
+ end
147
+
148
+ # @override minmax()
149
+ # @return [Array<Number>] The minimum value of the {Point}'s elements
150
+ # @override min(point)
151
+ # @return [Array<Point>] The element-wise minimum values of the receiver and the given {Point}
152
+ def minmax(*args)
153
+ if args.empty?
154
+ @elements.minmax
155
+ else
156
+ [min(*args), max(*args)]
157
+ end
158
+ end
159
+
122
160
  # @group Accessors
123
161
  # @param [Integer] i Index into the {Point}'s elements
124
162
  # @return [Numeric] Element i (starting at 0)
@@ -53,6 +53,44 @@ An object repesenting a N-dimensional {Point} with identical elements.
53
53
  []
54
54
  end
55
55
 
56
+ # @override max()
57
+ # @return [Number] The maximum value of the {Point}'s elements
58
+ # @override max(point)
59
+ # @return [Point] The element-wise maximum values of the receiver and the given {Point}
60
+ def max(*args)
61
+ if args.empty?
62
+ @value
63
+ else
64
+ args = args.first if 1 == args.size
65
+ Point[Array.new(args.size, @value).zip(args).map(&:max)]
66
+ end
67
+ end
68
+
69
+ # @override min()
70
+ # @return [Number] The minimum value of the {Point}'s elements
71
+ # @override min(point)
72
+ # @return [Point] The element-wise minimum values of the receiver and the given {Point}
73
+ def min(*args)
74
+ if args.empty?
75
+ @value
76
+ else
77
+ args = args.first if 1 == args.size
78
+ Point[Array.new(args.size, @value).zip(args).map(&:min)]
79
+ end
80
+ end
81
+
82
+ # @override minmax()
83
+ # @return [Array<Number>] The minimum value of the {Point}'s elements
84
+ # @override min(point)
85
+ # @return [Array<Point>] The element-wise minimum values of the receiver and the given {Point}
86
+ def minmax(*args)
87
+ if args.empty?
88
+ [@value, @value]
89
+ else
90
+ [min(*args), max(*args)]
91
+ end
92
+ end
93
+
56
94
  # @group Accessors
57
95
  # @param i [Integer] Index into the {Point}'s elements
58
96
  # @return [Numeric] Element i (starting at 0)
@@ -67,6 +67,44 @@ everything else, regardless of size. It's similar to the
67
67
  end
68
68
  # @endgroup
69
69
 
70
+ # @override max()
71
+ # @return [Number] The maximum value of the {Point}'s elements
72
+ # @override max(point)
73
+ # @return [Point] The element-wise maximum values of the receiver and the given {Point}
74
+ def max(*args)
75
+ if args.empty?
76
+ 1
77
+ else
78
+ args = args.first if 1 == args.size
79
+ Point[Array.new(args.size, 1).zip(args).map(&:max)]
80
+ end
81
+ end
82
+
83
+ # @override min()
84
+ # @return [Number] The minimum value of the {Point}'s elements
85
+ # @override min(point)
86
+ # @return [Point] The element-wise minimum values of the receiver and the given {Point}
87
+ def min(*args)
88
+ if args.empty?
89
+ 1
90
+ else
91
+ args = args.first if 1 == args.size
92
+ Point[Array.new(args.size, 1).zip(args).map(&:min)]
93
+ end
94
+ end
95
+
96
+ # @override minmax()
97
+ # @return [Array<Number>] The minimum value of the {Point}'s elements
98
+ # @override min(point)
99
+ # @return [Array<Point>] The element-wise minimum values of the receiver and the given {Point}
100
+ def minmax(*args)
101
+ if args.empty?
102
+ [1, 1]
103
+ else
104
+ [min(*args), max(*args)]
105
+ end
106
+ end
107
+
70
108
  # @group Arithmetic
71
109
 
72
110
  # @group Unary operators
@@ -67,6 +67,44 @@ everything else, regardless of size. You can think of it as an application of th
67
67
  end
68
68
  # @endgroup
69
69
 
70
+ # @override max()
71
+ # @return [Number] The maximum value of the {Point}'s elements
72
+ # @override max(point)
73
+ # @return [Point] The element-wise maximum values of the receiver and the given {Point}
74
+ def max(*args)
75
+ if args.empty?
76
+ 0
77
+ else
78
+ args = args.first if 1 == args.size
79
+ Array.new(args.size, 0).zip(args).map(&:max)
80
+ end
81
+ end
82
+
83
+ # @override min()
84
+ # @return [Number] The minimum value of the {Point}'s elements
85
+ # @override min(point)
86
+ # @return [Point] The element-wise minimum values of the receiver and the given {Point}
87
+ def min(*args)
88
+ if args.empty?
89
+ 0
90
+ else
91
+ args = args.first if 1 == args.size
92
+ Array.new(args.size, 0).zip(args).map(&:min)
93
+ end
94
+ end
95
+
96
+ # @override minmax()
97
+ # @return [Array<Number>] The minimum value of the {Point}'s elements
98
+ # @override min(point)
99
+ # @return [Array<Point>] The element-wise minimum values of the receiver and the given {Point}
100
+ def minmax(*args)
101
+ if args.empty?
102
+ [0, 0]
103
+ else
104
+ [min(*args), max(*args)]
105
+ end
106
+ end
107
+
70
108
  # @group Arithmetic
71
109
 
72
110
  # @group Unary operators
@@ -20,6 +20,11 @@ The {Square} class cluster is like the {Rectangle} class cluster, but not longer
20
20
  # @return [Point] The {Square}'s origin
21
21
  attr_reader :origin
22
22
 
23
+ # @!attribute points
24
+ # @return [Array<Point>] the corner {Point}s of the {Square} in counter-clockwise order
25
+ attr_reader :points
26
+ alias :vertices :points
27
+
23
28
  # @overload new(:origin, :size)
24
29
  # Creates a {Square} with the given origin and size
25
30
  # @option [Point] :origin The lower-left corner
@@ -75,6 +80,12 @@ The {Square} class cluster is like the {Rectangle} class cluster, but not longer
75
80
  true
76
81
  end
77
82
 
83
+ # @!attribute [r] edges
84
+ # @return [Array<Edge>] An array of {Edge}s corresponding to the sides of the {Square}
85
+ def edges
86
+ (points + [points.first]).each_cons(2).map {|v1,v2| Edge.new v1, v2}
87
+ end
88
+
78
89
  # @return [Point] The upper right corner of the bounding {Rectangle}
79
90
  def max
80
91
  @points.last
@@ -96,6 +107,11 @@ The {Square} class cluster is like the {Rectangle} class cluster, but not longer
96
107
  @points.first
97
108
  end
98
109
 
110
+ def points
111
+ p0, p1 = *@points
112
+ [p0, Point[p1.x, p0.y], p1, Point[p0.x, p1.y]]
113
+ end
114
+
99
115
  def height
100
116
  min, max = @points.minmax {|a,b| a.y <=> b.y}
101
117
  max.y - min.y
@@ -0,0 +1,25 @@
1
+ require 'minitest/autorun'
2
+ require 'geometry/bezier'
3
+
4
+ describe Geometry::Bezier do
5
+ subject { Geometry::Bezier.new [0,0], [1,1], [2,2], [3,3] }
6
+
7
+ it 'must have control points' do
8
+ subject.points.length.must_equal 4
9
+ end
10
+
11
+ it 'must generate Pascals Triangle' do
12
+ subject.binomial_coefficient(0).must_equal 1
13
+ subject.binomial_coefficient(1).must_equal 3
14
+ subject.binomial_coefficient(2).must_equal 3
15
+ subject.binomial_coefficient(3).must_equal 1
16
+ end
17
+
18
+ it 'must return nil when t is out of range' do
19
+ subject[2].must_equal nil
20
+ end
21
+
22
+ it 'must subscript on the parameter' do
23
+ subject[0.5].must_equal Point[1.5, 1.5]
24
+ end
25
+ end
@@ -16,6 +16,12 @@ describe Geometry::Edge do
16
16
  assert_equal(Geometry::Point[1,0], edge.last)
17
17
  end
18
18
 
19
+ it 'must have a convenience initializer' do
20
+ edge = Edge([0,0], [1,0])
21
+ edge.must_be_kind_of Geometry::Edge
22
+ edge.must_equal Edge.new([0,0], [1,0])
23
+ end
24
+
19
25
  it "must handle equality" do
20
26
  edge1 = Edge.new([1,0], [0,1])
21
27
  edge2 = Edge.new([1,0], [0,1])
@@ -24,6 +30,10 @@ describe Geometry::Edge do
24
30
  edge1.wont_equal edge3
25
31
  end
26
32
 
33
+ it 'must have a length' do
34
+ Edge.new([0,0], [1,0]).length.must_equal 1
35
+ end
36
+
27
37
  it "must return the height of the edge" do
28
38
  edge = Edge([0,0], [1,1])
29
39
  assert_equal(1, edge.height)
@@ -113,6 +113,27 @@ describe Geometry::PointSlopeLine do
113
113
  it "must have a slope attribute" do
114
114
  subject.slope.must_equal 3
115
115
  end
116
+
117
+ it "must handle equality" do
118
+ line2 = Geometry::PointSlopeLine.new([1,2], 3)
119
+ line3 = Geometry::PointSlopeLine.new([1,1], 4)
120
+ subject.must_equal line2
121
+ subject.wont_equal line3
122
+ end
123
+
124
+ it 'must handle equality with a SlopeInterceptLine' do
125
+ line2 = Geometry::SlopeInterceptLine.new(3, -1)
126
+ line3 = Geometry::SlopeInterceptLine.new(4, -1)
127
+ line2.must_equal subject
128
+ line3.wont_equal subject
129
+ end
130
+
131
+ it 'must handle equality with a TwoPointLine' do
132
+ line2 = Geometry::TwoPointLine.new([1,2], [2,5])
133
+ line3 = Geometry::TwoPointLine.new([1,2], [2,4])
134
+ line2.must_equal subject
135
+ line3.wont_equal subject
136
+ end
116
137
  end
117
138
 
118
139
  describe Geometry::SlopeInterceptLine do
@@ -121,6 +142,27 @@ describe Geometry::SlopeInterceptLine do
121
142
  it "must have a slope attribute" do
122
143
  subject.slope.must_equal 3
123
144
  end
145
+
146
+ it "must handle equality" do
147
+ line2 = Geometry::SlopeInterceptLine.new(3, 2)
148
+ line3 = Geometry::SlopeInterceptLine.new(4, 3)
149
+ subject.must_equal line2
150
+ subject.wont_equal line3
151
+ end
152
+
153
+ it 'must handle equality with a PointSlopeLine' do
154
+ line2 = Geometry::PointSlopeLine.new([0,2], 3)
155
+ line3 = Geometry::PointSlopeLine.new([0,2], 2)
156
+ line2.must_equal subject
157
+ line3.wont_equal subject
158
+ end
159
+
160
+ it 'must handle equality with a TwoPointLine' do
161
+ line2 = Geometry::TwoPointLine.new([0,2], [1,5])
162
+ line3 = Geometry::TwoPointLine.new([0,2], [1,4])
163
+ line2.must_equal subject
164
+ line3.wont_equal subject
165
+ end
124
166
  end
125
167
 
126
168
  describe Geometry::TwoPointLine do
@@ -129,4 +171,25 @@ describe Geometry::TwoPointLine do
129
171
  it "must have a slope attribute" do
130
172
  subject.slope.must_equal 1
131
173
  end
174
+
175
+ it "must handle equality" do
176
+ line2 = Geometry::TwoPointLine.new([1,2], [3,4])
177
+ line3 = Geometry::TwoPointLine.new([1,1], [5,5])
178
+ subject.must_equal line2
179
+ subject.wont_equal line3
180
+ end
181
+
182
+ it 'must handle equality with a PointSlopeLine' do
183
+ line2 = Geometry::PointSlopeLine.new([1,2], 1)
184
+ line3 = Geometry::PointSlopeLine.new([1,2], 2)
185
+ line2.must_equal subject
186
+ line3.wont_equal subject
187
+ end
188
+
189
+ it 'must handle equality with a SlopeInterceptLine' do
190
+ line2 = Geometry::SlopeInterceptLine.new(1, 1)
191
+ line3 = Geometry::SlopeInterceptLine.new(1, -1)
192
+ line2.must_equal subject
193
+ line3.wont_equal subject
194
+ end
132
195
  end
@@ -114,6 +114,58 @@ describe Geometry::Point do
114
114
  Point[1,2].dup.must_equal Point[1,2]
115
115
  end
116
116
 
117
+ describe 'minmax' do
118
+ it 'must have a minimum' do
119
+ Point[1,2].min.must_equal 1
120
+ end
121
+
122
+ it 'must minimum with another Point' do
123
+ Point[1,3].min(Point[4,2]).must_equal Point[1,2]
124
+ Point[1,3].min(Point[4,2]).must_be_kind_of Point
125
+ end
126
+
127
+ it 'must minimum with an Array' do
128
+ Point[1,3].min([4,2]).must_equal Point[1,2]
129
+ end
130
+
131
+ it 'must minimum with a multiple arguments' do
132
+ Point[1,3].min(4,2).must_equal Point[1,2]
133
+ end
134
+
135
+ it 'must have a maximum' do
136
+ Point[1,2].max.must_equal 2
137
+ end
138
+
139
+ it 'must maximum with another Point' do
140
+ Point[1,3].max(Point[4,2]).must_equal Point[4,3]
141
+ Point[1,3].max(Point[4,2]).must_be_kind_of Point
142
+ end
143
+
144
+ it 'must maximum with an Array' do
145
+ Point[1,3].max([4,2]).must_equal Point[4,3]
146
+ end
147
+
148
+ it 'must maximum with multiple arguments' do
149
+ Point[1,3].max(4,2).must_equal Point[4,3]
150
+ end
151
+
152
+ it 'must have a minmax' do
153
+ Point[1,2].minmax.must_equal [1,2]
154
+ end
155
+
156
+ it 'must minmax with another Point' do
157
+ Point[1,3].minmax(Point[4,2]).must_equal [Point[1,2], Point[4,3]]
158
+ end
159
+
160
+ it 'must minmax with an Array' do
161
+ Point[1,3].minmax([4,2]).must_equal [Point[1,2], Point[4,3]]
162
+ end
163
+
164
+ it 'must maximum with multiple arguments' do
165
+ Point[1,3].minmax(4,2).must_equal [Point[1,2], Point[4,3]]
166
+ end
167
+ end
168
+
117
169
  describe "arithmetic" do
118
170
  let(:left) { Point[1,2] }
119
171
  let(:right) { Point[3,4] }
@@ -5,6 +5,58 @@ describe Geometry::PointIso do
5
5
  let(:value) { 5 }
6
6
  subject { Geometry::PointIso.new(5) }
7
7
 
8
+ describe 'minmax' do
9
+ it 'must have a minimum' do
10
+ subject.min.must_equal 5
11
+ end
12
+
13
+ it 'must minimum with another Point' do
14
+ subject.min(Point[4,7]).must_equal Point[4,5]
15
+ subject.min(Point[4,7]).must_be_kind_of Point
16
+ end
17
+
18
+ it 'must minimum with an Array' do
19
+ subject.min([4,7]).must_equal Point[4,5]
20
+ end
21
+
22
+ it 'must minimum with a multiple arguments' do
23
+ subject.min(4,7).must_equal Point[4,5]
24
+ end
25
+
26
+ it 'must have a maximum' do
27
+ subject.max.must_equal 5
28
+ end
29
+
30
+ it 'must maximum with another Point' do
31
+ subject.max(Point[7,2]).must_equal Point[7,5]
32
+ subject.max(Point[7,2]).must_be_kind_of Point
33
+ end
34
+
35
+ it 'must maximum with an Array' do
36
+ subject.max([7,2]).must_equal Point[7,5]
37
+ end
38
+
39
+ it 'must maximum with multiple arguments' do
40
+ subject.max(7,2).must_equal Point[7,5]
41
+ end
42
+
43
+ it 'must have a minmax' do
44
+ subject.minmax.must_equal [5,5]
45
+ end
46
+
47
+ it 'must minmax with another Point' do
48
+ subject.minmax(Point[7,2]).must_equal [Point[5,2], Point[7,5]]
49
+ end
50
+
51
+ it 'must minmax with an Array' do
52
+ subject.minmax([7,2]).must_equal [Point[5,2], Point[7,5]]
53
+ end
54
+
55
+ it 'must maximum with multiple arguments' do
56
+ subject.minmax(7,2).must_equal [Point[5,2], Point[7,5]]
57
+ end
58
+ end
59
+
8
60
  describe 'arithmetic' do
9
61
  let(:left) { Point[1,2] }
10
62
  let(:right) { Point[3,4] }
@@ -5,6 +5,58 @@ describe Geometry::PointOne do
5
5
  subject { Geometry::PointOne.new }
6
6
  let(:one) { Geometry::PointOne.new }
7
7
 
8
+ describe 'minmax' do
9
+ it 'must have a minimum' do
10
+ subject.min.must_equal 1
11
+ end
12
+
13
+ it 'must minimum with another Point' do
14
+ subject.min(Point[0,7]).must_equal Point[0,1]
15
+ subject.min(Point[0,7]).must_be_kind_of Point
16
+ end
17
+
18
+ it 'must minimum with an Array' do
19
+ subject.min([0,7]).must_equal Point[0,1]
20
+ end
21
+
22
+ it 'must minimum with a multiple arguments' do
23
+ subject.min(0,7).must_equal Point[0,1]
24
+ end
25
+
26
+ it 'must have a maximum' do
27
+ subject.max.must_equal 1
28
+ end
29
+
30
+ it 'must maximum with another Point' do
31
+ subject.max(Point[7,0]).must_equal Point[7,1]
32
+ subject.max(Point[7,0]).must_be_kind_of Point
33
+ end
34
+
35
+ it 'must maximum with an Array' do
36
+ subject.max([7,0]).must_equal Point[7,1]
37
+ end
38
+
39
+ it 'must maximum with multiple arguments' do
40
+ subject.max(7,0).must_equal Point[7,1]
41
+ end
42
+
43
+ it 'must have a minmax' do
44
+ subject.minmax.must_equal [1,1]
45
+ end
46
+
47
+ it 'must minmax with another Point' do
48
+ subject.minmax(Point[7,0]).must_equal [Point[1,0], Point[7,1]]
49
+ end
50
+
51
+ it 'must minmax with an Array' do
52
+ subject.minmax([7,0]).must_equal [Point[1,0], Point[7,1]]
53
+ end
54
+
55
+ it 'must maximum with multiple arguments' do
56
+ subject.minmax(7,0).must_equal [Point[1,0], Point[7,1]]
57
+ end
58
+ end
59
+
8
60
  describe 'arithmetic' do
9
61
  let(:left) { Point[1,2] }
10
62
  let(:right) { Point[3,4] }
@@ -5,6 +5,56 @@ describe Geometry::PointZero do
5
5
  subject { Geometry::PointZero.new }
6
6
  let(:zero) { Geometry::PointZero.new }
7
7
 
8
+ describe 'minmax' do
9
+ it 'must have a minimum' do
10
+ subject.min.must_equal 0
11
+ end
12
+
13
+ it 'must minimum with another Point' do
14
+ subject.min(Point[-1,7]).must_equal Point[-1,0]
15
+ end
16
+
17
+ it 'must minimum with an Array' do
18
+ subject.min([-1,7]).must_equal Point[-1,0]
19
+ end
20
+
21
+ it 'must minimum with a multiple arguments' do
22
+ subject.min(-1,7).must_equal Point[-1,0]
23
+ end
24
+
25
+ it 'must have a maximum' do
26
+ subject.max.must_equal 0
27
+ end
28
+
29
+ it 'must maximum with another Point' do
30
+ subject.max(Point[7,-1]).must_equal Point[7,0]
31
+ end
32
+
33
+ it 'must maximum with an Array' do
34
+ subject.max([7,-1]).must_equal Point[7,0]
35
+ end
36
+
37
+ it 'must maximum with multiple arguments' do
38
+ subject.max(7,-1).must_equal Point[7,0]
39
+ end
40
+
41
+ it 'must have a minmax' do
42
+ subject.minmax.must_equal [0, 0]
43
+ end
44
+
45
+ it 'must minmax with another Point' do
46
+ subject.minmax(Point[7,-1]).must_equal [Point[0,-1], Point[7,0]]
47
+ end
48
+
49
+ it 'must minmax with an Array' do
50
+ subject.minmax([7,-1]).must_equal [Point[0,-1], Point[7,0]]
51
+ end
52
+
53
+ it 'must maximum with multiple arguments' do
54
+ subject.minmax(7,-1).must_equal [Point[0,-1], Point[7,0]]
55
+ end
56
+ end
57
+
8
58
  describe "arithmetic" do
9
59
  let(:left) { Point[1,2] }
10
60
  let(:right) { Point[3,4] }
@@ -65,6 +65,10 @@ describe Geometry::Square do
65
65
  subject.closed?.must_equal true
66
66
  end
67
67
 
68
+ it 'must have edges' do
69
+ subject.edges.must_equal [Edge([2,3], [3,3]), Edge.new([3,3], [3,4]), Edge.new([3,4], [2,4]), Edge.new([2,4], [2,3])]
70
+ end
71
+
68
72
  it "must have an origin accessor" do
69
73
  subject.origin.must_equal Point[2,3]
70
74
  end
@@ -80,6 +84,10 @@ describe Geometry::Square do
80
84
  it "must have a min property that returns the lower left corner of the bounding rectangle" do
81
85
  subject.min.must_equal Point[2, 3]
82
86
  end
87
+
88
+ it 'must have points' do
89
+ subject.points.must_equal [Point[2,3], Point[3,3], Point[3,4], Point[2,4]]
90
+ end
83
91
  end
84
92
  end
85
93
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: geometry
3
3
  version: !ruby/object:Gem::Version
4
- version: '6.3'
4
+ version: '6.4'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandon Fosdick
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-17 00:00:00.000000000 Z
11
+ date: 2014-11-18 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Geometric primitives and algorithms for Ruby
14
14
  email:
@@ -27,6 +27,7 @@ files:
27
27
  - lib/geometry.rb
28
28
  - lib/geometry/annulus.rb
29
29
  - lib/geometry/arc.rb
30
+ - lib/geometry/bezier.rb
30
31
  - lib/geometry/circle.rb
31
32
  - lib/geometry/cluster_factory.rb
32
33
  - lib/geometry/edge.rb
@@ -53,6 +54,7 @@ files:
53
54
  - test/geometry.rb
54
55
  - test/geometry/annulus.rb
55
56
  - test/geometry/arc.rb
57
+ - test/geometry/bezier.rb
56
58
  - test/geometry/circle.rb
57
59
  - test/geometry/edge.rb
58
60
  - test/geometry/line.rb
@@ -86,7 +88,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
86
88
  requirements:
87
89
  - - '>='
88
90
  - !ruby/object:Gem::Version
89
- version: '0'
91
+ version: '2.0'
90
92
  required_rubygems_version: !ruby/object:Gem::Requirement
91
93
  requirements:
92
94
  - - '>='
@@ -102,6 +104,7 @@ test_files:
102
104
  - test/geometry.rb
103
105
  - test/geometry/annulus.rb
104
106
  - test/geometry/arc.rb
107
+ - test/geometry/bezier.rb
105
108
  - test/geometry/circle.rb
106
109
  - test/geometry/edge.rb
107
110
  - test/geometry/line.rb