package ProGAL.geom2d; import java.awt.Color; import ProGAL.geom2d.Line; import ProGAL.math.Constants; import ProGAL.math.Functions; /** * A point in (x,y)-space represented using double precision. * @author R.Fonseca */ public class Point extends ProGAL.geomNd.Point { private static final long serialVersionUID = 8095991200265432551L; public static Point origo = new Point(0.0, 0.0); /** Construct a point at (0,0) */ public Point() { this(0,0); } /** Construct a point with the specified coordinates. */ public Point(double x, double y) { super(new double[]{x,y}); } /** Construct a point with the specified coordinates. */ public Point(double[] coords) { super(coords); } /** Construct a point with the same two first coordinates as p. */ public Point(ProGAL.geomNd.Point p){ this(p.getCoords()); } /** Return the x-coordinate */ public double x(){ return coords[0]; } /** Return the y-coordinate */ public double y(){ return coords[1]; } public Point clone(){ return new Point(coords[0], coords[1]); } /** Return a vector pointing from this point to p */ public Vector vectorTo(Point p){ return new Vector(p.coords[0]-coords[0], p.coords[1]-coords[1]); } /** Add the vector v to this point and return the result */ public Point add(Vector v){ return new Point(x()+v.x(), y()+v.y()); }; public Point add(double a, double b) { return new Point(x() + a, y() + b); } /** Add the vector v to this point and return the result (changes this object) */ public Point addThis(Vector v){ coords[0] += v.x(); coords[1] += v.y(); return this; } public Point addThis(Point p){ coords[0] += p.x(); coords[1] += p.y(); return this; } public Point addThis(double a, double b) { coords[0] += a; coords[1] += b; return this; } /** Subtract the vector v from this point and return the result */ public Point subtract(Vector v){ return new Point(x()-v.x(), y()-v.y()); } /** Subtract the vector v from this point and return the result (changes this object) */ public Point subtractThis(Vector v){ coords[0] -= v.x(); coords[1] -= v.y(); return this; } public Point subtractThis(Point p) { coords[0] -= p.x(); coords[1] -= p.y(); return this; } /** Returns the signed area of the triangle defined by the three points a, b and c (positive if counterclockwise) */ public static double area(Point a, Point b, Point c) { return a.x()*(b.y()-c.y()) + a.y()*(c.x()-b.x()) + b.x()*c.y() - c.x()*b.y(); } /* Returns true if the three points a, b, and c are collinear */ public static boolean collinear(Point a, Point b, Point c) { return area(a, b, c) < Constants.EPSILON; } /** returns squared distance of this point to the origo. */ public double getSquaredDistance() { return x()*x() + y()*y(); } /** returns squared distance of this point to point q. */ public double getSquaredDistance(Point q) { return Math.pow(x()-q.x(), 2) + Math.pow(y()-q.y(), 2); } /** returns squared distance of this point to segment s */ public double getSquaredDistance(LineSegment s) { double squaredSegmentLength = s.getSquaredLength(); if (squaredSegmentLength == 0.0) return getSquaredDistance(s.a); double sx = s.b.x() - s.a.x(); double sy = s.b.y() - s.a.y(); double t = ((x() - s.a.x()) * sx + (y() - s.a.y()) * sy)/squaredSegmentLength; if (t < 0) return getSquaredDistance(s.a); if (t > 1) return getSquaredDistance(s.b); return getSquaredDistance(new Point(s.a.x() + t*sx, s.a.y() + t*sy)); } /** returns distance of this point to segment s */ public double getDistance(LineSegment s) { return Math.sqrt(getSquaredDistance(s)); } /** Returns the angle between the points, but if they make a left turn the angle will be negative. */ public static double getSignedAngle(Point p1, Point p2, Point p3){ Vector v1 = p2.vectorTo(p1); Vector v2 = p2.vectorTo(p3); return Math.atan2(v1.x()*v2.y()-v1.y()*v2.x(), v1.dot(v2)); } /** Returns a positive double if the point is inside the circle through the 3 specified points (must be in clockwise order). */ public static double inCircle(Point p, Point q, Point r, Point s) { double pp = p.x()*p.x() + p.y()*p.y(); double qq = q.x()*q.x() + q.y()*q.y(); double rr = r.x()*r.x() + r.y()*r.y(); double ss = s.x()*s.x() + s.y()*s.y(); return pp*(q.x()*(r.y()-s.y()) + q.y()*(s.x()-r.x()) + r.x()*s.y() - r.y()*s.x()) - qq*(p.x()*(r.y()-s.y()) + p.y()*(s.x()-r.x()) + r.x()*s.y() - r.y()*s.x()) + rr*(p.x()*(q.y()-s.y()) + p.y()*(s.x()-q.x()) + q.x()*s.y() - q.y()*s.x()) - ss*(p.x()*(q.y()-r.y()) + p.y()*(r.x()-q.x()) + q.x()*r.y() - q.y()*r.x()); } /** Returns polar angle of this point */ public double polarAngle() { double angle = Math.acos(polarAngleCos()); if ((coords[1] < 0) || ((coords[1] == 0.0) && (coords[0] < 0.0))) angle = Constants.TAU - angle; return angle; } /** Returns the sinus of the polar angle of this point */ public double polarAngleSin() { return coords[1]/distance(); } /** Returns the cosinus of the polar angle of this point */ public double polarAngleCos() { return coords[0]/distance(); } /** Returns true if points a, b and c make a left turn at b */ public static boolean leftTurn(Point a, Point b, Point c ) { return area(a,b,c) > 0.0; } /** Returns true if points a, b and c make a right turn at b or are colinear */ public static boolean rightTurn(Point a, Point b, Point c ) { return area(a,b,c) <= 0.0; } /** Returns the midpoint of two points. */ public static Point midPoint(Point p, Point q) { return new Point((p.coords[0] + q.coords[0])/2, (p.coords[1] + q.coords[1])/2); } /** Creates a bisector line between points p and q */ public static Line getBisector(Point p, Point q) { if (!p.equals(q)) return new Line(midPoint(p,q), p.vectorTo(q)); return null; } /** Returns the line y = ax + b() where the coordinates of this point are (a,b) */ public Line getDualLine() { return new Line(x(), y()); } /** Return true iff o is a Point that has the same same coordinates as this. */ public boolean equals(Object o){ if(o instanceof Point) return equals((Point)o); return false; } /** Return true iff p has the same same coordinates as this. */ public boolean equals(Point p){ return Math.abs(coords[0]-p.coords[0])