package java.awt.geom; import java.awt.Rectangle; import java.awt.Shape; /** * An abstract class representing a line in two dimensional space * * @author Lawrie Griffiths * */ public abstract class Line2D implements Shape, Cloneable { /** * A line in 2D space using float coordinates */ public static class Float extends Line2D { /** * The x coordinate of the start of the line */ public float x1; /** * The y coordinate of the start of the line */ public float y1; /** * The x coordinate of the end of the line */ public float x2; /** * The y coordinate of the end of the line */ public float y2; /** * Creates a zero length line at (0,0) */ public Float() {}; /** * Create a line from (x1,y1) to (x2,y2) * * @param x1 the x coordinate of the start of the line * @param y1 the y coordinate of the start of the line * @param x2 the x coordinate of the end of the line * @param y2 the y coordinate of the end of the line */ public Float(float x1, float y1, float x2, float y2) { setLine(x1, y1, x2, y2); } /** * Set the float coordinates of the start and end of the line * * @param x1 the x coordinate of the start of the line * @param y1 the y coordinate of the start of the line * @param x2 the x coordinate of the end of the line * @param y2 the y coordinate of the end of the line */ public void setLine(float x1, float y1, float x2, float y2) { this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; } /** * Get the bounds of the line as a Rectangle2D */ public Rectangle2D getBounds2D() { float x, y, w, h; if (x1 < x2) { x = x1; w = x2 - x1; } else { x = x2; w = x1 - x2; } if (y1 < y2) { y = y1; h = y2 - y1; } else { y = y2; h = y1 - y2; } return new Rectangle2D.Float(x, y, w, h); } @Override public double getX1() { return (double) x1; } @Override public double getY1() { return (double) y1; } @Override public Point2D getP1() { return new Point2D.Float(x1, y1); } @Override public double getX2() { return (double) x2; } @Override public double getY2() { return (double) y2; } @Override public Point2D getP2() { return new Point2D.Float(x2, y2); } @Override public void setLine(double x1, double y1, double x2, double y2) { this.x1 = (float) x1; this.y1 = (float) y1; this.x2 = (float) x2; this.y2 = (float) y2; } } /** * A line in 2D space using float coordinates */ public static class Double extends Line2D { /** * the x coordinate of the start of the line */ public double x1; /** * The y coordinate of the sztart of the line */ public double y1; /** * The x coordinate of the end of the line */ public double x2; /** * The y coordinate of the start of the line */ public double y2; /** * Create a zero length line at (0,0) with double coordinates */ public Double() {}; /** * Create a line from (x1,y1) to (x2,y2) with double coordinate * * @param x1 the x coordinate of the start of the line * @param y1 the y coordinate of the start of the line * @param x2 the x coordinate of the end of the line * @param y2 the y coordinate of the end of the line */ public Double(double x1, double y1, double x2, double y2) { setLine(x1, y1, x2, y2); } @Override public double getX1() { return x1; } @Override public double getY1() { return y1; } @Override public Point2D getP1() { return new Point2D.Double(x1, y1); } @Override public double getX2() { return x2; } @Override public double getY2() { return y2; } @Override public Point2D getP2() { return new Point2D.Double(x2, y2); } @Override public void setLine(double x1, double y1, double x2, double y2) { this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; } /** * Get the bounds of the line as a Rectangle2D */ public Rectangle2D getBounds2D() { double x, y, w, h; if (x1 < x2) { x = x1; w = x2 - x1; } else { x = x2; w = x1 - x2; } if (y1 < y2) { y = y1; h = y2 - y1; } else { y = y2; h = y1 - y2; } return new Rectangle2D.Double(x, y, w, h); } } /** * This is an abstract class that cannot be instantiated: use Line2D.Float or Line2D.Double. */ protected Line2D() { } /** * Get the x coordinate of the start of the line * * @return the x coordinate as a double */ public abstract double getX1(); /** * Get the y coordinate of the start of the line * * @return the y coordinate as a double */ public abstract double getY1(); /** * Get the start point of the line as a Point2D * * @return the Point2D */ public abstract Point2D getP1(); /** * Get the x coordinate of the end of the line * * @return the x coordinate as a double */ public abstract double getX2(); /** * Get the y coordinate of the end of the line * * @return the y coordinate as a double */ public abstract double getY2(); /** * Get the end point of the line as a Point2D * * @return the Point2D */ public abstract Point2D getP2(); /** * Sets the end points of the line using double coordinates. * * @param x1 the x coordinate of the start point * @param y1 the y coordinate of the start point * @param x2 the x coordinate of the end point * @param y2 the y coordinate of the end point */ public abstract void setLine(double x1, double y1, double x2, double y2); /** * Sets the end points of the line from a given start and end point * @param p1 the start point * @param p2 the end point */ public void setLine(Point2D p1, Point2D p2) { setLine(p1.getX(), p1.getY(), p2.getX(), p2.getY()); } /** * Set the end points of a line to the same as a given line * * @param line the given line */ public void setLine(Line2D line) { setLine(line.getX1(), line.getY1(), line.getX2(), line.getY2()); } public boolean contains(double x, double y) { return false; } public boolean contains(Point2D p) { return false; } public boolean contains(double x, double y, double w, double h) { return false; } public boolean contains(Rectangle2D r) { return false; } public boolean intersects(double x, double y, double w, double h) { return intersects(new Rectangle2D.Double(x, y, w, h)); } /** * Test if this line intersects a given line * * @param x1 the x coordinate of the start of the given line * @param y1 the y coordinate of the start of the given line * @param x2 the x coordinate of the end of the given line * @param y2 the y coordinate of the end of the given line * @return true iff the lines intersect */ public boolean intersectsLine(double x1, double y1, double x2, double y2) { return linesIntersect(x1, y1, x2, y2, getX1(), getY1(), getX2(), getY2()); } /** * Tests if this line intersects a given line * * @param l the given line * @return true iff the lines intersect */ public boolean intersectsLine(Line2D l) { return linesIntersect(l.getX1(), l.getY1(), l.getX2(), l.getY2(), getX1(), getY1(), getX2(), getY2()); } /** * Test if one line intersects another line * * @param x1 the x coordinate of the start of the first line * @param y1 the y coordinate of the start of the first line * @param x2 the x coordinate of the end of the first line * @param y2 the y coordinate of the end of the first line * @param x3 the x coordinate of the start of the second line * @param y3 the y coordinate of the start of the second line * @param x4 the x coordinate of the end of the second line * @param y4 the y coordinate of the end of the second line * @return true iff the lines intersect */ public static boolean linesIntersect( double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { return ((relativeCCW(x1, y1, x2, y2, x3, y3) * relativeCCW(x1, y1, x2, y2, x4, y4) <= 0) && (relativeCCW(x3, y3, x4, y4, x1, y1) * relativeCCW(x3, y3, x4, y4, x2, y2) <= 0)); } public Rectangle getBounds() { return getBounds2D().getBounds(); } public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new RuntimeException(); } } /** * Returns an indicator of where the specified point * lies with respect to the line * * @param x1 the x coordinate of the start of the line * @param y1 the y coordinate of the start of the line * @param x2 the x coordinate of the end of the line * @param y2 the y coordinate of the end of the line * @param px the x coordinate of the specified point * @param py the y coordinate of the specified point * @return 0 iff the point is on the line else 1 or -1 depending * on whether the point in to the left or ahead of the line, or to the right or behind * the line segment */ public static int relativeCCW( double x1, double y1, double x2, double y2, double px, double py) { double tx = x2 - x1; double ty = y2 - y1; double tpx = px - x1; double tpy = py - y1; double ccw = tpx * ty - tpy * tx; if (ccw == 0) { ccw = tpx * tx + tpy * ty; if (ccw > 0) { tpx -= tx; tpy -= ty; ccw = tpx * tx + tpy * ty; if (ccw < 0) ccw = 0; } } return (ccw < 0) ? -1 : ((ccw > 0) ? 1 : 0); } /** * Returns an indicator of where the specified point * lies with respect to the line * * @param p the specified point * @return 0 iff the point is on the line else 1 or -1 depending * on whether the point in to the left or ahead of the line, or to the right or behind * the line segment */ public int relativeCCW(Point2D p) { return relativeCCW(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); } /** * Returns an indicator of where the specified point * lies with respect to the line. * * @param px the x coordinate of the specified point * @param py the y coordinate of the specified point * @return 0 iff the point is on the line else 1 or -1 depending * on whether the point in to the left or ahead of the line, or to the right or behind * the line segment */ public int relativeCCW(double px, double py) { return relativeCCW(getX1(), getY1(), getX2(), getY2(), px, py); } public boolean intersects(Rectangle2D r) { return r.intersectsLine(getX1(), getY1(), getX2(), getY2()); } }