516 lines
16 KiB
Java
516 lines
16 KiB
Java
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership.
|
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
* (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
/**
|
|
* @author Denis M. Kishenko
|
|
* @version $Revision$
|
|
*/
|
|
|
|
package java.awt;
|
|
|
|
import java.awt.Point;
|
|
import java.awt.Rectangle;
|
|
import java.awt.Shape;
|
|
import java.awt.geom.AffineTransform;
|
|
import java.awt.geom.PathIterator;
|
|
import java.awt.geom.Point2D;
|
|
import java.awt.geom.Rectangle2D;
|
|
import java.io.Serializable;
|
|
import java.util.NoSuchElementException;
|
|
|
|
import org.apache.harmony.awt.gl.*;
|
|
import org.apache.harmony.awt.internal.nls.Messages;
|
|
|
|
/**
|
|
* The Polygon class defines an closed area specified by n vertices and n edges.
|
|
* The coordinates of the vertices are specified by x, y arrays. The edges are
|
|
* the line segments from the point (x[i], y[i]) to the point (x[i+1], y[i+1]),
|
|
* for -1 < i < (n-1) plus the line segment from the point (x[n-1], y[n-1]) to
|
|
* the point (x[0], y[0]) point. The Polygon is empty if the number of vertices
|
|
* is zero.
|
|
*
|
|
* @since Android 1.0
|
|
*/
|
|
public class Polygon implements Shape, Serializable {
|
|
|
|
/**
|
|
* The Constant serialVersionUID.
|
|
*/
|
|
private static final long serialVersionUID = -6460061437900069969L;
|
|
|
|
/**
|
|
* The points buffer capacity.
|
|
*/
|
|
private static final int BUFFER_CAPACITY = 4;
|
|
|
|
/**
|
|
* The number of Polygon vertices.
|
|
*/
|
|
public int npoints;
|
|
|
|
/**
|
|
* The array of X coordinates of the vertices.
|
|
*/
|
|
public int[] xpoints;
|
|
|
|
/**
|
|
* The array of Y coordinates of the vertices.
|
|
*/
|
|
public int[] ypoints;
|
|
|
|
/**
|
|
* The smallest Rectangle that completely contains this Polygon.
|
|
*/
|
|
protected Rectangle bounds;
|
|
|
|
/*
|
|
* Polygon path iterator
|
|
*/
|
|
/**
|
|
* The internal Class Iterator.
|
|
*/
|
|
class Iterator implements PathIterator {
|
|
|
|
/**
|
|
* The source Polygon object.
|
|
*/
|
|
public Polygon p;
|
|
|
|
/**
|
|
* The path iterator transformation.
|
|
*/
|
|
public AffineTransform t;
|
|
|
|
/**
|
|
* The current segment index.
|
|
*/
|
|
public int index;
|
|
|
|
/**
|
|
* Constructs a new Polygon.Iterator for the given polygon and
|
|
* transformation
|
|
*
|
|
* @param at
|
|
* the AffineTransform object to apply rectangle path.
|
|
* @param p
|
|
* the p.
|
|
*/
|
|
public Iterator(AffineTransform at, Polygon p) {
|
|
this.p = p;
|
|
this.t = at;
|
|
if (p.npoints == 0) {
|
|
index = 1;
|
|
}
|
|
}
|
|
|
|
public int getWindingRule() {
|
|
return WIND_EVEN_ODD;
|
|
}
|
|
|
|
public boolean isDone() {
|
|
return index > p.npoints;
|
|
}
|
|
|
|
public void next() {
|
|
index++;
|
|
}
|
|
|
|
public int currentSegment(double[] coords) {
|
|
if (isDone()) {
|
|
// awt.110=Iterator out of bounds
|
|
throw new NoSuchElementException(Messages.getString("awt.110")); //$NON-NLS-1$
|
|
}
|
|
if (index == p.npoints) {
|
|
return SEG_CLOSE;
|
|
}
|
|
coords[0] = p.xpoints[index];
|
|
coords[1] = p.ypoints[index];
|
|
if (t != null) {
|
|
t.transform(coords, 0, coords, 0, 1);
|
|
}
|
|
return index == 0 ? SEG_MOVETO : SEG_LINETO;
|
|
}
|
|
|
|
public int currentSegment(float[] coords) {
|
|
if (isDone()) {
|
|
// awt.110=Iterator out of bounds
|
|
throw new NoSuchElementException(Messages.getString("awt.110")); //$NON-NLS-1$
|
|
}
|
|
if (index == p.npoints) {
|
|
return SEG_CLOSE;
|
|
}
|
|
coords[0] = p.xpoints[index];
|
|
coords[1] = p.ypoints[index];
|
|
if (t != null) {
|
|
t.transform(coords, 0, coords, 0, 1);
|
|
}
|
|
return index == 0 ? SEG_MOVETO : SEG_LINETO;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Instantiates a new empty polygon.
|
|
*/
|
|
public Polygon() {
|
|
xpoints = new int[BUFFER_CAPACITY];
|
|
ypoints = new int[BUFFER_CAPACITY];
|
|
}
|
|
|
|
/**
|
|
* Instantiates a new polygon with the specified number of vertices, and the
|
|
* given arrays of x, y vertex coordinates. The length of each coordinate
|
|
* array may not be less than the specified number of vertices but may be
|
|
* greater. Only the first n elements are used from each coordinate array.
|
|
*
|
|
* @param xpoints
|
|
* the array of X vertex coordinates.
|
|
* @param ypoints
|
|
* the array of Y vertex coordinates.
|
|
* @param npoints
|
|
* the number vertices of the polygon.
|
|
* @throws IndexOutOfBoundsException
|
|
* if the length of xpoints or ypoints is less than n.
|
|
* @throws NegativeArraySizeException
|
|
* if n is negative.
|
|
*/
|
|
public Polygon(int[] xpoints, int[] ypoints, int npoints) {
|
|
if (npoints > xpoints.length || npoints > ypoints.length) {
|
|
// awt.111=Parameter npoints is greater than array length
|
|
throw new IndexOutOfBoundsException(Messages.getString("awt.111")); //$NON-NLS-1$
|
|
}
|
|
if (npoints < 0) {
|
|
// awt.112=Negative number of points
|
|
throw new NegativeArraySizeException(Messages.getString("awt.112")); //$NON-NLS-1$
|
|
}
|
|
this.npoints = npoints;
|
|
this.xpoints = new int[npoints];
|
|
this.ypoints = new int[npoints];
|
|
System.arraycopy(xpoints, 0, this.xpoints, 0, npoints);
|
|
System.arraycopy(ypoints, 0, this.ypoints, 0, npoints);
|
|
}
|
|
|
|
/**
|
|
* Resets the current Polygon to an empty Polygon. More precisely, the
|
|
* number of Polygon vertices is set to zero, but x, y coordinates arrays
|
|
* are not affected.
|
|
*/
|
|
public void reset() {
|
|
npoints = 0;
|
|
bounds = null;
|
|
}
|
|
|
|
/**
|
|
* Invalidates the data that depends on the vertex coordinates. This method
|
|
* should be called after direct manipulations of the x, y vertex
|
|
* coordinates arrays to avoid unpredictable results of methods which rely
|
|
* on the bounding box.
|
|
*/
|
|
public void invalidate() {
|
|
bounds = null;
|
|
}
|
|
|
|
/**
|
|
* Adds the point to the Polygon and updates the bounding box accordingly.
|
|
*
|
|
* @param px
|
|
* the X coordinate of the added vertex.
|
|
* @param py
|
|
* the Y coordinate of the added vertex.
|
|
*/
|
|
public void addPoint(int px, int py) {
|
|
if (npoints == xpoints.length) {
|
|
int[] tmp;
|
|
|
|
tmp = new int[xpoints.length + BUFFER_CAPACITY];
|
|
System.arraycopy(xpoints, 0, tmp, 0, xpoints.length);
|
|
xpoints = tmp;
|
|
|
|
tmp = new int[ypoints.length + BUFFER_CAPACITY];
|
|
System.arraycopy(ypoints, 0, tmp, 0, ypoints.length);
|
|
ypoints = tmp;
|
|
}
|
|
|
|
xpoints[npoints] = px;
|
|
ypoints[npoints] = py;
|
|
npoints++;
|
|
|
|
if (bounds != null) {
|
|
bounds.setFrameFromDiagonal(Math.min(bounds.getMinX(), px), Math.min(bounds.getMinY(),
|
|
py), Math.max(bounds.getMaxX(), px), Math.max(bounds.getMaxY(), py));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the bounding rectangle of the Polygon. The bounding rectangle is the
|
|
* smallest rectangle which contains the Polygon.
|
|
*
|
|
* @return the bounding rectangle of the Polygon.
|
|
* @see java.awt.Shape#getBounds()
|
|
*/
|
|
public Rectangle getBounds() {
|
|
if (bounds != null) {
|
|
return bounds;
|
|
}
|
|
if (npoints == 0) {
|
|
return new Rectangle();
|
|
}
|
|
|
|
int bx1 = xpoints[0];
|
|
int by1 = ypoints[0];
|
|
int bx2 = bx1;
|
|
int by2 = by1;
|
|
|
|
for (int i = 1; i < npoints; i++) {
|
|
int x = xpoints[i];
|
|
int y = ypoints[i];
|
|
if (x < bx1) {
|
|
bx1 = x;
|
|
} else if (x > bx2) {
|
|
bx2 = x;
|
|
}
|
|
if (y < by1) {
|
|
by1 = y;
|
|
} else if (y > by2) {
|
|
by2 = y;
|
|
}
|
|
}
|
|
|
|
return bounds = new Rectangle(bx1, by1, bx2 - bx1, by2 - by1);
|
|
}
|
|
|
|
/**
|
|
* Gets the bounding rectangle of the Polygon. The bounding rectangle is the
|
|
* smallest rectangle which contains the Polygon.
|
|
*
|
|
* @return the bounding rectangle of the Polygon.
|
|
* @deprecated Use getBounds() method.
|
|
*/
|
|
@Deprecated
|
|
public Rectangle getBoundingBox() {
|
|
return getBounds();
|
|
}
|
|
|
|
/**
|
|
* Gets the Rectangle2D which represents Polygon bounds. The bounding
|
|
* rectangle is the smallest rectangle which contains the Polygon.
|
|
*
|
|
* @return the bounding rectangle of the Polygon.
|
|
* @see java.awt.Shape#getBounds2D()
|
|
*/
|
|
public Rectangle2D getBounds2D() {
|
|
return getBounds().getBounds2D();
|
|
}
|
|
|
|
/**
|
|
* Translates all vertices of Polygon the specified distances along X, Y
|
|
* axis.
|
|
*
|
|
* @param mx
|
|
* the distance to translate horizontally.
|
|
* @param my
|
|
* the distance to translate vertically.
|
|
*/
|
|
public void translate(int mx, int my) {
|
|
for (int i = 0; i < npoints; i++) {
|
|
xpoints[i] += mx;
|
|
ypoints[i] += my;
|
|
}
|
|
if (bounds != null) {
|
|
bounds.translate(mx, my);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks whether or not the point given by the coordinates x, y lies inside
|
|
* the Polygon.
|
|
*
|
|
* @param x
|
|
* the X coordinate of the point to check.
|
|
* @param y
|
|
* the Y coordinate of the point to check.
|
|
* @return true, if the specified point lies inside the Polygon, false
|
|
* otherwise.
|
|
* @deprecated Use contains(int, int) method.
|
|
*/
|
|
@Deprecated
|
|
public boolean inside(int x, int y) {
|
|
return contains((double)x, (double)y);
|
|
}
|
|
|
|
/**
|
|
* Checks whether or not the point given by the coordinates x, y lies inside
|
|
* the Polygon.
|
|
*
|
|
* @param x
|
|
* the X coordinate of the point to check.
|
|
* @param y
|
|
* the Y coordinate of the point to check.
|
|
* @return true, if the specified point lies inside the Polygon, false
|
|
* otherwise.
|
|
*/
|
|
public boolean contains(int x, int y) {
|
|
return contains((double)x, (double)y);
|
|
}
|
|
|
|
/**
|
|
* Checks whether or not the point with specified double coordinates lies
|
|
* inside the Polygon.
|
|
*
|
|
* @param x
|
|
* the X coordinate of the point to check.
|
|
* @param y
|
|
* the Y coordinate of the point to check.
|
|
* @return true, if the point given by the double coordinates lies inside
|
|
* the Polygon, false otherwise.
|
|
* @see java.awt.Shape#contains(double, double)
|
|
*/
|
|
public boolean contains(double x, double y) {
|
|
return Crossing.isInsideEvenOdd(Crossing.crossShape(this, x, y));
|
|
}
|
|
|
|
/**
|
|
* Checks whether or not the rectangle determined by the parameters [x, y,
|
|
* width, height] lies inside the Polygon.
|
|
*
|
|
* @param x
|
|
* the X coordinate of the rectangles's left upper corner as a
|
|
* double.
|
|
* @param y
|
|
* the Y coordinate of the rectangles's left upper corner as a
|
|
* double.
|
|
* @param width
|
|
* the width of rectangle as a double.
|
|
* @param height
|
|
* the height of rectangle as a double.
|
|
* @return true, if the specified rectangle lies inside the Polygon, false
|
|
* otherwise.
|
|
* @see java.awt.Shape#contains(double, double, double, double)
|
|
*/
|
|
public boolean contains(double x, double y, double width, double height) {
|
|
int cross = Crossing.intersectShape(this, x, y, width, height);
|
|
return cross != Crossing.CROSSING && Crossing.isInsideEvenOdd(cross);
|
|
}
|
|
|
|
/**
|
|
* Checks whether or not the rectangle determined by the parameters [x, y,
|
|
* width, height] intersects the interior of the Polygon.
|
|
*
|
|
* @param x
|
|
* the X coordinate of the rectangles's left upper corner as a
|
|
* double.
|
|
* @param y
|
|
* the Y coordinate of the rectangles's left upper corner as a
|
|
* double.
|
|
* @param width
|
|
* the width of rectangle as a double.
|
|
* @param height
|
|
* the height of rectangle as a double.
|
|
* @return true, if the specified rectangle intersects the interior of the
|
|
* Polygon, false otherwise.
|
|
* @see java.awt.Shape#intersects(double, double, double, double)
|
|
*/
|
|
public boolean intersects(double x, double y, double width, double height) {
|
|
int cross = Crossing.intersectShape(this, x, y, width, height);
|
|
return cross == Crossing.CROSSING || Crossing.isInsideEvenOdd(cross);
|
|
}
|
|
|
|
/**
|
|
* Checks whether or not the specified rectangle lies inside the Polygon.
|
|
*
|
|
* @param rect
|
|
* the Rectangle2D object.
|
|
* @return true, if the specified rectangle lies inside the Polygon, false
|
|
* otherwise.
|
|
* @see java.awt.Shape#contains(java.awt.geom.Rectangle2D)
|
|
*/
|
|
public boolean contains(Rectangle2D rect) {
|
|
return contains(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
|
|
}
|
|
|
|
/**
|
|
* Checks whether or not the specified Point lies inside the Polygon.
|
|
*
|
|
* @param point
|
|
* the Point object.
|
|
* @return true, if the specified Point lies inside the Polygon, false
|
|
* otherwise.
|
|
*/
|
|
public boolean contains(Point point) {
|
|
return contains(point.getX(), point.getY());
|
|
}
|
|
|
|
/**
|
|
* Checks whether or not the specified Point2D lies inside the Polygon.
|
|
*
|
|
* @param point
|
|
* the Point2D object.
|
|
* @return true, if the specified Point2D lies inside the Polygon, false
|
|
* otherwise.
|
|
* @see java.awt.Shape#contains(java.awt.geom.Point2D)
|
|
*/
|
|
public boolean contains(Point2D point) {
|
|
return contains(point.getX(), point.getY());
|
|
}
|
|
|
|
/**
|
|
* Checks whether or not the interior of rectangle specified by the
|
|
* Rectangle2D object intersects the interior of the Polygon.
|
|
*
|
|
* @param rect
|
|
* the Rectangle2D object.
|
|
* @return true, if the Rectangle2D intersects the interior of the Polygon,
|
|
* false otherwise.
|
|
* @see java.awt.Shape#intersects(java.awt.geom.Rectangle2D)
|
|
*/
|
|
public boolean intersects(Rectangle2D rect) {
|
|
return intersects(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
|
|
}
|
|
|
|
/**
|
|
* Gets the PathIterator object which gives the coordinates of the polygon,
|
|
* transformed according to the specified AffineTransform.
|
|
*
|
|
* @param t
|
|
* the specified AffineTransform object or null.
|
|
* @return PathIterator object for the Polygon.
|
|
* @see java.awt.Shape#getPathIterator(java.awt.geom.AffineTransform)
|
|
*/
|
|
public PathIterator getPathIterator(AffineTransform t) {
|
|
return new Iterator(t, this);
|
|
}
|
|
|
|
/**
|
|
* Gets the PathIterator object which gives the coordinates of the polygon,
|
|
* transformed according to the specified AffineTransform. The flatness
|
|
* parameter is ignored.
|
|
*
|
|
* @param t
|
|
* the specified AffineTransform object or null.
|
|
* @param flatness
|
|
* the maximum number of the control points for a given curve
|
|
* which varies from colinear before a subdivided curve is
|
|
* replaced by a straight line connecting the endpoints. This
|
|
* parameter is ignored for the Polygon class.
|
|
* @return PathIterator object for the Polygon.
|
|
* @see java.awt.Shape#getPathIterator(java.awt.geom.AffineTransform,
|
|
* double)
|
|
*/
|
|
public PathIterator getPathIterator(AffineTransform t, double flatness) {
|
|
return new Iterator(t, this);
|
|
}
|
|
|
|
}
|