geometry 6.2 → 6.3
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 +4 -4
 - data/.travis.yml +4 -0
 - data/README.markdown +58 -44
 - data/geometry.gemspec +1 -1
 - data/lib/geometry.rb +1 -0
 - data/lib/geometry/annulus.rb +74 -0
 - data/lib/geometry/circle.rb +6 -0
 - data/lib/geometry/edge.rb +6 -3
 - data/lib/geometry/obround.rb +6 -0
 - data/lib/geometry/point.rb +40 -3
 - data/lib/geometry/point_iso.rb +133 -0
 - data/lib/geometry/point_one.rb +131 -0
 - data/lib/geometry/point_zero.rb +19 -1
 - data/lib/geometry/polygon.rb +6 -6
 - data/lib/geometry/polyline.rb +4 -0
 - data/lib/geometry/rectangle.rb +6 -0
 - data/lib/geometry/regular_polygon.rb +59 -52
 - data/lib/geometry/rotation.rb +1 -0
 - data/lib/geometry/size.rb +41 -11
 - data/lib/geometry/size_one.rb +85 -0
 - data/lib/geometry/size_zero.rb +8 -0
 - data/lib/geometry/square.rb +6 -0
 - data/lib/geometry/triangle.rb +21 -0
 - data/test/geometry/annulus.rb +69 -0
 - data/test/geometry/circle.rb +36 -0
 - data/test/geometry/obround.rb +5 -0
 - data/test/geometry/point.rb +40 -5
 - data/test/geometry/point_iso.rb +189 -0
 - data/test/geometry/point_one.rb +199 -0
 - data/test/geometry/point_zero.rb +23 -2
 - data/test/geometry/polyline.rb +4 -0
 - data/test/geometry/rectangle.rb +4 -0
 - data/test/geometry/regular_polygon.rb +57 -11
 - data/test/geometry/rotation.rb +6 -0
 - data/test/geometry/size.rb +31 -10
 - data/test/geometry/size_one.rb +155 -0
 - data/test/geometry/size_zero.rb +8 -0
 - data/test/geometry/square.rb +4 -0
 - data/test/geometry/triangle.rb +16 -0
 - metadata +15 -2
 
| 
         @@ -0,0 +1,131 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require_relative 'point'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Geometry
         
     | 
| 
      
 4 
     | 
    
         
            +
            =begin rdoc
         
     | 
| 
      
 5 
     | 
    
         
            +
            An object repesenting a {Point} that is one unit away from the origin, along each
         
     | 
| 
      
 6 
     | 
    
         
            +
            axis, in N-dimensional space
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            A {PointOne} object is a {Point} that will always compare equal to one and unequal to
         
     | 
| 
      
 9 
     | 
    
         
            +
            everything else, regardless of size. It's similar to the
         
     | 
| 
      
 10 
     | 
    
         
            +
            {http://en.wikipedia.org/wiki/Null_Object_pattern Null Object Pattern}, but for ones.
         
     | 
| 
      
 11 
     | 
    
         
            +
            =end
         
     | 
| 
      
 12 
     | 
    
         
            +
                class PointOne
         
     | 
| 
      
 13 
     | 
    
         
            +
            	def eql?(other)
         
     | 
| 
      
 14 
     | 
    
         
            +
            	    if other.respond_to? :all?
         
     | 
| 
      
 15 
     | 
    
         
            +
            		other.all? {|e| e.eql? 1}
         
     | 
| 
      
 16 
     | 
    
         
            +
            	    else
         
     | 
| 
      
 17 
     | 
    
         
            +
            		other == 1
         
     | 
| 
      
 18 
     | 
    
         
            +
            	    end
         
     | 
| 
      
 19 
     | 
    
         
            +
            	end
         
     | 
| 
      
 20 
     | 
    
         
            +
            	alias == eql?
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            	def coerce(other)
         
     | 
| 
      
 23 
     | 
    
         
            +
            	    if other.is_a? Numeric
         
     | 
| 
      
 24 
     | 
    
         
            +
            		[other, 1]
         
     | 
| 
      
 25 
     | 
    
         
            +
            	    elsif other.is_a? Array
         
     | 
| 
      
 26 
     | 
    
         
            +
            		[other, Array.new(other.size, 1)]
         
     | 
| 
      
 27 
     | 
    
         
            +
            	    elsif other.is_a? Vector
         
     | 
| 
      
 28 
     | 
    
         
            +
            		[other, Vector[*Array.new(other.size, 1)]]
         
     | 
| 
      
 29 
     | 
    
         
            +
            	    else
         
     | 
| 
      
 30 
     | 
    
         
            +
            		[Point[other], Point[Array.new(other.size, 1)]]
         
     | 
| 
      
 31 
     | 
    
         
            +
            	    end
         
     | 
| 
      
 32 
     | 
    
         
            +
            	end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            	def is_a?(klass)
         
     | 
| 
      
 35 
     | 
    
         
            +
            	    (klass == Point) || super
         
     | 
| 
      
 36 
     | 
    
         
            +
            	end
         
     | 
| 
      
 37 
     | 
    
         
            +
            	alias :kind_of? :is_a?
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            	# This is a hack to get Array#== to work properly. It works on ruby 2.0 and 1.9.3.
         
     | 
| 
      
 40 
     | 
    
         
            +
            	def to_ary
         
     | 
| 
      
 41 
     | 
    
         
            +
            	    []
         
     | 
| 
      
 42 
     | 
    
         
            +
            	end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            # @group Accessors
         
     | 
| 
      
 45 
     | 
    
         
            +
            	# @param [Integer]  i	Index into the {Point}'s elements
         
     | 
| 
      
 46 
     | 
    
         
            +
            	# @return [Numeric] Element i (starting at 0)
         
     | 
| 
      
 47 
     | 
    
         
            +
            	def [](i)
         
     | 
| 
      
 48 
     | 
    
         
            +
            	    1
         
     | 
| 
      
 49 
     | 
    
         
            +
            	end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
            	# @attribute [r] x
         
     | 
| 
      
 52 
     | 
    
         
            +
            	#   @return [Numeric] X-component
         
     | 
| 
      
 53 
     | 
    
         
            +
            	def x
         
     | 
| 
      
 54 
     | 
    
         
            +
            	    1
         
     | 
| 
      
 55 
     | 
    
         
            +
            	end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
            	# @attribute [r] y
         
     | 
| 
      
 58 
     | 
    
         
            +
            	#   @return [Numeric] Y-component
         
     | 
| 
      
 59 
     | 
    
         
            +
            	def y
         
     | 
| 
      
 60 
     | 
    
         
            +
            	    1
         
     | 
| 
      
 61 
     | 
    
         
            +
            	end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
            	# @attribute [r] z
         
     | 
| 
      
 64 
     | 
    
         
            +
            	#   @return [Numeric] Z-component
         
     | 
| 
      
 65 
     | 
    
         
            +
            	def z
         
     | 
| 
      
 66 
     | 
    
         
            +
            	    1
         
     | 
| 
      
 67 
     | 
    
         
            +
            	end
         
     | 
| 
      
 68 
     | 
    
         
            +
            # @endgroup
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
            # @group Arithmetic
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
            # @group Unary operators
         
     | 
| 
      
 73 
     | 
    
         
            +
            	def +@
         
     | 
| 
      
 74 
     | 
    
         
            +
            	    self
         
     | 
| 
      
 75 
     | 
    
         
            +
            	end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
            	def -@
         
     | 
| 
      
 78 
     | 
    
         
            +
            	    -1
         
     | 
| 
      
 79 
     | 
    
         
            +
            	end
         
     | 
| 
      
 80 
     | 
    
         
            +
            # @endgroup
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
            	def +(other)
         
     | 
| 
      
 83 
     | 
    
         
            +
            	    case other
         
     | 
| 
      
 84 
     | 
    
         
            +
            		when Numeric
         
     | 
| 
      
 85 
     | 
    
         
            +
            		    Point.iso(other + 1)
         
     | 
| 
      
 86 
     | 
    
         
            +
            		when Size
         
     | 
| 
      
 87 
     | 
    
         
            +
            		    Point[other.map {|a| a + 1 }]
         
     | 
| 
      
 88 
     | 
    
         
            +
            		else
         
     | 
| 
      
 89 
     | 
    
         
            +
            		    if other.respond_to?(:map)
         
     | 
| 
      
 90 
     | 
    
         
            +
            			other.map {|a| a + 1 }
         
     | 
| 
      
 91 
     | 
    
         
            +
            		    else
         
     | 
| 
      
 92 
     | 
    
         
            +
            			Point[other + 1]
         
     | 
| 
      
 93 
     | 
    
         
            +
            		    end
         
     | 
| 
      
 94 
     | 
    
         
            +
            	    end
         
     | 
| 
      
 95 
     | 
    
         
            +
            	end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
            	def -(other)
         
     | 
| 
      
 98 
     | 
    
         
            +
            	    if other.is_a? Size
         
     | 
| 
      
 99 
     | 
    
         
            +
            		Point[other.map {|a| 1 - a }]
         
     | 
| 
      
 100 
     | 
    
         
            +
            	    elsif other.respond_to? :map
         
     | 
| 
      
 101 
     | 
    
         
            +
            		other.map {|a| 1 - a }
         
     | 
| 
      
 102 
     | 
    
         
            +
            	    elsif other == 1
         
     | 
| 
      
 103 
     | 
    
         
            +
            		Point.zero
         
     | 
| 
      
 104 
     | 
    
         
            +
            	    else
         
     | 
| 
      
 105 
     | 
    
         
            +
            		Point.iso(1 - other)
         
     | 
| 
      
 106 
     | 
    
         
            +
            	    end
         
     | 
| 
      
 107 
     | 
    
         
            +
            	end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
            	def *(other)
         
     | 
| 
      
 110 
     | 
    
         
            +
            	    raise OperationNotDefined unless other.is_a? Numeric
         
     | 
| 
      
 111 
     | 
    
         
            +
            	    other
         
     | 
| 
      
 112 
     | 
    
         
            +
            	end
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
            	def /(other)
         
     | 
| 
      
 115 
     | 
    
         
            +
            	    raise OperationNotDefined unless other.is_a? Numeric
         
     | 
| 
      
 116 
     | 
    
         
            +
            	    raise ZeroDivisionError if 0 == other
         
     | 
| 
      
 117 
     | 
    
         
            +
            	    1 / other
         
     | 
| 
      
 118 
     | 
    
         
            +
            	end
         
     | 
| 
      
 119 
     | 
    
         
            +
            # @endgroup
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
            	# @group Enumerable
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
            	# Return the first, or first n, elements (always 0)
         
     | 
| 
      
 124 
     | 
    
         
            +
            	# @param n [Number]	the number of elements to return
         
     | 
| 
      
 125 
     | 
    
         
            +
            	def first(n=nil)
         
     | 
| 
      
 126 
     | 
    
         
            +
            	    Array.new(n, 1) rescue 1
         
     | 
| 
      
 127 
     | 
    
         
            +
            	end
         
     | 
| 
      
 128 
     | 
    
         
            +
            	# @endgroup
         
     | 
| 
      
 129 
     | 
    
         
            +
                end
         
     | 
| 
      
 130 
     | 
    
         
            +
            end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
    
        data/lib/geometry/point_zero.rb
    CHANGED
    
    | 
         @@ -1,4 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require_relative 'point'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require_relative 'point_iso'
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
4 
     | 
    
         
             
            module Geometry
         
     | 
| 
       4 
5 
     | 
    
         
             
            =begin rdoc
         
     | 
| 
         @@ -30,6 +31,11 @@ everything else, regardless of size. You can think of it as an application of th 
     | 
|
| 
       30 
31 
     | 
    
         
             
            	    end
         
     | 
| 
       31 
32 
     | 
    
         
             
            	end
         
     | 
| 
       32 
33 
     | 
    
         | 
| 
      
 34 
     | 
    
         
            +
            	def is_a?(klass)
         
     | 
| 
      
 35 
     | 
    
         
            +
            	    (klass == Point) || super
         
     | 
| 
      
 36 
     | 
    
         
            +
            	end
         
     | 
| 
      
 37 
     | 
    
         
            +
            	alias :kind_of? :is_a?
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
       33 
39 
     | 
    
         
             
            	# This is a hack to get Array#== to work properly. It works on ruby 2.0 and 1.9.3.
         
     | 
| 
       34 
40 
     | 
    
         
             
            	def to_ary
         
     | 
| 
       35 
41 
     | 
    
         
             
            	    []
         
     | 
| 
         @@ -75,7 +81,9 @@ everything else, regardless of size. You can think of it as an application of th 
     | 
|
| 
       75 
81 
     | 
    
         | 
| 
       76 
82 
     | 
    
         
             
            	def +(other)
         
     | 
| 
       77 
83 
     | 
    
         
             
            	    case other
         
     | 
| 
       78 
     | 
    
         
            -
            		when Array 
     | 
| 
      
 84 
     | 
    
         
            +
            		when Array then other
         
     | 
| 
      
 85 
     | 
    
         
            +
            		when Numeric
         
     | 
| 
      
 86 
     | 
    
         
            +
            		    Point.iso(other)
         
     | 
| 
       79 
87 
     | 
    
         
             
            		else
         
     | 
| 
       80 
88 
     | 
    
         
             
            		    Point[other]
         
     | 
| 
       81 
89 
     | 
    
         
             
            	    end
         
     | 
| 
         @@ -84,6 +92,8 @@ everything else, regardless of size. You can think of it as an application of th 
     | 
|
| 
       84 
92 
     | 
    
         
             
            	def -(other)
         
     | 
| 
       85 
93 
     | 
    
         
             
            	    if other.is_a? Size
         
     | 
| 
       86 
94 
     | 
    
         
             
            		-Point[other]
         
     | 
| 
      
 95 
     | 
    
         
            +
            	    elsif other.is_a? Numeric
         
     | 
| 
      
 96 
     | 
    
         
            +
            		Point.iso(-other)
         
     | 
| 
       87 
97 
     | 
    
         
             
            	    elsif other.respond_to? :-@
         
     | 
| 
       88 
98 
     | 
    
         
             
            		-other
         
     | 
| 
       89 
99 
     | 
    
         
             
            	    elsif other.respond_to? :map
         
     | 
| 
         @@ -102,6 +112,14 @@ everything else, regardless of size. You can think of it as an application of th 
     | 
|
| 
       102 
112 
     | 
    
         
             
            	end
         
     | 
| 
       103 
113 
     | 
    
         
             
            # @endgroup
         
     | 
| 
       104 
114 
     | 
    
         | 
| 
      
 115 
     | 
    
         
            +
            	# @group Enumerable
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
            	# Return the first, or first n, elements (always 0)
         
     | 
| 
      
 118 
     | 
    
         
            +
            	# @param n [Number]	the number of elements to return
         
     | 
| 
      
 119 
     | 
    
         
            +
            	def first(n=nil)
         
     | 
| 
      
 120 
     | 
    
         
            +
            	    Array.new(n, 0) rescue 0
         
     | 
| 
      
 121 
     | 
    
         
            +
            	end
         
     | 
| 
      
 122 
     | 
    
         
            +
            	# @endgroup
         
     | 
| 
       105 
123 
     | 
    
         
             
                end
         
     | 
| 
       106 
124 
     | 
    
         
             
            end
         
     | 
| 
       107 
125 
     | 
    
         | 
    
        data/lib/geometry/polygon.rb
    CHANGED
    
    | 
         @@ -18,11 +18,11 @@ but there's currently nothing that enforces simplicity. 
     | 
|
| 
       18 
18 
     | 
    
         
             
                class Polygon < Polyline
         
     | 
| 
       19 
19 
     | 
    
         | 
| 
       20 
20 
     | 
    
         
             
            	# Construct a new Polygon from Points and/or Edges
         
     | 
| 
       21 
     | 
    
         
            -
            	#  The constructor will try to convert all of its arguments into Points and
         
     | 
| 
       22 
     | 
    
         
            -
            	#   Edges. Then successive Points will be collpased into Edges. Successive
         
     | 
| 
       23 
     | 
    
         
            -
            	#   Edges that share a common vertex will be added to the new Polygon. If
         
     | 
| 
       24 
     | 
    
         
            -
            	#   there's a gap between Edges it will be automatically filled with a new
         
     | 
| 
       25 
     | 
    
         
            -
            	#   Edge. The resulting Polygon will then be closed if it isn't already.
         
     | 
| 
      
 21 
     | 
    
         
            +
            	#  The constructor will try to convert all of its arguments into {Points} and
         
     | 
| 
      
 22 
     | 
    
         
            +
            	#   {Edges}. Then successive {Points} will be collpased into {Edges}. Successive
         
     | 
| 
      
 23 
     | 
    
         
            +
            	#   {Edges} that share a common vertex will be added to the new {Polygon}. If
         
     | 
| 
      
 24 
     | 
    
         
            +
            	#   there's a gap between {Edges} it will be automatically filled with a new
         
     | 
| 
      
 25 
     | 
    
         
            +
            	#   {Edge}. The resulting Polygon will then be closed, if it isn't already.
         
     | 
| 
       26 
26 
     | 
    
         
             
            	# @overload initialize(Edge, Edge, ...)
         
     | 
| 
       27 
27 
     | 
    
         
             
            	#   @return [Polygon]
         
     | 
| 
       28 
28 
     | 
    
         
             
            	# @overload initialize(Point, Point, ...)
         
     | 
| 
         @@ -116,7 +116,7 @@ but there's currently nothing that enforces simplicity. 
     | 
|
| 
       116 
116 
     | 
    
         
             
            			if (a.first == b.first) and (a.last == b.last)	    # Equal edges
         
     | 
| 
       117 
117 
     | 
    
         
             
            			elsif (a.first == b.last) and (a.last == b.first)   # Ignore equal but opposite edges
         
     | 
| 
       118 
118 
     | 
    
         
             
            			else
         
     | 
| 
       119 
     | 
    
         
            -
            			    if a. 
     | 
| 
      
 119 
     | 
    
         
            +
            			    if a.direction == b.direction # Same direction?
         
     | 
| 
       120 
120 
     | 
    
         
             
            				offsetA += 1 if ringA.insert_boundary(indexA + 1 + offsetA, b.first)
         
     | 
| 
       121 
121 
     | 
    
         
             
            				offsetB += 1 if ringB.insert_boundary(indexB + 1 + offsetB, a.last)
         
     | 
| 
       122 
122 
     | 
    
         
             
            			    else    # Opposite direction
         
     | 
    
        data/lib/geometry/polyline.rb
    CHANGED
    
    | 
         @@ -15,6 +15,10 @@ also like a {Path} in that it isn't necessarily closed. 
     | 
|
| 
       15 
15 
     | 
    
         
             
                class Polyline
         
     | 
| 
       16 
16 
     | 
    
         
             
            	attr_reader :edges, :vertices
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
      
 18 
     | 
    
         
            +
            	# @!attribute points
         
     | 
| 
      
 19 
     | 
    
         
            +
            	#   @return [Array<Point>]  all of the vertices of the {Polyline} (alias of #vertices)
         
     | 
| 
      
 20 
     | 
    
         
            +
            	alias :points :vertices
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
       18 
22 
     | 
    
         
             
            	# Construct a new Polyline from Points and/or Edges
         
     | 
| 
       19 
23 
     | 
    
         
             
            	# @note The constructor will try to convert all of its arguments into {Point}s and
         
     | 
| 
       20 
24 
     | 
    
         
             
            	#   {Edge}s. Then successive {Point}s will be collpased into {Edge}s. Successive
         
     | 
    
        data/lib/geometry/rectangle.rb
    CHANGED
    
    | 
         @@ -123,6 +123,12 @@ The {Rectangle} class cluster represents your typical arrangement of 4 corners a 
     | 
|
| 
       123 
123 
     | 
    
         
             
            	    Point[(max.x+min.x)/2, (max.y+min.y)/2]
         
     | 
| 
       124 
124 
     | 
    
         
             
            	end
         
     | 
| 
       125 
125 
     | 
    
         | 
| 
      
 126 
     | 
    
         
            +
            	# @!attribute closed?
         
     | 
| 
      
 127 
     | 
    
         
            +
            	#   @return [Bool]  always true
         
     | 
| 
      
 128 
     | 
    
         
            +
            	def closed?
         
     | 
| 
      
 129 
     | 
    
         
            +
            	    true
         
     | 
| 
      
 130 
     | 
    
         
            +
            	end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
       126 
132 
     | 
    
         
             
            	# @return [Array<Edge>]   The {Rectangle}'s four edges (counterclockwise)
         
     | 
| 
       127 
133 
     | 
    
         
             
            	def edges
         
     | 
| 
       128 
134 
     | 
    
         
             
            	    point0, point2 = *@points
         
     | 
| 
         @@ -1,4 +1,3 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require_relative 'cluster_factory'
         
     | 
| 
       2 
1 
     | 
    
         
             
            require_relative 'polygon'
         
     | 
| 
       3 
2 
     | 
    
         | 
| 
       4 
3 
     | 
    
         
             
            module Geometry
         
     | 
| 
         @@ -10,53 +9,49 @@ A {RegularPolygon} is a lot like a {Polygon}, but more regular. 
     | 
|
| 
       10 
9 
     | 
    
         
             
            == Usage
         
     | 
| 
       11 
10 
     | 
    
         
             
                polygon = Geometry::RegularPolygon.new sides:4, center:[1,2], radius:3
         
     | 
| 
       12 
11 
     | 
    
         
             
                polygon = Geometry::RegularPolygon.new sides:6, center:[1,2], diameter:6
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                polygon = Geometry::RegularPolygon.new sides:4, center:[1,2], inradius:3
         
     | 
| 
      
 14 
     | 
    
         
            +
                polygon = Geometry::RegularPolygon.new sides:6, center:[1,2], indiameter:6
         
     | 
| 
       13 
15 
     | 
    
         
             
            =end
         
     | 
| 
       14 
16 
     | 
    
         | 
| 
       15 
17 
     | 
    
         
             
                class RegularPolygon < Polygon
         
     | 
| 
       16 
     | 
    
         
            -
            	include ClusterFactory
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
18 
     | 
    
         
             
            	# @return [Point]   The {RegularPolygon}'s center point
         
     | 
| 
       19 
19 
     | 
    
         
             
            	attr_reader :center
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
       21 
21 
     | 
    
         
             
            	# @return [Number]  The {RegularPolygon}'s number of sides
         
     | 
| 
       22 
22 
     | 
    
         
             
            	attr_reader :edge_count
         
     | 
| 
       23 
23 
     | 
    
         | 
| 
       24 
     | 
    
         
            -
            	# @return [Number]  The {RegularPolygon}'s radius
         
     | 
| 
       25 
     | 
    
         
            -
            	attr_reader :radius
         
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
24 
     | 
    
         
             
            	# @overload new(sides, center, radius)
         
     | 
| 
       28 
25 
     | 
    
         
             
            	#   Construct a {RegularPolygon} using a center point and radius
         
     | 
| 
       29 
26 
     | 
    
         
             
            	#   @option options [Number]	:sides	The number of edges
         
     | 
| 
       30 
27 
     | 
    
         
             
            	#   @option options [Point]	:center	(PointZero) The center point of the {RegularPolygon}
         
     | 
| 
       31 
     | 
    
         
            -
            	#   @option options [Number]	:radius The  
     | 
| 
      
 28 
     | 
    
         
            +
            	#   @option options [Number]	:radius The circumradius of the {RegularPolygon}
         
     | 
| 
      
 29 
     | 
    
         
            +
            	# @overload new(sides, center, inradius)
         
     | 
| 
      
 30 
     | 
    
         
            +
            	#   Construct a {RegularPolygon} using a center point and radius
         
     | 
| 
      
 31 
     | 
    
         
            +
            	#   @option options [Number]	:sides	The number of edges
         
     | 
| 
      
 32 
     | 
    
         
            +
            	#   @option options [Point]	:center	(PointZero) The center point of the {RegularPolygon}
         
     | 
| 
      
 33 
     | 
    
         
            +
            	#   @option options [Number]	:inradius   The inradius of the {RegularPolygon}
         
     | 
| 
       32 
34 
     | 
    
         
             
            	# @overload new(sides, center, diameter)
         
     | 
| 
       33 
35 
     | 
    
         
             
            	#   Construct a {RegularPolygon} using a center point and diameter
         
     | 
| 
       34 
36 
     | 
    
         
             
            	#   @option options [Number]	:sides  The number of edges
         
     | 
| 
       35 
37 
     | 
    
         
             
            	#   @option options [Point]	:center	(PointZero) The center point of the {RegularPolygon}
         
     | 
| 
       36 
     | 
    
         
            -
            	#   @option options [Number]	:diameter   The  
     | 
| 
       37 
     | 
    
         
            -
            	 
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
            	    if options.has_key?(:radius)
         
     | 
| 
       44 
     | 
    
         
            -
            		self.allocate.tap {|polygon| polygon.send :initialize, options[:sides], center, options[:radius], &block }
         
     | 
| 
       45 
     | 
    
         
            -
            	    elsif options.has_key?(:diameter)
         
     | 
| 
       46 
     | 
    
         
            -
            		DiameterRegularPolygon.new options[:sides], center, options[:diameter], &block
         
     | 
| 
       47 
     | 
    
         
            -
            	    else
         
     | 
| 
       48 
     | 
    
         
            -
            		raise ArgumentError, "RegularPolygon.new requires a radius or a diameter"
         
     | 
| 
       49 
     | 
    
         
            -
            	    end
         
     | 
| 
       50 
     | 
    
         
            -
            	end
         
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
            	# Construct a new {RegularPolygon} from a centerpoint and radius
         
     | 
| 
       53 
     | 
    
         
            -
            	# @param    [Number]	edge_count  The number of edges
         
     | 
| 
       54 
     | 
    
         
            -
            	# @param    [Point]	center  The center point of the {Circle}
         
     | 
| 
       55 
     | 
    
         
            -
            	# @param    [Number]	radius  The radius of the {Circle}
         
     | 
| 
      
 38 
     | 
    
         
            +
            	#   @option options [Number]	:diameter   The circumdiameter of the {RegularPolygon}
         
     | 
| 
      
 39 
     | 
    
         
            +
            	# @overload new(sides, center, indiameter)
         
     | 
| 
      
 40 
     | 
    
         
            +
            	#   Construct a {RegularPolygon} using a center point and diameter
         
     | 
| 
      
 41 
     | 
    
         
            +
            	#   @option options [Number]	:sides  The number of edges
         
     | 
| 
      
 42 
     | 
    
         
            +
            	#   @option options [Point]	:center	(PointZero) The center point of the {RegularPolygon}
         
     | 
| 
      
 43 
     | 
    
         
            +
            	#   @option options [Number]	:indiameter   The circumdiameter of the {RegularPolygon}
         
     | 
| 
       56 
44 
     | 
    
         
             
            	# @return   [RegularPolygon]	A new {RegularPolygon} object
         
     | 
| 
       57 
     | 
    
         
            -
            	def initialize(edge_count, center, radius)
         
     | 
| 
       58 
     | 
    
         
            -
            	    @ 
     | 
| 
       59 
     | 
    
         
            -
            	     
     | 
| 
      
 45 
     | 
    
         
            +
            	def initialize(edge_count:nil, sides:nil, center:nil, radius:nil, diameter:nil, indiameter:nil, inradius:nil)
         
     | 
| 
      
 46 
     | 
    
         
            +
            	    @edge_count = edge_count || sides
         
     | 
| 
      
 47 
     | 
    
         
            +
            	    raise ArgumentError, "RegularPolygon requires an edge count" unless @edge_count
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            	    raise ArgumentError, "RegularPolygon.new requires a radius or a diameter" unless diameter || indiameter || inradius || radius
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
            	    @center = center ? Point[center] : Point.zero
         
     | 
| 
      
 52 
     | 
    
         
            +
            	    @diameter = diameter
         
     | 
| 
      
 53 
     | 
    
         
            +
            	    @indiameter = indiameter
         
     | 
| 
      
 54 
     | 
    
         
            +
            	    @inradius = inradius
         
     | 
| 
       60 
55 
     | 
    
         
             
            	    @radius = radius
         
     | 
| 
       61 
56 
     | 
    
         
             
            	end
         
     | 
| 
       62 
57 
     | 
    
         | 
| 
         @@ -65,6 +60,12 @@ A {RegularPolygon} is a lot like a {Polygon}, but more regular. 
     | 
|
| 
       65 
60 
     | 
    
         
             
            	end
         
     | 
| 
       66 
61 
     | 
    
         
             
            	alias :== :eql?
         
     | 
| 
       67 
62 
     | 
    
         | 
| 
      
 63 
     | 
    
         
            +
            	# Check to see if the {Polygon} is closed (always true)
         
     | 
| 
      
 64 
     | 
    
         
            +
            	# @return [True] Always true because a {Polygon} is always closed
         
     | 
| 
      
 65 
     | 
    
         
            +
            	def closed?
         
     | 
| 
      
 66 
     | 
    
         
            +
            	    true
         
     | 
| 
      
 67 
     | 
    
         
            +
            	end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
       68 
69 
     | 
    
         
             
            # @!group Accessors
         
     | 
| 
       69 
70 
     | 
    
         
             
            	# @return [Rectangle]	The smallest axis-aligned {Rectangle} that bounds the receiver
         
     | 
| 
       70 
71 
     | 
    
         
             
            	def bounds
         
     | 
| 
         @@ -74,8 +75,9 @@ A {RegularPolygon} is a lot like a {Polygon}, but more regular. 
     | 
|
| 
       74 
75 
     | 
    
         
             
            	# @!attribute [r] diameter
         
     | 
| 
       75 
76 
     | 
    
         
             
            	#   @return [Numeric] The diameter of the {RegularPolygon}
         
     | 
| 
       76 
77 
     | 
    
         
             
            	def diameter
         
     | 
| 
       77 
     | 
    
         
            -
            	    @radius 
     | 
| 
      
 78 
     | 
    
         
            +
            	    @diameter || (@radius && 2*@radius) || (@indiameter && @indiameter/cosine_half_angle)
         
     | 
| 
       78 
79 
     | 
    
         
             
            	end
         
     | 
| 
      
 80 
     | 
    
         
            +
            	alias :circumdiameter :diameter
         
     | 
| 
       79 
81 
     | 
    
         | 
| 
       80 
82 
     | 
    
         
             
            	# !@attribute [r] edges
         
     | 
| 
       81 
83 
     | 
    
         
             
            	def edges
         
     | 
| 
         @@ -88,6 +90,7 @@ A {RegularPolygon} is a lot like a {Polygon}, but more regular. 
     | 
|
| 
       88 
90 
     | 
    
         
             
            	def vertices
         
     | 
| 
       89 
91 
     | 
    
         
             
            	    (0...2*Math::PI).step(2*Math::PI/edge_count).map {|angle| center + Point[Math::cos(angle), Math::sin(angle)]*radius }
         
     | 
| 
       90 
92 
     | 
    
         
             
            	end
         
     | 
| 
      
 93 
     | 
    
         
            +
            	alias :points :vertices
         
     | 
| 
       91 
94 
     | 
    
         | 
| 
       92 
95 
     | 
    
         
             
            	# @return [Point]   The upper right corner of the bounding {Rectangle}
         
     | 
| 
       93 
96 
     | 
    
         
             
            	def max
         
     | 
| 
         @@ -103,34 +106,38 @@ A {RegularPolygon} is a lot like a {Polygon}, but more regular. 
     | 
|
| 
       103 
106 
     | 
    
         
             
            	def minmax
         
     | 
| 
       104 
107 
     | 
    
         
             
            	    [self.min, self.max]
         
     | 
| 
       105 
108 
     | 
    
         
             
            	end
         
     | 
| 
       106 
     | 
    
         
            -
            # @!endgroup
         
     | 
| 
       107 
     | 
    
         
            -
                end
         
     | 
| 
       108 
     | 
    
         
            -
             
     | 
| 
       109 
     | 
    
         
            -
                class DiameterRegularPolygon < RegularPolygon
         
     | 
| 
       110 
     | 
    
         
            -
            	# @return [Number]  The {RegularPolygon}'s diameter
         
     | 
| 
       111 
     | 
    
         
            -
            	attr_reader :diameter
         
     | 
| 
       112 
109 
     | 
    
         | 
| 
       113 
     | 
    
         
            -
            	#  
     | 
| 
       114 
     | 
    
         
            -
            	#  
     | 
| 
       115 
     | 
    
         
            -
            	 
     | 
| 
       116 
     | 
    
         
            -
             
     | 
| 
       117 
     | 
    
         
            -
            	# @return   [RegularPolygon]	A new {RegularPolygon} object
         
     | 
| 
       118 
     | 
    
         
            -
            	def initialize(edge_count, center, diameter)
         
     | 
| 
       119 
     | 
    
         
            -
            	    @center = center ? Point[center] : nil
         
     | 
| 
       120 
     | 
    
         
            -
            	    @edge_count = edge_count
         
     | 
| 
       121 
     | 
    
         
            -
            	    @diameter = diameter
         
     | 
| 
      
 110 
     | 
    
         
            +
            	# @!attribute indiameter
         
     | 
| 
      
 111 
     | 
    
         
            +
            	#   @return [Number]  the indiameter
         
     | 
| 
      
 112 
     | 
    
         
            +
            	def indiameter
         
     | 
| 
      
 113 
     | 
    
         
            +
            	    @indiameter || (@inradius && 2*@inradius) || (@diameter && (@diameter * cosine_half_angle)) || (@radius && (2 * @radius * cosine_half_angle))
         
     | 
| 
       122 
114 
     | 
    
         
             
            	end
         
     | 
| 
       123 
115 
     | 
    
         | 
| 
       124 
     | 
    
         
            -
            	 
     | 
| 
       125 
     | 
    
         
            -
             
     | 
| 
      
 116 
     | 
    
         
            +
            	# @!attribute inradius
         
     | 
| 
      
 117 
     | 
    
         
            +
            	#   @return [Number]  The inradius
         
     | 
| 
      
 118 
     | 
    
         
            +
            	def inradius
         
     | 
| 
      
 119 
     | 
    
         
            +
            	    @inradius || (@indiameter && @indiameter/2) || (@radius && (@radius * cosine_half_angle))
         
     | 
| 
       126 
120 
     | 
    
         
             
            	end
         
     | 
| 
       127 
     | 
    
         
            -
            	alias  
     | 
| 
      
 121 
     | 
    
         
            +
            	alias :apothem :inradius
         
     | 
| 
       128 
122 
     | 
    
         | 
| 
       129 
     | 
    
         
            -
            # @! 
     | 
| 
       130 
     | 
    
         
            -
            	# @return [Number] 
     | 
| 
      
 123 
     | 
    
         
            +
            	# @!attribute [r] radius
         
     | 
| 
      
 124 
     | 
    
         
            +
            	# @return [Number]  The {RegularPolygon}'s radius
         
     | 
| 
       131 
125 
     | 
    
         
             
            	def radius
         
     | 
| 
       132 
     | 
    
         
            -
            	    @diameter/2
         
     | 
| 
      
 126 
     | 
    
         
            +
            	    @radius || (@diameter && @diameter/2) || (@inradius && (@inradius / cosine_half_angle)) || (@indiameter && @indiameter/cosine_half_angle/2)
         
     | 
| 
      
 127 
     | 
    
         
            +
            	end
         
     | 
| 
      
 128 
     | 
    
         
            +
            	alias :circumradius :radius
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
            	# @!attribute [r] side_length
         
     | 
| 
      
 131 
     | 
    
         
            +
            	#   @return [Number]  The length of each side
         
     | 
| 
      
 132 
     | 
    
         
            +
            	def side_length
         
     | 
| 
      
 133 
     | 
    
         
            +
            	    2 * circumradius * Math.sin(Math::PI/edge_count)
         
     | 
| 
       133 
134 
     | 
    
         
             
            	end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
            private
         
     | 
| 
      
 137 
     | 
    
         
            +
            	def cosine_half_angle
         
     | 
| 
      
 138 
     | 
    
         
            +
            	    Math.cos(Math::PI/edge_count)
         
     | 
| 
      
 139 
     | 
    
         
            +
            	end
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
       134 
141 
     | 
    
         
             
            # @!endgroup
         
     | 
| 
       135 
142 
     | 
    
         
             
                end
         
     | 
| 
       136 
143 
     | 
    
         
             
            end
         
     | 
    
        data/lib/geometry/rotation.rb
    CHANGED
    
    | 
         @@ -105,6 +105,7 @@ A generalized representation of a rotation transformation. 
     | 
|
| 
       105 
105 
     | 
    
         
             
            	# @param [Point] point	the {Point} to rotate into the parent coordinate frame
         
     | 
| 
       106 
106 
     | 
    
         
             
            	# @return [Point]   the rotated {Point}
         
     | 
| 
       107 
107 
     | 
    
         
             
            	def transform(point)
         
     | 
| 
      
 108 
     | 
    
         
            +
            	    return point if point.is_a?(PointZero)
         
     | 
| 
       108 
109 
     | 
    
         
             
            	    m = matrix
         
     | 
| 
       109 
110 
     | 
    
         
             
            	    m ? Point[m * Point[point]] : point
         
     | 
| 
       110 
111 
     | 
    
         
             
            	end
         
     | 
    
        data/lib/geometry/size.rb
    CHANGED
    
    | 
         @@ -1,5 +1,8 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'matrix'
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            require_relative 'size_one'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require_relative 'size_zero'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
       3 
6 
     | 
    
         
             
            module Geometry
         
     | 
| 
       4 
7 
     | 
    
         
             
            =begin
         
     | 
| 
       5 
8 
     | 
    
         
             
            An object representing the size of something.
         
     | 
| 
         @@ -29,13 +32,42 @@ methods (width, height and depth). 
     | 
|
| 
       29 
32 
     | 
    
         
             
            	    array.flatten!
         
     | 
| 
       30 
33 
     | 
    
         
             
            	    super *array
         
     | 
| 
       31 
34 
     | 
    
         
             
            	end
         
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            	# Creates and returns a new {SizeOne} instance. Or, a {Size} full of ones if the size argument is given.
         
     | 
| 
      
 37 
     | 
    
         
            +
            	# @param size [Number] the size of the new {Size} full of ones
         
     | 
| 
      
 38 
     | 
    
         
            +
            	# @return [SizeOne] A new {SizeOne} instance
         
     | 
| 
      
 39 
     | 
    
         
            +
            	def self.one(size=nil)
         
     | 
| 
      
 40 
     | 
    
         
            +
            	    size ? Size[Array.new(size, 1)] : SizeOne.new
         
     | 
| 
      
 41 
     | 
    
         
            +
            	end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
            	# Creates and returns a new {SizeOne} instance. Or, a {Size} full of zeros if the size argument is given.
         
     | 
| 
      
 44 
     | 
    
         
            +
            	# @param size [Number] the size of the new {Size} full of zeros
         
     | 
| 
      
 45 
     | 
    
         
            +
            	# @return [SizeOne] A new {SizeOne} instance
         
     | 
| 
      
 46 
     | 
    
         
            +
            	def self.zero(size=nil)
         
     | 
| 
      
 47 
     | 
    
         
            +
            	    size ? Size[Array.new(size, 0)] : SizeOne.new
         
     | 
| 
      
 48 
     | 
    
         
            +
            	end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
       33 
50 
     | 
    
         
             
            	# Allow comparison with an Array, otherwise do the normal thing
         
     | 
| 
       34 
51 
     | 
    
         
             
            	def ==(other)
         
     | 
| 
       35 
52 
     | 
    
         
             
            	    return @elements == other if other.is_a?(Array)
         
     | 
| 
       36 
53 
     | 
    
         
             
            	    super other
         
     | 
| 
       37 
54 
     | 
    
         
             
            	end
         
     | 
| 
       38 
55 
     | 
    
         | 
| 
      
 56 
     | 
    
         
            +
            	# Override Vector#[] to allow for regular array slicing
         
     | 
| 
      
 57 
     | 
    
         
            +
            	def [](*args)
         
     | 
| 
      
 58 
     | 
    
         
            +
            	    @elements[*args]
         
     | 
| 
      
 59 
     | 
    
         
            +
            	end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
            	def coerce(other)
         
     | 
| 
      
 62 
     | 
    
         
            +
            	    case other
         
     | 
| 
      
 63 
     | 
    
         
            +
            		when Array then [Size[*other], self]
         
     | 
| 
      
 64 
     | 
    
         
            +
            		when Numeric then [Size[Array.new(self.size, other)], self]
         
     | 
| 
      
 65 
     | 
    
         
            +
            		when Vector then [Size[*other], self]
         
     | 
| 
      
 66 
     | 
    
         
            +
            		else
         
     | 
| 
      
 67 
     | 
    
         
            +
            		raise TypeError, "#{self.class} can't be coerced into #{other.class}"
         
     | 
| 
      
 68 
     | 
    
         
            +
            	    end
         
     | 
| 
      
 69 
     | 
    
         
            +
            	end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
       39 
71 
     | 
    
         
             
            	def inspect
         
     | 
| 
       40 
72 
     | 
    
         
             
            	    'Size' + @elements.inspect
         
     | 
| 
       41 
73 
     | 
    
         
             
            	end
         
     | 
| 
         @@ -91,13 +123,12 @@ methods (width, height and depth). 
     | 
|
| 
       91 
123 
     | 
    
         
             
            		left = top = -args.shift
         
     | 
| 
       92 
124 
     | 
    
         
             
            		right = bottom = 0
         
     | 
| 
       93 
125 
     | 
    
         
             
            	    elsif 2 == args.size
         
     | 
| 
       94 
     | 
    
         
            -
            		left = -args.shift
         
     | 
| 
       95 
     | 
    
         
            -
            		top = -args.shift
         
     | 
| 
       96 
     | 
    
         
            -
            		right = bottom = 0
         
     | 
| 
      
 126 
     | 
    
         
            +
            		left = right = -args.shift
         
     | 
| 
      
 127 
     | 
    
         
            +
            		top = bottom = -args.shift
         
     | 
| 
       97 
128 
     | 
    
         
             
            	    end
         
     | 
| 
       98 
129 
     | 
    
         | 
| 
       99 
     | 
    
         
            -
            	    left = -options[:x] if options[:x]
         
     | 
| 
       100 
     | 
    
         
            -
            	    top = -options[:y] if options[:y]
         
     | 
| 
      
 130 
     | 
    
         
            +
            	    left = right = -options[:x] if options[:x]
         
     | 
| 
      
 131 
     | 
    
         
            +
            	    top = bottom = -options[:y] if options[:y]
         
     | 
| 
       101 
132 
     | 
    
         | 
| 
       102 
133 
     | 
    
         
             
            	    top = -options[:top] if options[:top]
         
     | 
| 
       103 
134 
     | 
    
         
             
            	    left = -options[:left] if options[:left]
         
     | 
| 
         @@ -125,13 +156,12 @@ methods (width, height and depth). 
     | 
|
| 
       125 
156 
     | 
    
         
             
            		left = top = args.shift
         
     | 
| 
       126 
157 
     | 
    
         
             
            		right = bottom = 0
         
     | 
| 
       127 
158 
     | 
    
         
             
            	    elsif 2 == args.size
         
     | 
| 
       128 
     | 
    
         
            -
            		left = args.shift
         
     | 
| 
       129 
     | 
    
         
            -
            		top = args.shift
         
     | 
| 
       130 
     | 
    
         
            -
            		right = bottom = 0
         
     | 
| 
      
 159 
     | 
    
         
            +
            		left = right = args.shift
         
     | 
| 
      
 160 
     | 
    
         
            +
            		top = bottom = args.shift
         
     | 
| 
       131 
161 
     | 
    
         
             
            	    end
         
     | 
| 
       132 
162 
     | 
    
         | 
| 
       133 
     | 
    
         
            -
            	    left = options[:x] if options[:x]
         
     | 
| 
       134 
     | 
    
         
            -
            	    top = options[:y] if options[:y]
         
     | 
| 
      
 163 
     | 
    
         
            +
            	    left = right = options[:x] if options[:x]
         
     | 
| 
      
 164 
     | 
    
         
            +
            	    top = bottom = options[:y] if options[:y]
         
     | 
| 
       135 
165 
     | 
    
         | 
| 
       136 
166 
     | 
    
         
             
            	    top = options[:top] if options[:top]
         
     | 
| 
       137 
167 
     | 
    
         
             
            	    left = options[:left] if options[:left]
         
     |