1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.geometry.euclidean.twod;
18
19 import java.util.Arrays;
20 import java.util.Objects;
21
22 import org.apache.commons.geometry.euclidean.AbstractBounds;
23 import org.apache.commons.geometry.euclidean.twod.shape.Parallelogram;
24 import org.apache.commons.numbers.core.Precision;
25
26
27
28
29
30
31
32 public final class Bounds2D extends AbstractBounds<Vector2D, Bounds2D> {
33
34
35
36
37
38 private Bounds2D(final Vector2D min, final Vector2D max) {
39 super(min, max);
40 }
41
42
43 @Override
44 public boolean hasSize(final Precision.DoubleEquivalence precision) {
45 final Vector2D diag = getDiagonal();
46
47 return !precision.eqZero(diag.getX()) &&
48 !precision.eqZero(diag.getY());
49 }
50
51
52 @Override
53 public boolean contains(final Vector2D pt) {
54 final double x = pt.getX();
55 final double y = pt.getY();
56
57 final Vector2D min = getMin();
58 final Vector2D max = getMax();
59
60 return x >= min.getX() && x <= max.getX() &&
61 y >= min.getY() && y <= max.getY();
62 }
63
64
65 @Override
66 public boolean contains(final Vector2D pt, final Precision.DoubleEquivalence precision) {
67 final double x = pt.getX();
68 final double y = pt.getY();
69
70 final Vector2D min = getMin();
71 final Vector2D max = getMax();
72
73 return precision.gte(x, min.getX()) && precision.lte(x, max.getX()) &&
74 precision.gte(y, min.getY()) && precision.lte(y, max.getY());
75 }
76
77
78 @Override
79 public boolean intersects(final Bounds2D other) {
80 final Vector2D aMin = getMin();
81 final Vector2D aMax = getMax();
82
83 final Vector2D bMin = other.getMin();
84 final Vector2D bMax = other.getMax();
85
86 return aMin.getX() <= bMax.getX() && aMax.getX() >= bMin.getX() &&
87 aMin.getY() <= bMax.getY() && aMax.getY() >= bMin.getY();
88 }
89
90
91 @Override
92 public Bounds2D intersection(final Bounds2D other) {
93 if (intersects(other)) {
94 final Vector2D aMin = getMin();
95 final Vector2D aMax = getMax();
96
97 final Vector2D bMin = other.getMin();
98 final Vector2D bMax = other.getMax();
99
100
101 final double minX = Math.max(aMin.getX(), bMin.getX());
102 final double minY = Math.max(aMin.getY(), bMin.getY());
103
104 final double maxX = Math.min(aMax.getX(), bMax.getX());
105 final double maxY = Math.min(aMax.getY(), bMax.getY());
106
107 return new Bounds2D(
108 Vector2D.of(minX, minY),
109 Vector2D.of(maxX, maxY));
110 }
111
112 return null;
113 }
114
115
116
117
118
119
120 @Override
121 public Parallelogram toRegion(final Precision.DoubleEquivalence precision) {
122 return Parallelogram.axisAligned(getMin(), getMax(), precision);
123 }
124
125
126 @Override
127 public int hashCode() {
128 return Objects.hash(getMin(), getMax());
129 }
130
131
132 @Override
133 public boolean equals(final Object obj) {
134 if (obj == this) {
135 return true;
136 } else if (!(obj instanceof Bounds2D)) {
137 return false;
138 }
139
140 final Bounds2D other = (Bounds2D) obj;
141
142 return getMin().equals(other.getMin()) &&
143 getMax().equals(other.getMax());
144 }
145
146
147
148
149
150
151 public static Bounds2D from(final Vector2D first, final Vector2D... more) {
152 final Builder builder = builder();
153
154 builder.add(first);
155 builder.addAll(Arrays.asList(more));
156
157 return builder.build();
158 }
159
160
161
162
163
164 public static Bounds2D from(final Iterable<Vector2D> points) {
165 final Builder builder = builder();
166
167 builder.addAll(points);
168
169 return builder.build();
170 }
171
172
173
174
175 public static Builder builder() {
176 return new Builder();
177 }
178
179
180
181 public static final class Builder {
182
183
184 private double minX = Double.POSITIVE_INFINITY;
185
186
187 private double minY = Double.POSITIVE_INFINITY;
188
189
190 private double maxX = Double.NEGATIVE_INFINITY;
191
192
193 private double maxY = Double.NEGATIVE_INFINITY;
194
195
196 private Builder() { }
197
198
199
200
201
202 public Builder add(final Vector2D pt) {
203 final double x = pt.getX();
204 final double y = pt.getY();
205
206 minX = Math.min(x, minX);
207 minY = Math.min(y, minY);
208
209 maxX = Math.max(x, maxX);
210 maxY = Math.max(y, maxY);
211
212 return this;
213 }
214
215
216
217
218
219 public Builder addAll(final Iterable<? extends Vector2D> pts) {
220 for (final Vector2D pt : pts) {
221 add(pt);
222 }
223
224 return this;
225 }
226
227
228
229
230
231 public Builder add(final Bounds2D bounds) {
232 add(bounds.getMin());
233 add(bounds.getMax());
234
235 return this;
236 }
237
238
239
240
241 public boolean hasBounds() {
242 return Double.isFinite(minX) &&
243 Double.isFinite(minY) &&
244 Double.isFinite(maxX) &&
245 Double.isFinite(maxY);
246 }
247
248
249
250
251
252
253
254
255 public Bounds2D build() {
256 final Vector2D min = Vector2D.of(minX, minY);
257 final Vector2D max = Vector2D.of(maxX, maxY);
258
259 if (!hasBounds()) {
260 if (Double.isInfinite(minX) && minX > 0 &&
261 Double.isInfinite(maxX) && maxX < 0) {
262 throw new IllegalStateException("Cannot construct bounds: no points given");
263 }
264
265 throw new IllegalStateException("Invalid bounds: min= " + min + ", max= " + max);
266 }
267
268 return new Bounds2D(min, max);
269 }
270 }
271 }