1
2
3
4
5 package math.geom2d.domain;
6
7 import java.util.ArrayList;
8 import java.util.Collection;
9 import java.util.Iterator;
10
11 import math.geom2d.Box2D;
12 import math.geom2d.Point2D;
13 import math.geom2d.Shape2D;
14 import math.geom2d.UnboundedShapeException;
15 import math.geom2d.curve.ContinuousCurve2D;
16 import math.geom2d.curve.Curve2D;
17 import math.geom2d.curve.CurveArray2D;
18 import math.geom2d.curve.CurveSet2D;
19 import math.geom2d.curve.Curve2DUtils;
20 import math.geom2d.polygon.Polyline2D;
21
22
23
24
25
26
27 public abstract class Boundary2DUtils {
28
29
30
31
32
33
34
35 public final static CurveSet2D<ContinuousOrientedCurve2D> clipContinuousOrientedCurve(
36 ContinuousOrientedCurve2D curve, Box2D box) {
37
38 CurveArray2D<ContinuousOrientedCurve2D> result =
39 new CurveArray2D<ContinuousOrientedCurve2D>();
40 for (ContinuousCurve2D cont :
41 Curve2DUtils.clipContinuousCurve(curve, box))
42 if (cont instanceof ContinuousOrientedCurve2D)
43 result.addCurve((ContinuousOrientedCurve2D) cont);
44
45 return result;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100 }
101
102
103
104
105
106 public final static BoundarySet2D<ContinuousBoundary2D> clipBoundary(
107 Boundary2D boundary, Box2D box) {
108
109 if (!box.isBounded())
110 throw new UnboundedShapeException();
111
112
113 ContinuousOrientedCurve2D curve;
114
115
116
117
118 BoundarySet2D<ContinuousBoundary2D> res =
119 new BoundarySet2D<ContinuousBoundary2D>();
120
121
122 CurveSet2D<ContinuousOrientedCurve2D> clipped;
123
124
125 CurveArray2D<ContinuousOrientedCurve2D> curveSet =
126 new CurveArray2D<ContinuousOrientedCurve2D>();
127
128
129 Collection<? extends ContinuousBoundary2D> boundaryCurves =
130 boundary.getBoundaryCurves();
131
132
133
134
135 for (ContinuousBoundary2D boundaryCurve : boundaryCurves) {
136 clipped = Boundary2DUtils.clipContinuousOrientedCurve(
137 boundaryCurve, box);
138
139 for (ContinuousOrientedCurve2D clip : clipped)
140 curveSet.addCurve(clip);
141 }
142
143
144 int nc = curveSet.getCurveNumber();
145 double[] startPositions = new double[nc];
146 double[] endPositions = new double[nc];
147
148
149 boolean intersect = false;
150
151
152 ContinuousOrientedCurve2D[] curves =
153 new ContinuousOrientedCurve2D[nc];
154
155
156 Curve2D boxBoundary = box.getBoundary();
157
158
159 Iterator<ContinuousOrientedCurve2D> iter = curveSet.getCurves()
160 .iterator();
161
162 for (int i = 0; i<nc; i++) {
163
164 curve = iter.next();
165 curves[i] = curve;
166
167 if (curve.isClosed()) {
168 startPositions[i] = java.lang.Double.NaN;
169 endPositions[i] = java.lang.Double.NaN;
170 continue;
171 }
172
173
174 startPositions[i] = boxBoundary.getPosition(curve.getFirstPoint());
175 endPositions[i] = boxBoundary.getPosition(curve.getLastPoint());
176
177
178 intersect = true;
179 }
180
181
182
183
184 int nb = nc;
185
186
187 int c = 0;
188
189
190 while (c<nb) {
191 int ind = c;
192
193 while (curves[ind]==null)
194 ind++;
195
196
197 curve = curves[ind];
198
199
200 if (curve.isClosed()) {
201
202 if (curve instanceof ContinuousBoundary2D) {
203 res.addCurve((ContinuousBoundary2D) curve);
204 } else {
205 BoundaryPolyCurve2D<ContinuousOrientedCurve2D> bnd =
206 new BoundaryPolyCurve2D<ContinuousOrientedCurve2D>();
207 bnd.addCurve(curve);
208 res.addCurve(bnd);
209 }
210 curves[ind] = null;
211
212
213 c++;
214 continue;
215 }
216
217
218 BoundaryPolyCurve2D<ContinuousOrientedCurve2D> boundary0 =
219 new BoundaryPolyCurve2D<ContinuousOrientedCurve2D>();
220
221
222 boundary0.addCurve(curve);
223
224
225 Point2D p0 = curve.getFirstPoint();
226 Point2D p1 = curve.getLastPoint();
227
228
229 int ind0 = ind;
230
231
232 ArrayList<Integer> indices = new ArrayList<Integer>();
233 indices.add(new Integer(ind));
234
235
236 ind = findNextCurveIndex(startPositions, endPositions[ind0]);
237
238
239 while (ind!=ind0) {
240
241
242 curve = curves[ind];
243
244
245 boundary0.addCurve(getBoundaryPortion(box, p1, curve
246 .getFirstPoint()));
247
248
249 boundary0.addCurve(curve);
250
251 indices.add(new Integer(ind));
252
253
254 ind = findNextCurveIndex(startPositions, endPositions[ind]);
255
256
257 p1 = curve.getLastPoint();
258
259
260 nb--;
261 }
262
263
264 boundary0.addCurve(getBoundaryPortion(box, p1, p0));
265
266
267 res.addCurve(boundary0);
268
269
270 Iterator<Integer> iter2 = indices.iterator();
271 while (iter2.hasNext())
272 curves[iter2.next().intValue()] = null;
273
274
275 c++;
276 }
277
278
279
280
281 if (!intersect) {
282 Point2D vertex = box.getVertices().iterator().next();
283 if (boundary.isInside(vertex))
284 res.addCurve(box.getAsRectangle().getBoundary().getFirstCurve());
285 }
286
287
288 return res;
289 }
290
291 public final static int findNextCurveIndex(double[] positions, double pos) {
292 int ind = -1;
293 double posMin = java.lang.Double.MAX_VALUE;
294 for (int i = 0; i<positions.length; i++) {
295
296 if (java.lang.Double.isNaN(positions[i]))
297 continue;
298
299 if (positions[i]-pos<Shape2D.ACCURACY)
300 continue;
301
302
303 if (positions[i]<posMin) {
304 ind = i;
305 posMin = positions[i];
306 }
307 }
308
309 if (ind!=-1)
310 return ind;
311
312
313
314 for (int i = 0; i<positions.length; i++) {
315 if (java.lang.Double.isNaN(positions[i]))
316 continue;
317 if (positions[i]-posMin<Shape2D.ACCURACY) {
318 ind = i;
319 posMin = positions[i];
320 }
321 }
322 return ind;
323 }
324
325
326
327
328
329
330
331
332
333 public final static Polyline2D getBoundaryPortion(Box2D box, Point2D p0,
334 Point2D p1) {
335 Boundary2D boundary = box.getBoundary();
336
337
338 double t0 = boundary.getPosition(p0);
339 double t1 = boundary.getPosition(p1);
340
341
342 int ind0 = (int) Math.floor(t0);
343 int ind1 = (int) Math.floor(t1);
344
345
346 if (ind0==ind1&&t0<t1)
347 return new Polyline2D(new Point2D[] { p0, p1 });
348
349
350
351
352 ArrayList<Point2D> vertices = new ArrayList<Point2D>(6);
353
354
355 vertices.add(p0);
356
357
358 int ind = (ind0+1)%4;
359
360
361 while (ind!=ind1) {
362 vertices.add(boundary.getPoint(ind));
363 ind = (ind+1)%4;
364 }
365 vertices.add(boundary.getPoint(ind));
366
367
368 vertices.add(p1);
369
370 return new Polyline2D(vertices);
371 }
372 }