home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / awt / geom / Line2D.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  15.8 KB  |  590 lines

  1. /*
  2.  * @(#)Line2D.java    1.9 98/03/18
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.awt.geom;
  16.  
  17. import java.awt.Shape;
  18. import java.awt.Rectangle;
  19.  
  20. /**
  21.  * A line segment in (x, y) coordinate space.
  22.  * For the purposes of the Shape interface, a coordinate is considered
  23.  * to be inside or contained by this line segment if the coordinate
  24.  * lies exactly on the line segment.
  25.  * <p>
  26.  * This class is only the abstract superclass for all objects which
  27.  * store a 2D line segment.
  28.  * The actual storage representation of the coordinates is left to
  29.  * the subclass.
  30.  *
  31.  * @version 10 Feb 1997
  32.  * @author    Jim Graham
  33.  */
  34. public abstract class Line2D implements Shape, Cloneable {
  35.     /**
  36.      * A line segment specified with float coordinates.
  37.      */
  38.     public static class Float extends Line2D {
  39.     /**
  40.      * The X coordinate of the start point of the line segment.
  41.      */
  42.     public float x1;
  43.  
  44.     /**
  45.      * The Y coordinate of the start point of the line segment.
  46.      */
  47.     public float y1;
  48.  
  49.     /**
  50.      * The X coordinate of the end point of the line segment.
  51.      */
  52.     public float x2;
  53.  
  54.     /**
  55.      * The Y coordinate of the end point of the line segment.
  56.      */
  57.     public float y2;
  58.  
  59.     /**
  60.      * Constructs and initializes a Line with coordinates (0, 0) -> (0, 0).
  61.      */
  62.     public Float() {
  63.     }
  64.  
  65.     /**
  66.      * Constructs and initializes a Line from the specified coordinates.
  67.      */
  68.     public Float(float x1, float y1, float x2, float y2) {
  69.         setLine(x1, y1, x2, y2);
  70.     }
  71.  
  72.     /**
  73.      * Constructs and initializes a Line from the specified Points.
  74.      */
  75.     public Float(Point2D p1, Point2D p2) {
  76.         setLine(p1, p2);
  77.     }
  78.  
  79.     /**
  80.      * Returns the X coordinate of the start point in double precision.
  81.      */
  82.     public double getX1() {
  83.         return (double) x1;
  84.     }
  85.  
  86.     /**
  87.      * Returns the Y coordinate of the start point in double precision.
  88.      */
  89.     public double getY1() {
  90.         return (double) y1;
  91.     }
  92.  
  93.     /**
  94.      * Returns the X coordinate of the end point in double precision.
  95.      */
  96.     public double getX2() {
  97.         return (double) x2;
  98.     }
  99.  
  100.     /**
  101.      * Returns the Y coordinate of the end point in double precision.
  102.      */
  103.     public double getY2() {
  104.         return (double) y2;
  105.     }
  106.  
  107.     /**
  108.      * Sets the location of the endpoints of this line to the specified
  109.      * double coordinates.
  110.      */
  111.     public void setLine(double x1, double y1, double x2, double y2) {
  112.         this.x1 = (float) x1;
  113.         this.y1 = (float) y1;
  114.         this.x2 = (float) x2;
  115.         this.y2 = (float) y2;
  116.     }
  117.  
  118.     /**
  119.      * Return the high precision bounding box of the shape.
  120.      */
  121.     public Rectangle2D getBounds2D() {
  122.         float x, y, w, h;
  123.         if (x1 < x2) {
  124.         x = x1;
  125.         w = x2 - x1;
  126.         } else {
  127.         x = x2;
  128.         w = x1 - x2;
  129.         }
  130.         if (y1 < y2) {
  131.         y = y1;
  132.         h = y2 - y1;
  133.         } else {
  134.         y = y2;
  135.         h = y1 - y2;
  136.         }
  137.         return new Rectangle2D.Float(x, y, w, h);
  138.     }
  139.     }
  140.  
  141.     /**
  142.      * A line segment specified with double coordinates.
  143.      */
  144.     public static class Double extends Line2D {
  145.     /**
  146.      * The X coordinate of the start point of the line segment.
  147.      */
  148.     public double x1;
  149.  
  150.     /**
  151.      * The Y coordinate of the start point of the line segment.
  152.      */
  153.     public double y1;
  154.  
  155.     /**
  156.      * The X coordinate of the end point of the line segment.
  157.      */
  158.     public double x2;
  159.  
  160.     /**
  161.      * The Y coordinate of the end point of the line segment.
  162.      */
  163.     public double y2;
  164.  
  165.     /**
  166.      * Constructs and initializes a Line with coordinates (0, 0) -> (0, 0).
  167.      */
  168.     public Double() {
  169.     }
  170.  
  171.     /**
  172.      * Constructs and initializes a Line from the specified coordinates.
  173.      */
  174.     public Double(double x1, double y1, double x2, double y2) {
  175.         setLine(x1, y1, x2, y2);
  176.     }
  177.  
  178.     /**
  179.      * Constructs and initializes a Line from the specified Points.
  180.      */
  181.     public Double(Point2D p1, Point2D p2) {
  182.         setLine(p1, p2);
  183.     }
  184.  
  185.     /**
  186.      * Returns the X coordinate of the start point in double precision.
  187.      */
  188.     public double getX1() {
  189.         return x1;
  190.     }
  191.  
  192.     /**
  193.      * Returns the Y coordinate of the start point in double precision.
  194.      */
  195.     public double getY1() {
  196.         return y1;
  197.     }
  198.  
  199.     /**
  200.      * Returns the X coordinate of the end point in double precision.
  201.      */
  202.     public double getX2() {
  203.         return x2;
  204.     }
  205.  
  206.     /**
  207.      * Returns the Y coordinate of the end point in double precision.
  208.      */
  209.     public double getY2() {
  210.         return y2;
  211.     }
  212.  
  213.     /**
  214.      * Sets the location of the endpoints of this line to the specified
  215.      * double coordinates.
  216.      */
  217.     public void setLine(double x1, double y1, double x2, double y2) {
  218.         this.x1 = x1;
  219.         this.y1 = y1;
  220.         this.x2 = x2;
  221.         this.y2 = y2;
  222.     }
  223.  
  224.     /**
  225.      * Return the high precision bounding box of the shape.
  226.      */
  227.     public Rectangle2D getBounds2D() {
  228.         double x, y, w, h;
  229.         if (x1 < x2) {
  230.         x = x1;
  231.         w = x2 - x1;
  232.         } else {
  233.         x = x2;
  234.         w = x1 - x2;
  235.         }
  236.         if (y1 < y2) {
  237.         y = y1;
  238.         h = y2 - y1;
  239.         } else {
  240.         y = y2;
  241.         h = y1 - y2;
  242.         }
  243.         return new Rectangle2D.Double(x, y, w, h);
  244.     }
  245.     }
  246.  
  247.     protected Line2D() {
  248.     }
  249.  
  250.     /**
  251.      * Returns the X coordinate of the start point in double precision.
  252.      */
  253.     public abstract double getX1();
  254.  
  255.     /**
  256.      * Returns the Y coordinate of the start point in double precision.
  257.      */
  258.     public abstract double getY1();
  259.  
  260.     /**
  261.      * Returns the X coordinate of the end point in double precision.
  262.      */
  263.     public abstract double getX2();
  264.  
  265.     /**
  266.      * Returns the Y coordinate of the end point in double precision.
  267.      */
  268.     public abstract double getY2();
  269.  
  270.     /**
  271.      * Sets the location of the endpoints of this line to the specified
  272.      * double coordinates.
  273.      */
  274.     public abstract void setLine(double x1, double y1, double x2, double y2);
  275.  
  276.     /**
  277.      * Sets the location of the endpoints of this line to the specified
  278.      * Point coordinates.
  279.      */
  280.     public void setLine(Point2D p1, Point2D p2) {
  281.     setLine(p1.getX(), p1.getY(), p2.getX(), p2.getY());
  282.     }
  283.  
  284.     /**
  285.      * Sets the location of the endpoints of this line to the same
  286.      * as those in the specified Line.
  287.      */
  288.     public void setLine(Line2D l) {
  289.     setLine(l.getX1(), l.getY1(), l.getX2(), l.getY2());
  290.     }
  291.  
  292.     /**
  293.      * Test if a given (x, y) coordinate is colinear with the line segment.
  294.      */
  295.     public boolean colinear(double x, double y) {
  296.     return ((x - getX1()) * (getY2() - getY1()) ==
  297.         (y - getY1()) * (getX2() - getX1()));
  298.     }
  299.  
  300.     /**
  301.      * Test if a given Point is colinear with the line segment.
  302.      */
  303.     public boolean colinear(Point2D p) {
  304.     return colinear(p.getX(), p.getY());
  305.     }
  306.  
  307.     /**
  308.      * Return an indicator of where the specified point (px, py) lies
  309.      * with respect to the line segment from (x1, y1) to (x2, y2).
  310.      * The value will be 1 if the line segment must turn counterclockwise
  311.      * to point at the specified point, -1 if it must turn clockwise,
  312.      * or 0 if the point lies exactly on the line segment.
  313.      * If the point is colinear with the line segment, but not between
  314.      * the endpoints, then the value will be -1 if the point lies
  315.      * "beyond (x1, y1)" or 1 if the point lies "beyond (x2, y2)".
  316.      */
  317.     public static int relativeCCW(double x1, double y1,
  318.                   double x2, double y2,
  319.                   double px, double py) {
  320.     x2 -= x1;
  321.     y2 -= y1;
  322.     px -= x1;
  323.     py -= y1;
  324.     double ccw = px * y2 - py * x2;
  325.     if (ccw == 0.0) {
  326.         // The point is colinear, classify based on which side of
  327.         // the segment the point falls on.  We can calculate a
  328.         // relative value using the projection of px,py onto the
  329.         // segment - a negative value indicates the point projects
  330.         // outside of the segment in the direction of the particular
  331.         // endpoint used as the origin for the projection.
  332.         ccw = px * x2 + py * y2;
  333.         if (ccw > 0.0) {
  334.         // Reverse the projection to be relative to the original x2,y2
  335.         // x2 and y2 are simply negated.
  336.         // px and py need to have (x2 - x1) or (y2 - y1) subtracted
  337.         //    from them (based on the original values)
  338.         // Since we really want to get a positive answer when the
  339.         //    point is "beyond (x2,y2)", then we want to calculate
  340.         //    the inverse anyway - thus we leave x2 & y2 negated.
  341.         px -= x2;
  342.         py -= y2;
  343.         ccw = px * x2 + py * y2;
  344.         if (ccw < 0.0) {
  345.             ccw = 0.0;
  346.         }
  347.         }
  348.     }
  349.     return (ccw < 0.0) ? -1 : ((ccw > 0.0) ? 1 : 0);
  350.     }
  351.  
  352.     /**
  353.      * Return an indicator of where the specified point (x, y) lies
  354.      * with respect to this line segment.
  355.      * The value will be 1 if the line segment must turn counterclockwise
  356.      * to point at the specified point, -1 if it must turn clockwise,
  357.      * or 0 if the point lies exactly on the line segment.
  358.      * If the point is colinear with the line segment, but not between
  359.      * the endpoints, then the value will be -1 if the point lies
  360.      * "beyond (x1, y1)" or 1 if the point lies "beyond (x2, y2)".
  361.      */
  362.     public int relativeCCW(double x, double y) {
  363.     return relativeCCW(getX1(), getY1(), getX2(), getY2(), x, y);
  364.     }
  365.  
  366.     /**
  367.      * Return an indicator of where the specified point lies
  368.      * with respect to this line segment.
  369.      * The value will be 1 if the line segment must turn counterclockwise
  370.      * to point at the specified point, -1 if it must turn clockwise,
  371.      * or 0 if the point lies exactly on the line segment.
  372.      * If the point is colinear with the line segment, but not between
  373.      * the endpoints, then the value will be -1 if the point lies
  374.      * "beyond (x1, y1)" or 1 if the point lies "beyond (x2, y2)".
  375.      */
  376.     public int relativeCCW(Point2D p) {
  377.     return relativeCCW(getX1(), getY1(), getX2(), getY2(),
  378.                p.getX(), p.getY());
  379.     }
  380.  
  381.     /**
  382.      * Tests if the line segment from (x1, y1) to (x2, y2) intersects
  383.      * the line segment from (x3, y3) to (x4, y4).
  384.      */
  385.     public static boolean linesIntersect(double x1, double y1,
  386.                      double x2, double y2,
  387.                      double x3, double y3,
  388.                      double x4, double y4) {
  389.     return ((relativeCCW(x1, y1, x2, y2, x3, y3) *
  390.          relativeCCW(x1, y1, x2, y2, x4, y4) <= 0)
  391.         && (relativeCCW(x3, y3, x4, y4, x1, y1) *
  392.             relativeCCW(x3, y3, x4, y4, x2, y2) <= 0));
  393.     }
  394.  
  395.     /**
  396.      * Tests if the line segment from (x1, y1) to (x2, y2) intersects
  397.      * this line segment.
  398.      */
  399.     public boolean intersectsLine(double x1, double y1, double x2, double y2) {
  400.     return linesIntersect(x1, y1, x2, y2,
  401.                   getX1(), getY1(), getX2(), getY2());
  402.     }
  403.  
  404.     /**
  405.      * Tests if the given line segment intersects this line segment.
  406.      */
  407.     public boolean intersectsLine(Line2D l) {
  408.     return linesIntersect(l.getX1(), l.getY1(), l.getX2(), l.getY2(),
  409.                   getX1(), getY1(), getX2(), getY2());
  410.     }
  411.  
  412.     /**
  413.      * Returns the square of the distance from a point to a line segment.
  414.      * @param x0 the x coordinate of the beginning of the line segment
  415.      * @param y0 the y coordinate of the beginning of the line segment
  416.      * @param x1 the x coordinate of the end of the line segment
  417.      * @param y1 the y coordinate of the end of the line segment
  418.      * @param px the x coordinate of the point being measured
  419.      * @param py the y coordinate of the point being measured
  420.      */
  421.     public static double ptSegDistSq(double x0, double y0,
  422.                      double x1, double y1,
  423.                      double px, double py) {
  424.     // Adjust vectors relative to x0,y0
  425.     // x1,y1 becomes relative vector from x0,y0 to end of segment
  426.     x1 -= x0;
  427.     y1 -= y0;
  428.     // px,py becomes relative vector from x0,y0 to test point
  429.     px -= x0;
  430.     py -= y0;
  431.     double dotprod = px * x1 + py * y1;
  432.     double projlenSq;
  433.     if (dotprod <= 0.0) {
  434.         // px,py is on the side of x0,y0 away from x1,y1
  435.         // distance to segment is length of px,py vector
  436.         // "length of its (clipped) projection" is now 0.0
  437.         projlenSq = 0.0;
  438.     } else {
  439.         // switch to backwards vectors relative to x1,y1
  440.         // x1,y1 are already the negative of x0,y0=>x1,y1
  441.         // to get px,py to be the negative of px,py=>x1,y1
  442.         // the dot product of two negated vectors is the same
  443.         // as the dot product of the two normal vectors
  444.         px = x1 - px;
  445.         py = y1 - py;
  446.         dotprod = px * x1 + py * y1;
  447.         if (dotprod <= 0.0) {
  448.         // px,py is on the side of x1,y1 away from x0,y0
  449.         // distance to segment is length of (backwards) px,py vector
  450.         // "length of its (clipped) projection" is now 0.0
  451.         projlenSq = 0.0;
  452.         } else {
  453.         // px,py is between x0,y0 and x1,y1
  454.         // dotprod is the length of the px,py vector
  455.         // projected on the x1,y1=>x0,y0 vector times the
  456.         // length of the x1,y1=>x0,y0 vector
  457.         projlenSq = dotprod * dotprod / (x1 * x1 + y1 * y1);
  458.         }
  459.     }
  460.     // Distance to line is now the length of the relative point
  461.     // vector minus the length of its projection onto the line
  462.     // (which is zero if the projection falls outside the range
  463.     //  of the line segment).
  464.     return px * px + py * py - projlenSq;
  465.     }
  466.  
  467.     /**
  468.      * Returns the distance from a point to a line segment.
  469.      * @param x0 the x coordinate of the beginning of the line segment
  470.      * @param y0 the y coordinate of the beginning of the line segment
  471.      * @param x1 the x coordinate of the end of the line segment
  472.      * @param y1 the y coordinate of the end of the line segment
  473.      * @param px the x coordinate of the point being measured
  474.      * @param py the y coordinate of the point being measured
  475.      */
  476.     public static double ptSegDist(double x0, double y0,
  477.                    double x1, double y1,
  478.                    double px, double py) {
  479.     return Math.sqrt(ptSegDistSq(x0, y0, x1, y1, px, py));
  480.     }
  481.  
  482.     /**
  483.      * Test if a given coordinate is inside the boundary of the shape.
  484.      */
  485.     public boolean contains(double x, double y) {
  486.     double x1 = getX1();
  487.     double x2 = getX2();
  488.     if (x1 < x2) {
  489.         if (x < x1 || x > x2) {
  490.         return false;
  491.         }
  492.     } else {
  493.         if (x < x2 || x > x1) {
  494.         return false;
  495.         }
  496.     }
  497.     double y1 = getY1();
  498.     double y2 = getY2();
  499.     if (y1 < y2) {
  500.         if (y < y1 || y > y2) {
  501.         return false;
  502.         }
  503.     } else {
  504.         if (y < y2 || y > y1) {
  505.         return false;
  506.         }
  507.     }
  508.     return (colinear(x, y));
  509.     }
  510.  
  511.     /**
  512.      * Test if a given Point is inside the boundary of the shape.
  513.      */
  514.     public boolean contains(Point2D p) {
  515.     return contains(p.getX(), p.getY());
  516.     }
  517.  
  518.     /**
  519.      * Test if the Shape intersects the interior of a given
  520.      * set of rectangular coordinates.
  521.      */
  522.     public boolean intersects(double x, double y, double w, double h) {
  523.     return intersects(new Rectangle2D.Double(x, y, w, h));
  524.     }
  525.  
  526.     /**
  527.      * Test if the Shape intersects the interior of a given
  528.      * Rectangle.
  529.      */
  530.     public boolean intersects(Rectangle2D r) {
  531.     return r.intersectsLine(getX1(), getY1(), getX2(), getY2());
  532.     }
  533.  
  534.     /**
  535.      * Test if the interior of the Shape entirely contains the given
  536.      * set of rectangular coordinates.
  537.      */
  538.     public boolean contains(double x, double y, double w, double h) {
  539.     return false;
  540.     }
  541.  
  542.     /**
  543.      * Test if the interior of the Shape entirely contains the given
  544.      * Rectangle.
  545.      */
  546.     public boolean contains(Rectangle2D r) {
  547.     return false;
  548.     }
  549.  
  550.     /**
  551.      * Return the bounding box of the shape.
  552.      */
  553.     public Rectangle getBounds() {
  554.     return getBounds2D().getBounds();
  555.     }
  556.  
  557.     /**
  558.      * Return an iteration object that defines the boundary of the
  559.      * shape.
  560.      */
  561.     public PathIterator getPathIterator(AffineTransform at) {
  562.     return new LineIterator(this, at);
  563.     }
  564.  
  565.     /**
  566.      * Return an iteration object that defines the boundary of the
  567.      * flattened shape.
  568.      */
  569.     public PathIterator getPathIterator(AffineTransform at, double flatness) {
  570.     return new LineIterator(this, at);
  571.     }
  572.  
  573.     /**
  574.      * Creates a new object of the same class as this object.
  575.      *
  576.      * @return     a clone of this instance.
  577.      * @exception  OutOfMemoryError            if there is not enough memory.
  578.      * @see        java.lang.Cloneable
  579.      * @since      JDK1.2
  580.      */
  581.     public Object clone() {
  582.     try {
  583.         return super.clone();
  584.     } catch (CloneNotSupportedException e) {
  585.         // this shouldn't happen, since we are Cloneable
  586.         throw new InternalError();
  587.     }
  588.     }
  589. }
  590.