View Javadoc

1   /*
2    *  MicroEmulator
3    *  GeoTools java GIS tookit (c) The Centre for Computational Geography 2002
4    *
5    *  This library is free software; you can redistribute it and/or
6    *  modify it under the terms of the GNU Lesser General Public
7    *  License as published by the Free Software Foundation; either
8    *  version 2.1 of the License, or (at your option) any later version.
9    *
10   *  This library is distributed in the hope that it will be useful,
11   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   *  Lesser General Public License for more details.
14   *
15   *  You should have received a copy of the GNU Lesser General Public
16   *  License along with this library; if not, write to the Free Software
17   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   */
19  
20  package org.microemu.device.impl;
21  
22  /**
23   * This class is intended for storing georaphical polygons such as boundary data
24   * for wards, coastlines etc.<p>
25   *
26   * Extracted from uk.ac.leeds.ccg.geotools.GeoPolygon
27   *
28   * @author James Macgill
29   * @author Mathieu Van Loon - getPointsAsArrayX, getPointsAsArrayY, dropVector
30   * @since 0.5.0
31   */
32  public class Polygon extends Shape {
33  
34  	/**
35  	 * Number of points in polygon.
36  	 */
37  	public int npoints;
38  
39  	/**
40  	 * Array of points.
41  	 */
42  	public int xpoints[];
43  
44  	/**
45  	 * Array of points.
46  	 */
47  	public int[] ypoints;
48  
49  	private Rectangle bounds = new Rectangle();
50  
51  	/**
52  	 * Create an empty polygon.
53  	 */
54  	public Polygon() {
55  	}
56  
57  	/**
58  	 * Construct a polygon with full details.
59  	 *
60  	 * @param id Polygon ID.
61  	 * @param xcent X-coordinate of centroid.
62  	 * @param ycent Y-coordinate of centroid.
63  	 * @param xpoints Array of x values (npoints in size).
64  	 * @param ypoints Array of y values (npoints in size).
65  	 * @param npoints Number of points.
66  	 */
67  	public Polygon(int[] xpoints, int[] ypoints, int npoints) {
68  
69  		this.xpoints = new int[npoints];
70  		this.ypoints = new int[npoints];
71  		this.npoints = npoints;
72  		//Add a try here to catch failed array copy
73  		System.arraycopy(xpoints, 0, this.xpoints, 0, npoints);
74  		System.arraycopy(ypoints, 0, this.ypoints, 0, npoints);
75  
76  		for (int i = 0; i < npoints; i++) {
77  			bounds.add(xpoints[i], ypoints[i]);
78  		}
79  	}
80  
81  	/**
82  	 * Construct a GeoPolygon based on an existing GeoPolygon.
83  	 *
84  	 * @param poly GeoPolygon to clone.
85  	 */
86  	public Polygon(Polygon poly) {
87  		this(poly.xpoints, poly.ypoints, poly.npoints);
88  	}
89  
90  	/**
91  	 * Add a vertex to the polygon.
92  	 *
93  	 * @param x X-coordinate of point to add.
94  	 * @param y Y-coordinate of point to add.
95  	 */
96  	public void addPoint(int x, int y) {
97  		if (npoints > 0) {
98  			int xtemp[];
99  			int ytemp[];
100 			xtemp = xpoints;
101 			ytemp = ypoints;
102 			xpoints = new int[npoints + 1];
103 
104 			System.arraycopy(xtemp, 0, xpoints, 0, npoints);
105 			xtemp = null;
106 			ypoints = new int[npoints + 1];
107 			System.arraycopy(ytemp, 0, ypoints, 0, npoints);
108 			ytemp = null;
109 		} else {
110 			xpoints = new int[1];
111 			ypoints = new int[1];
112 		}
113 		npoints++;
114 		xpoints[npoints - 1] = x;//-1 to account for 0 array indexing
115 		ypoints[npoints - 1] = y;
116 
117 		bounds.add(x, y);
118 	}
119 
120 	public Rectangle getBounds() {
121 		return bounds;
122 	}
123 
124 	/**
125      * Tests to see if a point is contained by this polygon.
126      * 
127      * @param p
128      *            The GeoPoint to test.
129      * @return boolean True if point is contained by this polygon.
130      */
131 	public boolean contains(int x, int y) {
132 
133 		/*if(!getMultiPartBounds().contains(p)){
134 		 return false;
135 		 }*/
136 
137 		if (getBounds().contains(x, y)) {
138 
139 //          Tested and work just fine
140 			boolean c = false;
141 			for (int i = 0, j = npoints - 1; i < npoints; j = i++) {
142 				if ((((ypoints[i] <= y) && (y < ypoints[j])) || ((ypoints[j] <= y) && (y < ypoints[i])))
143 						&& (x < ((double)(xpoints[j] - xpoints[i]) * (y - ypoints[i])) / (ypoints[j] - ypoints[i]) + xpoints[i])) {
144 					c = !c;
145 				}
146 			}
147 			return c;
148 			
149 //           This code does not work as expected even after fixes for double
150 //
151 //			/* Start andys code */
152 //			int number_of_lines_crossed = 0; // holds lines intersecting with 
153 //			number_of_lines_crossed = 0; // set lines crossed = 0 for each polygon
154 //			// lets us know which part start we're looking for	   
155 //			for (int i = 0; i < npoints - 1; i++) {
156 //				//GeoPoint A = new GeoPoint();
157 //				//GeoPoint B = new GeoPoint();        
158 //				//A.y = ypoints[i];                                       // get y-coordinate
159 //				//A.x = xpoints[i];                                       // get x-coordinate 
160 //				//B.y = ypoints[i+1];                                     // get next y-coordinate
161 //				//B.x = xpoints[i+1];                                     // get next x-coordinate
162 //
163 //				if (y != ypoints[i + 1] && (y <= Math.max(ypoints[i], ypoints[i + 1]))
164 //						&& (y >= Math.min(ypoints[i], ypoints[i + 1])) && ((xpoints[i] >= x) || (xpoints[i + 1] >= x))) { // if polygon contains a suitable value
165 //					if (((xpoints[i] >= x) && (xpoints[i + 1] >= x))) {
166 //						number_of_lines_crossed++;//simple case
167 //					} else {
168 //						double gradient; //   calc. gradient
169 //						if (xpoints[i] > xpoints[i + 1]) {
170 //							gradient = ((double) (xpoints[i] - xpoints[i + 1]) / (double) (ypoints[i] - ypoints[i + 1]));
171 //						} else {
172 //							gradient = ((double) (xpoints[i + 1] - xpoints[i]) / (double) (ypoints[i + 1] - ypoints[i]));
173 //						}
174 //						double x_intersection_axis = (xpoints[i] - (gradient * ypoints[i])); // calc. intersect with x-axis
175 //						double x_intersection_line = (gradient * y) + x_intersection_axis; // calc. intersect with y=const
176 //						//  line extending from location 
177 //						if ((x_intersection_line <= Math.max(xpoints[i], xpoints[i + 1]))
178 //								&& // check intersect inside polygon 
179 //								(x_intersection_line >= Math.min(xpoints[i], xpoints[i + 1]))
180 //								&& (x_intersection_line >= x)) {
181 //							number_of_lines_crossed++; // increment line counter
182 //						} // end check for inside polygon
183 //					}
184 //				} // end of if polygon points suitable
185 //			} // end of run through points in polygon
186 //
187 //			if ((number_of_lines_crossed != 0) && // if number of polygon lines crossed
188 //					(((number_of_lines_crossed % 2) == 1))) { //   by a line in one direction from the
189 //				return true; //   initial location is odd, the location
190 //
191 //				//   lies in that polygon
192 //
193 //			} // end of run through polygons
194 
195 		}
196 		return false; // return stuffing if things get this far
197 
198 	} // end of method whichPolygon	   
199 
200 }