1
2 package math.geom2d.polygon;
3
4 import java.awt.Graphics2D;
5 import java.util.ArrayList;
6 import java.util.Collection;
7 import java.util.Collections;
8
9 import math.geom2d.AffineTransform2D;
10 import math.geom2d.Box2D;
11 import math.geom2d.Point2D;
12 import math.geom2d.circulinear.CirculinearBoundarySet2D;
13 import math.geom2d.circulinear.CirculinearCurve2DUtils;
14 import math.geom2d.circulinear.CirculinearDomain2D;
15 import math.geom2d.circulinear.GenericCirculinearDomain2D;
16 import math.geom2d.domain.Boundary2D;
17 import math.geom2d.domain.Boundary2DUtils;
18 import math.geom2d.domain.BoundarySet2D;
19 import math.geom2d.domain.ContinuousBoundary2D;
20 import math.geom2d.domain.Domain2D;
21 import math.geom2d.line.LineSegment2D;
22 import math.geom2d.transform.CircleInversion2D;
23
24
25
26
27
28
29
30 public class MultiPolygon2D implements Domain2D, Polygon2D {
31
32 ArrayList<LinearRing2D> rings = new ArrayList<LinearRing2D>();
33
34
35
36
37 public MultiPolygon2D() {
38 }
39
40 public MultiPolygon2D(LinearRing2D ring) {
41 rings.add(ring);
42 }
43
44 public MultiPolygon2D(LinearRing2D[] rings) {
45 for (LinearRing2D ring : rings)
46 this.rings.add(ring);
47 }
48
49 public MultiPolygon2D(SimplePolygon2D polygon) {
50 rings.addAll(polygon.getBoundary().getCurves());
51 }
52
53 public MultiPolygon2D(Collection<LinearRing2D> lines) {
54 rings.addAll(lines);
55 }
56
57
58
59
60 public void addPolygon(SimplePolygon2D polygon) {
61 rings.addAll(polygon.getBoundary().getCurves());
62 }
63
64
65
66
67
68
69 public Collection<SimplePolygon2D> getPolygons() {
70
71 ArrayList<SimplePolygon2D> polygons = new ArrayList<SimplePolygon2D>();
72
73
74 for (LinearRing2D ring : rings)
75 polygons.add(new SimplePolygon2D(ring.getVertices()));
76 return polygons;
77 }
78
79
80
81
82 @Deprecated
83 public void addPolyline(LinearRing2D ring) {
84 rings.add(ring);
85 }
86
87 public void addRing(LinearRing2D ring) {
88 rings.add(ring);
89 }
90
91
92
93
94
95
96
97
98 public Collection<LinearRing2D> getRings() {
99 return Collections.unmodifiableList(rings);
100 }
101
102
103
104
105
106
107
108 public CirculinearDomain2D transform(CircleInversion2D inv) {
109 return new GenericCirculinearDomain2D(
110 this.getBoundary().transform(inv));
111 }
112
113
114
115
116 public CirculinearDomain2D getBuffer(double dist) {
117 return CirculinearCurve2DUtils.computeBuffer(
118 this.getBoundary(), dist);
119 }
120
121
122
123
124
125 public CirculinearBoundarySet2D<LinearRing2D> getBoundary() {
126 return new CirculinearBoundarySet2D<LinearRing2D>(rings);
127 }
128
129 public Polygon2D complement() {
130
131 ArrayList<LinearRing2D> reverseLines = new ArrayList<LinearRing2D>(rings.size());
132
133
134 for (LinearRing2D ring : rings)
135 reverseLines.add(ring.getReverseCurve());
136
137
138 return new MultiPolygon2D(reverseLines);
139 }
140
141
142
143
144 public Collection<LineSegment2D> getEdges() {
145 ArrayList<LineSegment2D> edges = new ArrayList<LineSegment2D>();
146 for (LinearRing2D ring : rings)
147 edges.addAll(ring.getEdges());
148 return edges;
149 }
150
151 public int getEdgeNumber() {
152 int count = 0;
153 for (LinearRing2D ring : rings)
154 count += ring.getVertexNumber();
155 return count;
156 }
157
158 public Collection<Point2D> getVertices() {
159 ArrayList<Point2D> points = new ArrayList<Point2D>();
160 for (LinearRing2D ring : rings)
161 points.addAll(ring.getVertices());
162 return points;
163 }
164
165
166
167
168
169
170 public Point2D getVertex(int i) {
171 int count = 0;
172 LinearRing2D boundary = null;
173
174 for (LinearRing2D ring : rings) {
175 int nv = ring.getVertexNumber();
176 if (count+nv>i) {
177 boundary = ring;
178 break;
179 }
180 count += nv;
181 }
182
183 if (boundary==null)
184 throw new IndexOutOfBoundsException();
185
186 return boundary.getVertex(i-count);
187 }
188
189 public int getVertexNumber() {
190 int count = 0;
191 for (LinearRing2D ring : rings)
192 count += ring.getVertexNumber();
193 return count;
194 }
195
196
197
198
199 public Box2D getBoundingBox() {
200
201 Box2D box = new Box2D(
202 Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY,
203 Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY);
204
205
206 for (LinearRing2D ring : this.rings)
207 box = box.union(ring.getBoundingBox());
208
209
210 return box;
211 }
212
213
214
215
216 public MultiPolygon2D clip(Box2D box) {
217
218 BoundarySet2D<?> boundary =
219 Boundary2DUtils.clipBoundary(this.getBoundary(), box);
220
221
222 ArrayList<LinearRing2D> boundaries = new ArrayList<LinearRing2D>(
223 boundary.getCurveNumber());
224 for (ContinuousBoundary2D curve : boundary.getBoundaryCurves())
225 boundaries.add((LinearRing2D) curve);
226
227
228 return new MultiPolygon2D(boundaries);
229 }
230
231 public double getDistance(java.awt.geom.Point2D p) {
232 return Math.max(this.getBoundary().getSignedDistance(p), 0);
233 }
234
235 public double getDistance(double x, double y) {
236 return Math.max(this.getBoundary().getSignedDistance(x, y), 0);
237 }
238
239 public boolean isBounded() {
240
241 Boundary2D boundary = this.getBoundary();
242 if (!boundary.isBounded())
243 return false;
244
245
246 double area = 0;
247 for (LinearRing2D ring : rings)
248 area += ring.getSignedArea();
249
250
251 return area>0;
252 }
253
254
255
256
257
258 public boolean isEmpty() {
259
260 for (LinearRing2D ring : rings)
261 if (!ring.isEmpty())
262 return false;
263 return true;
264 }
265
266 public MultiPolygon2D transform(AffineTransform2D trans) {
267
268 ArrayList<LinearRing2D> transformed =
269 new ArrayList<LinearRing2D>(rings.size());
270
271
272 for (LinearRing2D ring : rings)
273 transformed.add(ring.transform(trans));
274
275
276 return new MultiPolygon2D(transformed);
277 }
278
279 public boolean contains(java.awt.geom.Point2D point) {
280 double angle = 0;
281 for (LinearRing2D ring : this.rings)
282 angle += ring.getWindingAngle(point);
283 return angle>Math.PI;
284 }
285
286 public boolean contains(double x, double y) {
287 return this.contains(new math.geom2d.Point2D(x, y));
288 }
289
290 public void draw(Graphics2D g2) {
291 g2.draw(this.getBoundary().getGeneralPath());
292 }
293
294 public void fill(Graphics2D g) {
295 g.fill(this.getBoundary().getGeneralPath());
296 }
297
298 @Override
299 public boolean equals(Object obj) {
300 if(!(obj instanceof MultiPolygon2D))
301 return false;
302
303
304 MultiPolygon2D polygon = (MultiPolygon2D) obj;
305 if(polygon.rings.size()!=this.rings.size())
306 return false;
307
308
309 for(int i=0; i<rings.size(); i++)
310 if(!this.rings.get(i).equals(polygon.rings.get(i)))
311 return false;
312
313 return true;
314 }
315
316 @Override
317 public MultiPolygon2D clone() {
318
319 ArrayList<LinearRing2D> array = new ArrayList<LinearRing2D>(rings.size());
320
321
322 for(LinearRing2D ring : rings)
323 array.add(ring.clone());
324
325
326 return new MultiPolygon2D(array);
327 }
328 }