1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package math.geom2d.polygon;
27
28
29 import java.awt.Graphics2D;
30 import java.util.ArrayList;
31 import java.util.Collection;
32
33 import math.geom2d.AffineTransform2D;
34 import math.geom2d.Box2D;
35 import math.geom2d.Point2D;
36 import math.geom2d.circulinear.CirculinearBoundarySet2D;
37 import math.geom2d.circulinear.CirculinearDomain2D;
38 import math.geom2d.circulinear.CirculinearDomain2DUtils;
39 import math.geom2d.circulinear.GenericCirculinearDomain2D;
40 import math.geom2d.domain.Boundary2DUtils;
41 import math.geom2d.domain.BoundarySet2D;
42 import math.geom2d.domain.ContinuousBoundary2D;
43 import math.geom2d.domain.Domain2D;
44 import math.geom2d.domain.GenericDomain2D;
45 import math.geom2d.line.LineSegment2D;
46 import math.geom2d.transform.CircleInversion2D;
47
48
49
50
51 public class SimplePolygon2D implements Polygon2D {
52
53
54
55
56
57
58
59
60
61
62
63 protected ArrayList<Point2D> points = new ArrayList<Point2D>();
64
65
66
67
68
69
70
71 public SimplePolygon2D() {
72 }
73
74
75
76
77
78
79 public SimplePolygon2D(Point2D[] tab) {
80 points = new ArrayList<Point2D>(tab.length);
81 for (Point2D element : tab)
82 points.add(element);
83 }
84
85
86
87
88
89
90
91 public SimplePolygon2D(double[] xcoords, double[] ycoords) {
92 points = new ArrayList<Point2D>(xcoords.length);
93 for (int i = 0; i<xcoords.length; i++)
94 points.add(new Point2D(xcoords[i], ycoords[i]));
95 }
96
97 public SimplePolygon2D(Collection<? extends Point2D> points) {
98 this.points = new ArrayList<Point2D>(points.size());
99 this.points.addAll(points);
100 }
101
102
103
104
105
106
107
108
109
110
111 public static SimplePolygon2D create(Collection<? extends Point2D> points) {
112 return new SimplePolygon2D(points);
113 }
114
115
116
117
118
119
120 public static SimplePolygon2D create(Point2D[] points) {
121 return new SimplePolygon2D(points);
122 }
123
124
125
126
127
128
129
130
131 public void addVertex(Point2D point) {
132 this.points.add(point);
133 }
134
135
136
137
138
139
140 public void removeVertex(Point2D point) {
141 this.points.remove(point);
142 }
143
144
145
146
147
148 @Deprecated
149 public void addPoint(Point2D point) {
150 this.points.add(point);
151 }
152
153
154
155
156
157
158
159 @Deprecated
160 public void removePoint(Point2D point) {
161 this.points.remove(point);
162 }
163
164
165
166
167
168 public double getArea() {
169 return Math.abs(this.getSignedArea());
170 }
171
172
173
174
175
176
177
178
179
180
181 public double getSignedArea() {
182 double area = 0;
183 Point2D prev = this.points.get(points.size()-1);
184 for (Point2D point : this.points) {
185 area += prev.getX()*point.getY()-prev.getY()*point.getX();
186 prev = point;
187 }
188 return area /= 2;
189 }
190
191
192
193
194
195
196
197
198
199 public Point2D getCentroid() {
200 double xc = 0;
201 double yc = 0;
202 double tmp = 0;
203 Point2D prev = this.points.get(points.size()-1);
204 for (Point2D point : this.points) {
205 tmp = prev.getX()*point.getY()-prev.getY()*point.getX();
206 xc += tmp*(point.getX()+prev.getX());
207 yc += tmp*(point.getY()+prev.getY());
208 prev = point;
209 }
210 double area = this.getSignedArea()*6;
211 return new Point2D(xc/area, yc/area);
212 }
213
214
215
216
217
218
219
220
221
222 public int getWindingNumber(double x, double y) {
223 return Polygon2DUtils.windingNumber(points, new Point2D(x, y));
224 }
225
226
227
228
229
230 @Deprecated
231 public void clearPoints() {
232 this.points.clear();
233 }
234
235
236
237
238 public void clearVertices() {
239 this.points.clear();
240 }
241
242
243
244
245 public void setVertex(int index, Point2D position) {
246 this.points.set(index, position);
247 }
248
249
250
251
252
253
254
255
256
257 public Collection<Point2D> getVertices() {
258 return points;
259 }
260
261
262
263
264
265
266 public Point2D getVertex(int i) {
267 return points.get(i);
268 }
269
270
271
272
273
274
275 public int getVertexNumber() {
276 return points.size();
277 }
278
279
280
281
282 public Collection<LineSegment2D> getEdges() {
283
284 int nPoints = this.points.size();
285 ArrayList<LineSegment2D> edges = new ArrayList<LineSegment2D>(nPoints);
286
287 if (nPoints==0)
288 return edges;
289
290 for (int i = 0; i<nPoints-1; i++)
291 edges.add(new LineSegment2D(points.get(i), points.get(i+1)));
292
293 edges.add(new LineSegment2D(points.get(nPoints-1), points.get(0)));
294
295 return edges;
296 }
297
298
299
300
301
302 public int getEdgeNumber() {
303 return points.size();
304 }
305
306
307
308
309 public Collection<LinearRing2D> getRings() {
310 ArrayList<LinearRing2D> rings = new ArrayList<LinearRing2D>(1);
311 rings.add(new LinearRing2D(points));
312 return rings;
313 }
314
315
316
317
318
319
320
321
322 public CirculinearDomain2D transform(CircleInversion2D inv) {
323 return new GenericCirculinearDomain2D(
324 this.getBoundary().transform(inv));
325 }
326
327
328
329
330 public CirculinearDomain2D getBuffer(double dist) {
331 return CirculinearDomain2DUtils.computeBuffer(this, dist);
332 }
333
334
335
336
337
338
339
340 public CirculinearBoundarySet2D<LinearRing2D> getBoundary() {
341 Point2D[] array = new Point2D[this.points.size()];
342 for (int i = 0; i<this.points.size(); i++)
343 array[i] = this.points.get(i);
344
345 return new CirculinearBoundarySet2D<LinearRing2D>(
346 new LinearRing2D(array));
347 }
348
349
350
351
352 public SimplePolygon2D complement() {
353 int nPoints = this.points.size();
354
355 Point2D[] res = new Point2D[nPoints];
356
357 if (nPoints>0)
358 res[0] = this.points.get(0);
359
360 for (int i = 1; i<nPoints; i++) {
361 res[i] = this.points.get(nPoints-i);
362 }
363 return new SimplePolygon2D(res);
364 }
365
366
367
368
369
370
371
372
373
374
375 public double getDistance(java.awt.geom.Point2D p) {
376 return getDistance(p.getX(), p.getY());
377 }
378
379
380
381
382
383
384 public double getDistance(double x, double y) {
385 if (contains(x, y))
386 return 0;
387 return getBoundary().getDistance(x, y);
388 }
389
390
391
392
393
394
395
396 public double getSignedDistance(java.awt.geom.Point2D p) {
397 return getSignedDistance(p.getX(), p.getY());
398 }
399
400
401
402
403
404
405
406 public double getSignedDistance(double x, double y) {
407 double dist = getBoundary().getDistance(x, y);
408 if (contains(x, y))
409 return -dist;
410 else
411 return dist;
412 }
413
414
415
416
417 public Domain2D clip(Box2D box) {
418 BoundarySet2D<ContinuousBoundary2D> boundarySet =
419 Boundary2DUtils.clipBoundary(this.getBoundary(), box);
420
421
422 return new GenericDomain2D(boundarySet);
423 }
424
425
426
427
428 public Box2D getBoundingBox() {
429 return getBoundary().getBoundingBox();
430 }
431
432
433
434
435 public boolean isBounded() {
436 return this.getSignedArea()>0;
437 }
438
439 public boolean isEmpty() {
440 return points.size()==0;
441 }
442
443
444
445
446
447 public SimplePolygon2D transform(AffineTransform2D trans) {
448 int nPoints = this.points.size();
449
450 Point2D[] array = new Point2D[nPoints];
451 Point2D[] res = new Point2D[nPoints];
452
453 for (int i = 0; i<nPoints; i++) {
454 array[i] = this.points.get(i);
455 res[i] = new Point2D();
456 }
457 trans.transform(array, res);
458
459 SimplePolygon2D poly = new SimplePolygon2D(res);
460 if (!trans.isDirect())
461 poly = poly.complement();
462
463 return poly;
464 }
465
466
467
468
469
470
471
472
473 public boolean contains(java.awt.geom.Point2D p) {
474 return contains(p.getX(), p.getY());
475 }
476
477
478
479
480
481 public boolean contains(double x, double y) {
482 return this.getWindingNumber(x, y)==1
483 ||this.getBoundary().contains(x, y);
484 }
485
486
487
488
489 public java.awt.geom.GeneralPath getGeneralPath() {
490 java.awt.geom.GeneralPath path = new java.awt.geom.GeneralPath();
491 if (points.size()<2)
492 return path;
493
494
495 Point2D point = points.get(0);
496 path.moveTo((float) (point.getX()), (float) (point.getY()));
497
498
499 for (int i = 0; i<points.size(); i++) {
500 point = points.get(i);
501 path.lineTo((float) (point.getX()), (float) (point.getY()));
502 }
503
504
505 point = points.get(0);
506 path.lineTo((float) (point.getX()), (float) (point.getY()));
507 path.closePath();
508
509 return path;
510 }
511
512 public void draw(Graphics2D g2) {
513 g2.draw(this.getGeneralPath());
514 }
515
516 public void fill(Graphics2D g) {
517 g.fill(this.getGeneralPath());
518 }
519
520
521
522
523
524
525
526
527
528 @Override
529 public boolean equals(Object obj) {
530 if (!(obj instanceof SimplePolygon2D))
531 return false;
532
533 SimplePolygon2D polygon = (SimplePolygon2D) obj;
534
535 if (polygon.getVertexNumber()!=this.getVertexNumber())
536 return false;
537
538 if (!polygon.getBoundingBox().equals(this.getBoundingBox()))
539 return false;
540
541 for (Point2D point : polygon.getVertices()) {
542 if (!this.points.contains(point))
543 return false;
544 }
545
546 return true;
547 }
548
549 @Override
550 public SimplePolygon2D clone() {
551 ArrayList<Point2D> array = new ArrayList<Point2D>(points.size());
552 for(Point2D point : points)
553 array.add(point.clone());
554 return new SimplePolygon2D(array);
555 }
556
557 }