/*
* 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
* Dumbed-down for JavaME by CG 20121006
*/
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;
public class Polygon implements Shape, Serializable {
private static final long serialVersionUID = -6460061437900069969L;
/**
* The points buffer capacity
*/
private static final int BUFFER_CAPACITY = 4;
public int npoints;
public int[] xpoints;
public int[] ypoints;
protected Rectangle bounds;
private boolean[] isPeak;
/*
* Polygon path 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 given polygon and transformation
* @param l - the source Line2D object
* @param at - the AffineTransform object to apply rectangle path
*/
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("Iterator out of bounds");
}
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("Iterator out of bounds");
}
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 Polygon() {
xpoints = new int[BUFFER_CAPACITY];
ypoints = new int[BUFFER_CAPACITY];
}
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("Parameter npoints is greater than array length");
}
if (npoints < 0) {
// awt.112=Negative number of points
throw new NegativeArraySizeException("Negative number of points");
}
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);
}
public void reset() {
npoints = 0;
bounds = null;
isPeak = null;
}
public void invalidate() {
bounds = null;
isPeak = null;
}
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++;
bounds = null;
isPeak = null;
}
public Rectangle getBounds() {
if (bounds != null) {
return bounds;
}
if (npoints == 0) {
return new Rectangle();
}
isPeak = new boolean[npoints];
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;
}
}
int last = npoints - 1;
// first point
isPeak[0] = (ypoints[0]<ypoints[last] && ypoints[0]<ypoints[1]) || (ypoints[0]>ypoints[last] && ypoints[0]>ypoints[1]);
for (int i=1; i<last; i++) {
isPeak[i] = ((ypoints[i]<ypoints[i-1] && ypoints[i]<ypoints[i+1]) || (ypoints[i]>ypoints[i-1] && ypoints[i]>ypoints[i+1]));
}
isPeak[last] = ((ypoints[last]<ypoints[last-1] && ypoints[last]<ypoints[0])||(ypoints[last]>ypoints[last-1] && ypoints[last]>ypoints[0]));
return bounds = new Rectangle(bx1, by1, bx2 - bx1, by2 - by1);
}
/**
* @deprecated
*/
public Rectangle getBoundingBox() {
return getBounds();
}
public Rectangle2D getBounds2D() {
return getBounds().getBounds2D();
}
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);
}
}
/**
* @deprecated
*/
public boolean inside(int x, int y) {
return contains((double) x, (double) y);
}
public boolean contains(int x, int y) {
return contains((double) x, (double) y);
}
public boolean contains(double x, double y) {
// Harmony code
// return Crossing.isInsideEvenOdd(Crossing.crossShape(this, x, y));
// Based on Rudolph
if (bounds == null) {
getBounds();
}
if (!bounds.contains(x,y)) {
return false;
}
int intersections=0;
int last=npoints-1; //for ease of calculation
// count intersections bigger then x0
// line from <this> to next point
for(int i=0; i<last;i++) {
if ((y==ypoints[i] && !isPeak[i] && xpoints[i]>x)
|| (ypoints[i]<y && ypoints[i+1]>y && x<(xpoints[i]+(xpoints[i+1]-xpoints[i])*(y-ypoints[i])/(ypoints[i+1]-ypoints[i])) )
|| (ypoints[i]>y && ypoints[i+1]<y && x<(xpoints[i]+(xpoints[i+1]-xpoints[i])*(y-ypoints[i])/(ypoints[i+1]-ypoints[i])) ) )
intersections++;
}
// last line from last to first point
if ((y==ypoints[last] && !isPeak[last] && xpoints[last]>x)
||(ypoints[last]<y && ypoints[0]>y && x<(xpoints[last]+(xpoints[0]-xpoints[last])*(y-ypoints[last])/(ypoints[0]-ypoints[last])) )
||(ypoints[last]>y && ypoints[0]<y && x<(xpoints[last]+(xpoints[0]-xpoints[last])*(y-ypoints[last])/(ypoints[0]-ypoints[last]))))
intersections++;
return (intersections%2>0);
}
public boolean contains(double x, double y, double width, double height) {
// TODO
// int cross = Crossing.intersectShape(this, x, y, width, height);
// return cross != Crossing.CROSSING && Crossing.isInsideEvenOdd(cross);
throw new RuntimeException("Not yet implemented");
}
public boolean intersects(double x, double y, double width, double height) {
// TODO
// int cross = Crossing.intersectShape(this, x, y, width, height);
// return cross == Crossing.CROSSING || Crossing.isInsideEvenOdd(cross);
throw new RuntimeException("Not yet implemented");
}
public boolean contains(Rectangle2D rect) {
return contains(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
}
public boolean contains(Point point) {
return contains(point.getX(), point.getY());
}
public boolean contains(Point2D point) {
return contains(point.getX(), point.getY());
}
public boolean intersects(Rectangle2D rect) {
return intersects(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
}
public PathIterator getPathIterator(AffineTransform t) {
return new Iterator(t, this);
}
public PathIterator getPathIterator(AffineTransform t, double flatness) {
return new Iterator(t, this);
}
}