package ProGAL.geom2d; import java.awt.Color; import ProGAL.math.Constants; public class Line implements Shape { protected Point p; // point on the line protected Vector n; // normal vector of the line, unit length /** creates a line through a given point and with a given normal vector */ public Line(Point p, Vector n) { this.p = p; this.n = n.normalize(); } /** creates a line through 2 given points */ public Line(Point p, Point q) { this.p = p; n = new Vector(p.y()-q.y(), q.x()-p.x()); n.normalizeThis(); } /** creates a line through a given segment */ public Line(LineSegment seg) { p = seg.a; n = new Vector(seg.a.y()-seg.b.y(), seg.b.x() - seg.a.x()); n = n.normalize(); } /** creates a line ax + by + c = 0 */ public Line(double a, double b, double c) { n = new Vector(a,b); n.normalizeThis(); if (b != 0.0) p = new Point(0.0,-c/b); else p = new Point(-c/a,0.0); } /** creates a line y = ax + c */ public Line(double a, double c) { n = new Vector(-a, 1); n.normalizeThis(); p = new Point(0.0, c); } /** Creates a bisector line between points p and q */ public static Line getBisectorLine(Point p, Point q) { if (!p.equals(q)) return new Line(Point.midPoint(p,q), p.vectorTo(q)); return null; } public Point getPoint() { return p; } public Vector getDirection() { return new Vector(n.y(),-n.x()); } public double getSlope() { if (!isVertical()) return n.x()/n.y(); else return Double.MAX_VALUE; } public boolean isVertical() { return n.y() == 0.0; } public boolean isParallelWith(Line l) { return Math.abs(Vector.crossProduct(n, l.n)) < Constants.EPSILON; } public boolean isAbove(Point q) { return Point.leftTurn(p, p.add(this.getDirection()), q); } public boolean isBelow(Point q) { return Point.leftTurn(p, p.subtract(this.getDirection()), q); } public static boolean areParallel(Line l1, Line l2) { return Vector.crossProduct(l1.n, l2.n) == 0.0; } /** * translates the line so it goes through the point <p * @param p */ public void translateTo(Point p) { this.p = p; } /** * projects point p onto THIS line * @param q point to be projected * @return projection on the line * */ public Point projectPoint(Point q) { double t = n.y()*(q.x()-p.x()) - n.x()*(q.y()-p.y()); return new Point(n.y()*t+p.x(), p.y()-n.x()*t); } public double projectionParameter(Point q){ return n.y()*(q.x()-p.x()) - n.x()*(q.y()-p.y()); } /* * returns the intersection of two lines using Cramer's rule, see Ericson, Section 3.1.5. * Runtime exception is thrown if the lines are parallel. * Modified by Pawel on June 23, 2010 */ public static Point getIntersection(Line l1, Line l2) { double denom = l1.n.x()*l2.n.y() - l1.n.y()*l2.n.x(); if (Math.abs(denom) < Constants.EPSILON) throw new RuntimeException("Lines are parallel"); else { double e = l1.n.x()*l1.p.x() + l1.n.y()*l1.p.y(); double f = l2.n.x()*l2.p.x() + l2.n.y()*l2.p.y(); return new Point((e*l2.n.y() - f*l1.n.y())/denom, (f*l1.n.x() - e*l2.n.x())/denom); } } public String toString(String name) { return "Line[" + name + ",point:" + p.toString() + ",normal:" + n.toString()+"]"; } @Override public String toString() { return toString(""); } public void toConsole(String name) { System.out.println(toString(name)); } public void toConsole() { System.out.println(toString("")); } /** returns the point on the line at distance d from the line-defining point p */ public Point getPoint(double d) { Vector dir = this.getDirection(); return new Point(p.x()+d*dir.x(), p.y()+d*dir.y()); } /** returns the distance of the point q to the line */ public double getDistance(Point q) { return Math.abs(n.x()*q.x() + n.y()*q.y() - n.x()*p.x() - n.y()*p.y())/Math.sqrt(n.x()*n.x() + n.y()*n.y()); } public double intersectionParameter(Line l) { Vector dir = getDirection(); Vector lDir = l.getDirection(); double denom = lDir.y()*dir.x()-lDir.x()*dir.y(); Vector c = l.p.vectorTo(p); double s = (lDir.x()*c.y()-lDir.y()*c.x())/denom; return s; } @Override public Point getCenter() { return getPoint(0); } @Override public boolean contains(Point p) { return false; } }