# frozen-string-literal: truemoduleChunkyPNG# Factory method for {ChunkyPNG::Vector} instances.## @overload Vector(x0, y0, x1, y1, x2, y2, ...)# Creates a vector by parsing two subsequent values in the argument list# as x- and y-coordinate of a point.# @return [ChunkyPNG::Vector] The instantiated vector.# @overload Vector(string)# Creates a vector by parsing coordinates from the input string.# @return [ChunkyPNG::Vector] The instantiated vector.# @overload Vector(pointlike, pointlike, pointlike, ...)# Creates a vector by converting every argument to a point using {ChunkyPNG.Point}.# @return [ChunkyPNG::Vector] The instantiated vector.## @return [ChunkyPNG::Vector] The vector created by this factory method.# @raise [ArgumentError] If the given arguments could not be understood as a vector.# @see ChunkyPNG::Vectordefself.Vector(*args)returnargs.firstifargs.length==1&&args.first.is_a?(ChunkyPNG::Vector)ifargs.length==1&&args.first.respond_to?(:scan)ChunkyPNG::Vector.new(ChunkyPNG::Vector.multiple_from_string(args.first))# e.g. ['1,1 2,2 3,3']elseChunkyPNG::Vector.new(ChunkyPNG::Vector.multiple_from_array(args))# e.g. [[1,1], [2,2], [3,3]] or [1,1,2,2,3,3]endend# Class that represents a vector of points, i.e. a list of {ChunkyPNG::Point} instances.## Vectors can be created quite flexibly. See the {ChunkyPNG.Vector} factory methods for# more information on how to construct vectors.classVectorincludeEnumerable# @return [Array<ChunkyPNG::Point>] The array that holds all the points in this vector.attr_reader:points# Initializes a vector based on a list of Point instances.## You usually do not want to use this method directly, but call {ChunkyPNG.Vector} instead.## @param [Array<ChunkyPNG::Point>] points# @see ChunkyPNG.Vectordefinitialize(points=[])@points=pointsend# Iterates over all the edges in this vector.## An edge is a combination of two subsequent points in the vector. Together, they will form# a path from the first point to the last point## @param [true, false] close Whether to close the path, i.e. return an edge that connects the last# point in the vector back to the first point.# @return [void]# @raise [ChunkyPNG::ExpectationFailed] if the vector contains less than two points.# @see #edgesdefeach_edge(close=true)raiseChunkyPNG::ExpectationFailed,"Not enough points in this path to draw an edge!"iflength<2points.each_cons(2){|a,b|yield(a,b)}yield(points.last,points.first)ifcloseend# Returns the point with the given indexof this vector.# @param [Integer] index The 0-based index of the point in this vector.# @return [ChunkyPNG::Point] The point instance.def[](index)points[index]end# Returns an enumerator that will iterate over all the edges in this vector.# @param (see #each_edge)# @return [Enumerator] The enumerator that iterates over the edges.# @raise [ChunkyPNG::ExpectationFailed] if the vector contains less than two points.# @see #each_edgedefedges(close=true)to_enum(:each_edge,close)end# Returns the number of points in this vector.# @return [Integer] The length of the points array.deflengthpoints.lengthend# Iterates over all the points in this vector# @yield [ChunkyPNG::Point] The points in the correct order.# @return [void]defeach(&block)points.each(&block)end# Comparison between two vectors for quality.# @param [ChunkyPNG::Vector] other The vector to compare with.# @return [true, false] true if the list of points are identicaldefeql?(other)other.points==pointsendalias==eql?# Returns the range in x-coordinates for all the points in this vector.# @return [Range] The (inclusive) range of x-coordinates.defx_rangeRange.new(*points.map{|p|p.x}.minmax)end# Returns the range in y-coordinates for all the points in this vector.# @return [Range] The (inclusive) range of y-coordinates.defy_rangeRange.new(*points.map{|p|p.y}.minmax)end# Finds the lowest x-coordinate in this vector.# @return [Integer] The lowest x-coordinate of all the points in the vector.defmin_xx_range.firstend# Finds the highest x-coordinate in this vector.# @return [Integer] The highest x-coordinate of all the points in the vector.defmax_xx_range.lastend# Finds the lowest y-coordinate in this vector.# @return [Integer] The lowest y-coordinate of all the points in the vector.defmin_yy_range.firstend# Finds the highest y-coordinate in this vector.# @return [Integer] The highest y-coordinate of all the points in the vector.defmax_yy_range.lastend# Returns the offset from (0,0) of the minimal bounding box of all the# points in this vector# @return [ChunkyPNG::Point] A point that describes the top left corner if a# minimal bounding box would be drawn around all the points in the vector.defoffsetChunkyPNG::Point.new(min_x,min_y)end# Returns the width of the minimal bounding box of all the points in this vector.# @return [Integer] The x-distance between the points that are farthest from each other.defwidth1+(max_x-min_x)end# Returns the height of the minimal bounding box of all the points in this vector.# @return [Integer] The y-distance between the points that are farthest from each other.defheight1+(max_y-min_y)end# Returns the dimension of the minimal bounding rectangle of the points in this vector.# @return [ChunkyPNG::Dimension] The dimension instance with the width and heightdefdimensionChunkyPNG::Dimension.new(width,height)end# @return [Array<ChunkyPNG::Point>] The list of points interpreted from the input array.defself.multiple_from_array(source)return[]ifsource.empty?ifsource.first.is_a?(Numeric)||source.first=~/^\d+$/raiseArgumentError,"The points array is expected to have an even number of items!"ifsource.length%2!=0points=[]source.each_slice(2){|x,y|points<<ChunkyPNG::Point.new(x,y)}returnpointselsesource.map{|p|ChunkyPNG::Point(p)}endend# @return [Array<ChunkyPNG::Point>] The list of points parsed from the string.defself.multiple_from_string(source_str)multiple_from_array(source_str.scan(/[\(\[\{]?(\d+)\s*[,x]?\s*(\d+)[\)\]\}]?/))endendend