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 }