geometry 5 → 6

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/Gemfile CHANGED
@@ -1,4 +1,7 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- # Specify your gem's dependencies in geometry.gemspec
4
3
  gemspec
4
+
5
+ group :test do
6
+ gem 'rake'
7
+ end
data/README.markdown CHANGED
@@ -1,6 +1,8 @@
1
1
  Geometry for Ruby
2
2
  =================
3
3
 
4
+ [![Build Status](https://travis-ci.org/bfoz/geometry.png)](https://travis-ci.org/bfoz/geometry)
5
+
4
6
  Classes and methods for the handling of all of the basic geometry that you
5
7
  learned in high school (and then forgot).
6
8
 
@@ -12,8 +14,7 @@ that don't work in higher dimensions and I'll do my best to fix them.
12
14
  License
13
15
  -------
14
16
 
15
- Copyright 2012 Brandon Fosdick <bfoz@bfoz.net> and released under the BSD
16
- license.
17
+ Copyright 2012-2013 Brandon Fosdick <bfoz@bfoz.net> and released under the BSD license.
17
18
 
18
19
  Primitives
19
20
  ----------
@@ -22,9 +23,9 @@ Primitives
22
23
  - Size
23
24
  - Line
24
25
  - Edge
25
- - Circle
26
+ - [Arc](http://en.wikipedia.org/wiki/Arc_(geometry)), Circle
26
27
  - Rectangle, Square
27
- - Path, [Polyline](http://en.wikipedia.org/wiki/Polyline), [Polygon](http://en.wikipedia.org/wiki/Polygon)
28
+ - Path, [Polyline](http://en.wikipedia.org/wiki/Polyline), [Polygon](http://en.wikipedia.org/wiki/Polygon), [RegularPolygon](http://en.wikipedia.org/wiki/Regular_polygon)
28
29
  - Transformation
29
30
  - [Triangle](http://en.wikipedia.org/wiki/Triangle)
30
31
  - [Obround](http://en.wiktionary.org/wiki/obround)
@@ -66,10 +67,25 @@ Examples
66
67
  Geometry::Line.vertical(x=0)
67
68
  ```
68
69
 
70
+ ### Rectangle
71
+ ```ruby
72
+ # A Rectangle made from two corner points
73
+ Geometry::Rectangle.new [1,2], [2,3]
74
+ Geometry::Rectangle.new from:[1,2], to:[2,3]
75
+
76
+ Geometry::Rectangle.new center:[1,2], size:[1,1] # Using a center point and a size
77
+ Geometry::Rectangle.new origin:[1,2], size:[1,1] # Using an origin point and a size
78
+
79
+ # A Rectangle with its origin at [0, 0] and a size of [10, 20]
80
+ Geometry::Rectangle.new size: [10, 20]
81
+ Geometry::Rectangle.new size: Size[10, 20]
82
+ Geometry::Rectangle.new width: 10, height: 20
83
+ ```
84
+
69
85
  ### Circle
70
86
  ```ruby
71
87
  # A circle at Point[1,2] with a radius of 3
72
- circle = Geometry::Circle.new [1,2], 3
88
+ circle = Geometry::Circle.new center:[1,2], radius:3
73
89
  ```
74
90
 
75
91
  ### Polygon
@@ -77,3 +93,8 @@ Examples
77
93
  # A polygon that looks a lot like a square
78
94
  polygon = Geometry::Polygon.new [0,0], [1,0], [1,1], [0,1]
79
95
  ```
96
+ ### Regular Polygon
97
+ ```ruby
98
+ # Everyone loves a good hexagon
99
+ hexagon = Geometry::RegularPolygon.new 6, :diameter => 3
100
+ ```
data/Rakefile CHANGED
@@ -1,8 +1,11 @@
1
1
  require "bundler/gem_tasks"
2
2
  require 'rake/testtask'
3
3
 
4
+ task :default => :test
5
+
4
6
  Rake::TestTask.new do |t|
5
7
  t.libs.push "lib"
8
+ # t.test_files = FileList['test/**/rectangle.rb']
6
9
  t.test_files = FileList['test/**/*.rb']
7
10
  t.verbose = true
8
11
  end
data/geometry.gemspec CHANGED
@@ -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 = '5'
6
+ s.version = '6'
7
7
  s.authors = ["Brandon Fosdick"]
8
8
  s.email = ["bfoz@bfoz.net"]
9
9
  s.homepage = "http://github.com/bfoz/geometry"
data/lib/geometry.rb CHANGED
@@ -1,12 +1,14 @@
1
1
  require_relative 'geometry/arc'
2
2
  require_relative 'geometry/circle'
3
3
  require_relative 'geometry/line'
4
+ require_relative 'geometry/obround'
4
5
  require_relative 'geometry/path'
5
6
  require_relative 'geometry/point'
6
7
  require_relative 'geometry/point_zero'
7
8
  require_relative 'geometry/polygon'
8
9
  require_relative 'geometry/polyline'
9
10
  require_relative 'geometry/rectangle'
11
+ require_relative 'geometry/regular_polygon'
10
12
  require_relative 'geometry/rotation'
11
13
  require_relative 'geometry/size'
12
14
  require_relative 'geometry/size_zero'
@@ -16,37 +18,4 @@ require_relative 'geometry/triangle'
16
18
  require_relative 'geometry/vector'
17
19
 
18
20
  module Geometry
19
- # @overload Line(array0, array1)
20
- # @param [Array] array0 First endpoint
21
- # @param [Array] array1 Second endpoint
22
- # @return [TwoPointLine]
23
- # @overload Line(point0, point1)
24
- # @param [Point] point0 First endpoint
25
- # @param [Point] point1 Second endpoint
26
- # @return [TwoPointLine]
27
- # @overload Line(vector0, vector1)
28
- # @param [Vector] vector0 First endpoint
29
- # @param [Vector] vector1 Second endpoint
30
- # @return [TwoPointLine]
31
- # @overload Line(y_intercept, slope)
32
- # @param [Numeric] y_intercept Y-intercept
33
- # @param [Numeric] slope Slope
34
- # @return [SlopeInterceptLine]
35
- # @overload Line(point, slope)
36
- # @param [Point] point Starting point
37
- # @param [Numeric] slope Slope
38
- # @return [PointSlopeLine]
39
- def self.line(*args)
40
- Line[*args]
41
- end
42
-
43
- # @overload Point(x,y,z,...)
44
- # @return [Point]
45
- # @overload Point(Point)
46
- # @return [Point]
47
- # @overload Point(Vector)
48
- # @return [Point]
49
- def self.point(*args)
50
- Point[*args]
51
- end
52
21
  end
data/lib/geometry/arc.rb CHANGED
@@ -6,11 +6,11 @@ require_relative 'point'
6
6
  module Geometry
7
7
 
8
8
  =begin rdoc
9
- Arcs are Circles that don't quite go all the way around
9
+ {http://en.wikipedia.org/wiki/Arc_(geometry) Arcs} are Circles that don't quite go all the way around
10
10
 
11
11
  == Usage
12
12
  An {Arc} with its center at [1,1] and a radius of 2 that starts at the X-axis and goes to the Y-axis (counter-clockwise)
13
- arc = Geometry::Arc.new [1,1], 2, 0, 90
13
+ arc = Geometry::Arc.new center:[1,1], radius:2, start:0, end:90
14
14
  =end
15
15
 
16
16
  class Arc
@@ -20,22 +20,26 @@ An {Arc} with its center at [1,1] and a radius of 2 that starts at the X-axis an
20
20
  attr_reader :radius
21
21
  attr_reader :start_angle, :end_angle
22
22
 
23
- # @overload new(center_point, start_point, end_point)
23
+ # @overload new(center, start, end)
24
24
  # Create a new {Arc} given center, start and end {Point}s
25
- # @param [Point] center_point The {Point} at the center
26
- # @param [Point] start_point The {Arc} starts at the start {Point}
27
- # @param [Point] end_point The {Point} where it all ends
28
- # @overload initialize(center, radius, start_angle, end_angle)
29
- # Create a new {Arc} given a center, a radius and start and end angles
30
- # @param [Point] center The {Point} at the center of it all
31
- # @param [Numeric] radius Radius
32
- # @param [Numeric] start_angle Starting angle
33
- # @param [Numeric] end_angle Ending angle
34
- def self.new(*args)
35
- if 4 == args.size
36
- original_new(*args)
37
- elsif 3 == args.size
38
- ThreePointArc.new(*args)
25
+ # @option options [Point] :center (PointZero) The {Point} at the center
26
+ # @option options [Point] :start The {Arc} starts at the start {Point}
27
+ # @option options [Point] :end The {Point} where it all ends
28
+ # @return [Arc]
29
+ # @overload new(center, radius, start, end)
30
+ # Create a new {Arc} given a center {Point}, a radius and start and end angles
31
+ # @option options [Point] :center (PointZero) The {Point} at the center of it all
32
+ # @option options [Numeric] :radius Radius
33
+ # @option options [Numeric] :start Starting angle
34
+ # @option options [Numeric] :end Ending angle
35
+ # @return [ThreePointArc]
36
+ def self.new(options={})
37
+ center = options.delete(:center) || PointZero.new
38
+
39
+ if options.has_key?(:radius)
40
+ original_new(center, options[:radius], options[:start], options[:end])
41
+ else
42
+ ThreePointArc.new(center, options[:start], options[:end])
39
43
  end
40
44
  end
41
45
 
@@ -8,9 +8,9 @@ Circles come in all shapes and sizes, but they're usually round.
8
8
 
9
9
  == Usage
10
10
  circle = Geometry::Circle.new [1,2], 3
11
- circle = Geometry::Circle.new [1,2], :radius => 3
12
- circle = Geometry::Circle.new [1,2], :diameter => 6
13
- circle = Geometry::Circle.new :center => [1,2], :diameter => 6
11
+ circle = Geometry::Circle.new center:[1,2], radius:3
12
+ circle = Geometry::Circle.new center:[1,2], diameter:6
13
+ circle = Geometry::Circle.new diameter:6
14
14
  =end
15
15
 
16
16
  class Circle
@@ -22,26 +22,24 @@ Circles come in all shapes and sizes, but they're usually round.
22
22
  # @return [Number] The {Circle}'s radius
23
23
  attr_reader :radius
24
24
 
25
- # @overload new(circle, radius)
25
+ # @overload new(center, radius)
26
26
  # Construct a {Circle} using a centerpoint and radius
27
27
  # @param [Point] center The center point of the {Circle}
28
28
  # @param [Number] radius The radius of the {Circle}
29
- # @overload new(options)
29
+ # @overload new(center, radius)
30
30
  # Construct a circle using named center and radius parameters
31
- # @option options [Point] :center
31
+ # @option options [Point] :center (PointZero)
32
32
  # @option options [Number] :radius
33
- # @overload new(options)
33
+ # @overload new(center, diameter)
34
34
  # Construct a circle using named center and diameter parameters
35
- # @option options [Point] :center
35
+ # @option options [Point] :center (PointZero)
36
36
  # @option options [Number] :diameter
37
37
  def self.new(*args, &block)
38
38
  options, args = args.partition {|a| a.is_a? Hash}
39
39
  options = options.reduce({}, :merge)
40
40
  center, radius = args[0..1]
41
41
 
42
- center = Point[center || options[:center]]
43
- raise ArgumentError, "Circle.new requires a center" unless center
44
-
42
+ center ||= (options[:center] || PointZero.new)
45
43
  radius ||= options[:radius]
46
44
 
47
45
  if radius
@@ -62,12 +60,37 @@ Circles come in all shapes and sizes, but they're usually round.
62
60
  @radius = radius
63
61
  end
64
62
 
63
+ def eql?(other)
64
+ (self.center == other.center) && (self.radius == other.radius)
65
+ end
66
+ alias :== :eql?
67
+
65
68
  # @!group Accessors
69
+ # @return [Rectangle] The smallest axis-aligned {Rectangle} that bounds the receiver
70
+ def bounds
71
+ return Rectangle.new(self.min, self.max)
72
+ end
73
+
66
74
  # @!attribute [r] diameter
67
75
  # @return [Numeric] The diameter of the {Circle}
68
76
  def diameter
69
77
  @radius*2
70
78
  end
79
+
80
+ # @return [Point] The upper right corner of the bounding {Rectangle}
81
+ def max
82
+ @center+radius
83
+ end
84
+
85
+ # @return [Point] The lower left corner of the bounding {Rectangle}
86
+ def min
87
+ @center-radius
88
+ end
89
+
90
+ # @return [Array<Point>] The lower left and upper right corners of the bounding {Rectangle}
91
+ def minmax
92
+ [self.min, self.max]
93
+ end
71
94
  # @!endgroup
72
95
  end
73
96
 
@@ -84,8 +107,13 @@ Circles come in all shapes and sizes, but they're usually round.
84
107
  @diameter = diameter
85
108
  end
86
109
 
110
+ def eql?(other)
111
+ (self.center == other.center) && (self.diameter == other.diameter)
112
+ end
113
+ alias :== :eql?
114
+
87
115
  # @!group Accessors
88
- # @return The {Circle}'s radius
116
+ # @return [Number] The {Circle}'s radius
89
117
  def radius
90
118
  @diameter/2
91
119
  end
data/lib/geometry/edge.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'mathn'
2
+
1
3
  require_relative 'point'
2
4
 
3
5
  module Geometry
@@ -24,6 +26,22 @@ An edge. It's a line segment between 2 points. Generally part of a {Polygon}.
24
26
  (@first == other.first) && (@last == other.last)
25
27
  end
26
28
 
29
+ # @param [Point] point A {Point} to spaceship with
30
+ # @return [Boolean] Returns 1 if the {Point} is strictly to the left of the receiver, -1 to the right, and 0 if the point is on the receiver
31
+ def <=>(point)
32
+ case point
33
+ when Point
34
+ k = (@last.x - @first.x) * (point.y - @first.y) - (point.x - @first.x) * (@last.y - @first.y)
35
+ if 0 == k
36
+ (((@first.x <=> point.x) + (@last.x <=> point.x)).abs <= 1) && (((@first.y <=> point.y) + (@last.y <=> point.y)).abs <= 1) ? 0 : nil
37
+ else
38
+ k <=> 0
39
+ end
40
+ else
41
+ raise ArgumentError, "Can't spaceship with #{point.class}"
42
+ end
43
+ end
44
+
27
45
  # Return a new {Edge} with swapped endpoints
28
46
  def reverse
29
47
  Edge.new(@last, @first)
@@ -77,8 +95,12 @@ An edge. It's a line segment between 2 points. Generally part of a {Polygon}.
77
95
  end
78
96
 
79
97
  # Find the intersection of two {Edge}s (http://bloggingmath.wordpress.com/2009/05/29/line-segment-intersection/)
98
+ # @param [Edge] other The other {Edge}
80
99
  # @return [Point] The intersection of the two {Edge}s, nil if they don't intersect, true if they're collinear and overlapping, and false if they're collinear and non-overlapping
81
100
  def intersection(other)
101
+ return self.first if (self.first == other.first) or (self.first == other.last)
102
+ return self.last if (self.last == other.first) or (self.last == other.last)
103
+
82
104
  p0, p1 = self.first, self.last
83
105
  p2, p3 = other.first, other.last
84
106
  v1, v2 = self.vector, other.vector
data/lib/geometry/line.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require_relative 'cluster_factory'
1
2
  require_relative 'point'
2
3
 
3
4
  module Geometry
@@ -28,6 +29,7 @@ Supports two-point, slope-intercept, and point-slope initializer forms
28
29
  =end
29
30
 
30
31
  class Line
32
+ include ClusterFactory
31
33
 
32
34
  # @overload [](Array, Array)
33
35
  # @return [TwoPointLine]
@@ -56,6 +58,25 @@ Supports two-point, slope-intercept, and point-slope initializer forms
56
58
  end
57
59
  end
58
60
 
61
+ # @overload new(from, to)
62
+ # @option options [Point] :from A starting {Point}
63
+ # @option options [Point] :to An end {Point}
64
+ # @return [TwoPointLine]
65
+ # @overload new(start, end)
66
+ # @option options [Point] :start A starting {Point}
67
+ # @option options [Point] :end An end {Point}
68
+ # @return [TwoPointLine]
69
+ def self.new(options={})
70
+ from = options[:from] || options[:start]
71
+ to = options[:end] || options[:to]
72
+
73
+ if from and to
74
+ TwoPointLine.new(from, to)
75
+ else
76
+ raise ArgumentError, "Start and end Points must be provided"
77
+ end
78
+ end
79
+
59
80
  def self.horizontal(y_intercept=0)
60
81
  SlopeInterceptLine.new(0, y_intercept)
61
82
  end
@@ -0,0 +1,238 @@
1
+ require_relative 'cluster_factory'
2
+ require_relative 'point'
3
+
4
+ module Geometry
5
+
6
+ =begin
7
+ The {Obround} class cluster represents a rectangle with semicircular end caps
8
+
9
+ {http://en.wiktionary.org/wiki/obround}
10
+ =end
11
+
12
+ class Obround
13
+ include ClusterFactory
14
+
15
+ # @overload new(width, height)
16
+ # Creates a {Obround} of the given width and height, centered on the origin
17
+ # @param [Number] height Height
18
+ # @param [Number] width Width
19
+ # @return [CenteredObround]
20
+ # @overload new(size)
21
+ # Creates a {Obround} of the given {Size} centered on the origin
22
+ # @param [Size] size Width and height
23
+ # @return [CenteredObround]
24
+ # @overload new(point0, point1)
25
+ # Creates a {Obround} using the given {Point}s
26
+ # @param [Point] point0 A corner
27
+ # @param [Point] point1 The other corner
28
+ # @overload new(origin, size)
29
+ # Creates a {Obround} from the given origin and size
30
+ # @param [Point] origin Lower-left corner
31
+ # @param [Size] size Width and height
32
+ # @return [SizedObround]
33
+ # @overload new(left, bottom, right, top)
34
+ # Creates a {Obround} from the locations of each side
35
+ # @param [Number] left X-coordinate of the left side
36
+ # @param [Number] bottom Y-coordinate of the bottom edge
37
+ # @param [Number] right X-coordinate of the right side
38
+ # @param [Number] top Y-coordinate of the top edge
39
+ # @return [Obround]
40
+ def self.new(*args)
41
+ case args.size
42
+ when 1
43
+ CenteredObround.new(args[0])
44
+ when 2
45
+ if args.all? {|a| a.is_a?(Numeric) }
46
+ CenteredObround.new(Size[*args])
47
+ elsif args.all? {|a| a.is_a?(Array) || a.is_a?(Point) }
48
+ original_new(*args)
49
+ elsif (args[0].is_a?(Point) or args[0].is_a?(Array))and args[1].is_a?(Size)
50
+ SizedObround.new(*args)
51
+ else
52
+ raise ArgumentError, "Invalid arguments #{args}"
53
+ end
54
+ when 4
55
+ raise ArgumentError unless args.all? {|a| a.is_a?(Numeric)}
56
+ left, bottom, right, top = *args
57
+ original_new(Point[left, bottom], Point[right, top])
58
+ end
59
+ end
60
+
61
+ # Create a {Obround} using the given {Point}s
62
+ # @param [Point0] point0 The bottom-left corner (closest to the origin)
63
+ # @param [Point1] point1 The top-right corner (farthest from the origin)
64
+ def initialize(point0, point1)
65
+ point0, point1 = Point[point0], Point[point1]
66
+ raise(ArgumentError, "Point sizes must match") unless point0.size == point1.size
67
+
68
+ # Reorder the points to get lower-left and upper-right
69
+ if (point0.x > point1.x) && (point0.y > point1.y)
70
+ point0, point1 = point1, point0
71
+ else
72
+ p0x, p1x = [point0.x, point1.x].minmax
73
+ p0y, p1y = [point0.y, point1.y].minmax
74
+ point0 = Point[p0x, p0y]
75
+ point1 = Point[p1x, p1y]
76
+ end
77
+ @points = [point0, point1]
78
+ end
79
+
80
+ def eql?(other)
81
+ self.points == other.points
82
+ end
83
+ alias :== :eql?
84
+
85
+ # @group Accessors
86
+
87
+ # @return [Point] The {Obround}'s center
88
+ def center
89
+ min, max = @points.minmax {|a,b| a.y <=> b.y}
90
+ Point[(max.x+min.x)/2, (max.y+min.y)/2]
91
+ end
92
+
93
+ # @return [Array<Point>] The {Obround}'s four points (counterclockwise)
94
+ def points
95
+ point0, point2 = *@points
96
+ point1 = Point[point2.x, point0.y]
97
+ point3 = Point[point0.x, point2.y]
98
+ [point0, point1, point2, point3]
99
+ end
100
+
101
+ def origin
102
+ minx = @points.min {|a,b| a.x <=> b.x}
103
+ miny = @points.min {|a,b| a.y <=> b.y}
104
+ Point[minx.x, miny.y]
105
+ end
106
+
107
+ def height
108
+ min, max = @points.minmax {|a,b| a.y <=> b.y}
109
+ max.y - min.y
110
+ end
111
+
112
+ def width
113
+ min, max = @points.minmax {|a,b| a.x <=> b.x}
114
+ max.x - min.x
115
+ end
116
+ # @endgroup
117
+ end
118
+
119
+ class CenteredObround < Obround
120
+ # @return [Point] The {Obround}'s center
121
+ attr_accessor :center
122
+ attr_reader :origin
123
+ # @return [Size] The {Size} of the {Obround}
124
+ attr_accessor :size
125
+
126
+ # @overload new(width, height)
127
+ # Creates a {Obround} of the given width and height, centered on the origin
128
+ # @param [Number] height Height
129
+ # @param [Number] width Width
130
+ # @return [CenteredObround]
131
+ # @overload new(size)
132
+ # Creates a {Obround} of the given {Size} centered on the origin
133
+ # @param [Size] size Width and height
134
+ # @return [CenteredObround]
135
+ # @overload new(center, size)
136
+ # Creates a {Obround} with the given center point and size
137
+ # @param [Point] center
138
+ # @param [Size] size
139
+ def initialize(*args)
140
+ if args[0].is_a?(Size)
141
+ @center = Point[0,0]
142
+ @size = args[0]
143
+ elsif args[0].is_a?(Geometry::Point) and args[1].is_a?(Geometry::Size)
144
+ @center, @size = args[0,1]
145
+ elsif (2 == args.size) and args.all? {|a| a.is_a?(Numeric)}
146
+ @center = Point[0,0]
147
+ @size = Geometry::Size[*args]
148
+ end
149
+ end
150
+
151
+ def eql?(other)
152
+ (self.center == other.center) && (self.size == other.size)
153
+ end
154
+ alias :== :eql?
155
+
156
+ # @group Accessors
157
+ # @return [Array<Point>] The {Obround}'s four points (clockwise)
158
+ def points
159
+ point0 = @center - @size/2.0
160
+ point2 = @center + @size/2.0
161
+ point1 = Point[point0.x,point2.y]
162
+ point3 = Point[point2.x, point0.y]
163
+ [point0, point1, point2, point3]
164
+ end
165
+
166
+ def height
167
+ @size.height
168
+ end
169
+
170
+ def width
171
+ @size.width
172
+ end
173
+ # @endgroup
174
+ end
175
+
176
+ class SizedObround < Obround
177
+ # @return [Point] The {Obround}'s center
178
+ attr_reader :center
179
+ # @return [Point] The {Obround}'s origin
180
+ attr_accessor :origin
181
+ # @return [Size] The {Size} of the {Obround}
182
+ attr_accessor :size
183
+
184
+ # @overload new(width, height)
185
+ # Creates an {Obround} of the given width and height with its origin at [0,0]
186
+ # @param [Number] height Height
187
+ # @param [Number] width Width
188
+ # @return SizedObround
189
+ # @overload new(size)
190
+ # Creates an {Obround} of the given {Size} with its origin at [0,0]
191
+ # @param [Size] size Width and height
192
+ # @return SizedObround
193
+ # @overload new(origin, size)
194
+ # Creates an {Obround} with the given origin point and size
195
+ # @param [Point] origin
196
+ # @param [Size] size
197
+ # @return SizedObround
198
+ def initialize(*args)
199
+ if args[0].is_a?(Size)
200
+ @origin = Point[0,0]
201
+ @size = args[0]
202
+ elsif (args[0].is_a?(Point) or args[0].is_a?(Array)) and args[1].is_a?(Geometry::Size)
203
+ @origin, @size = Point[args[0]], args[1]
204
+ elsif (2 == args.size) and args.all? {|a| a.is_a?(Numeric)}
205
+ @origin = Point[0,0]
206
+ @size = Geometry::Size[*args]
207
+ end
208
+ end
209
+
210
+ def eql?(other)
211
+ (self.origin == other.origin) && (self.size == other.size)
212
+ end
213
+ alias :== :eql?
214
+
215
+ # @group Accessors
216
+ def center
217
+ @origin + @size/2
218
+ end
219
+
220
+ # @return [Array<Point>] The {Obround}'s four points (clockwise)
221
+ def points
222
+ point0 = @origin
223
+ point2 = @origin + @size
224
+ point1 = Point[point0.x,point2.y]
225
+ point3 = Point[point2.x, point0.y]
226
+ [point0, point1, point2, point3]
227
+ end
228
+
229
+ def height
230
+ @size.height
231
+ end
232
+
233
+ def width
234
+ @size.width
235
+ end
236
+ # @endgroup
237
+ end
238
+ end