home *** CD-ROM | disk | FTP | other *** search
Java Source | 1998-03-20 | 15.8 KB | 590 lines |
- /*
- * @(#)Line2D.java 1.9 98/03/18
- *
- * Copyright 1997, 1998 by Sun Microsystems, Inc.,
- * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
- * All rights reserved.
- *
- * This software is the confidential and proprietary information
- * of Sun Microsystems, Inc. ("Confidential Information"). You
- * shall not disclose such Confidential Information and shall use
- * it only in accordance with the terms of the license agreement
- * you entered into with Sun.
- */
-
- package java.awt.geom;
-
- import java.awt.Shape;
- import java.awt.Rectangle;
-
- /**
- * A line segment in (x, y) coordinate space.
- * For the purposes of the Shape interface, a coordinate is considered
- * to be inside or contained by this line segment if the coordinate
- * lies exactly on the line segment.
- * <p>
- * This class is only the abstract superclass for all objects which
- * store a 2D line segment.
- * The actual storage representation of the coordinates is left to
- * the subclass.
- *
- * @version 10 Feb 1997
- * @author Jim Graham
- */
- public abstract class Line2D implements Shape, Cloneable {
- /**
- * A line segment specified with float coordinates.
- */
- public static class Float extends Line2D {
- /**
- * The X coordinate of the start point of the line segment.
- */
- public float x1;
-
- /**
- * The Y coordinate of the start point of the line segment.
- */
- public float y1;
-
- /**
- * The X coordinate of the end point of the line segment.
- */
- public float x2;
-
- /**
- * The Y coordinate of the end point of the line segment.
- */
- public float y2;
-
- /**
- * Constructs and initializes a Line with coordinates (0, 0) -> (0, 0).
- */
- public Float() {
- }
-
- /**
- * Constructs and initializes a Line from the specified coordinates.
- */
- public Float(float x1, float y1, float x2, float y2) {
- setLine(x1, y1, x2, y2);
- }
-
- /**
- * Constructs and initializes a Line from the specified Points.
- */
- public Float(Point2D p1, Point2D p2) {
- setLine(p1, p2);
- }
-
- /**
- * Returns the X coordinate of the start point in double precision.
- */
- public double getX1() {
- return (double) x1;
- }
-
- /**
- * Returns the Y coordinate of the start point in double precision.
- */
- public double getY1() {
- return (double) y1;
- }
-
- /**
- * Returns the X coordinate of the end point in double precision.
- */
- public double getX2() {
- return (double) x2;
- }
-
- /**
- * Returns the Y coordinate of the end point in double precision.
- */
- public double getY2() {
- return (double) y2;
- }
-
- /**
- * Sets the location of the endpoints of this line to the specified
- * double coordinates.
- */
- 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;
- }
-
- /**
- * Return the high precision bounding box of the shape.
- */
- 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);
- }
- }
-
- /**
- * A line segment specified with double coordinates.
- */
- public static class Double extends Line2D {
- /**
- * The X coordinate of the start point of the line segment.
- */
- public double x1;
-
- /**
- * The Y coordinate of the start point of the line segment.
- */
- public double y1;
-
- /**
- * The X coordinate of the end point of the line segment.
- */
- public double x2;
-
- /**
- * The Y coordinate of the end point of the line segment.
- */
- public double y2;
-
- /**
- * Constructs and initializes a Line with coordinates (0, 0) -> (0, 0).
- */
- public Double() {
- }
-
- /**
- * Constructs and initializes a Line from the specified coordinates.
- */
- public Double(double x1, double y1, double x2, double y2) {
- setLine(x1, y1, x2, y2);
- }
-
- /**
- * Constructs and initializes a Line from the specified Points.
- */
- public Double(Point2D p1, Point2D p2) {
- setLine(p1, p2);
- }
-
- /**
- * Returns the X coordinate of the start point in double precision.
- */
- public double getX1() {
- return x1;
- }
-
- /**
- * Returns the Y coordinate of the start point in double precision.
- */
- public double getY1() {
- return y1;
- }
-
- /**
- * Returns the X coordinate of the end point in double precision.
- */
- public double getX2() {
- return x2;
- }
-
- /**
- * Returns the Y coordinate of the end point in double precision.
- */
- public double getY2() {
- return y2;
- }
-
- /**
- * Sets the location of the endpoints of this line to the specified
- * double coordinates.
- */
- public void setLine(double x1, double y1, double x2, double y2) {
- this.x1 = x1;
- this.y1 = y1;
- this.x2 = x2;
- this.y2 = y2;
- }
-
- /**
- * Return the high precision bounding box of the shape.
- */
- 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);
- }
- }
-
- protected Line2D() {
- }
-
- /**
- * Returns the X coordinate of the start point in double precision.
- */
- public abstract double getX1();
-
- /**
- * Returns the Y coordinate of the start point in double precision.
- */
- public abstract double getY1();
-
- /**
- * Returns the X coordinate of the end point in double precision.
- */
- public abstract double getX2();
-
- /**
- * Returns the Y coordinate of the end point in double precision.
- */
- public abstract double getY2();
-
- /**
- * Sets the location of the endpoints of this line to the specified
- * double coordinates.
- */
- public abstract void setLine(double x1, double y1, double x2, double y2);
-
- /**
- * Sets the location of the endpoints of this line to the specified
- * Point coordinates.
- */
- public void setLine(Point2D p1, Point2D p2) {
- setLine(p1.getX(), p1.getY(), p2.getX(), p2.getY());
- }
-
- /**
- * Sets the location of the endpoints of this line to the same
- * as those in the specified Line.
- */
- public void setLine(Line2D l) {
- setLine(l.getX1(), l.getY1(), l.getX2(), l.getY2());
- }
-
- /**
- * Test if a given (x, y) coordinate is colinear with the line segment.
- */
- public boolean colinear(double x, double y) {
- return ((x - getX1()) * (getY2() - getY1()) ==
- (y - getY1()) * (getX2() - getX1()));
- }
-
- /**
- * Test if a given Point is colinear with the line segment.
- */
- public boolean colinear(Point2D p) {
- return colinear(p.getX(), p.getY());
- }
-
- /**
- * Return an indicator of where the specified point (px, py) lies
- * with respect to the line segment from (x1, y1) to (x2, y2).
- * The value will be 1 if the line segment must turn counterclockwise
- * to point at the specified point, -1 if it must turn clockwise,
- * or 0 if the point lies exactly on the line segment.
- * If the point is colinear with the line segment, but not between
- * the endpoints, then the value will be -1 if the point lies
- * "beyond (x1, y1)" or 1 if the point lies "beyond (x2, y2)".
- */
- public static int relativeCCW(double x1, double y1,
- double x2, double y2,
- double px, double py) {
- x2 -= x1;
- y2 -= y1;
- px -= x1;
- py -= y1;
- double ccw = px * y2 - py * x2;
- if (ccw == 0.0) {
- // The point is colinear, classify based on which side of
- // the segment the point falls on. We can calculate a
- // relative value using the projection of px,py onto the
- // segment - a negative value indicates the point projects
- // outside of the segment in the direction of the particular
- // endpoint used as the origin for the projection.
- ccw = px * x2 + py * y2;
- if (ccw > 0.0) {
- // Reverse the projection to be relative to the original x2,y2
- // x2 and y2 are simply negated.
- // px and py need to have (x2 - x1) or (y2 - y1) subtracted
- // from them (based on the original values)
- // Since we really want to get a positive answer when the
- // point is "beyond (x2,y2)", then we want to calculate
- // the inverse anyway - thus we leave x2 & y2 negated.
- px -= x2;
- py -= y2;
- ccw = px * x2 + py * y2;
- if (ccw < 0.0) {
- ccw = 0.0;
- }
- }
- }
- return (ccw < 0.0) ? -1 : ((ccw > 0.0) ? 1 : 0);
- }
-
- /**
- * Return an indicator of where the specified point (x, y) lies
- * with respect to this line segment.
- * The value will be 1 if the line segment must turn counterclockwise
- * to point at the specified point, -1 if it must turn clockwise,
- * or 0 if the point lies exactly on the line segment.
- * If the point is colinear with the line segment, but not between
- * the endpoints, then the value will be -1 if the point lies
- * "beyond (x1, y1)" or 1 if the point lies "beyond (x2, y2)".
- */
- public int relativeCCW(double x, double y) {
- return relativeCCW(getX1(), getY1(), getX2(), getY2(), x, y);
- }
-
- /**
- * Return an indicator of where the specified point lies
- * with respect to this line segment.
- * The value will be 1 if the line segment must turn counterclockwise
- * to point at the specified point, -1 if it must turn clockwise,
- * or 0 if the point lies exactly on the line segment.
- * If the point is colinear with the line segment, but not between
- * the endpoints, then the value will be -1 if the point lies
- * "beyond (x1, y1)" or 1 if the point lies "beyond (x2, y2)".
- */
- public int relativeCCW(Point2D p) {
- return relativeCCW(getX1(), getY1(), getX2(), getY2(),
- p.getX(), p.getY());
- }
-
- /**
- * Tests if the line segment from (x1, y1) to (x2, y2) intersects
- * the line segment from (x3, y3) to (x4, y4).
- */
- 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));
- }
-
- /**
- * Tests if the line segment from (x1, y1) to (x2, y2) intersects
- * this line segment.
- */
- public boolean intersectsLine(double x1, double y1, double x2, double y2) {
- return linesIntersect(x1, y1, x2, y2,
- getX1(), getY1(), getX2(), getY2());
- }
-
- /**
- * Tests if the given line segment intersects this line segment.
- */
- public boolean intersectsLine(Line2D l) {
- return linesIntersect(l.getX1(), l.getY1(), l.getX2(), l.getY2(),
- getX1(), getY1(), getX2(), getY2());
- }
-
- /**
- * Returns the square of the distance from a point to a line segment.
- * @param x0 the x coordinate of the beginning of the line segment
- * @param y0 the y coordinate of the beginning of the line segment
- * @param x1 the x coordinate of the end of the line segment
- * @param y1 the y coordinate of the end of the line segment
- * @param px the x coordinate of the point being measured
- * @param py the y coordinate of the point being measured
- */
- public static double ptSegDistSq(double x0, double y0,
- double x1, double y1,
- double px, double py) {
- // Adjust vectors relative to x0,y0
- // x1,y1 becomes relative vector from x0,y0 to end of segment
- x1 -= x0;
- y1 -= y0;
- // px,py becomes relative vector from x0,y0 to test point
- px -= x0;
- py -= y0;
- double dotprod = px * x1 + py * y1;
- double projlenSq;
- if (dotprod <= 0.0) {
- // px,py is on the side of x0,y0 away from x1,y1
- // distance to segment is length of px,py vector
- // "length of its (clipped) projection" is now 0.0
- projlenSq = 0.0;
- } else {
- // switch to backwards vectors relative to x1,y1
- // x1,y1 are already the negative of x0,y0=>x1,y1
- // to get px,py to be the negative of px,py=>x1,y1
- // the dot product of two negated vectors is the same
- // as the dot product of the two normal vectors
- px = x1 - px;
- py = y1 - py;
- dotprod = px * x1 + py * y1;
- if (dotprod <= 0.0) {
- // px,py is on the side of x1,y1 away from x0,y0
- // distance to segment is length of (backwards) px,py vector
- // "length of its (clipped) projection" is now 0.0
- projlenSq = 0.0;
- } else {
- // px,py is between x0,y0 and x1,y1
- // dotprod is the length of the px,py vector
- // projected on the x1,y1=>x0,y0 vector times the
- // length of the x1,y1=>x0,y0 vector
- projlenSq = dotprod * dotprod / (x1 * x1 + y1 * y1);
- }
- }
- // Distance to line is now the length of the relative point
- // vector minus the length of its projection onto the line
- // (which is zero if the projection falls outside the range
- // of the line segment).
- return px * px + py * py - projlenSq;
- }
-
- /**
- * Returns the distance from a point to a line segment.
- * @param x0 the x coordinate of the beginning of the line segment
- * @param y0 the y coordinate of the beginning of the line segment
- * @param x1 the x coordinate of the end of the line segment
- * @param y1 the y coordinate of the end of the line segment
- * @param px the x coordinate of the point being measured
- * @param py the y coordinate of the point being measured
- */
- public static double ptSegDist(double x0, double y0,
- double x1, double y1,
- double px, double py) {
- return Math.sqrt(ptSegDistSq(x0, y0, x1, y1, px, py));
- }
-
- /**
- * Test if a given coordinate is inside the boundary of the shape.
- */
- public boolean contains(double x, double y) {
- double x1 = getX1();
- double x2 = getX2();
- if (x1 < x2) {
- if (x < x1 || x > x2) {
- return false;
- }
- } else {
- if (x < x2 || x > x1) {
- return false;
- }
- }
- double y1 = getY1();
- double y2 = getY2();
- if (y1 < y2) {
- if (y < y1 || y > y2) {
- return false;
- }
- } else {
- if (y < y2 || y > y1) {
- return false;
- }
- }
- return (colinear(x, y));
- }
-
- /**
- * Test if a given Point is inside the boundary of the shape.
- */
- public boolean contains(Point2D p) {
- return contains(p.getX(), p.getY());
- }
-
- /**
- * Test if the Shape intersects the interior of a given
- * set of rectangular coordinates.
- */
- public boolean intersects(double x, double y, double w, double h) {
- return intersects(new Rectangle2D.Double(x, y, w, h));
- }
-
- /**
- * Test if the Shape intersects the interior of a given
- * Rectangle.
- */
- public boolean intersects(Rectangle2D r) {
- return r.intersectsLine(getX1(), getY1(), getX2(), getY2());
- }
-
- /**
- * Test if the interior of the Shape entirely contains the given
- * set of rectangular coordinates.
- */
- public boolean contains(double x, double y, double w, double h) {
- return false;
- }
-
- /**
- * Test if the interior of the Shape entirely contains the given
- * Rectangle.
- */
- public boolean contains(Rectangle2D r) {
- return false;
- }
-
- /**
- * Return the bounding box of the shape.
- */
- public Rectangle getBounds() {
- return getBounds2D().getBounds();
- }
-
- /**
- * Return an iteration object that defines the boundary of the
- * shape.
- */
- public PathIterator getPathIterator(AffineTransform at) {
- return new LineIterator(this, at);
- }
-
- /**
- * Return an iteration object that defines the boundary of the
- * flattened shape.
- */
- public PathIterator getPathIterator(AffineTransform at, double flatness) {
- return new LineIterator(this, at);
- }
-
- /**
- * Creates a new object of the same class as this object.
- *
- * @return a clone of this instance.
- * @exception OutOfMemoryError if there is not enough memory.
- * @see java.lang.Cloneable
- * @since JDK1.2
- */
- public Object clone() {
- try {
- return super.clone();
- } catch (CloneNotSupportedException e) {
- // this shouldn't happen, since we are Cloneable
- throw new InternalError();
- }
- }
- }
-