module Geometry =begin rdoc An object repesenting a {Point} that is one unit away from the origin, along each axis, in N-dimensional space A {PointOne} object is a {Point} that will always compare equal to one and unequal to everything else, regardless of size. It's similar to the {http://en.wikipedia.org/wiki/Null_Object_pattern Null Object Pattern}, but for ones. =end class PointOne def eql?(other) if other.respond_to? :all? other.all? {|e| e.eql? 1} else other == 1 end end alias == eql? def coerce(other) if other.is_a? Numeric [other, 1] elsif other.is_a? Array [other, Array.new(other.size, 1)] elsif other.is_a? Vector [other, Vector[*Array.new(other.size, 1)]] else [Point[other], Point[Array.new(other.size, 1)]] end end def is_a?(klass) (klass == Point) || super end alias :kind_of? :is_a? # This is a hack to get Array#== to work properly. It works on ruby 2.0 and 1.9.3. def to_ary [] end # @group Accessors # @param [Integer] i Index into the {Point}'s elements # @return [Numeric] Element i (starting at 0) def [](i) 1 end # @attribute [r] x # @return [Numeric] X-component def x 1 end # @attribute [r] y # @return [Numeric] Y-component def y 1 end # @attribute [r] z # @return [Numeric] Z-component def z 1 end # @endgroup # @override max() # @return [Number] The maximum value of the {Point}'s elements # @override max(point) # @return [Point] The element-wise maximum values of the receiver and the given {Point} def max(*args) if args.empty? 1 else args = args.first if 1 == args.size Point[Array.new(args.size, 1).zip(args).map(&:max)] end end # @override min() # @return [Number] The minimum value of the {Point}'s elements # @override min(point) # @return [Point] The element-wise minimum values of the receiver and the given {Point} def min(*args) if args.empty? 1 else args = args.first if 1 == args.size Point[Array.new(args.size, 1).zip(args).map(&:min)] end end # @override minmax() # @return [Array<Number>] The minimum value of the {Point}'s elements # @override min(point) # @return [Array<Point>] The element-wise minimum values of the receiver and the given {Point} def minmax(*args) if args.empty? [1, 1] else [min(*args), max(*args)] end end # Returns a new {Point} with the given number of elements removed from the end # @return [Point] the popped elements def pop(count=1) Point[Array.new(count, 1)] end # Removes the first element and returns it # @return [Point] the shifted elements def shift(count=1) Point[Array.new(count, 1)] end # @group Arithmetic # @group Unary operators def +@ self end def -@ -1 end # @endgroup def +(other) case other when Numeric Point.iso(other + 1) when Size Point[other.map {|a| a + 1 }] else if other.respond_to?(:map) other.map {|a| a + 1 } else Point[other + 1] end end end def -(other) if other.is_a? Size Point[other.map {|a| 1 - a }] elsif other.respond_to? :map other.map {|a| 1 - a } elsif other == 1 Point.zero else Point.iso(1 - other) end end def *(other) raise OperationNotDefined unless other.is_a? Numeric other end def /(other) raise OperationNotDefined unless other.is_a? Numeric raise ZeroDivisionError if 0 == other 1 / other end # @endgroup # @group Enumerable # Return the first, or first n, elements (always 0) # @param n [Number] the number of elements to return def first(n=nil) Array.new(n, 1) rescue 1 end # @endgroup end end