package ij.process;
import java.awt.Rectangle;
import java.awt.Polygon;
import java.awt.geom.Rectangle2D;
public class FloatPolygon {
private Rectangle bounds;
private float minX, minY, maxX, maxY;
public int npoints;
public float xpoints[];
public float ypoints[];
public FloatPolygon() {
npoints = 0;
xpoints = new float[10];
ypoints = new float[10];
}
public FloatPolygon(float xpoints[], float ypoints[]) {
if (xpoints.length!=ypoints.length)
throw new IllegalArgumentException("xpoints.length!=ypoints.length");
this.npoints = xpoints.length;
this.xpoints = xpoints;
this.ypoints = ypoints;
}
public FloatPolygon(float xpoints[], float ypoints[], int npoints) {
this.npoints = npoints;
this.xpoints = xpoints;
this.ypoints = ypoints;
}
public boolean contains(double x, double y) {
boolean inside = false;
for (int i=0, j=npoints-1; i<npoints; j=i++) {
if (((ypoints[i]>=y)!=(ypoints[j]>=y)) &&
(x>((double)xpoints[j]-xpoints[i])*((double)y-ypoints[i])/((double)ypoints[j]-ypoints[i])+(double)xpoints[i]))
inside = !inside;
}
return inside;
}
public boolean contains(float x, float y) {
return contains((double)x, (double)y);
}
public Rectangle getBounds() {
if (npoints==0)
return new Rectangle();
if (bounds==null)
calculateBounds(xpoints, ypoints, npoints);
return bounds.getBounds();
}
public Rectangle2D.Double getFloatBounds() {
if (npoints==0)
return new Rectangle2D.Double();
if (bounds==null)
calculateBounds(xpoints, ypoints, npoints);
return new Rectangle2D.Double(minX, minY, maxX-minX, maxY-minY);
}
void calculateBounds(float[] xpoints, float[] ypoints, int npoints) {
minX = Float.MAX_VALUE;
minY = Float.MAX_VALUE;
maxX = Float.MIN_VALUE;
maxY = Float.MIN_VALUE;
for (int i=0; i<npoints; i++) {
float x = xpoints[i];
minX = Math.min(minX, x);
maxX = Math.max(maxX, x);
float y = ypoints[i];
minY = Math.min(minY, y);
maxY = Math.max(maxY, y);
}
int iMinX = (int)Math.floor(minX);
int iMinY = (int)Math.floor(minY);
bounds = new Rectangle(iMinX, iMinY, (int)(maxX-iMinX+0.5), (int)(maxY-iMinY+0.5));
}
public void addPoint(float x, float y) {
if (npoints==xpoints.length) {
float[] tmp = new float[npoints*2];
System.arraycopy(xpoints, 0, tmp, 0, npoints);
xpoints = tmp;
tmp = new float[npoints*2];
System.arraycopy(ypoints, 0, tmp, 0, npoints);
ypoints = tmp;
}
xpoints[npoints] = x;
ypoints[npoints] = y;
npoints++;
bounds = null;
}
public void addPoint(double x, double y) {
addPoint((float)x, (float)y);
}
public FloatPolygon duplicate() {
int n = this.npoints;
float[] xpoints = new float[n];
float[] ypoints = new float[n];
System.arraycopy(this.xpoints, 0, xpoints, 0, n);
System.arraycopy(this.ypoints, 0, ypoints, 0, n);
return new FloatPolygon(xpoints, ypoints, n);
}
public double getLength(boolean isLine) {
double dx, dy;
double length = 0.0;
for (int i=0; i<(npoints-1); i++) {
dx = xpoints[i+1]-xpoints[i];
dy = ypoints[i+1]-ypoints[i];
length += Math.sqrt(dx*dx+dy*dy);
}
if (!isLine) {
dx = xpoints[0]-xpoints[npoints-1];
dy = ypoints[0]-ypoints[npoints-1];
length += Math.sqrt(dx*dx+dy*dy);
}
return length;
}
public FloatPolygon getConvexHull() {
float[] xx = new float[npoints];
float[] yy = new float[npoints];
int n2 = 0;
float smallestY = Float.MAX_VALUE;
for (int i=0; i<npoints; i++) {
float y = ypoints[i];
if (y<smallestY)
smallestY = y;
}
float smallestX = Float.MAX_VALUE;
int p1 = 0; for (int i=0; i<npoints; i++) {
float x = xpoints[i];
float y = ypoints[i];
if (y==smallestY && x<smallestX) {
smallestX = x;
p1 = i;
}
}
int pstart = p1; int count = 0;
do {
double x1 = xpoints[p1];
double y1 = ypoints[p1];
int p2 = p1;
double x2=0, y2=0;
do {
p2++; if (p2==npoints) p2 = 0;
if (p2 == p1) break; x2 = xpoints[p2]; y2 = ypoints[p2];
} while (x2 == x1 && y2 == y1);
int p3 = p2+1; if (p3==npoints) p3 = 0;
if (p2 != p1) do {
double x3 = xpoints[p3];
double y3 = ypoints[p3];
double determinate = x1*(y2-y3)-y1*(x2-x3)+(y3*x2-y2*x3);
boolean collinearAndFurther = false;
if (determinate == 0 && p3 != p2) { double d2sqr = sqr(x2-x1) + sqr(y2-y1);
double d3sqr = sqr(x3-x1) + sqr(y3-y1);
collinearAndFurther = d3sqr > d2sqr;
}
if (determinate > 0 || collinearAndFurther) {
x2=x3; y2=y3; p2=p3; }
p3 ++; if (p3==npoints) p3 = 0;
} while (p3 != p1);
xx[n2] = (float)x1; yy[n2] = (float)y1;
n2++;
if (p2 == p1) break; p1 = p2;
if (n2 > 1 && xpoints[p1]==xx[0] && ypoints[p1]==yy[0]) break; } while (p1!=pstart);
return new FloatPolygon(xx, yy, n2);
}
public synchronized void translate(double x, double y) {
float fx = (float)x;
float fy = (float)y;
for (int i=0; i<npoints; i++) {
xpoints[i] += fx;
ypoints[i] += fy;
}
}
private double sqr(double x) {return x*x;}
private double crossProduct(double x1, double y1, double x2, double y2) {
return (double)x1*y2 - (double)x2*y1;
}
public String toString() {
return "FloatPolygon[npoints="+npoints+"]";
}
}