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

  1. /*
  2.  * @(#)Polygon.java    1.23 98/03/18
  3.  *
  4.  * Copyright 1995-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. package java.awt;
  15.  
  16. import java.awt.geom.AffineTransform;
  17. import java.awt.geom.PathIterator;
  18. import java.awt.geom.Point2D;
  19. import java.awt.geom.Rectangle2D;
  20.  
  21. /**
  22.  * The <code>Polygon</code> class encapsulates a description of a 
  23.  * closed, two-dimensional region within a coordinate space. This 
  24.  * region is bounded by an arbitrary number of line segments, each of 
  25.  * which is one side of the polygon. Internally, a polygon 
  26.  * comprises of a list of (<i>x</i>, <i>y</i>) coordinate pairs, 
  27.  * where each pair defines a <i>vertex</i> of the polygon, and two 
  28.  * successive pairs are the endpoints of a line that is a side of the 
  29.  * polygon. The first and final pairs of (<i>x</i>, <i>y</i>) 
  30.  * points are joined by a line segment that closes the polygon.
  31.  *
  32.  * @version     1.23, 03/18/98
  33.  * @author     Sami Shaio
  34.  * @author      Herb Jellinek
  35.  * @since       JDK1.0
  36.  */
  37. public class Polygon implements Shape, java.io.Serializable {
  38.  
  39.     /**
  40.      * The total number of points.
  41.      */
  42.     public int npoints = 0;
  43.  
  44.     /**
  45.      * The array of <i>x</i> coordinates. 
  46.      */
  47.     public int xpoints[] = new int[4];
  48.  
  49.     /**
  50.      * The array of <i>y</i> coordinates. 
  51.      */
  52.     public int ypoints[] = new int[4];
  53.     
  54.     /*
  55.      * Bounds of the polygon.
  56.      */
  57.     protected Rectangle bounds = null;
  58.     
  59.     /* 
  60.      * JDK 1.1 serialVersionUID 
  61.      */
  62.     private static final long serialVersionUID = -6460061437900069969L;
  63.  
  64.     /**
  65.      * Creates an empty polygon.
  66.      */
  67.     public Polygon() {
  68.     }
  69.  
  70.     /**
  71.      * Constructs and initializes a polygon from the specified 
  72.      * parameters. 
  73.      * @param      xpoints   an array of <i>x</i> coordinates.
  74.      * @param      ypoints   an array of <i>y</i> coordinates.
  75.      * @param      npoints   the total number of points in the polygon.
  76.      * @exception  NegativeArraySizeException if the value of
  77.      *                       <code>npoints</code> is negative.
  78.      */
  79.     public Polygon(int xpoints[], int ypoints[], int npoints) {
  80.     this.npoints = npoints;
  81.     this.xpoints = new int[npoints];
  82.     this.ypoints = new int[npoints];
  83.     System.arraycopy(xpoints, 0, this.xpoints, 0, npoints);
  84.     System.arraycopy(ypoints, 0, this.ypoints, 0, npoints);    
  85.     }
  86.     
  87.     /**
  88.      * Translates the vertices by <code>deltaX</code> along the 
  89.      * <i>x</i> axis and by <code>deltaY</code> along the 
  90.      * <i>y</i> axis.
  91.      * @param deltaX the amount to translate along the <i>x</i> axis
  92.      * @param deltaY the amount to translate along the <i>y</i> axis
  93.      * @since JDK1.1
  94.      */
  95.     public void translate(int deltaX, int deltaY) {
  96.     for (int i = 0; i < npoints; i++) {
  97.         xpoints[i] += deltaX;
  98.         ypoints[i] += deltaY;
  99.     }
  100.     if (bounds != null) {
  101.         bounds.translate(deltaX, deltaY);
  102.     }
  103.     }
  104.  
  105.     /*
  106.      * Calculate the bounding box of the points passed to the constructor.
  107.      * Sets 'bounds' to the result.
  108.      */
  109.     void calculateBounds(int xpoints[], int ypoints[], int npoints) {
  110.     int boundsMinX = Integer.MAX_VALUE;
  111.     int boundsMinY = Integer.MAX_VALUE;
  112.     int boundsMaxX = Integer.MIN_VALUE;
  113.     int boundsMaxY = Integer.MIN_VALUE;
  114.     
  115.     for (int i = 0; i < npoints; i++) {
  116.         int x = xpoints[i];
  117.         boundsMinX = Math.min(boundsMinX, x);
  118.         boundsMaxX = Math.max(boundsMaxX, x);
  119.         int y = ypoints[i];
  120.         boundsMinY = Math.min(boundsMinY, y);
  121.         boundsMaxY = Math.max(boundsMaxY, y);
  122.     }
  123.     bounds = new Rectangle(boundsMinX, boundsMinY,
  124.                    boundsMaxX - boundsMinX,
  125.                    boundsMaxY - boundsMinY);
  126.     }
  127.  
  128.     /*
  129.      * Update the bounding box to fit the point x, y.
  130.      */
  131.     void updateBounds(int x, int y) {
  132.     if (x < bounds.x) {
  133.         bounds.width = bounds.width + (bounds.x - x);
  134.         bounds.x = x;
  135.     }
  136.     else {
  137.         bounds.width = Math.max(bounds.width, x - bounds.x);
  138.         // bounds.x = bounds.x;
  139.     }
  140.  
  141.     if (y < bounds.y) {
  142.         bounds.height = bounds.height + (bounds.y - y);
  143.         bounds.y = y;
  144.     }
  145.     else {
  146.         bounds.height = Math.max(bounds.height, y - bounds.y);
  147.         // bounds.y = bounds.y;
  148.     }
  149.     }    
  150.  
  151.     /**
  152.      * Appends a point to this polygon. 
  153.      * <p>
  154.      * If an operation that calculates the bounding box of this polygon
  155.      * has already been performed, such as <code>getBounds</code> 
  156.      * or <code>contains</code>, then this method updates the bounding box. 
  157.      * @param       x   the <i>x</i> coordinate of the point.
  158.      * @param       y   the <i>y</i> coordinate of the point.
  159.      * @see         java.awt.Polygon#getBounds
  160.      * @see         java.awt.Polygon#contains
  161.      */
  162.     public void addPoint(int x, int y) {
  163.     if (npoints == xpoints.length) {
  164.         int tmp[];
  165.  
  166.         tmp = new int[npoints * 2];
  167.         System.arraycopy(xpoints, 0, tmp, 0, npoints);
  168.         xpoints = tmp;
  169.  
  170.         tmp = new int[npoints * 2];
  171.         System.arraycopy(ypoints, 0, tmp, 0, npoints);
  172.         ypoints = tmp;
  173.     }
  174.     xpoints[npoints] = x;
  175.     ypoints[npoints] = y;
  176.     npoints++;
  177.     if (bounds != null) {
  178.         updateBounds(x, y);
  179.     }
  180.     }
  181.  
  182.     /**
  183.      * Gets the bounding box of this polygon. The bounding box is the
  184.      * smallest rectangle whose sides are parallel to the <i>x</i> and
  185.      * <i>y</i> axes of the coordinate space, and that can completely
  186.      * contain the polygon.
  187.      * @return      a rectangle that defines the bounds of this polygon.
  188.      * @since       JDK1.1
  189.      */
  190.     public Rectangle getBounds() {
  191.     return getBoundingBox();
  192.     }
  193.  
  194.     /**
  195.      * @deprecated As of JDK version 1.1,
  196.      * replaced by <code>getBounds()</code>.
  197.      */
  198.     public Rectangle getBoundingBox() {
  199.     if (bounds == null) {
  200.         calculateBounds(xpoints, ypoints, npoints);
  201.     }
  202.     return bounds;
  203.     }
  204.  
  205.     /**
  206.      * Determines whether the specified point is inside the Polygon.
  207.      * Uses an even-odd insideness rule (also known as an alternating
  208.      * rule).
  209.      * @param p the point to be tested
  210.      */
  211.     public boolean contains(Point p) {
  212.     return contains(p.x, p.y);
  213.     }
  214.  
  215.     /**
  216.      * Determines whether the specified point is contained by this polygon.   
  217.      * <p>
  218.      * (The <code>contains</code> method is based on code by 
  219.      * Hanpeter van Vliet [hvvliet@inter.nl.net].) 
  220.      * @param      x  the <i>x</i> coordinate of the point to be tested.
  221.      * @param      y  the <i>y</i> coordinate of the point to be tested.
  222.      * @return     <code>true</code> if the point (<i>x</i>, <i>y</i>) 
  223.      *                       is contained by this polygon; 
  224.      *                       <code>false</code> otherwise.
  225.      * @since      JDK1.1
  226.      */
  227.     public boolean contains(int x, int y) {
  228.     return contains((double) x, (double) y);
  229.     }
  230.  
  231.     /**
  232.      * @deprecated As of JDK version 1.1,
  233.      * replaced by <code>contains(int, int)</code>.
  234.      */
  235.     public boolean inside(int x, int y) {
  236.     return contains((double) x, (double) y);
  237.     }
  238.  
  239.     /**
  240.      * Return the high precision bounding box of the shape.
  241.      */
  242.     public Rectangle2D getBounds2D() {
  243.     Rectangle r = getBounds();
  244.     return new Rectangle2D.Float(r.x, r.y, r.width, r.height);
  245.     }
  246.  
  247.     /**
  248.      * Test if a given coordinate is inside the boundary of the shape.
  249.      */
  250.     public boolean contains(double x, double y) {
  251.         if (getBoundingBox().contains(x, y)) {
  252.             int hits = 0;
  253.             int ySave = 0;
  254.  
  255.             // Find a vertex that is not on the halfline
  256.             int i = 0;
  257.             while (i < npoints && ypoints[i] == y) {
  258.                 i++;
  259.         }
  260.  
  261.             // Walk the edges of the polygon
  262.             for (int n = 0; n < npoints; n++) {
  263.                 int j = (i + 1) % npoints;
  264.  
  265.                 int dx = xpoints[j] - xpoints[i];
  266.                 int dy = ypoints[j] - ypoints[i];
  267.  
  268.                 // Ignore horizontal edges completely
  269.                 if (dy != 0) {
  270.                     // Check to see if the edge intersects
  271.                     // the horizontal halfline through (x, y)
  272.                     double rx = x - xpoints[i];
  273.                     double ry = y - ypoints[i];
  274.  
  275.                     // Deal with edges starting or ending on the halfline
  276.                     if (ypoints[j] == y && xpoints[j] >= x) {
  277.                         ySave = ypoints[i];
  278.             }
  279.                     if (ypoints[i] == y && xpoints[i] >= x) {
  280.                         if ((ySave > y) != (ypoints[j] > y)) {
  281.                 hits--;
  282.             }
  283.             }
  284.  
  285.                     // Tally intersections with halfline
  286.                     double s = ry / dy;
  287.                     if (s >= 0.0 && s <= 1.0 && (s * dx) >= rx) {
  288.                         hits++;
  289.             }
  290.                 }
  291.                 i = j;
  292.             }
  293.  
  294.             // Inside if number of intersections odd
  295.             return (hits % 2) != 0;
  296.         }
  297.         return false;
  298.     }
  299.  
  300.     /**
  301.      * Test if a given Point is inside the boundary of the shape.
  302.      */
  303.     public boolean contains(Point2D p) {
  304.     return contains(p.getX(), p.getY());
  305.     }
  306.  
  307.     /**
  308.      * Test if the interior of the Shape intersects the interior of a given
  309.      * set of rectangular coordinates.
  310.      */
  311.     public boolean intersects(double x, double y, double w, double h) {
  312.         throw new NoSuchMethodError ("not implemented yet");
  313.     }
  314.  
  315.     /**
  316.      * Test if the interior of the Shape intersects the interior of a given
  317.      * Rectangle.
  318.      */
  319.     public boolean intersects(Rectangle2D r) {
  320.     return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
  321.     }
  322.  
  323.     /**
  324.      * Test if the interior of the Shape entirely contains the given
  325.      * set of rectangular coordinates.
  326.      */
  327.     public boolean contains(double x, double y, double w, double h) {
  328.         throw new NoSuchMethodError ("not implemented yet");
  329.     }
  330.  
  331.     /**
  332.      * Test if the interior of the Shape entirely contains the given
  333.      * Rectangle.
  334.      */
  335.     public boolean contains(Rectangle2D r) {
  336.     return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
  337.     }
  338.  
  339.     /**
  340.      * Return an iterator object that iterates along the boundary of
  341.      * the shape and provides access to the geometry of the outline
  342.      * of the shape.
  343.      * An optional affine transform can be specified in which case
  344.      * the coordinates returned in the iteration will be transformed
  345.      * accordingly.
  346.      * @param at an optional AffineTransform to be applied to the
  347.      * coordinates as they are returned in the iteration, or null
  348.      * if the untransformed coordinates are desired.
  349.      */
  350.     public PathIterator getPathIterator(AffineTransform at) {
  351.     return new PolygonPathIterator(this, at);
  352.     }
  353.  
  354.     /**
  355.      * Return an iterator object that iterates along the boundary of
  356.      * the shape and provides access to a flattened view of the
  357.      * geometry of the outline of the shape.
  358.      * Only SEG_MOVETO, SEG_LINETO, and SEG_CLOSE point types will
  359.      * be returned by the iterator.
  360.      * The amount of subdivision of the curved segments is controlled
  361.      * by the <code>flatness</code> parameter which specifies ?REMIND?.
  362.      * An optional affine transform can be specified in which case
  363.      * the coordinates returned in the iteration will be transformed
  364.      * accordingly.
  365.      * @param at an optional AffineTransform to be applied to the
  366.      * coordinates as they are returned in the iteration, or null
  367.      * if the untransformed coordinates are desired.
  368.      * @param flatness the maximum amount that the control points
  369.      * for a given curve can vary from colinear before a subdivided
  370.      * curve is replaced by a straight line connecting the endpoints.
  371.      */
  372.     public PathIterator getPathIterator(AffineTransform at, double flatness) {
  373.     return getPathIterator(at);
  374.     }
  375.  
  376.     class PolygonPathIterator implements PathIterator {
  377.     Polygon poly;
  378.     AffineTransform transform;
  379.     int index;
  380.  
  381.     public PolygonPathIterator(Polygon pg, AffineTransform at) {
  382.         poly = pg;
  383.         transform = at;
  384.     }
  385.  
  386.     /**
  387.      * Return the winding rule for determining the interior of the
  388.      * path.
  389.      * @see PathIterator#WIND_NON_ZERO
  390.      */
  391.     public int getWindingRule() {
  392.         return WIND_EVEN_ODD;
  393.     }
  394.  
  395.     /**
  396.      * Tests if there are more points to read.
  397.      * @return true if there are more points to read
  398.      */
  399.     public boolean isDone() {
  400.         return index > poly.npoints;
  401.     }
  402.  
  403.     /**
  404.      * Moves the iterator to the next segment of the path forwards
  405.      * along the primary direction of traversal as long as there are
  406.      * more points in that direction.
  407.      */
  408.     public void next() {
  409.         index++;
  410.     }
  411.  
  412.     /**
  413.      * Returns the coordinates and type of the current path segment in
  414.      * the iteration.
  415.      * The return value is the path segment type:
  416.      * SEG_MOVETO, SEG_LINETO, or SEG_CLOSE.
  417.      * A float array of length 2 must be passed in and may be used to
  418.      * store the coordinates of the point(s).
  419.      * Each point is stored as a pair of float x,y coordinates.
  420.      * SEG_MOVETO and SEG_LINETO types will return one point,
  421.      * and SEG_CLOSE will not return any points.
  422.      * @see PathIterator#SEG_MOVETO
  423.      * @see PathIterator#SEG_LINETO
  424.      * @see PathIterator#SEG_CLOSE
  425.      */
  426.     public int currentSegment(float[] coords) {
  427.         if (index >= poly.npoints) {
  428.         return SEG_CLOSE;
  429.         }
  430.         coords[0] = poly.xpoints[index];
  431.         coords[1] = poly.ypoints[index];
  432.         if (transform != null) {
  433.         transform.transform(coords, 0, coords, 0, 1);
  434.         }
  435.         return (index == 0 ? SEG_MOVETO : SEG_LINETO);
  436.     }
  437.  
  438.     /**
  439.      * Returns the coordinates and type of the current path segment in
  440.      * the iteration.
  441.      * The return value is the path segment type:
  442.      * SEG_MOVETO, SEG_LINETO, or SEG_CLOSE.
  443.      * A double array of length 2 must be passed in and may be used to
  444.      * store the coordinates of the point(s).
  445.      * Each point is stored as a pair of double x,y coordinates.
  446.      * SEG_MOVETO and SEG_LINETO types will return one point,
  447.      * and SEG_CLOSE will not return any points.
  448.      * @see PathIterator#SEG_MOVETO
  449.      * @see PathIterator#SEG_LINETO
  450.      * @see PathIterator#SEG_CLOSE
  451.      */
  452.     public int currentSegment(double[] coords) {
  453.         if (index >= poly.npoints) {
  454.         return SEG_CLOSE;
  455.         }
  456.         coords[0] = poly.xpoints[index];
  457.         coords[1] = poly.ypoints[index];
  458.         if (transform != null) {
  459.         transform.transform(coords, 0, coords, 0, 1);
  460.         }
  461.         return (index == 0 ? SEG_MOVETO : SEG_LINETO);
  462.     }
  463.     }
  464. }
  465.