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
27
28 package math.geom2d;
29
30
31 import java.awt.Graphics2D;
32 import java.util.ArrayList;
33 import java.util.Collection;
34
35 import math.geom2d.domain.Boundary2D;
36 import math.geom2d.domain.BoundaryPolyCurve2D;
37 import math.geom2d.domain.BoundarySet2D;
38 import math.geom2d.line.AbstractLine2D;
39 import math.geom2d.line.LineArc2D;
40 import math.geom2d.line.LineSegment2D;
41 import math.geom2d.line.LinearShape2D;
42 import math.geom2d.line.StraightLine2D;
43 import math.geom2d.polygon.HRectangle2D;
44 import math.geom2d.polygon.LinearRing2D;
45
46
47
48
49
50
51 public class Box2D implements Cloneable {
52
53
54
55
56 private double xmin = 0;
57 private double xmax = 0;
58 private double ymin = 0;
59 private double ymax = 0;
60
61
62
63
64
65 public Box2D() {
66 this(0, 0, 0, 0);
67 }
68
69
70
71
72
73
74 public Box2D(double x0, double x1, double y0, double y1) {
75 xmin = Math.min(x0, x1);
76 xmax = Math.max(x0, x1);
77 ymin = Math.min(y0, y1);
78 ymax = Math.max(y0, y1);
79 }
80
81
82 public Box2D(java.awt.geom.Rectangle2D rect) {
83 this(rect.getX(), rect.getX()+rect.getWidth(), rect.getY(), rect.getY()
84 +rect.getHeight());
85 }
86
87
88
89
90
91 public Box2D(Point2D p1, Point2D p2) {
92 this(p1.getX(), p2.getX(), p1.getY(), p2.getY());
93 }
94
95
96 public Box2D(Point2D point, double w, double h) {
97 this(point.getX(), point.getX()+w, point.getY(), point.getY()+h);
98 }
99
100
101
102
103
104
105
106
107 public final static Box2D create(double xmin, double xmax, double ymin, double ymax) {
108 return new Box2D(xmin, xmax, ymin, ymax);
109 }
110
111
112
113
114 public final static Box2D create(Point2D p1, Point2D p2) {
115 return new Box2D(p1, p2);
116 }
117
118
119
120
121 public double getMinX() {
122 return xmin;
123 }
124
125 public double getMinY() {
126 return ymin;
127 }
128
129 public double getMaxX() {
130 return xmax;
131 }
132
133 public double getMaxY() {
134 return ymax;
135 }
136
137 public double getWidth() {
138 return xmax-xmin;
139 }
140
141 public double getHeight() {
142 return ymax-ymin;
143 }
144
145
146 public boolean isBounded() {
147 if (Double.isInfinite(xmin))
148 return false;
149 if (Double.isInfinite(ymin))
150 return false;
151 if (Double.isInfinite(xmax))
152 return false;
153 if (Double.isInfinite(ymax))
154 return false;
155 return true;
156 }
157
158
159
160
161 public boolean contains(java.awt.geom.Point2D point) {
162 double x = point.getX();
163 double y = point.getY();
164 if (x<xmin)
165 return false;
166 if (y<ymin)
167 return false;
168 if (x>xmax)
169 return false;
170 if (y>ymax)
171 return false;
172 return true;
173 }
174
175 public boolean contains(double x, double y) {
176 if (x<xmin)
177 return false;
178 if (y<ymin)
179 return false;
180 if (x>xmax)
181 return false;
182 if (y>ymax)
183 return false;
184 return true;
185 }
186
187
188
189
190
191
192
193
194 public boolean containsBounds(Shape2D shape) {
195 if (!shape.isBounded())
196 return false;
197 for (Point2D point : shape.getBoundingBox().getVertices())
198 if (!contains(point))
199 return false;
200
201 return true;
202 }
203
204
205
206
207
208
209
210
211
212
213
214 public Collection<StraightLine2D> getClippingLines() {
215 ArrayList<StraightLine2D> lines = new ArrayList<StraightLine2D>(4);
216
217 if (!(Double.isInfinite(ymin)||Double.isNaN(ymin)))
218 lines.add(new StraightLine2D(0, ymin, 1, 0));
219 if (!(Double.isInfinite(xmax)||Double.isNaN(xmax)))
220 lines.add(new StraightLine2D(xmax, 0, 0, 1));
221 if (!(Double.isInfinite(ymax)||Double.isNaN(ymax)))
222 lines.add(new StraightLine2D(0, ymax, -1, 0));
223 if (!(Double.isInfinite(xmin)||Double.isNaN(xmin)))
224 lines.add(new StraightLine2D(xmin, 0, 0, -1));
225 return lines;
226 }
227
228
229
230
231
232 public Collection<LinearShape2D> getEdges() {
233 ArrayList<LinearShape2D> edges = new ArrayList<LinearShape2D>(4);
234
235 if (isBounded()) {
236 edges.add(new LineSegment2D(xmin, ymin, xmax, ymin));
237 edges.add(new LineSegment2D(xmax, ymin, xmax, ymax));
238 edges.add(new LineSegment2D(xmax, ymax, xmin, ymax));
239 edges.add(new LineSegment2D(xmin, ymax, xmin, ymin));
240 return edges;
241 }
242
243 if (!Double.isInfinite(ymin)) {
244 if (Double.isInfinite(xmin)&&Double.isInfinite(xmax))
245 edges.add(new StraightLine2D(0, ymin, 1, 0));
246 else if (!Double.isInfinite(xmin)&&!Double.isInfinite(xmax))
247 edges.add(new LineSegment2D(xmin, ymin, xmax, ymin));
248 else
249 edges.add(new LineArc2D(0, ymin, 1, 0, xmin, xmax));
250 }
251
252 if (!Double.isInfinite(xmax)) {
253 if (Double.isInfinite(ymin)&&Double.isInfinite(ymax))
254 edges.add(new StraightLine2D(xmax, 0, 0, 1));
255 else if (!Double.isInfinite(ymin)&&!Double.isInfinite(ymax))
256 edges.add(new LineSegment2D(xmax, ymin, xmax, ymax));
257 else
258 edges.add(new LineArc2D(xmax, 0, 0, 1, ymin, ymax));
259 }
260
261 if (!Double.isInfinite(ymax)) {
262 if (Double.isInfinite(xmin)&&Double.isInfinite(xmax))
263 edges.add(new StraightLine2D(0, ymax, 1, 0));
264 else if (!Double.isInfinite(xmin)&&!Double.isInfinite(xmax))
265 edges.add(new LineSegment2D(xmax, ymax, xmin, ymax));
266 else
267 edges.add(new LineArc2D(0, ymin, 1, 0, xmin, xmax)
268 .getReverseCurve());
269 }
270
271 if (!Double.isInfinite(xmin)) {
272 if (Double.isInfinite(ymin)&&Double.isInfinite(ymax))
273 edges.add(new StraightLine2D(xmin, 0, 0, -1));
274 else if (!Double.isInfinite(ymin)&&!Double.isInfinite(ymax))
275 edges.add(new LineSegment2D(xmin, ymax, xmin, ymin));
276 else
277 edges.add(new LineArc2D(xmin, 0, 0, 1, ymin, ymax)
278 .getReverseCurve());
279 }
280
281 return edges;
282 }
283
284
285
286
287
288
289
290
291 public Boundary2D getBoundary() {
292
293
294 if (isBounded()) {
295 Point2D pts[] = new Point2D[4];
296 pts[0] = new Point2D(xmin, ymin);
297 pts[1] = new Point2D(xmax, ymin);
298 pts[2] = new Point2D(xmax, ymax);
299 pts[3] = new Point2D(xmin, ymax);
300 return new LinearRing2D(pts);
301 }
302
303
304 boolean bx0 = !Double.isInfinite(xmin);
305 boolean bx1 = !Double.isInfinite(xmax);
306 boolean by0 = !Double.isInfinite(ymin);
307 boolean by1 = !Double.isInfinite(ymax);
308
309
310 if (!bx0&&!bx1) {
311 if (!by0&&!by1)
312 return new BoundarySet2D<StraightLine2D>();
313 if (by0&&!by1)
314 return new StraightLine2D(0, ymin, 1, 0);
315 if (!by0&&by1)
316 return new StraightLine2D(0, ymax, -1, 0);
317 return new BoundarySet2D<StraightLine2D>(new StraightLine2D[] {
318 new StraightLine2D(0, ymin, 1, 0),
319 new StraightLine2D(0, ymax, -1, 0) });
320 }
321
322
323 if (!by0&&!by1) {
324 if (!bx0&&!bx1)
325 return new BoundarySet2D<StraightLine2D>();
326 if (bx0&&!bx1)
327 return new StraightLine2D(xmin, 0, 0, -1);
328 if (!bx0&&bx1)
329 return new StraightLine2D(xmax, 0, 0, 1);
330 return new BoundarySet2D<StraightLine2D>(new StraightLine2D[] {
331 new StraightLine2D(xmin, 0, 0, -1),
332 new StraightLine2D(xmax, 0, 0, 1) });
333 }
334
335
336
337 if (bx0&&by0)
338 return new BoundaryPolyCurve2D<LineArc2D>(
339 new LineArc2D[] {
340 new LineArc2D(xmin, ymin, 0, -1,
341 Double.NEGATIVE_INFINITY, 0),
342 new LineArc2D(xmin, ymin, 1, 0, 0,
343 Double.POSITIVE_INFINITY) });
344
345 if (bx1&&by0)
346 return new BoundaryPolyCurve2D<LineArc2D>(
347 new LineArc2D[] {
348 new LineArc2D(xmax, ymin, 1, 0,
349 Double.NEGATIVE_INFINITY, 0),
350 new LineArc2D(xmax, ymin, 0, 1, 0,
351 Double.POSITIVE_INFINITY) });
352
353 if (bx1&&by1)
354 return new BoundaryPolyCurve2D<LineArc2D>(
355 new LineArc2D[] {
356 new LineArc2D(xmax, ymax, 0, 1,
357 Double.NEGATIVE_INFINITY, 0),
358 new LineArc2D(xmax, ymax, -1, 0, 0,
359 Double.POSITIVE_INFINITY) });
360
361 if (bx0&&by1)
362 return new BoundaryPolyCurve2D<LineArc2D>(new LineArc2D[] {
363 new LineArc2D(xmin, ymax, -1, 0, Double.NEGATIVE_INFINITY,
364 0),
365 new LineArc2D(xmin, ymax, 0, -1, 0,
366 Double.POSITIVE_INFINITY) });
367
368
369
370 if (bx0)
371 return new BoundaryPolyCurve2D<AbstractLine2D>(
372 new AbstractLine2D[] {
373 new LineArc2D(xmin, ymax, -1, 0,
374 Double.NEGATIVE_INFINITY, 0),
375 new LineSegment2D(xmin, ymax, xmin, ymin),
376 new LineArc2D(xmin, ymin, 1, 0, 0,
377 Double.POSITIVE_INFINITY) });
378
379 if (bx1)
380 return new BoundaryPolyCurve2D<AbstractLine2D>(
381 new AbstractLine2D[] {
382 new LineArc2D(xmax, ymin, 1, 0,
383 Double.NEGATIVE_INFINITY, 0),
384 new LineSegment2D(xmax, ymin, xmax, ymax),
385 new LineArc2D(xmax, ymax, -1, 0, 0,
386 Double.POSITIVE_INFINITY) });
387
388 if (by0)
389 return new BoundaryPolyCurve2D<AbstractLine2D>(
390 new AbstractLine2D[] {
391 new LineArc2D(xmin, ymin, 0, -1,
392 Double.NEGATIVE_INFINITY, 0),
393 new LineSegment2D(xmin, ymin, xmax, ymin),
394 new LineArc2D(xmax, ymin, 0, 1, 0,
395 Double.POSITIVE_INFINITY) });
396
397 if (by1)
398 return new BoundaryPolyCurve2D<AbstractLine2D>(
399 new AbstractLine2D[] {
400 new LineArc2D(xmax, ymax, 0, 1,
401 Double.NEGATIVE_INFINITY, 0),
402 new LineSegment2D(xmax, ymax, xmin, ymax),
403 new LineArc2D(xmin, ymax, 0, -1, 0,
404 Double.POSITIVE_INFINITY) });
405
406 return null;
407 }
408
409 public Collection<Point2D> getVertices() {
410 ArrayList<Point2D> points = new ArrayList<Point2D>(4);
411 boolean bx0 = !(Double.isInfinite(xmin)||Double.isNaN(xmin));
412 boolean bx1 = !(Double.isInfinite(xmax)||Double.isNaN(xmax));
413 boolean by0 = !(Double.isInfinite(ymin)||Double.isNaN(ymin));
414 boolean by1 = !(Double.isInfinite(ymax)||Double.isNaN(ymax));
415 if (bx0&&by0)
416 points.add(new Point2D(xmin, ymin));
417 if (bx1&&by0)
418 points.add(new Point2D(xmax, ymin));
419 if (bx0&&by1)
420 points.add(new Point2D(xmin, ymax));
421 if (bx1&&by1)
422 points.add(new Point2D(xmax, ymax));
423 return points;
424 }
425
426
427 public int getVertexNumber() {
428 return this.getVertices().size();
429 }
430
431
432
433
434
435
436
437
438
439
440 public Box2D union(Box2D box) {
441 double xmin = Math.min(this.xmin, box.xmin);
442 double xmax = Math.max(this.xmax, box.xmax);
443 double ymin = Math.min(this.ymin, box.ymin);
444 double ymax = Math.max(this.ymax, box.ymax);
445 return new Box2D(xmin, xmax, ymin, ymax);
446 }
447
448
449
450
451
452
453
454
455 public Box2D intersection(Box2D box) {
456 double xmin = Math.max(this.xmin, box.xmin);
457 double xmax = Math.min(this.xmax, box.xmax);
458 double ymin = Math.max(this.ymin, box.ymin);
459 double ymax = Math.min(this.ymax, box.ymax);
460 return new Box2D(xmin, xmax, ymin, ymax);
461 }
462
463
464
465
466
467
468
469 public Box2D merge(Box2D box) {
470 this.xmin = Math.min(this.xmin, box.xmin);
471 this.xmax = Math.max(this.xmax, box.xmax);
472 this.ymin = Math.min(this.ymin, box.ymin);
473 this.ymax = Math.max(this.ymax, box.ymax);
474 return this;
475 }
476
477
478
479
480
481
482
483 public Box2D clip(Box2D box) {
484 this.xmin = Math.max(this.xmin, box.xmin);
485 this.xmax = Math.min(this.xmax, box.xmax);
486 this.ymin = Math.max(this.ymin, box.ymin);
487 this.ymax = Math.min(this.ymax, box.ymax);
488 return this;
489 }
490
491
492
493
494 public Box2D transform(AffineTransform2D trans) {
495 if (this.isBounded()) {
496
497
498 Collection<Point2D> points = this.getVertices();
499 double xmin = Double.POSITIVE_INFINITY;
500 double xmax = Double.NEGATIVE_INFINITY;
501 double ymin = Double.POSITIVE_INFINITY;
502 double ymax = Double.NEGATIVE_INFINITY;
503 for (Point2D point : points) {
504 point = point.transform(trans);
505 xmin = Math.min(xmin, point.getX());
506 ymin = Math.min(ymin, point.getY());
507 xmax = Math.max(xmax, point.getX());
508 ymax = Math.max(ymax, point.getY());
509 }
510 return new Box2D(xmin, xmax, ymin, ymax);
511 }
512
513
514 double xmin = Double.NEGATIVE_INFINITY;
515 double xmax = Double.POSITIVE_INFINITY;
516 double ymin = Double.NEGATIVE_INFINITY;
517 double ymax = Double.POSITIVE_INFINITY;
518
519 return new Box2D(xmin, xmax, ymin, ymax);
520 }
521
522
523
524
525
526
527
528
529
530 public java.awt.Rectangle getAsAWTRectangle() {
531 int xr = (int) Math.floor(this.xmin);
532 int yr = (int) Math.floor(this.ymin);
533 int wr = (int) Math.ceil(this.xmax-xr);
534 int hr = (int) Math.ceil(this.ymax-yr);
535 return new java.awt.Rectangle(xr, yr, wr, hr);
536 }
537
538
539
540
541
542
543
544 public java.awt.geom.Rectangle2D getAsAWTRectangle2D() {
545 return new HRectangle2D(xmin, ymin, xmax-xmin, ymax-ymin);
546 }
547
548
549
550
551
552
553
554 public HRectangle2D getAsRectangle() {
555 return new HRectangle2D(xmin, ymin, xmax-xmin, ymax-ymin);
556 }
557
558 public void draw(Graphics2D g2) {
559 if (!isBounded())
560 throw new UnboundedShapeException();
561 this.getBoundary().draw(g2);
562 }
563
564 public void fill(Graphics2D g2) {
565 if (!isBounded())
566 throw new UnboundedShapeException();
567 this.getBoundary().fill(g2);
568 }
569
570 public Box2D getBoundingBox() {
571 return new Box2D(this.getMinX(), this.getMaxX(), this.getMinY(), this
572 .getMaxY());
573 }
574
575
576
577
578 @Override
579 public String toString() {
580 return new String("Box2D("+xmin+","+xmax+","+ymin+","+ymax+")");
581 }
582
583
584
585
586
587 @Override
588 public boolean equals(Object obj) {
589
590 if (!(obj instanceof Box2D))
591 return false;
592 Box2D box = (Box2D) obj;
593
594 if (Math.abs(box.xmin-this.xmin)>Shape2D.ACCURACY)
595 return false;
596 if (Math.abs(box.ymin-this.ymin)>Shape2D.ACCURACY)
597 return false;
598 if (Math.abs(box.xmax-this.xmax)>Shape2D.ACCURACY)
599 return false;
600 if (Math.abs(box.ymax-this.ymax)>Shape2D.ACCURACY)
601 return false;
602
603 return true;
604 }
605
606 @Override
607 public Box2D clone() {
608 return new Box2D(xmin, xmax, ymin, ymax);
609 }
610 }