# frozen-string-literal: true module ChunkyPNG # Factory method to create {ChunkyPNG::Point} instances. # # This method tries to be as flexible as possible with regards to the given input: besides # explicit coordinates, this method also accepts arrays, hashes, strings, {ChunkyPNG::Dimension} # instances and anything that responds to :x and :y. # # @overload Point(x, y) # @param [Integer, :to_i] x The x-coordinate # @param [Integer, :to_i] y The y-coordinate # @return [ChunkyPNG::Point] The instantiated point. # # @overload Point(array) # @param [Array] array A two element array which represent the x- and y-coordinate. # @return [ChunkyPNG::Point] The instantiated point. # # @overload Point(hash) # @param [Hash] array A hash with the :x or 'x' and :y or # 'y' keys set, which will be used as coordinates. # @return [ChunkyPNG::Point] The instantiated point. # # @overload Point(string) # @param [String] string A string that contains the coordinates, e.g. '0, 4', # '(0 4)', [0,4}', etc. # @return [ChunkyPNG::Point] The instantiated point. # # @return [ChunkyPNG::Point] # @raise [ArgumentError] if the arguments weren't understood. # @see ChunkyPNG::Point def self.Point(*args) case args.length when 2 then ChunkyPNG::Point.new(*args) when 1 then build_point_from_object(args.first) else raise ArgumentError, "Don't know how to construct a point from #{args.inspect}!" end end def self.build_point_from_object(source) case source when ChunkyPNG::Point source when ChunkyPNG::Dimension ChunkyPNG::Point.new(source.width, source.height) when Array ChunkyPNG::Point.new(source[0], source[1]) when Hash x = source[:x] || source["x"] y = source[:y] || source["y"] ChunkyPNG::Point.new(x, y) when ChunkyPNG::Point::POINT_REGEXP ChunkyPNG::Point.new($1.to_i, $2.to_i) else if source.respond_to?(:x) && source.respond_to?(:y) ChunkyPNG::Point.new(source.x, source.y) else raise ArgumentError, "Don't know how to construct a point from #{source.inspect}!" end end end private_class_method :build_point_from_object # Simple class that represents a point on a canvas using an x and y coordinate. # # This class implements some basic methods to handle comparison, the splat operator and # bounds checking that make it easier to work with coordinates. # # @see ChunkyPNG.Point class Point # @return [Regexp] The regexp to parse points from a string. # @private POINT_REGEXP = /^[\(\[\{]?(\d+)\s*[,]?\s*(\d+)[\)\]\}]?$/ # @return [Integer] The x-coordinate of the point. attr_accessor :x # @return [Integer] The y-coordinate of the point. attr_accessor :y # Initializes a new point instance. # @param [Integer, :to_i] x The x-coordinate. # @param [Integer, :to_i] y The y-coordinate. def initialize(x, y) @x, @y = x.to_i, y.to_i end # Checks whether 2 points are identical. # @return [true, false] true iff the x and y coordinates match def eql?(other) other.x == x && other.y == y end alias == eql? # Compares 2 points. # # It will first compare the y coordinate, and it only takes the x-coordinate into # account if the y-coordinates of the points are identical. This way, an array of # points will be sorted into the order in which they would occur in the pixels # array returned by {ChunkyPNG::Canvas#pixels}. # # @param [ChunkyPNG::Point] other The point to compare this point with. # @return [-1, 0, 1] -1 If this point comes before the other one, 1 # if after, and 0 if the points are identical. def <=>(other) (y <=> other.y) == 0 ? x <=> other.x : y <=> other.y end # Converts the point instance to an array. # @return [Array] A 2-element array, i.e. [x, y]. def to_a [x, y] end alias to_ary to_a # Checks whether the point falls into a dimension # @param [ChunkyPNG::Dimension, ...] dimension_like The dimension of which the bounds # should be taken for the check. # @return [true, false] true iff the x and y coordinate fall width the width # and height of the dimension. def within_bounds?(*dimension_like) ChunkyPNG::Dimension(*dimension_like).include?(self) end end end