1/*
2 * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
3 *
4 * NVIDIA CORPORATION and its licensors retain all intellectual property
5 * and proprietary rights in and to this software, related documentation
6 * and any modifications thereto. Any use, reproduction, disclosure or
7 * distribution of this software and related documentation without an express
8 * license agreement from NVIDIA CORPORATION is strictly prohibited.
9 */
10// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
11// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
12
13
14#ifndef PX_FOUNDATION_PX_BOUNDS3_H
15#define PX_FOUNDATION_PX_BOUNDS3_H
16
17/** \addtogroup foundation
18@{
19*/
20
21#include "foundation/PxTransform.h"
22#include "foundation/PxMat33.h"
23
24#ifndef PX_DOXYGEN
25namespace physx
26{
27#endif
28
29// maximum extents defined such that floating point exceptions are avoided for standard use cases
30#define PX_MAX_BOUNDS_EXTENTS (PX_MAX_REAL * 0.25f)
31
32/**
33\brief Class representing 3D range or axis aligned bounding box.
34
35Stored as minimum and maximum extent corners. Alternate representation
36would be center and dimensions.
37May be empty or nonempty. For nonempty bounds, minimum <= maximum has to hold for all axes.
38Empty bounds have to be represented as minimum = PX_MAX_BOUNDS_EXTENTS and maximum = -PX_MAX_BOUNDS_EXTENTS for all axes.
39All other representations are invalid and the behavior is undefined.
40*/
41class PxBounds3
42{
43public:
44
45 /**
46 \brief Default constructor, not performing any initialization for performance reason.
47 \remark Use empty() function below to construct empty bounds.
48 */
49 PX_CUDA_CALLABLE PX_FORCE_INLINE PxBounds3() {}
50
51 /**
52 \brief Construct from two bounding points
53 */
54 PX_CUDA_CALLABLE PX_FORCE_INLINE PxBounds3(const PxVec3& minimum, const PxVec3& maximum);
55
56 /**
57 \brief Return empty bounds.
58 */
59 static PX_CUDA_CALLABLE PX_FORCE_INLINE PxBounds3 empty();
60
61 /**
62 \brief returns the AABB containing v0 and v1.
63 \param v0 first point included in the AABB.
64 \param v1 second point included in the AABB.
65 */
66 static PX_CUDA_CALLABLE PX_FORCE_INLINE PxBounds3 boundsOfPoints(const PxVec3& v0, const PxVec3& v1);
67
68 /**
69 \brief returns the AABB from center and extents vectors.
70 \param center Center vector
71 \param extent Extents vector
72 */
73 static PX_CUDA_CALLABLE PX_FORCE_INLINE PxBounds3 centerExtents(const PxVec3& center, const PxVec3& extent);
74
75 /**
76 \brief Construct from center, extent, and (not necessarily orthogonal) basis
77 */
78 static PX_CUDA_CALLABLE PX_INLINE PxBounds3 basisExtent(const PxVec3& center, const PxMat33& basis, const PxVec3& extent);
79
80 /**
81 \brief Construct from pose and extent
82 */
83 static PX_CUDA_CALLABLE PX_INLINE PxBounds3 poseExtent(const PxTransform& pose, const PxVec3& extent);
84
85 /**
86 \brief gets the transformed bounds of the passed AABB (resulting in a bigger AABB).
87
88 This version is safe to call for empty bounds.
89
90 \param[in] matrix Transform to apply, can contain scaling as well
91 \param[in] bounds The bounds to transform.
92 */
93 static PX_CUDA_CALLABLE PX_INLINE PxBounds3 transformSafe(const PxMat33& matrix, const PxBounds3& bounds);
94
95 /**
96 \brief gets the transformed bounds of the passed AABB (resulting in a bigger AABB).
97
98 Calling this method for empty bounds leads to undefined behavior. Use #transformSafe() instead.
99
100 \param[in] matrix Transform to apply, can contain scaling as well
101 \param[in] bounds The bounds to transform.
102 */
103 static PX_CUDA_CALLABLE PX_INLINE PxBounds3 transformFast(const PxMat33& matrix, const PxBounds3& bounds);
104
105 /**
106 \brief gets the transformed bounds of the passed AABB (resulting in a bigger AABB).
107
108 This version is safe to call for empty bounds.
109
110 \param[in] transform Transform to apply, can contain scaling as well
111 \param[in] bounds The bounds to transform.
112 */
113 static PX_CUDA_CALLABLE PX_INLINE PxBounds3 transformSafe(const PxTransform& transform, const PxBounds3& bounds);
114
115 /**
116 \brief gets the transformed bounds of the passed AABB (resulting in a bigger AABB).
117
118 Calling this method for empty bounds leads to undefined behavior. Use #transformSafe() instead.
119
120 \param[in] transform Transform to apply, can contain scaling as well
121 \param[in] bounds The bounds to transform.
122 */
123 static PX_CUDA_CALLABLE PX_INLINE PxBounds3 transformFast(const PxTransform& transform, const PxBounds3& bounds);
124
125 /**
126 \brief Sets empty to true
127 */
128 PX_CUDA_CALLABLE PX_FORCE_INLINE void setEmpty();
129
130 /**
131 \brief Sets the bounds to maximum size [-PX_MAX_BOUNDS_EXTENTS, PX_MAX_BOUNDS_EXTENTS].
132 */
133 PX_CUDA_CALLABLE PX_FORCE_INLINE void setMaximal();
134
135 /**
136 \brief expands the volume to include v
137 \param v Point to expand to.
138 */
139 PX_CUDA_CALLABLE PX_FORCE_INLINE void include(const PxVec3& v);
140
141 /**
142 \brief expands the volume to include b.
143 \param b Bounds to perform union with.
144 */
145 PX_CUDA_CALLABLE PX_FORCE_INLINE void include(const PxBounds3& b);
146
147 PX_CUDA_CALLABLE PX_FORCE_INLINE bool isEmpty() const;
148
149 /**
150 \brief indicates whether the intersection of this and b is empty or not.
151 \param b Bounds to test for intersection.
152 */
153 PX_CUDA_CALLABLE PX_FORCE_INLINE bool intersects(const PxBounds3& b) const;
154
155 /**
156 \brief computes the 1D-intersection between two AABBs, on a given axis.
157 \param a the other AABB
158 \param axis the axis (0, 1, 2)
159 */
160 PX_CUDA_CALLABLE PX_FORCE_INLINE bool intersects1D(const PxBounds3& a, PxU32 axis) const;
161
162 /**
163 \brief indicates if these bounds contain v.
164 \param v Point to test against bounds.
165 */
166 PX_CUDA_CALLABLE PX_FORCE_INLINE bool contains(const PxVec3& v) const;
167
168 /**
169 \brief checks a box is inside another box.
170 \param box the other AABB
171 */
172 PX_CUDA_CALLABLE PX_FORCE_INLINE bool isInside(const PxBounds3& box) const;
173
174 /**
175 \brief returns the center of this axis aligned box.
176 */
177 PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 getCenter() const;
178
179 /**
180 \brief get component of the box's center along a given axis
181 */
182 PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getCenter(PxU32 axis) const;
183
184 /**
185 \brief get component of the box's extents along a given axis
186 */
187 PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getExtents(PxU32 axis) const;
188
189 /**
190 \brief returns the dimensions (width/height/depth) of this axis aligned box.
191 */
192 PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 getDimensions() const;
193
194 /**
195 \brief returns the extents, which are half of the width/height/depth.
196 */
197 PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 getExtents() const;
198
199 /**
200 \brief scales the AABB.
201
202 This version is safe to call for empty bounds.
203
204 \param scale Factor to scale AABB by.
205 */
206 PX_CUDA_CALLABLE PX_FORCE_INLINE void scaleSafe(PxF32 scale);
207
208 /**
209 \brief scales the AABB.
210
211 Calling this method for empty bounds leads to undefined behavior. Use #scaleSafe() instead.
212
213 \param scale Factor to scale AABB by.
214 */
215 PX_CUDA_CALLABLE PX_FORCE_INLINE void scaleFast(PxF32 scale);
216
217 /**
218 fattens the AABB in all 3 dimensions by the given distance.
219
220 This version is safe to call for empty bounds.
221 */
222 PX_CUDA_CALLABLE PX_FORCE_INLINE void fattenSafe(PxReal distance);
223
224 /**
225 fattens the AABB in all 3 dimensions by the given distance.
226
227 Calling this method for empty bounds leads to undefined behavior. Use #fattenSafe() instead.
228 */
229 PX_CUDA_CALLABLE PX_FORCE_INLINE void fattenFast(PxReal distance);
230
231 /**
232 checks that the AABB values are not NaN
233 */
234 PX_CUDA_CALLABLE PX_FORCE_INLINE bool isFinite() const;
235
236 /**
237 checks that the AABB values describe a valid configuration.
238 */
239 PX_CUDA_CALLABLE PX_FORCE_INLINE bool isValid() const;
240
241 PxVec3 minimum, maximum;
242};
243
244
245PX_CUDA_CALLABLE PX_FORCE_INLINE PxBounds3::PxBounds3(const PxVec3& minimum_, const PxVec3& maximum_)
246: minimum(minimum_), maximum(maximum_)
247{
248}
249
250PX_CUDA_CALLABLE PX_FORCE_INLINE PxBounds3 PxBounds3::empty()
251{
252 return PxBounds3(PxVec3(PX_MAX_BOUNDS_EXTENTS), PxVec3(-PX_MAX_BOUNDS_EXTENTS));
253}
254
255PX_CUDA_CALLABLE PX_FORCE_INLINE bool PxBounds3::isFinite() const
256{
257 return minimum.isFinite() && maximum.isFinite();
258}
259
260PX_CUDA_CALLABLE PX_FORCE_INLINE PxBounds3 PxBounds3::boundsOfPoints(const PxVec3& v0, const PxVec3& v1)
261{
262 return PxBounds3(v0.minimum(v1), v0.maximum(v1));
263}
264
265PX_CUDA_CALLABLE PX_FORCE_INLINE PxBounds3 PxBounds3::centerExtents(const PxVec3& center, const PxVec3& extent)
266{
267 return PxBounds3(center - extent, center + extent);
268}
269
270PX_CUDA_CALLABLE PX_INLINE PxBounds3 PxBounds3::basisExtent(const PxVec3& center, const PxMat33& basis, const PxVec3& extent)
271{
272 // extended basis vectors
273 PxVec3 c0 = basis.column0 * extent.x;
274 PxVec3 c1 = basis.column1 * extent.y;
275 PxVec3 c2 = basis.column2 * extent.z;
276
277 PxVec3 w;
278 // find combination of base vectors that produces max. distance for each component = sum of abs()
279 w.x = PxAbs(c0.x) + PxAbs(c1.x) + PxAbs(c2.x);
280 w.y = PxAbs(c0.y) + PxAbs(c1.y) + PxAbs(c2.y);
281 w.z = PxAbs(c0.z) + PxAbs(c1.z) + PxAbs(c2.z);
282
283 return PxBounds3(center - w, center + w);
284}
285
286PX_CUDA_CALLABLE PX_INLINE PxBounds3 PxBounds3::poseExtent(const PxTransform& pose, const PxVec3& extent)
287{
288 return basisExtent(pose.p, PxMat33(pose.q), extent);
289}
290
291PX_CUDA_CALLABLE PX_FORCE_INLINE void PxBounds3::setEmpty()
292{
293 minimum = PxVec3(PX_MAX_BOUNDS_EXTENTS);
294 maximum = PxVec3(-PX_MAX_BOUNDS_EXTENTS);
295}
296
297PX_CUDA_CALLABLE PX_FORCE_INLINE void PxBounds3::setMaximal()
298{
299 minimum = PxVec3(-PX_MAX_BOUNDS_EXTENTS);
300 maximum = PxVec3(PX_MAX_BOUNDS_EXTENTS);
301}
302
303PX_CUDA_CALLABLE PX_FORCE_INLINE void PxBounds3::include(const PxVec3& v)
304{
305 PX_ASSERT(isValid());
306 minimum = minimum.minimum(v);
307 maximum = maximum.maximum(v);
308}
309
310PX_CUDA_CALLABLE PX_FORCE_INLINE void PxBounds3::include(const PxBounds3& b)
311{
312 PX_ASSERT(isValid());
313 minimum = minimum.minimum(b.minimum);
314 maximum = maximum.maximum(b.maximum);
315}
316
317PX_CUDA_CALLABLE PX_FORCE_INLINE bool PxBounds3::isEmpty() const
318{
319 PX_ASSERT(isValid());
320 return minimum.x > maximum.x;
321}
322
323PX_CUDA_CALLABLE PX_FORCE_INLINE bool PxBounds3::intersects(const PxBounds3& b) const
324{
325 PX_ASSERT(isValid() && b.isValid());
326 return !(b.minimum.x > maximum.x || minimum.x > b.maximum.x ||
327 b.minimum.y > maximum.y || minimum.y > b.maximum.y ||
328 b.minimum.z > maximum.z || minimum.z > b.maximum.z);
329}
330
331PX_CUDA_CALLABLE PX_FORCE_INLINE bool PxBounds3::intersects1D(const PxBounds3& a, PxU32 axis) const
332{
333 PX_ASSERT(isValid() && a.isValid());
334 return maximum[axis] >= a.minimum[axis] && a.maximum[axis] >= minimum[axis];
335}
336
337PX_CUDA_CALLABLE PX_FORCE_INLINE bool PxBounds3::contains(const PxVec3& v) const
338{
339 PX_ASSERT(isValid());
340
341 return !(v.x < minimum.x || v.x > maximum.x ||
342 v.y < minimum.y || v.y > maximum.y ||
343 v.z < minimum.z || v.z > maximum.z);
344}
345
346PX_CUDA_CALLABLE PX_FORCE_INLINE bool PxBounds3::isInside(const PxBounds3& box) const
347{
348 PX_ASSERT(isValid() && box.isValid());
349 if(box.minimum.x>minimum.x) return false;
350 if(box.minimum.y>minimum.y) return false;
351 if(box.minimum.z>minimum.z) return false;
352 if(box.maximum.x<maximum.x) return false;
353 if(box.maximum.y<maximum.y) return false;
354 if(box.maximum.z<maximum.z) return false;
355 return true;
356}
357
358PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 PxBounds3::getCenter() const
359{
360 PX_ASSERT(isValid());
361 return (minimum+maximum) * 0.5f;
362}
363
364PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal PxBounds3::getCenter(PxU32 axis) const
365{
366 PX_ASSERT(isValid());
367 return (minimum[axis] + maximum[axis]) * 0.5f;
368}
369
370PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal PxBounds3::getExtents(PxU32 axis) const
371{
372 PX_ASSERT(isValid());
373 return (maximum[axis] - minimum[axis]) * 0.5f;
374}
375
376PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 PxBounds3::getDimensions() const
377{
378 PX_ASSERT(isValid());
379 return maximum - minimum;
380}
381
382PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 PxBounds3::getExtents() const
383{
384 PX_ASSERT(isValid());
385 return getDimensions() * 0.5f;
386}
387
388PX_CUDA_CALLABLE PX_FORCE_INLINE void PxBounds3::scaleSafe(PxF32 scale)
389{
390 PX_ASSERT(isValid());
391 if (!isEmpty())
392 scaleFast(scale);
393}
394
395PX_CUDA_CALLABLE PX_FORCE_INLINE void PxBounds3::scaleFast(PxF32 scale)
396{
397 PX_ASSERT(isValid());
398 *this = centerExtents(getCenter(), getExtents() * scale);
399}
400
401PX_CUDA_CALLABLE PX_FORCE_INLINE void PxBounds3::fattenSafe(PxReal distance)
402{
403 PX_ASSERT(isValid());
404 if (!isEmpty())
405 fattenFast(distance);
406}
407
408PX_CUDA_CALLABLE PX_FORCE_INLINE void PxBounds3::fattenFast(PxReal distance)
409{
410 PX_ASSERT(isValid());
411 minimum.x -= distance;
412 minimum.y -= distance;
413 minimum.z -= distance;
414
415 maximum.x += distance;
416 maximum.y += distance;
417 maximum.z += distance;
418}
419
420PX_CUDA_CALLABLE PX_INLINE PxBounds3 PxBounds3::transformSafe(const PxMat33& matrix, const PxBounds3& bounds)
421{
422 PX_ASSERT(bounds.isValid());
423 return !bounds.isEmpty() ? transformFast(matrix, bounds) : bounds;
424}
425
426PX_CUDA_CALLABLE PX_INLINE PxBounds3 PxBounds3::transformFast(const PxMat33& matrix, const PxBounds3& bounds)
427{
428 PX_ASSERT(bounds.isValid());
429 return PxBounds3::basisExtent(matrix * bounds.getCenter(), matrix, bounds.getExtents());
430}
431
432PX_CUDA_CALLABLE PX_INLINE PxBounds3 PxBounds3::transformSafe(const PxTransform& transform, const PxBounds3& bounds)
433{
434 PX_ASSERT(bounds.isValid());
435 return !bounds.isEmpty() ? transformFast(transform, bounds) : bounds;
436}
437
438PX_CUDA_CALLABLE PX_INLINE PxBounds3 PxBounds3::transformFast(const PxTransform& transform, const PxBounds3& bounds)
439{
440 PX_ASSERT(bounds.isValid());
441 return PxBounds3::basisExtent(transform.transform(bounds.getCenter()), PxMat33(transform.q), bounds.getExtents());
442}
443
444PX_CUDA_CALLABLE PX_FORCE_INLINE bool PxBounds3::isValid() const
445{
446 return (isFinite() &&
447 (((minimum.x <= maximum.x) && (minimum.y <= maximum.y) && (minimum.z <= maximum.z)) ||
448 ((minimum.x == PX_MAX_BOUNDS_EXTENTS) && (minimum.y == PX_MAX_BOUNDS_EXTENTS) && (minimum.z == PX_MAX_BOUNDS_EXTENTS) &&
449 (maximum.x == -PX_MAX_BOUNDS_EXTENTS) && (maximum.y == -PX_MAX_BOUNDS_EXTENTS) && (maximum.z == -PX_MAX_BOUNDS_EXTENTS)))
450 );
451}
452
453#ifndef PX_DOXYGEN
454} // namespace physx
455#endif
456
457/** @} */
458#endif // PX_FOUNDATION_PX_BOUNDS3_H
459