• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2  * Copyright 2011 See AUTHORS file.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  ******************************************************************************/
16 
17 package com.badlogic.gdx.math.collision;
18 
19 import java.io.Serializable;
20 import java.util.List;
21 
22 import com.badlogic.gdx.math.Matrix4;
23 import com.badlogic.gdx.math.Vector3;
24 
25 /** Encapsulates an axis aligned bounding box represented by a minimum and a maximum Vector. Additionally you can query for the
26  * bounding box's center, dimensions and corner points.
27  *
28  * @author badlogicgames@gmail.com, Xoppa */
29 public class BoundingBox implements Serializable {
30 	private static final long serialVersionUID = -1286036817192127343L;
31 
32 	private final static Vector3 tmpVector = new Vector3();
33 
34 	public final Vector3 min = new Vector3();
35 	public final Vector3 max = new Vector3();
36 
37 	private final Vector3 cnt = new Vector3();
38 	private final Vector3 dim = new Vector3();
39 
40 	/** @param out The {@link Vector3} to receive the center of the bounding box.
41 	 * @return The vector specified with the out argument. */
getCenter(Vector3 out)42 	public Vector3 getCenter (Vector3 out) {
43 		return out.set(cnt);
44 	}
45 
getCenterX()46 	public float getCenterX () {
47 		return cnt.x;
48 	}
49 
getCenterY()50 	public float getCenterY () {
51 		return cnt.y;
52 	}
53 
getCenterZ()54 	public float getCenterZ () {
55 		return cnt.z;
56 	}
57 
getCorner000(final Vector3 out)58 	public Vector3 getCorner000 (final Vector3 out) {
59 		return out.set(min.x, min.y, min.z);
60 	}
61 
getCorner001(final Vector3 out)62 	public Vector3 getCorner001 (final Vector3 out) {
63 		return out.set(min.x, min.y, max.z);
64 	}
65 
getCorner010(final Vector3 out)66 	public Vector3 getCorner010 (final Vector3 out) {
67 		return out.set(min.x, max.y, min.z);
68 	}
69 
getCorner011(final Vector3 out)70 	public Vector3 getCorner011 (final Vector3 out) {
71 		return out.set(min.x, max.y, max.z);
72 	}
73 
getCorner100(final Vector3 out)74 	public Vector3 getCorner100 (final Vector3 out) {
75 		return out.set(max.x, min.y, min.z);
76 	}
77 
getCorner101(final Vector3 out)78 	public Vector3 getCorner101 (final Vector3 out) {
79 		return out.set(max.x, min.y, max.z);
80 	}
81 
getCorner110(final Vector3 out)82 	public Vector3 getCorner110 (final Vector3 out) {
83 		return out.set(max.x, max.y, min.z);
84 	}
85 
getCorner111(final Vector3 out)86 	public Vector3 getCorner111 (final Vector3 out) {
87 		return out.set(max.x, max.y, max.z);
88 	}
89 
90 	/** @param out The {@link Vector3} to receive the dimensions of this bounding box on all three axis.
91 	 * @return The vector specified with the out argument */
getDimensions(final Vector3 out)92 	public Vector3 getDimensions (final Vector3 out) {
93 		return out.set(dim);
94 	}
95 
getWidth()96 	public float getWidth () {
97 		return dim.x;
98 	}
99 
getHeight()100 	public float getHeight () {
101 		return dim.y;
102 	}
103 
getDepth()104 	public float getDepth () {
105 		return dim.z;
106 	}
107 
108 	/** @param out The {@link Vector3} to receive the minimum values.
109 	 * @return The vector specified with the out argument */
getMin(final Vector3 out)110 	public Vector3 getMin (final Vector3 out) {
111 		return out.set(min);
112 	}
113 
114 	/** @param out The {@link Vector3} to receive the maximum values.
115 	 * @return The vector specified with the out argument */
getMax(final Vector3 out)116 	public Vector3 getMax (final Vector3 out) {
117 		return out.set(max);
118 	}
119 
120 	/** Constructs a new bounding box with the minimum and maximum vector set to zeros. */
BoundingBox()121 	public BoundingBox () {
122 		clr();
123 	}
124 
125 	/** Constructs a new bounding box from the given bounding box.
126 	 *
127 	 * @param bounds The bounding box to copy */
BoundingBox(BoundingBox bounds)128 	public BoundingBox (BoundingBox bounds) {
129 		this.set(bounds);
130 	}
131 
132 	/** Constructs the new bounding box using the given minimum and maximum vector.
133 	 *
134 	 * @param minimum The minimum vector
135 	 * @param maximum The maximum vector */
BoundingBox(Vector3 minimum, Vector3 maximum)136 	public BoundingBox (Vector3 minimum, Vector3 maximum) {
137 		this.set(minimum, maximum);
138 	}
139 
140 	/** Sets the given bounding box.
141 	 *
142 	 * @param bounds The bounds.
143 	 * @return This bounding box for chaining. */
set(BoundingBox bounds)144 	public BoundingBox set (BoundingBox bounds) {
145 		return this.set(bounds.min, bounds.max);
146 	}
147 
148 	/** Sets the given minimum and maximum vector.
149 	 *
150 	 * @param minimum The minimum vector
151 	 * @param maximum The maximum vector
152 	 * @return This bounding box for chaining. */
set(Vector3 minimum, Vector3 maximum)153 	public BoundingBox set (Vector3 minimum, Vector3 maximum) {
154 		min.set(minimum.x < maximum.x ? minimum.x : maximum.x, minimum.y < maximum.y ? minimum.y : maximum.y,
155 			minimum.z < maximum.z ? minimum.z : maximum.z);
156 		max.set(minimum.x > maximum.x ? minimum.x : maximum.x, minimum.y > maximum.y ? minimum.y : maximum.y,
157 			minimum.z > maximum.z ? minimum.z : maximum.z);
158 		cnt.set(min).add(max).scl(0.5f);
159 		dim.set(max).sub(min);
160 		return this;
161 	}
162 
163 	/** Sets the bounding box minimum and maximum vector from the given points.
164 	 *
165 	 * @param points The points.
166 	 * @return This bounding box for chaining. */
set(Vector3[] points)167 	public BoundingBox set (Vector3[] points) {
168 		this.inf();
169 		for (Vector3 l_point : points)
170 			this.ext(l_point);
171 		return this;
172 	}
173 
174 	/** Sets the bounding box minimum and maximum vector from the given points.
175 	 *
176 	 * @param points The points.
177 	 * @return This bounding box for chaining. */
set(List<Vector3> points)178 	public BoundingBox set (List<Vector3> points) {
179 		this.inf();
180 		for (Vector3 l_point : points)
181 			this.ext(l_point);
182 		return this;
183 	}
184 
185 	/** Sets the minimum and maximum vector to positive and negative infinity.
186 	 *
187 	 * @return This bounding box for chaining. */
inf()188 	public BoundingBox inf () {
189 		min.set(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY);
190 		max.set(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY);
191 		cnt.set(0, 0, 0);
192 		dim.set(0, 0, 0);
193 		return this;
194 	}
195 
196 	/** Extends the bounding box to incorporate the given {@link Vector3}.
197 	 * @param point The vector
198 	 * @return This bounding box for chaining. */
ext(Vector3 point)199 	public BoundingBox ext (Vector3 point) {
200 		return this.set(min.set(min(min.x, point.x), min(min.y, point.y), min(min.z, point.z)),
201 			max.set(Math.max(max.x, point.x), Math.max(max.y, point.y), Math.max(max.z, point.z)));
202 	}
203 
204 	/** Sets the minimum and maximum vector to zeros.
205 	 * @return This bounding box for chaining. */
clr()206 	public BoundingBox clr () {
207 		return this.set(min.set(0, 0, 0), max.set(0, 0, 0));
208 	}
209 
210 	/** Returns whether this bounding box is valid. This means that {@link #max} is greater than {@link #min}.
211 	 * @return True in case the bounding box is valid, false otherwise */
isValid()212 	public boolean isValid () {
213 		return min.x < max.x && min.y < max.y && min.z < max.z;
214 	}
215 
216 	/** Extends this bounding box by the given bounding box.
217 	 *
218 	 * @param a_bounds The bounding box
219 	 * @return This bounding box for chaining. */
ext(BoundingBox a_bounds)220 	public BoundingBox ext (BoundingBox a_bounds) {
221 		return this.set(min.set(min(min.x, a_bounds.min.x), min(min.y, a_bounds.min.y), min(min.z, a_bounds.min.z)),
222 			max.set(max(max.x, a_bounds.max.x), max(max.y, a_bounds.max.y), max(max.z, a_bounds.max.z)));
223 	}
224 
225 	/** Extends this bounding box by the given sphere.
226 	 *
227 	 * @param center Sphere center
228 	 * @param radius Sphere radius
229 	 * @return This bounding box for chaining. */
ext(Vector3 center, float radius)230 	public BoundingBox ext (Vector3 center, float radius) {
231 		return this.set(min.set(min(min.x, center.x - radius), min(min.y, center.y - radius), min(min.z, center.z - radius)),
232 			max.set(max(max.x, center.x + radius), max(max.y, center.y + radius), max(max.z, center.z + radius)));
233 	}
234 
235 	/** Extends this bounding box by the given transformed bounding box.
236 	 *
237 	 * @param bounds The bounding box
238 	 * @param transform The transformation matrix to apply to bounds, before using it to extend this bounding box.
239 	 * @return This bounding box for chaining. */
ext(BoundingBox bounds, Matrix4 transform)240 	public BoundingBox ext (BoundingBox bounds, Matrix4 transform) {
241 		ext(tmpVector.set(bounds.min.x, bounds.min.y, bounds.min.z).mul(transform));
242 		ext(tmpVector.set(bounds.min.x, bounds.min.y, bounds.max.z).mul(transform));
243 		ext(tmpVector.set(bounds.min.x, bounds.max.y, bounds.min.z).mul(transform));
244 		ext(tmpVector.set(bounds.min.x, bounds.max.y, bounds.max.z).mul(transform));
245 		ext(tmpVector.set(bounds.max.x, bounds.min.y, bounds.min.z).mul(transform));
246 		ext(tmpVector.set(bounds.max.x, bounds.min.y, bounds.max.z).mul(transform));
247 		ext(tmpVector.set(bounds.max.x, bounds.max.y, bounds.min.z).mul(transform));
248 		ext(tmpVector.set(bounds.max.x, bounds.max.y, bounds.max.z).mul(transform));
249 		return this;
250 	}
251 
252 	/** Multiplies the bounding box by the given matrix. This is achieved by multiplying the 8 corner points and then calculating
253 	 * the minimum and maximum vectors from the transformed points.
254 	 *
255 	 * @param transform The matrix
256 	 * @return This bounding box for chaining. */
mul(Matrix4 transform)257 	public BoundingBox mul (Matrix4 transform) {
258 		final float x0 = min.x, y0 = min.y, z0 = min.z, x1 = max.x, y1 = max.y, z1 = max.z;
259 		inf();
260 		ext(tmpVector.set(x0, y0, z0).mul(transform));
261 		ext(tmpVector.set(x0, y0, z1).mul(transform));
262 		ext(tmpVector.set(x0, y1, z0).mul(transform));
263 		ext(tmpVector.set(x0, y1, z1).mul(transform));
264 		ext(tmpVector.set(x1, y0, z0).mul(transform));
265 		ext(tmpVector.set(x1, y0, z1).mul(transform));
266 		ext(tmpVector.set(x1, y1, z0).mul(transform));
267 		ext(tmpVector.set(x1, y1, z1).mul(transform));
268 		return this;
269 	}
270 
271 	/** Returns whether the given bounding box is contained in this bounding box.
272 	 * @param b The bounding box
273 	 * @return Whether the given bounding box is contained */
contains(BoundingBox b)274 	public boolean contains (BoundingBox b) {
275 		return !isValid()
276 			|| (min.x <= b.min.x && min.y <= b.min.y && min.z <= b.min.z && max.x >= b.max.x && max.y >= b.max.y && max.z >= b.max.z);
277 	}
278 
279 	/** Returns whether the given bounding box is intersecting this bounding box (at least one point in).
280 	 * @param b The bounding box
281 	 * @return Whether the given bounding box is intersected */
intersects(BoundingBox b)282 	public boolean intersects (BoundingBox b) {
283 		if (!isValid()) return false;
284 
285 		// test using SAT (separating axis theorem)
286 
287 		float lx = Math.abs(this.cnt.x - b.cnt.x);
288 		float sumx = (this.dim.x / 2.0f) + (b.dim.x / 2.0f);
289 
290 		float ly = Math.abs(this.cnt.y - b.cnt.y);
291 		float sumy = (this.dim.y / 2.0f) + (b.dim.y / 2.0f);
292 
293 		float lz = Math.abs(this.cnt.z - b.cnt.z);
294 		float sumz = (this.dim.z / 2.0f) + (b.dim.z / 2.0f);
295 
296 		return (lx <= sumx && ly <= sumy && lz <= sumz);
297 
298 	}
299 
300 	/** Returns whether the given vector is contained in this bounding box.
301 	 * @param v The vector
302 	 * @return Whether the vector is contained or not. */
contains(Vector3 v)303 	public boolean contains (Vector3 v) {
304 		return min.x <= v.x && max.x >= v.x && min.y <= v.y && max.y >= v.y && min.z <= v.z && max.z >= v.z;
305 	}
306 
307 	@Override
toString()308 	public String toString () {
309 		return "[" + min + "|" + max + "]";
310 	}
311 
312 	/** Extends the bounding box by the given vector.
313 	 *
314 	 * @param x The x-coordinate
315 	 * @param y The y-coordinate
316 	 * @param z The z-coordinate
317 	 * @return This bounding box for chaining. */
ext(float x, float y, float z)318 	public BoundingBox ext (float x, float y, float z) {
319 		return this.set(min.set(min(min.x, x), min(min.y, y), min(min.z, z)), max.set(max(max.x, x), max(max.y, y), max(max.z, z)));
320 	}
321 
min(final float a, final float b)322 	static final float min (final float a, final float b) {
323 		return a > b ? b : a;
324 	}
325 
max(final float a, final float b)326 	static final float max (final float a, final float b) {
327 		return a > b ? a : b;
328 	}
329 }
330