Ignore:
Timestamp:
Apr 27, 2004, 8:39:34 PM (22 years ago)
Author:
bird
Message:

GCC v3.3.3 sources.

Location:
branches/GNU/src/gcc
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/GNU/src/gcc

    • Property svn:ignore
      •  

        old new  
        2626configure.vr
        2727configure.vrs
         28
        2829Makefile
        29 dir.info
        3030lost+found
        3131update.out
  • branches/GNU/src/gcc/libjava/java/awt/Polygon.java

    • Property cvs2svn:cvs-rev changed from 1.1 to 1.1.1.2
    r1390 r1391  
    1 /* Copyright (C) 2001  Free Software Foundation
    2 
    3    This file is part of libjava.
    4 
    5 This software is copyrighted work licensed under the terms of the
    6 Libjava License.  Please consult the file "LIBJAVA_LICENSE" for
    7 details.  */
     1/* Polygon.java -- class representing a polygon
     2   Copyright (C) 1999, 2002 Free Software Foundation, Inc.
     3
     4This file is part of GNU Classpath.
     5
     6GNU Classpath is free software; you can redistribute it and/or modify
     7it under the terms of the GNU General Public License as published by
     8the Free Software Foundation; either version 2, or (at your option)
     9any later version.
     10
     11GNU Classpath is distributed in the hope that it will be useful, but
     12WITHOUT ANY WARRANTY; without even the implied warranty of
     13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14General Public License for more details.
     15
     16You should have received a copy of the GNU General Public License
     17along with GNU Classpath; see the file COPYING.  If not, write to the
     18Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     1902111-1307 USA.
     20
     21Linking this library statically or dynamically with other modules is
     22making a combined work based on this library.  Thus, the terms and
     23conditions of the GNU General Public License cover the whole
     24combination.
     25
     26As a special exception, the copyright holders of this library give you
     27permission to link this library with independent modules to produce an
     28executable, regardless of the license terms of these independent
     29modules, and to copy and distribute the resulting executable under
     30terms of your choice, provided that you also meet, for each linked
     31independent module, the terms and conditions of the license of that
     32module.  An independent module is a module which is not derived from
     33or based on this library.  If you modify this library, you may extend
     34this exception to your version of the library, but you are not
     35obligated to do so.  If you do not wish to do so, delete this
     36exception statement from your version. */
     37
    838
    939package java.awt;
    1040
    11 import java.awt.geom.*;
     41import java.awt.geom.AffineTransform;
     42import java.awt.geom.PathIterator;
     43import java.awt.geom.Point2D;
     44import java.awt.geom.Rectangle2D;
    1245import java.io.Serializable;
    13 import java.util.Arrays;
    1446
    1547/**
    16  * @author Tom Tromey <[email protected]>
    17  * @date May 10, 2001
     48 * This class represents a polygon, a closed, two-dimensional region in a
     49 * coordinate space. The region is bounded by an arbitrary number of line
     50 * segments, between (x,y) coordinate vertices. The polygon has even-odd
     51 * winding, meaning that a point is inside the shape if it crosses the
     52 * boundary an odd number of times on the way to infinity.
     53 *
     54 * <p>There are some public fields; if you mess with them in an inconsistent
     55 * manner, it is your own fault when you get NullPointerException,
     56 * ArrayIndexOutOfBoundsException, or invalid results. Also, this class is
     57 * not threadsafe.
     58 *
     59 * @author Aaron M. Renn <[email protected]>
     60 * @author Eric Blake <[email protected]>
     61 * @since 1.0
     62 * @status updated to 1.4
    1863 */
    19 
    20 /** The Polygon class represents a closed region whose boundary is
    21     made of line segments.  The Polygon is defined by its vertices.  */
    2264public class Polygon implements Shape, Serializable
    2365{
    24   /** The bounds of the polygon.  This is null until the bounds have
    25    *  been computed for the first time; then it is correctly
    26    *  maintained whenever it is modified.  */
     66  /**
     67   * Compatible with JDK 1.0+.
     68   */
     69  private static final long serialVersionUID = -6460061437900069969L;
     70
     71  /**
     72   * This total number of endpoints.
     73   *
     74   * @serial the number of endpoints, possibly less than the array sizes
     75   */
     76  public int npoints;
     77
     78  /**
     79   * The array of X coordinates of endpoints. This should not be null.
     80   *
     81   * @see #addPoint(int, int)
     82   * @serial the x coordinates
     83   */
     84  public int[] xpoints;
     85
     86  /**
     87   * The array of Y coordinates of endpoints. This should not be null.
     88   *
     89   * @see #addPoint(int, int)
     90   * @serial the y coordinates
     91   */
     92  public int[] ypoints;
     93
     94  /**
     95   * The bounding box of this polygon. This is lazily created and cached, so
     96   * it must be invalidated after changing points.
     97   *
     98   * @see #getBounds()
     99   * @serial the bounding box, or null
     100   */
    27101  protected Rectangle bounds;
    28102
    29   /** The number of points in the polygon.  */
    30   public int npoints;
    31 
    32   /** The x coordinates of the points.  */
    33   public int[] xpoints;
    34 
    35   /** The y coordinates of the points.  */
    36   public int[] ypoints;
    37 
    38   /** Create a new, empty Polygon.  */
    39   public Polygon ()
    40   {
    41     this.xpoints = new int[0];
    42     this.ypoints = new int[0];
    43     this.npoints = 0;
    44   }
    45 
    46   /** Create a new Polygon from the given vertices.
    47    * @param xpoints The x coordinates
    48    * @param ypoints The y coordinates
    49    * @param npoints The number of points
    50    */
    51   public Polygon (int[] xpoints, int[] ypoints, int npoints)
    52   {
    53     // We make explicit copies instead of relying on clone so that we
    54     // ensure the new arrays are the same size.
     103  /**
     104   * Cached flattened version - condense points and parallel lines, so the
     105   * result has area if there are >= 3 condensed vertices. flat[0] is the
     106   * number of condensed points, and (flat[odd], flat[odd+1]) form the
     107   * condensed points.
     108   *
     109   * @see #condense()
     110   * @see #contains(double, double)
     111   * @see #contains(double, double, double, double)
     112   */
     113  private transient int[] condensed;
     114
     115  /**
     116   * Initializes an empty polygon.
     117   */
     118  public Polygon()
     119  {
     120    // Leave room for growth.
     121    xpoints = new int[4];
     122    ypoints = new int[4];
     123  }
     124
     125  /**
     126   * Create a new polygon with the specified endpoints. The arrays are copied,
     127   * so that future modifications to the parameters do not affect the polygon.
     128   *
     129   * @param xpoints the array of X coordinates for this polygon
     130   * @param ypoints the array of Y coordinates for this polygon
     131   * @param npoints the total number of endpoints in this polygon
     132   * @throws NegativeArraySizeException if npoints is negative
     133   * @throws IndexOutOfBoundsException if npoints exceeds either array
     134   * @throws NullPointerException if xpoints or ypoints is null
     135   */
     136  public Polygon(int[] xpoints, int[] ypoints, int npoints)
     137  {
    55138    this.xpoints = new int[npoints];
    56139    this.ypoints = new int[npoints];
    57     System.arraycopy (xpoints, 0, this.xpoints, 0, npoints);
    58     System.arraycopy (ypoints, 0, this.ypoints, 0, npoints);
    59   }
    60 
    61   /** Append the specified point to this Polygon.
    62    * @param x The x coordinate
    63    * @param y The y coordinate
    64    */
    65   public void addPoint (int x, int y)
    66   {
    67     int[] newx = new int[npoints + 1];
    68     System.arraycopy (xpoints, 0, newx, 0, npoints);
    69     int[] newy = new int[npoints + 1];
    70     System.arraycopy (ypoints, 0, newy, 0, npoints);
    71     newx[npoints] = x;
    72     newy[npoints] = y;
    73     ++npoints;
    74     xpoints = newx;
    75     ypoints = newy;
    76 
    77     // It is simpler to just recompute.
     140    System.arraycopy(xpoints, 0, this.xpoints, 0, npoints);
     141    System.arraycopy(ypoints, 0, this.ypoints, 0, npoints);
     142    this.npoints = npoints;
     143  }
     144
     145  /**
     146   * Reset the polygon to be empty. The arrays are left alone, to avoid object
     147   * allocation, but the number of points is set to 0, and all cached data
     148   * is discarded. If you are discarding a huge number of points, it may be
     149   * more efficient to just create a new Polygon.
     150   *
     151   * @see #invalidate()
     152   * @since 1.4
     153   */
     154  public void reset()
     155  {
     156    npoints = 0;
     157    invalidate();
     158  }
     159
     160  /**
     161   * Invalidate or flush all cached data. After direct manipulation of the
     162   * public member fields, this is necessary to avoid inconsistent results
     163   * in methods like <code>contains</code>.
     164   *
     165   * @see #getBounds()
     166   * @since 1.4
     167   */
     168  public void invalidate()
     169  {
     170    bounds = null;
     171    condensed = null;
     172  }
     173
     174  /**
     175   * Translates the polygon by adding the specified values to all X and Y
     176   * coordinates. This updates the bounding box, if it has been calculated.
     177   *
     178   * @param dx the amount to add to all X coordinates
     179   * @param dy the amount to add to all Y coordinates
     180   * @since 1.1
     181   */
     182  public void translate(int dx, int dy)
     183  {
     184    int i = npoints;
     185    while (--i >= 0)
     186      {
     187        xpoints[i] += dx;
     188        xpoints[i] += dy;
     189      }
    78190    if (bounds != null)
    79       computeBoundingBox ();
    80   }
    81 
    82   /** Return true if the indicated point is inside this Polygon.
    83    * This uses an even-odd rule to determine insideness.
    84    * @param x The x coordinate
    85    * @param y The y coordinate
    86    * @returns true if the point is contained by this Polygon.
    87    */
    88   public boolean contains (double x, double y)
    89   {
    90     // What we do is look at each line segment.  If the line segment
    91     // crosses the "scan line" at y at a point x' < x, then we
    92     // increment our counter.  At the end, an even number means the
    93     // point is outside the polygon.  Instead of a number, though, we
    94     // use a boolean.
     191      {
     192        bounds.x += dx;
     193        bounds.y += dy;
     194      }
     195    condensed = null;
     196  }
     197
     198  /**
     199   * Adds the specified endpoint to the polygon. This updates the bounding
     200   * box, if it has been created.
     201   *
     202   * @param x the X coordinate of the point to add
     203   * @param y the Y coordiante of the point to add
     204   */
     205  public void addPoint(int x, int y)
     206  {
     207    if (npoints + 1 > xpoints.length)
     208      {
     209        int[] newx = new int[npoints + 1];
     210        System.arraycopy(xpoints, 0, newx, 0, npoints);
     211        xpoints = newx;
     212      }
     213    if (npoints + 1 > ypoints.length)
     214      {
     215        int[] newy = new int[npoints + 1];
     216        System.arraycopy(ypoints, 0, newy, 0, npoints);
     217        ypoints = newy;
     218      }
     219    xpoints[npoints] = x;
     220    ypoints[npoints] = y;
     221    npoints++;
     222    if (bounds != null)
     223      {
     224        if (npoints == 1)
     225          {
     226            bounds.x = x;
     227            bounds.y = y;
     228          }
     229        else
     230          {
     231            if (x < bounds.x)
     232              {
     233                bounds.width += bounds.x - x;
     234                bounds.x = x;
     235              }
     236            else if (x > bounds.x + bounds.width)
     237              bounds.width = x - bounds.x;
     238            if (y < bounds.y)
     239              {
     240                bounds.height += bounds.y - y;
     241                bounds.y = y;
     242              }
     243            else if (y > bounds.y + bounds.height)
     244              bounds.height = y - bounds.y;
     245          }
     246      }
     247    condensed = null;
     248  }
     249
     250  /**
     251   * Returns the bounding box of this polygon. This is the smallest
     252   * rectangle with sides parallel to the X axis that will contain this
     253   * polygon.
     254   *
     255   * @return the bounding box for this polygon
     256   * @see #getBounds2D()
     257   * @since 1.1
     258   */
     259  public Rectangle getBounds()
     260  {
     261    if (bounds == null)
     262      {
     263        if (npoints == 0)
     264          return bounds = new Rectangle();
     265        int i = npoints - 1;
     266        int minx = xpoints[i];
     267        int maxx = minx;
     268        int miny = ypoints[i];
     269        int maxy = miny;
     270        while (--i >= 0)
     271          {
     272            int x = xpoints[i];
     273            int y = ypoints[i];
     274            if (x < minx)
     275              minx = x;
     276            else if (x > maxx)
     277              maxx = x;
     278            if (y < miny)
     279              miny = y;
     280            else if (y > maxy)
     281              maxy = y;
     282          }
     283        bounds = new Rectangle(minx, maxy, maxx - minx, maxy - miny);
     284      }
     285    return bounds;
     286  }
     287
     288  /**
     289   * Returns the bounding box of this polygon. This is the smallest
     290   * rectangle with sides parallel to the X axis that will contain this
     291   * polygon.
     292   *
     293   * @return the bounding box for this polygon
     294   * @see #getBounds2D()
     295   * @deprecated use {@link #getBounds()} instead
     296   */
     297  public Rectangle getBoundingBox()
     298  {
     299    return getBounds();
     300  }
     301
     302  /**
     303   * Tests whether or not the specified point is inside this polygon.
     304   *
     305   * @param p the point to test
     306   * @return true if the point is inside this polygon
     307   * @throws NullPointerException if p is null
     308   * @see #contains(double, double)
     309   */
     310  public boolean contains(Point p)
     311  {
     312    return contains(p.getX(), p.getY());
     313  }
     314
     315  /**
     316   * Tests whether or not the specified point is inside this polygon.
     317   *
     318   * @param x the X coordinate of the point to test
     319   * @param y the Y coordinate of the point to test
     320   * @return true if the point is inside this polygon
     321   * @see #contains(double, double)
     322   * @since 1.1
     323   */
     324  public boolean contains(int x, int y)
     325  {
     326    return contains((double) x, (double) y);
     327  }
     328
     329  /**
     330   * Tests whether or not the specified point is inside this polygon.
     331   *
     332   * @param x the X coordinate of the point to test
     333   * @param y the Y coordinate of the point to test
     334   * @return true if the point is inside this polygon
     335   * @see #contains(double, double)
     336   * @deprecated use {@link #contains(int, int)} instead
     337   */
     338  public boolean inside(int x, int y)
     339  {
     340    return contains((double) x, (double) y);
     341  }
     342
     343  /**
     344   * Returns a high-precision bounding box of this polygon. This is the
     345   * smallest rectangle with sides parallel to the X axis that will contain
     346   * this polygon.
     347   *
     348   * @return the bounding box for this polygon
     349   * @see #getBounds()
     350   * @since 1.2
     351   */
     352  public Rectangle2D getBounds2D()
     353  {
     354    // For polygons, the integer version is exact!
     355    return getBounds();
     356  }
     357
     358  /**
     359   * Tests whether or not the specified point is inside this polygon.
     360   *
     361   * @param x the X coordinate of the point to test
     362   * @param y the Y coordinate of the point to test
     363   * @return true if the point is inside this polygon
     364   * @since 1.2
     365   */
     366  public boolean contains(double x, double y)
     367  {
     368    // First, the obvious bounds checks.
     369    if (! condense() || ! getBounds().contains(x, y))
     370      return false;
     371    // A point is contained if a ray to (-inf, y) crosses an odd number
     372    // of segments. This must obey the semantics of Shape when the point is
     373    // exactly on a segment or vertex: a point is inside only if the adjacent
     374    // point in the increasing x or y direction is also inside. Note that we
     375    // are guaranteed that the condensed polygon has area, and no consecutive
     376    // segments with identical slope.
    95377    boolean inside = false;
    96     for (int i = 0; i < npoints; ++i)
    97       {
    98         // Handle the wrap case.
    99         int x2 = (i == npoints) ? xpoints[0] : xpoints[i + 1];
    100         int y2 = (i == npoints) ? ypoints[0] : ypoints[i + 1];
    101 
    102         if (ypoints[i] == y2)
    103           {
    104             // We ignore horizontal lines.  This might give weird
    105             // results in some situations -- ?
    106             continue;
    107           }
    108 
    109         double t = (y - ypoints[i]) / (double) (y2 - ypoints[i]);
    110         double x3 = xpoints[i] + t * (x2 - xpoints[i]);
    111         if (x3 < x)
    112           inside = ! inside;
    113       }
    114 
     378    int limit = condensed[0];
     379    int curx = condensed[(limit << 1) - 1];
     380    int cury = condensed[limit << 1];
     381    for (int i = 1; i <= limit; i++)
     382      {
     383        int priorx = curx;
     384        int priory = cury;
     385        curx = condensed[(i << 1) - 1];
     386        cury = condensed[i << 1];
     387        if ((priorx > x && curx > x) // Left of segment, or NaN.
     388            || (priory > y && cury > y) // Below segment, or NaN.
     389            || (priory < y && cury < y)) // Above segment.
     390          continue;
     391        if (priory == cury) // Horizontal segment, y == cury == priory
     392          {
     393            if (priorx < x && curx < x) // Right of segment.
     394              {
     395                inside = ! inside;
     396                continue;
     397              }
     398            // Did we approach this segment from above or below?
     399            // This mess is necessary to obey rules of Shape.
     400            priory = condensed[((limit + i - 2) % limit) << 1];
     401            boolean above = priory > cury;
     402            if ((curx == x && (curx > priorx || above))
     403                || (priorx == x && (curx < priorx || ! above))
     404                || (curx > priorx && ! above) || above)
     405              inside = ! inside;
     406            continue;
     407          }
     408        if (priorx == x && priory == y) // On prior vertex.
     409          continue;
     410        if (priorx == curx // Vertical segment.
     411            || (priorx < x && curx < x)) // Right of segment.
     412          {
     413            inside = ! inside;
     414            continue;
     415          }
     416        // The point is inside the segment's bounding box, compare slopes.
     417        double leftx = curx > priorx ? priorx : curx;
     418        double lefty = curx > priorx ? priory : cury;
     419        double slopeseg = (double) (cury - priory) / (curx - priorx);
     420        double slopepoint = (double) (y - lefty) / (x - leftx);
     421        if ((slopeseg > 0 && slopeseg > slopepoint)
     422            || slopeseg < slopepoint)
     423          inside = ! inside;
     424      }
    115425    return inside;
    116426  }
    117427
    118   /** Return true if the indicated rectangle is entirely inside this
    119    * Polygon.
    120    * This uses an even-odd rule to determine insideness.
    121    * @param x The x coordinate
    122    * @param y The y coordinate
    123    * @param w The width
    124    * @param h The height
    125    * @returns true if the rectangle is contained by this Polygon.
    126    */
    127   public boolean contains (double x, double y, double w, double h)
    128   {
    129     return intersectOrContains (x, y, w, h, false);
    130   }
    131 
    132   /** Return true if the indicated point is inside this Polygon.
    133    * This uses an even-odd rule to determine insideness.
    134    * @param x The x coordinate
    135    * @param y The y coordinate
    136    * @returns true if the point is contained by this Polygon.
    137    */
    138   public boolean contains (int x, int y)
    139   {
    140     return contains ((double) x, (double) y);
    141   }
    142 
    143   /** Return true if the indicated point is inside this Polygon.
    144    * This uses an even-odd rule to determine insideness.
    145    * @param p The point
    146    * @returns true if the point is contained by this Polygon.
    147    */
    148   public boolean contains (Point p)
    149   {
    150     return contains (p.x, p.y);
    151   }
    152 
    153   /** Return true if the indicated point is inside this Polygon.
    154    * This uses an even-odd rule to determine insideness.
    155    * @param p The point
    156    * @returns true if the point is contained by this Polygon.
    157    */
    158   public boolean contains (Point2D p)
    159   {
    160     return contains (p.getX (), p.getY ());
    161   }
    162 
    163   /** Return true if the indicated rectangle is entirely inside this
    164    * Polygon.  This uses an even-odd rule to determine insideness.
    165    * @param r The rectangle
    166    * @returns true if the rectangle is contained by this Polygon.
    167    */
    168   public boolean contains (Rectangle2D r)
    169   {
    170     return contains (r.getX (), r.getY (), r.getWidth (), r.getHeight ());
    171   }
    172 
    173   /** Returns the bounds of this Polygon.
    174    * @deprecated Use getBounds() instead.
    175    */
    176   public Rectangle getBoundingBox ()
    177   {
    178     if (bounds == null)
    179       computeBoundingBox ();
    180     return bounds;
    181   }
    182 
    183   /** Returns the bounds of this Polygon.  */
    184   public Rectangle getBounds ()
    185   {
    186     if (bounds == null)
    187       computeBoundingBox ();
    188     return bounds;
    189   }
    190 
    191   /** Returns the bounds of this Polygon.  */
    192   public Rectangle2D getBounds2D ()
    193   {
    194     if (bounds == null)
    195       computeBoundingBox ();
    196     return bounds;              // Why not?
    197   }
    198 
    199   /** Return an iterator for the boundary of this Polygon.
    200    * @param at A transform to apply to the coordinates.
    201    * @returns A path iterator for the Polygon's boundary.
    202    */
    203   public PathIterator getPathIterator (AffineTransform at)
    204   {
    205     return new Iterator (at);
    206   }
    207 
    208   /** Return an iterator for the boundary of this Polygon.
    209    * @param at A transform to apply to the coordinates.
    210    * @param flatness The flatness of the result; it is ignored by
    211    *                 this class.
    212    * @returns A path iterator for the Polygon's boundary.
    213    */
    214   public PathIterator getPathIterator (AffineTransform at, double flatness)
    215   {
    216     // We ignore the flatness.
    217     return new Iterator (at);
    218   }
    219 
    220   /** @deprecated use contains(int,int).  */
    221   public boolean inside (int x, int y)
    222   {
    223     return contains (x, y);
    224   }
    225 
    226   /** Return true if this Polygon's interior intersects the given
    227    * rectangle's interior.
    228    * @param x The x coordinate
    229    * @param y The y coordinate
    230    * @param w The width
    231    * @param h The height
    232    */
    233   public boolean intersects (double x, double y, double w, double h)
    234   {
    235     return intersectOrContains (x, y, w, h, true);
    236   }
    237 
    238   /** Return true if this Polygon's interior intersects the given
    239    * rectangle's interior.
    240    * @param r The rectangle
    241    */
    242   public boolean intersects (Rectangle2D r)
    243   {
    244     return intersects (r.getX (), r.getY (), r.getWidth (), r.getHeight ());
    245   }
    246 
    247   // This tests for intersection with or containment of a rectangle,
    248   // depending on the INTERSECT argument.
    249   private boolean intersectOrContains (double x, double y, double w, double h,
    250                                        boolean intersect)
    251   {
    252     // First compute the rectangle of possible intersection points.
    253     Rectangle r = getBounds ();
    254     int minx = Math.max (r.x, (int) x);
    255     int maxx = Math.min (r.x + r.width, (int) (x + w));
    256     int miny = Math.max (r.y, (int) y);
    257     int maxy = Math.min (r.y + r.height, (int) (y + h));
    258 
    259     if (miny > maxy)
     428  /**
     429   * Tests whether or not the specified point is inside this polygon.
     430   *
     431   * @param p the point to test
     432   * @return true if the point is inside this polygon
     433   * @throws NullPointerException if p is null
     434   * @see #contains(double, double)
     435   * @since 1.2
     436   */
     437  public boolean contains(Point2D p)
     438  {
     439    return contains(p.getX(), p.getY());
     440  }
     441
     442  /**
     443   * Test if a high-precision rectangle intersects the shape. This is true
     444   * if any point in the rectangle is in the shape. This implementation is
     445   * precise.
     446   *
     447   * @param x the x coordinate of the rectangle
     448   * @param y the y coordinate of the rectangle
     449   * @param w the width of the rectangle, treated as point if negative
     450   * @param h the height of the rectangle, treated as point if negative
     451   * @return true if the rectangle intersects this shape
     452   * @since 1.2
     453   */
     454  public boolean intersects(double x, double y, double w, double h)
     455  {
     456    // First, the obvious bounds checks.
     457    if (w <= 0 || h <= 0 || npoints == 0 ||
     458        ! getBounds().intersects(x, y, w, h))
     459      return false; // Disjoint bounds.
     460    if ((x <= bounds.x && x + w >= bounds.x + bounds.width
     461         && y <= bounds.y && y + h >= bounds.y + bounds.height)
     462        || contains(x, y))
     463      return true; // Rectangle contains the polygon, or one point matches.
     464    // If any vertex is in the rectangle, the two might intersect.
     465    int curx = 0;
     466    int cury = 0;
     467    for (int i = 0; i < npoints; i++)
     468      {
     469        curx = xpoints[i];
     470        cury = ypoints[i];
     471        if (curx >= x && curx < x + w && cury >= y && cury < y + h
     472            && contains(curx, cury)) // Boundary check necessary.
     473          return true;
     474      }
     475    // Finally, if at least one of the four bounding lines intersect any
     476    // segment of the polygon, return true. Be careful of the semantics of
     477    // Shape; coinciding lines do not necessarily return true.
     478    for (int i = 0; i < npoints; i++)
     479      {
     480        int priorx = curx;
     481        int priory = cury;
     482        curx = xpoints[i];
     483        cury = ypoints[i];
     484        if (priorx == curx) // Vertical segment.
     485          {
     486            if (curx < x || curx >= x + w) // Outside rectangle.
     487              continue;
     488            if ((cury >= y + h && priory <= y)
     489                || (cury <= y && priory >= y + h))
     490              return true; // Bisects rectangle.
     491            continue;
     492          }
     493        if (priory == cury) // Horizontal segment.
     494          {
     495            if (cury < y || cury >= y + h) // Outside rectangle.
     496              continue;
     497            if ((curx >= x + w && priorx <= x)
     498                || (curx <= x && priorx >= x + w))
     499              return true; // Bisects rectangle.
     500            continue;
     501          }
     502        // Slanted segment.
     503        double slope = (double) (cury - priory) / (curx - priorx);
     504        double intersect = slope * (x - curx) + cury;
     505        if (intersect > y && intersect < y + h) // Intersects left edge.
     506          return true;
     507        intersect = slope * (x + w - curx) + cury;
     508        if (intersect > y && intersect < y + h) // Intersects right edge.
     509          return true;
     510        intersect = (y - cury) / slope + curx;
     511        if (intersect > x && intersect < x + w) // Intersects bottom edge.
     512          return true;
     513        intersect = (y + h - cury) / slope + cury;
     514        if (intersect > x && intersect < x + w) // Intersects top edge.
     515          return true;
     516      }
     517    return false;
     518  }
     519
     520  /**
     521   * Test if a high-precision rectangle intersects the shape. This is true
     522   * if any point in the rectangle is in the shape. This implementation is
     523   * precise.
     524   *
     525   * @param r the rectangle
     526   * @return true if the rectangle intersects this shape
     527   * @throws NullPointerException if r is null
     528   * @see #intersects(double, double, double, double)
     529   * @since 1.2
     530   */
     531  public boolean intersects(Rectangle2D r)
     532  {
     533    return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
     534  }
     535
     536  /**
     537   * Test if a high-precision rectangle lies completely in the shape. This is
     538   * true if all points in the rectangle are in the shape. This implementation
     539   * is precise.
     540   *
     541   * @param x the x coordinate of the rectangle
     542   * @param y the y coordinate of the rectangle
     543   * @param w the width of the rectangle, treated as point if negative
     544   * @param h the height of the rectangle, treated as point if negative
     545   * @return true if the rectangle is contained in this shape
     546   * @since 1.2
     547   */
     548  public boolean contains(double x, double y, double w, double h)
     549  {
     550    // First, the obvious bounds checks.
     551    if (w <= 0 || h <= 0 || ! contains(x, y)
     552        || ! bounds.contains(x, y, w, h))
    260553      return false;
    261 
    262     double[] crosses = new double[npoints + 1];
    263 
    264     for (; miny < maxy; ++miny)
    265       {
    266         // First compute every place where the polygon might intersect
    267         // the scan line at Y.
    268         int ins = 0;
    269         for (int i = 0; i < npoints; ++i)
    270           {
    271             // Handle the wrap case.
    272             int x2 = (i == npoints) ? xpoints[0] : xpoints[i + 1];
    273             int y2 = (i == npoints) ? ypoints[0] : ypoints[i + 1];
    274 
    275             if (ypoints[i] == y2)
    276               {
    277                 // We ignore horizontal lines.  This might give weird
    278                 // results in some situations -- ?
    279                 continue;
    280               }
    281 
    282             double t = (((double) miny - ypoints[i])
    283                         / (double) (y2 - ypoints[i]));
    284             double x3 = xpoints[i] + t * (x2 - xpoints[i]);
    285             crosses[ins++] = x3;
    286           }
    287 
    288         // Now we can sort into increasing order and look to see if
    289         // any point in the rectangle is in the polygon.  We examine
    290         // every other pair due to our even-odd rule.
    291         Arrays.sort (crosses, 0, ins);
    292         int i = intersect ? 0 : 1;
    293         for (; i < ins - 1; i += 2)
    294           {
    295             // Pathological case.
    296             if (crosses[i] == crosses[i + 1])
    297               continue;
    298 
    299             // Found a point on the inside.
    300             if ((crosses[i] >= x && crosses[i] < x + w)
    301                 || (crosses[i + 1] >= x && crosses[i + 1] < x + w))
    302               {
    303                 // If we're checking containment then we just lost.
    304                 // But if we're checking intersection then we just
    305                 // won.
    306                 return intersect;
    307               }
    308           }
    309       }
    310 
    311     return false;
    312   }
    313 
    314   /** Translates all the vertices of the polygon via a given vector.
    315    * @param deltaX The X offset
    316    * @param deltaY The Y offset
    317    */
    318   public void translate (int deltaX, int deltaY)
    319   {
    320     for (int i = 0; i < npoints; ++i)
    321       {
    322         xpoints[i] += deltaX;
    323         ypoints[i] += deltaY;
    324       }
    325 
    326     if (bounds != null)
    327       {
    328         bounds.x += deltaX;
    329         bounds.y += deltaY;
    330       }
    331   }
    332 
    333   // This computes the bounding box if required.
    334   private void computeBoundingBox ()
    335   {
    336     if (npoints == 0)
    337       {
    338         // This is wrong if the user adds a new point, but we
    339         // account for that in addPoint().
    340         bounds = new Rectangle (0, 0, 0, 0);
    341       }
    342     else
    343       {
    344         int maxx = xpoints[0];
    345         int minx = xpoints[0];
    346         int maxy = ypoints[0];
    347         int miny = ypoints[0];
    348 
    349         for (int i = 1; i < npoints; ++i)
    350           {
    351             maxx = Math.max (maxx, xpoints[i]);
    352             minx = Math.min (minx, xpoints[i]);
    353             maxy = Math.max (maxy, ypoints[i]);
    354             miny = Math.min (miny, ypoints[i]);
    355           }
    356 
    357         bounds = new Rectangle (minx, miny, maxx - minx, maxy - miny);
    358       }
    359   }
    360 
    361   private class Iterator implements PathIterator
    362   {
    363     public AffineTransform xform;
    364     public int where;
    365 
    366     public Iterator (AffineTransform xform)
     554    // Now, if any of the four bounding lines intersects a polygon segment,
     555    // return false. The previous check had the side effect of setting
     556    // the condensed array, which we use. Be careful of the semantics of
     557    // Shape; coinciding lines do not necessarily return false.
     558    int limit = condensed[0];
     559    int curx = condensed[(limit << 1) - 1];
     560    int cury = condensed[limit << 1];
     561    for (int i = 1; i <= limit; i++)
     562      {
     563        int priorx = curx;
     564        int priory = cury;
     565        curx = condensed[(i << 1) - 1];
     566        cury = condensed[i << 1];
     567        if (curx > x && curx < x + w && cury > y && cury < y + h)
     568          return false; // Vertex is in rectangle.
     569        if (priorx == curx) // Vertical segment.
     570          {
     571            if (curx < x || curx > x + w) // Outside rectangle.
     572              continue;
     573            if ((cury >= y + h && priory <= y)
     574                || (cury <= y && priory >= y + h))
     575              return false; // Bisects rectangle.
     576            continue;
     577          }
     578        if (priory == cury) // Horizontal segment.
     579          {
     580            if (cury < y || cury > y + h) // Outside rectangle.
     581              continue;
     582            if ((curx >= x + w && priorx <= x)
     583                || (curx <= x && priorx >= x + w))
     584              return false; // Bisects rectangle.
     585            continue;
     586          }
     587        // Slanted segment.
     588        double slope = (double) (cury - priory) / (curx - priorx);
     589        double intersect = slope * (x - curx) + cury;
     590        if (intersect > y && intersect < y + h) // Intersects left edge.
     591          return false;
     592        intersect = slope * (x + w - curx) + cury;
     593        if (intersect > y && intersect < y + h) // Intersects right edge.
     594          return false;
     595        intersect = (y - cury) / slope + curx;
     596        if (intersect > x && intersect < x + w) // Intersects bottom edge.
     597          return false;
     598        intersect = (y + h - cury) / slope + cury;
     599        if (intersect > x && intersect < x + w) // Intersects top edge.
     600          return false;
     601      }
     602    return true;
     603  }
     604
     605  /**
     606   * Test if a high-precision rectangle lies completely in the shape. This is
     607   * true if all points in the rectangle are in the shape. This implementation
     608   * is precise.
     609   *
     610   * @param r the rectangle
     611   * @return true if the rectangle is contained in this shape
     612   * @throws NullPointerException if r is null
     613   * @see #contains(double, double, double, double)
     614   * @since 1.2
     615   */
     616  public boolean contains(Rectangle2D r)
     617  {
     618    return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
     619  }
     620
     621  /**
     622   * Return an iterator along the shape boundary. If the optional transform
     623   * is provided, the iterator is transformed accordingly. Each call returns
     624   * a new object, independent from others in use. This class is not
     625   * threadsafe to begin with, so the path iterator is not either.
     626   *
     627   * @param transform an optional transform to apply to the iterator
     628   * @return a new iterator over the boundary
     629   * @since 1.2
     630   */
     631  public PathIterator getPathIterator(final AffineTransform transform)
     632  {
     633    return new PathIterator()
    367634    {
    368       this.xform = xform;
    369       where = 0;
    370     }
    371 
    372     public int currentSegment (double[] coords)
    373     {
    374       int r;
    375 
    376       if (where < npoints)
    377         {
    378           coords[0] = xpoints[where];
    379           coords[1] = ypoints[where];
    380           r = (where == 0) ? SEG_MOVETO : SEG_LINETO;
    381           xform.transform (coords, 0, coords, 0, 1);
    382           ++where;
    383         }
    384       else
    385         r = SEG_CLOSE;
    386 
    387       return r;
    388     }
    389 
    390     public int currentSegment (float[] coords)
    391     {
    392       int r;
    393 
    394       if (where < npoints)
    395         {
    396           coords[0] = xpoints[where];
    397           coords[1] = ypoints[where];
    398           r = (where == 0) ? SEG_MOVETO : SEG_LINETO;
    399           xform.transform (coords, 0, coords, 0, 1);
    400         }
    401       else
    402         r = SEG_CLOSE;
    403 
    404       return r;
    405     }
    406 
    407     public int getWindingRule ()
    408     {
    409       return WIND_EVEN_ODD;
    410     }
    411 
    412     public boolean isDone ()
    413     {
    414       return where == npoints + 1;
    415     }
    416 
    417     public void next ()
    418     {
    419       ++where;
    420     }
    421   }
    422 }
     635      /** The current vertex of iteration. */
     636      private int vertex;
     637
     638      public int getWindingRule()
     639      {
     640        return WIND_EVEN_ODD;
     641      }
     642
     643      public boolean isDone()
     644      {
     645        return vertex > npoints;
     646      }
     647
     648      public void next()
     649      {
     650        vertex++;
     651      }
     652
     653      public int currentSegment(float[] coords)
     654      {
     655        if (vertex >= npoints)
     656          return SEG_CLOSE;
     657        coords[0] = xpoints[vertex];
     658        coords[1] = ypoints[vertex];
     659        if (transform != null)
     660          transform.transform(coords, 0, coords, 0, 1);
     661        return vertex == 0 ? SEG_MOVETO : SEG_LINETO;
     662      }
     663
     664      public int currentSegment(double[] coords)
     665      {
     666        if (vertex >= npoints)
     667          return SEG_CLOSE;
     668        coords[0] = xpoints[vertex];
     669        coords[1] = ypoints[vertex];
     670        if (transform != null)
     671          transform.transform(coords, 0, coords, 0, 1);
     672        return vertex == 0 ? SEG_MOVETO : SEG_LINETO;
     673      }
     674    };
     675  }
     676
     677  /**
     678   * Return an iterator along the flattened version of the shape boundary.
     679   * Since polygons are already flat, the flatness parameter is ignored, and
     680   * the resulting iterator only has SEG_MOVETO, SEG_LINETO and SEG_CLOSE
     681   * points. If the optional transform is provided, the iterator is
     682   * transformed accordingly. Each call returns a new object, independent
     683   * from others in use. This class is not threadsafe to begin with, so the
     684   * path iterator is not either.
     685   *
     686   * @param transform an optional transform to apply to the iterator
     687   * @param double the maximum distance for deviation from the real boundary
     688   * @return a new iterator over the boundary
     689   * @since 1.2
     690   */
     691  public PathIterator getPathIterator(AffineTransform transform,
     692                                      double flatness)
     693  {
     694    return getPathIterator(transform);
     695  }
     696
     697  /**
     698   * Helper for contains, which caches a condensed version of the polygon.
     699   * This condenses all colinear points, so that consecutive segments in
     700   * the condensed version always have different slope.
     701   *
     702   * @return true if the condensed polygon has area
     703   * @see #condensed
     704   * @see #contains(double, double)
     705   */
     706  private boolean condense()
     707  {
     708    if (npoints <= 2)
     709      return false;
     710    if (condensed != null)
     711      return condensed[0] > 2;
     712    condensed = new int[npoints * 2 + 1];
     713    int curx = xpoints[npoints - 1];
     714    int cury = ypoints[npoints - 1];
     715    double curslope = Double.NaN;
     716    int count = 0;
     717  outer:
     718    for (int i = 0; i < npoints; i++)
     719      {
     720        int priorx = curx;
     721        int priory = cury;
     722        double priorslope = curslope;
     723        curx = xpoints[i];
     724        cury = ypoints[i];
     725        while (curx == priorx && cury == priory)
     726          {
     727            if (++i == npoints)
     728              break outer;
     729            curx = xpoints[i];
     730            cury = ypoints[i];
     731          }
     732        curslope = (curx == priorx ? Double.POSITIVE_INFINITY
     733                    : (double) (cury - priory) / (curx - priorx));
     734        if (priorslope == curslope)
     735          {
     736            if (count > 1 && condensed[(count << 1) - 3] == curx
     737                && condensed[(count << 1) - 2] == cury)
     738              {
     739                count--;
     740                continue;
     741              }
     742          }
     743        else
     744          count++;
     745        condensed[(count << 1) - 1] = curx;
     746        condensed[count << 1] = cury;
     747      }
     748    condensed[0] = count;
     749    return count > 2;
     750  }
     751} // class Polygon
Note: See TracChangeset for help on using the changeset viewer.