source: trunk/src/gcc/libjava/java/awt/Polygon.java@ 736

Last change on this file since 736 was 2, checked in by bird, 23 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 10.9 KB
Line 
1/* Copyright (C) 2001 Free Software Foundation
2
3 This file is part of libjava.
4
5This software is copyrighted work licensed under the terms of the
6Libjava License. Please consult the file "LIBJAVA_LICENSE" for
7details. */
8
9package java.awt;
10
11import java.awt.geom.*;
12import java.io.Serializable;
13import java.util.Arrays;
14
15/**
16 * @author Tom Tromey <[email protected]>
17 * @date May 10, 2001
18 */
19
20/** The Polygon class represents a closed region whose boundary is
21 made of line segments. The Polygon is defined by its vertices. */
22public class Polygon implements Shape, Serializable
23{
24 /** The bounds of the polygon. This is null until the bounds have
25 * been computed for the first time; then it is correctly
26 * maintained whenever it is modified. */
27 protected Rectangle bounds;
28
29 /** The number of points in the polygon. */
30 public int npoints;
31
32 /** The x coordinates of the points. */
33 public int[] xpoints;
34
35 /** The y coordinates of the points. */
36 public int[] ypoints;
37
38 /** Create a new, empty Polygon. */
39 public Polygon ()
40 {
41 this.xpoints = new int[0];
42 this.ypoints = new int[0];
43 this.npoints = 0;
44 }
45
46 /** Create a new Polygon from the given vertices.
47 * @param xpoints The x coordinates
48 * @param ypoints The y coordinates
49 * @param npoints The number of points
50 */
51 public Polygon (int[] xpoints, int[] ypoints, int npoints)
52 {
53 // We make explicit copies instead of relying on clone so that we
54 // ensure the new arrays are the same size.
55 this.xpoints = new int[npoints];
56 this.ypoints = new int[npoints];
57 System.arraycopy (xpoints, 0, this.xpoints, 0, npoints);
58 System.arraycopy (ypoints, 0, this.ypoints, 0, npoints);
59 }
60
61 /** Append the specified point to this Polygon.
62 * @param x The x coordinate
63 * @param y The y coordinate
64 */
65 public void addPoint (int x, int y)
66 {
67 int[] newx = new int[npoints + 1];
68 System.arraycopy (xpoints, 0, newx, 0, npoints);
69 int[] newy = new int[npoints + 1];
70 System.arraycopy (ypoints, 0, newy, 0, npoints);
71 newx[npoints] = x;
72 newy[npoints] = y;
73 ++npoints;
74 xpoints = newx;
75 ypoints = newy;
76
77 // It is simpler to just recompute.
78 if (bounds != null)
79 computeBoundingBox ();
80 }
81
82 /** Return true if the indicated point is inside this Polygon.
83 * This uses an even-odd rule to determine insideness.
84 * @param x The x coordinate
85 * @param y The y coordinate
86 * @returns true if the point is contained by this Polygon.
87 */
88 public boolean contains (double x, double y)
89 {
90 // What we do is look at each line segment. If the line segment
91 // crosses the "scan line" at y at a point x' < x, then we
92 // increment our counter. At the end, an even number means the
93 // point is outside the polygon. Instead of a number, though, we
94 // use a boolean.
95 boolean inside = false;
96 for (int i = 0; i < npoints; ++i)
97 {
98 // Handle the wrap case.
99 int x2 = (i == npoints) ? xpoints[0] : xpoints[i + 1];
100 int y2 = (i == npoints) ? ypoints[0] : ypoints[i + 1];
101
102 if (ypoints[i] == y2)
103 {
104 // We ignore horizontal lines. This might give weird
105 // results in some situations -- ?
106 continue;
107 }
108
109 double t = (y - ypoints[i]) / (double) (y2 - ypoints[i]);
110 double x3 = xpoints[i] + t * (x2 - xpoints[i]);
111 if (x3 < x)
112 inside = ! inside;
113 }
114
115 return inside;
116 }
117
118 /** Return true if the indicated rectangle is entirely inside this
119 * Polygon.
120 * This uses an even-odd rule to determine insideness.
121 * @param x The x coordinate
122 * @param y The y coordinate
123 * @param w The width
124 * @param h The height
125 * @returns true if the rectangle is contained by this Polygon.
126 */
127 public boolean contains (double x, double y, double w, double h)
128 {
129 return intersectOrContains (x, y, w, h, false);
130 }
131
132 /** Return true if the indicated point is inside this Polygon.
133 * This uses an even-odd rule to determine insideness.
134 * @param x The x coordinate
135 * @param y The y coordinate
136 * @returns true if the point is contained by this Polygon.
137 */
138 public boolean contains (int x, int y)
139 {
140 return contains ((double) x, (double) y);
141 }
142
143 /** Return true if the indicated point is inside this Polygon.
144 * This uses an even-odd rule to determine insideness.
145 * @param p The point
146 * @returns true if the point is contained by this Polygon.
147 */
148 public boolean contains (Point p)
149 {
150 return contains (p.x, p.y);
151 }
152
153 /** Return true if the indicated point is inside this Polygon.
154 * This uses an even-odd rule to determine insideness.
155 * @param p The point
156 * @returns true if the point is contained by this Polygon.
157 */
158 public boolean contains (Point2D p)
159 {
160 return contains (p.getX (), p.getY ());
161 }
162
163 /** Return true if the indicated rectangle is entirely inside this
164 * Polygon. This uses an even-odd rule to determine insideness.
165 * @param r The rectangle
166 * @returns true if the rectangle is contained by this Polygon.
167 */
168 public boolean contains (Rectangle2D r)
169 {
170 return contains (r.getX (), r.getY (), r.getWidth (), r.getHeight ());
171 }
172
173 /** Returns the bounds of this Polygon.
174 * @deprecated Use getBounds() instead.
175 */
176 public Rectangle getBoundingBox ()
177 {
178 if (bounds == null)
179 computeBoundingBox ();
180 return bounds;
181 }
182
183 /** Returns the bounds of this Polygon. */
184 public Rectangle getBounds ()
185 {
186 if (bounds == null)
187 computeBoundingBox ();
188 return bounds;
189 }
190
191 /** Returns the bounds of this Polygon. */
192 public Rectangle2D getBounds2D ()
193 {
194 if (bounds == null)
195 computeBoundingBox ();
196 return bounds; // Why not?
197 }
198
199 /** Return an iterator for the boundary of this Polygon.
200 * @param at A transform to apply to the coordinates.
201 * @returns A path iterator for the Polygon's boundary.
202 */
203 public PathIterator getPathIterator (AffineTransform at)
204 {
205 return new Iterator (at);
206 }
207
208 /** Return an iterator for the boundary of this Polygon.
209 * @param at A transform to apply to the coordinates.
210 * @param flatness The flatness of the result; it is ignored by
211 * this class.
212 * @returns A path iterator for the Polygon's boundary.
213 */
214 public PathIterator getPathIterator (AffineTransform at, double flatness)
215 {
216 // We ignore the flatness.
217 return new Iterator (at);
218 }
219
220 /** @deprecated use contains(int,int). */
221 public boolean inside (int x, int y)
222 {
223 return contains (x, y);
224 }
225
226 /** Return true if this Polygon's interior intersects the given
227 * rectangle's interior.
228 * @param x The x coordinate
229 * @param y The y coordinate
230 * @param w The width
231 * @param h The height
232 */
233 public boolean intersects (double x, double y, double w, double h)
234 {
235 return intersectOrContains (x, y, w, h, true);
236 }
237
238 /** Return true if this Polygon's interior intersects the given
239 * rectangle's interior.
240 * @param r The rectangle
241 */
242 public boolean intersects (Rectangle2D r)
243 {
244 return intersects (r.getX (), r.getY (), r.getWidth (), r.getHeight ());
245 }
246
247 // This tests for intersection with or containment of a rectangle,
248 // depending on the INTERSECT argument.
249 private boolean intersectOrContains (double x, double y, double w, double h,
250 boolean intersect)
251 {
252 // First compute the rectangle of possible intersection points.
253 Rectangle r = getBounds ();
254 int minx = Math.max (r.x, (int) x);
255 int maxx = Math.min (r.x + r.width, (int) (x + w));
256 int miny = Math.max (r.y, (int) y);
257 int maxy = Math.min (r.y + r.height, (int) (y + h));
258
259 if (miny > maxy)
260 return false;
261
262 double[] crosses = new double[npoints + 1];
263
264 for (; miny < maxy; ++miny)
265 {
266 // First compute every place where the polygon might intersect
267 // the scan line at Y.
268 int ins = 0;
269 for (int i = 0; i < npoints; ++i)
270 {
271 // Handle the wrap case.
272 int x2 = (i == npoints) ? xpoints[0] : xpoints[i + 1];
273 int y2 = (i == npoints) ? ypoints[0] : ypoints[i + 1];
274
275 if (ypoints[i] == y2)
276 {
277 // We ignore horizontal lines. This might give weird
278 // results in some situations -- ?
279 continue;
280 }
281
282 double t = (((double) miny - ypoints[i])
283 / (double) (y2 - ypoints[i]));
284 double x3 = xpoints[i] + t * (x2 - xpoints[i]);
285 crosses[ins++] = x3;
286 }
287
288 // Now we can sort into increasing order and look to see if
289 // any point in the rectangle is in the polygon. We examine
290 // every other pair due to our even-odd rule.
291 Arrays.sort (crosses, 0, ins);
292 int i = intersect ? 0 : 1;
293 for (; i < ins - 1; i += 2)
294 {
295 // Pathological case.
296 if (crosses[i] == crosses[i + 1])
297 continue;
298
299 // Found a point on the inside.
300 if ((crosses[i] >= x && crosses[i] < x + w)
301 || (crosses[i + 1] >= x && crosses[i + 1] < x + w))
302 {
303 // If we're checking containment then we just lost.
304 // But if we're checking intersection then we just
305 // won.
306 return intersect;
307 }
308 }
309 }
310
311 return false;
312 }
313
314 /** Translates all the vertices of the polygon via a given vector.
315 * @param deltaX The X offset
316 * @param deltaY The Y offset
317 */
318 public void translate (int deltaX, int deltaY)
319 {
320 for (int i = 0; i < npoints; ++i)
321 {
322 xpoints[i] += deltaX;
323 ypoints[i] += deltaY;
324 }
325
326 if (bounds != null)
327 {
328 bounds.x += deltaX;
329 bounds.y += deltaY;
330 }
331 }
332
333 // This computes the bounding box if required.
334 private void computeBoundingBox ()
335 {
336 if (npoints == 0)
337 {
338 // This is wrong if the user adds a new point, but we
339 // account for that in addPoint().
340 bounds = new Rectangle (0, 0, 0, 0);
341 }
342 else
343 {
344 int maxx = xpoints[0];
345 int minx = xpoints[0];
346 int maxy = ypoints[0];
347 int miny = ypoints[0];
348
349 for (int i = 1; i < npoints; ++i)
350 {
351 maxx = Math.max (maxx, xpoints[i]);
352 minx = Math.min (minx, xpoints[i]);
353 maxy = Math.max (maxy, ypoints[i]);
354 miny = Math.min (miny, ypoints[i]);
355 }
356
357 bounds = new Rectangle (minx, miny, maxx - minx, maxy - miny);
358 }
359 }
360
361 private class Iterator implements PathIterator
362 {
363 public AffineTransform xform;
364 public int where;
365
366 public Iterator (AffineTransform xform)
367 {
368 this.xform = xform;
369 where = 0;
370 }
371
372 public int currentSegment (double[] coords)
373 {
374 int r;
375
376 if (where < npoints)
377 {
378 coords[0] = xpoints[where];
379 coords[1] = ypoints[where];
380 r = (where == 0) ? SEG_MOVETO : SEG_LINETO;
381 xform.transform (coords, 0, coords, 0, 1);
382 ++where;
383 }
384 else
385 r = SEG_CLOSE;
386
387 return r;
388 }
389
390 public int currentSegment (float[] coords)
391 {
392 int r;
393
394 if (where < npoints)
395 {
396 coords[0] = xpoints[where];
397 coords[1] = ypoints[where];
398 r = (where == 0) ? SEG_MOVETO : SEG_LINETO;
399 xform.transform (coords, 0, coords, 0, 1);
400 }
401 else
402 r = SEG_CLOSE;
403
404 return r;
405 }
406
407 public int getWindingRule ()
408 {
409 return WIND_EVEN_ODD;
410 }
411
412 public boolean isDone ()
413 {
414 return where == npoints + 1;
415 }
416
417 public void next ()
418 {
419 ++where;
420 }
421 }
422}
Note: See TracBrowser for help on using the repository browser.