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