/************************************************************************** * Copyright (c) 2001, 2002, 2003 by Punch Telematix. All rights reserved. * * * * Redistribution and use in source and binary forms, with or without * * modification, are permitted provided that the following conditions * * are met: * * 1. Redistributions of source code must retain the above copyright * * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * * notice, this list of conditions and the following disclaimer in the * * documentation and/or other materials provided with the distribution. * * 3. Neither the name of Punch Telematix nor the names of * * other contributors may be used to endorse or promote products * * derived from this software without specific prior written permission.* * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL PUNCH TELEMATIX OR OTHER CONTRIBUTORS BE LIABLE * * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **************************************************************************/ package java.awt; /****************************************************************************************************************************************/ /** * Polygon class * Note that the actual drawing of the polygon is done in the functions drawPolygon and fillPolygon of java.awt.Graphics */ /****************************************************************************************************************************************/ public class Polygon implements Shape, java.io.Serializable { private static final long serialVersionUID = -6460061437900069969L; /** Protected variable fectangle bounds: accessible through getBounds */ protected Rectangle bounds; /** * Public variables */ public int xpoints[]; public int ypoints[]; public int npoints; /** Access Polygon.bounds. For more security send a copy of the value to avoid manipulation of the boundaries from outside */ public Rectangle getBounds() {return new Rectangle(bounds);} /** deprecated */ public Rectangle getBoundingBox() {return new Rectangle(bounds);} private boolean[] isPeak; /****************************************************************************************************************************************/ /** * full constructor */ public Polygon(int[] x, int[] y, int size) { if (size < 0) throw new NegativeArraySizeException(); else if (size ==0){ npoints=0; xpoints = new int[1]; ypoints = new int[1]; bounds = new Rectangle(); isPeak = new boolean[1]; } else if (size ==1){ npoints=0; xpoints = new int[1]; ypoints = new int[1]; bounds = new Rectangle(); if(x.length>=1) { xpoints[0]=x[0]; bounds.x=x[0]; } else xpoints[0]=0; if(y.length>=1) { ypoints[0]=y[0]; bounds.y=y[0]; } else ypoints[0]=0; isPeak = new boolean[1]; isPeak[0]=true; } else { //variables npoints=size; xpoints = new int[size]; ypoints = new int[size]; isPeak = new boolean[size]; bounds = new Rectangle(x[0],y[0],x[0],y[0]); xpoints[0]=x[0]; ypoints[0]=y[0]; //assign x-values and calculate horizontal boundaries for(int i=1; i<npoints && i<x.length; i++) { xpoints[i]=x[i]; if(x[i]<bounds.x) bounds.x = x[i]; else if(x[i]>bounds.width) bounds.width = x[i]; } //in calculations above, we used 'width' as an absolute position for simplicity => convert to true width bounds.width-=bounds.x; //assign y-values and calculate vertical boundaries for(int i=1; i<npoints && i<y.length; i++) { ypoints[i]=y[i]; if(y[i]<bounds.y) bounds.y= y[i]; else if(y[i]>bounds.height) bounds.height = y[i]; } //idem as above: 'height' value to true height bounds.height-=bounds.y; // calculate peeks size--; //int lastsize =npoint-1; //first point isPeak[0]= ((ypoints[0]<ypoints[size] && ypoints[0]<ypoints[1]) || (ypoints[0]>ypoints[size] && ypoints[0]>ypoints[1])); //next&previous are both bigger or both smaller //in between for(int i=1; i<size; i++) isPeak[i]= ((ypoints[i]<ypoints[i-1] && ypoints[i]<ypoints[i+1]) || (ypoints[i]>ypoints[i-1] && ypoints[i]>ypoints[i+1])); //last point isPeak[size]=((ypoints[size]<ypoints[size-1] && ypoints[size]<ypoints[0])||(ypoints[size]>ypoints[size-1] && ypoints[size]>ypoints[0])); } } /** * Default constructor */ public Polygon() { this(null,null,0); } /****************************************************************************************************************************************/ /** * Add a point to the polygon point array */ public void addPoint(int x, int y) { if(npoints==0) { //xpoints = new int[1]; //already done above xpoints[0]=x; //ypoints = new int[1]; //already done above ypoints[0]=y; //isPeak = new boolean[1]; isPeak[0]=true; bounds.setBounds(x,y,0,0); npoints=1; } else if(npoints==1) { //bounds.x= xpoints[0] //already done above //bounds.y= ypoints[0] //already done above xpoints = new int[2]; xpoints[0]=bounds.x; xpoints[1]=x; ypoints = new int[2]; ypoints[0]=bounds.y; ypoints[1]=y; isPeak = new boolean[2]; isPeak[0]=true; isPeak[1]=true; //bounds if(x<bounds.x) { bounds.width=bounds.x-x; bounds.x=x; } else bounds.width=x-bounds.x; if(y<bounds.y) { bounds.height=bounds.y-y; bounds.y=y; } else bounds.height=y-bounds.y; npoints=2; } else { //new arrays of size npoints+1 int[] swapx = new int[npoints + 1]; int[] swapy = new int[npoints + 1]; boolean[] peaks = new boolean[npoints + 1]; //bounds if(x<bounds.x) { bounds.width=bounds.width+bounds.x-x; bounds.x=x; } else if(x>(bounds.x+bounds.width) ) bounds.width=x-bounds.x; if(y<bounds.y) { bounds.height=bounds.width+bounds.y-y; bounds.y=y; } else if(y>(bounds.y+bounds.height) ) bounds.height=y-bounds.y; // copy values into new array for(int i=0;i<npoints;i++) { swapx[i]=xpoints[i]; swapy[i]=ypoints[i]; peaks[i]=isPeak[i]; } //add new values and swap swapx[npoints]=x; swapy[npoints]=y; // calculate if... new point makes previous last point now become a peek peaks[npoints-1]=((swapy[npoints-2]>swapy[npoints-1] && y>swapy[npoints-1])||(swapy[npoints-2]<swapy[npoints-1] && y<swapy[npoints-1])); // calculate if... new point is a peek in itselves peaks[npoints]=((y>swapy[npoints-1] && y>swapy[0]) || (y<swapy[npoints-1] && y<swapy[0])); // calculate if... new point makes first point now become a peek peaks[0]=((swapy[1]>swapy[0] && y>swapy[0]) || (swapy[1]<swapy[0] && y<swapy[0])); xpoints = swapx; ypoints = swapy; isPeak = peaks; npoints++; } //System.out.println("added ("+x+","+y+"), new size "+npoints+", new bounds "+bounds); } /****************************************************************************************************************************************/ /** * Translate all points by the given amount */ public void translate(int offsetx, int offsety) { for (int i = 0; i < npoints; i++) { xpoints[i] += offsetx; ypoints[i] += offsety; } bounds.translate(offsetx, offsety); } /****************************************************************************************************************************************/ /** * Check if given point inside polygon * TODO: call native check in analogy to g.fillPolygon algorithm */ public boolean contains(Point p) { return contains(p.x, p.y); } public boolean contains(int x, int y) { if(!bounds.contains(x,y)) return false; //else 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 inside(int x, int y) { return contains(x, y); } public String toString() { return getClass().getName() +" number of points: " + npoints; } }