require 'bizziePath' require 'bizzieLibrary' class Point def initialize(coords) @coords = coords end def +(val) newCoords = [] @coords.each_index do |index| newCoords << @coords[index] + val.coords[index] end return self.class.new(newCoords) end def -(val) return self + (val * -1.0) end def *(val) return scale(val) end # projection onto the first n coordinates def project(n) return Point.new(coords[0..(n-1)]) end def coords @coords end def dimension coords.length end def dim dimension end def to_s coords.to_s end def scale(val) return self.class.new(coords.map {|x| x * val}) end def distance(pt) diffs = [] coords.each_index do |x| diffs << pt.coords[x] - coords[x] end return squareRoot(sum(diffs.map {|x| $square[x]})) end end # Point2d # order is an important quality of points - therefore, the coordinates are # stored as an array # we don't keep a list of points because we are not prepared to dispose of points class Point2d < Point def initialize(x, y = 0) if (x.instance_of?(Array)) super(x) else xy = [x, y] super(xy) end end def +(val) if (val.instance_of?(Point2d)) return Point2d.new(x + val.x, y + val.y) elsif (val.instance_of?(Array)) return Point2d.new(x + val[0], y + val[1]) end end def -(val) if (val.instance_of?(Point2d)) return Vector2d.new(x - val.x, y - val.y) end end def ==(val) val != nil && val.instance_of?(Point2d) && x == val.x && y == val.y end def x @coords[0] end def y @coords[1] end def Point2d.origin return Point2d.new(0, 0) end end $origin2d = Point2d.origin $originNd = lambda {|x| retArray = [] (1..x).each do |y| retArray << 0.0 end return Point.new(retArray) } # linguistic helpers def distance(pt1, pt2) return pt1.distance(pt2) end # returns a combination in x and y of the coords of the points def bilinearCombinationPoints2d(pt1, pt2, epsilonX, epsilonY) return Point2d.new( linearCombinationReals(pt1.x, pt2.x, epsilonX), linearCombinationReals(pt1.y, pt2.y, epsilonY)) end # returns a linear combination of pt1 and pt2 # epsilon between 0 and 1 def linearCombinationPoints2d(pt1, pt2, epsilon) return bilinearCombinationPoints2d(pt1, pt2, epsilon, epsilon) end def midpoint2d(pt1, pt2) return linearCombinationPoints2d(pt1, pt2, 0.5) end def linearCombination(pt1, pt2, epsilon) retCoords = [] counter = 0 while counter < pt1.coords.length retCoords << linearCombinationReals(pt1.coords[counter], pt2.coords[counter], epsilon) counter += 1 end return pt1.class.new(retCoords) end # the "natural" unitary operators for 2d points def flipX(pt) return Point2d.new(pt.x, -1 * pt.y) end def flipY(pt) return Point2d.new(-1 * pt.x, pt.y) end def flipOrigin(pt) return Point2d.new(-1 * pt.x, -1 * pt.y) end def contraction(pt, epsilon) return linearCombinationPoints2d($origin2d, pt, epsilon) end def rot90(pt) return Point2d.new(-1 * pt.y, pt.x) end def rot270(pt) return Point2d.new(pt.y, -1 * pt.x) end # x' = xcosT - ysinT and y' = xsinT + ycosT def rotation(pt, theta) theta = (2 * $pi * theta) / 360.0 x = pt.x * Math.cos(theta) - pt.y * Math.sin(theta) y = pt.x * Math.sin(theta) + pt.y * Math.cos(theta) return Point2d.new(x, y) end # the "natural" midpoints/projections def projx1midpoint2d(pt1, pt2) return bilinearCombinationPoints2d(pt1, pt2, 0.0, 0.5) end def projx2midpoint2d(pt1, pt2) return bilinearCombinationPoints2d(pt1, pt2, 1.0, 0.5) end def projy1midpoint2d(pt1, pt2) return bilinearCombinationPoints2d(pt1, pt2, 0.5, 0.0) end def projy2midpoint2d(pt1, pt2) return bilinearCombinationPoints2d(pt1, pt2, 0.5, 1.0) end def projx1y22d(pt1, pt2) return bilinearCombinationPoints2d(pt1, pt2, 0.0, 1.0) end def projx2y12d(pt1, pt2) return bilinearCombinationPoints2d(pt1, pt2, 1.0, 0.0) end # rotates and translates pt2 w/r/t pt1 - positive theta is counter-clockwise # theta = 0 to 360 def rotTrans(pt1, pt2, theta, magnitude) diff = pt2 - pt1 res = contraction(rotation(diff, theta), magnitude) return pt1 + res end class Line < ContinuousPath def initialize(p1, p2 = 0, directed=false) if p1.instance_of?(Array) @p1 = p1[0] @p2 = p1[1] else @p1 = p1 @p2 = p2 end @directed = directed end def p1 return @p1 end def p2 return @p2 end def directed return directed end def length return @pt1.distance(@pt2) end def doPathPoint(epsilon) return linearCombination(@p1, @p2, epsilon) end end #META: PATH # each point can be an array of values class Line2d < Line def initialize(p1, p2, directed=false) if p1.instance_of?(Array) p1 = Point2d.new(p1[0], p1[1]) end if p2.instance_of?(Array) p2 = Point2d.new(p2[0], p2[1]) end super(p1, p2, directed) end def vect return p2 - p1 end def ==(val) return (val != nil) && (val.instance_of?(Line2d)) && ((p1 == val.p1 && p2 == val.p2) || (p1 == val.p2 && p2 == val.p2)) end end class Vector2d < Line2d def initialize(x, y = nil) if y == nil super($origin2d, x, true) else super($origin2d, Point2d.new(x, y), true) end end def x return p2.x end def y return p2.y end def pt p2 end def perp return Vector2d.new(rot90(pt)) end def dotProduct(vect) return (vect.x * x + vect.y * y) end def neg return Vector2d.new(flipOrigin(pt)) end end