Plasma Engine  2.0
Loading...
Searching...
No Matches
BoundingBox_inl.h
1#pragma once
2
3#include <Foundation/Math/Mat4.h>
4
5template <typename Type>
7
8template <typename Type>
10{
11 *this = MakeFromMinMax(vMin, vMax);
12}
13
14template <typename Type>
22
23template <typename Type>
25{
27 res.m_vMin.Set(plMath::MaxValue<Type>());
28 res.m_vMax.Set(-plMath::MaxValue<Type>());
29 return res;
30}
31
32template <typename Type>
34{
36 res.m_vMin = vCenter - vHalfExtents;
37 res.m_vMax = vCenter + vHalfExtents;
38 return res;
39}
40
41template <typename Type>
43{
45 res.m_vMin = vMin;
46 res.m_vMax = vMax;
48 PL_ASSERT_DEBUG(res.IsValid(), "The given values don't create a valid bounding box ({0} | {1} | {2} - {3} | {4} | {5})", plArgF(vMin.x, 2), plArgF(vMin.y, 2), plArgF(vMin.z, 2), plArgF(vMax.x, 2), plArgF(vMax.y, 2), plArgF(vMax.z, 2));
49
50 return res;
51}
52
53template <typename Type>
54PL_FORCE_INLINE plBoundingBoxTemplate<Type> plBoundingBoxTemplate<Type>::MakeFromPoints(const plVec3Template<Type>* pPoints, plUInt32 uiNumPoints, plUInt32 uiStride /*= sizeof(plVec3Template<Type>)*/)
55{
56 plBoundingBoxTemplate<Type> res = MakeInvalid();
57 res.ExpandToInclude(pPoints, uiNumPoints, uiStride);
58 return res;
60
61template <typename Type>
63{
64 PL_NAN_ASSERT(this);
65 PL_ASSERT_DEBUG(out_pCorners != nullptr, "Out Parameter must not be nullptr.");
66
67 out_pCorners[0].Set(m_vMin.x, m_vMin.y, m_vMin.z);
68 out_pCorners[1].Set(m_vMin.x, m_vMin.y, m_vMax.z);
69 out_pCorners[2].Set(m_vMin.x, m_vMax.y, m_vMin.z);
70 out_pCorners[3].Set(m_vMin.x, m_vMax.y, m_vMax.z);
71 out_pCorners[4].Set(m_vMax.x, m_vMin.y, m_vMin.z);
72 out_pCorners[5].Set(m_vMax.x, m_vMin.y, m_vMax.z);
73 out_pCorners[6].Set(m_vMax.x, m_vMax.y, m_vMin.z);
74 out_pCorners[7].Set(m_vMax.x, m_vMax.y, m_vMax.z);
75}
76
77template <typename Type>
79{
80 return m_vMin + GetHalfExtents();
81}
82
83template <typename Type>
85{
86 return m_vMax - m_vMin;
87}
88
89template <typename Type>
91{
92 return (m_vMax - m_vMin) / (Type)2;
93}
94
95template <typename Type>
97{
98 return (m_vMin.IsValid() && m_vMax.IsValid() && m_vMin.x <= m_vMax.x && m_vMin.y <= m_vMax.y && m_vMin.z <= m_vMax.z);
99}
100
101template <typename Type>
103{
104 return m_vMin.IsNaN() || m_vMax.IsNaN();
105}
106
107template <typename Type>
109{
110 m_vMin = m_vMin.CompMin(vPoint);
111 m_vMax = m_vMax.CompMax(vPoint);
112}
114template <typename Type>
117 PL_ASSERT_DEBUG(rhs.IsValid(), "rhs must be a valid AABB.");
118 m_vMin = m_vMin.CompMin(rhs.m_vMin);
119 m_vMax = m_vMax.CompMax(rhs.m_vMax);
120}
121
122template <typename Type>
123void plBoundingBoxTemplate<Type>::ExpandToInclude(const plVec3Template<Type>* pPoints, plUInt32 uiNumPoints, plUInt32 uiStride)
124{
125 PL_ASSERT_DEBUG(pPoints != nullptr, "Array may not be nullptr.");
126 PL_ASSERT_DEBUG(uiStride >= sizeof(plVec3Template<Type>), "Data may not overlap.");
127
128 const plVec3Template<Type>* pCur = &pPoints[0];
130 for (plUInt32 i = 0; i < uiNumPoints; ++i)
131 {
132 ExpandToInclude(*pCur);
133
134 pCur = plMemoryUtils::AddByteOffset(pCur, uiStride);
136}
137
138template <typename Type>
140{
141 plVec3Template<Type> vHalfExtents = GetHalfExtents();
142 const plVec3Template<Type> vCenter = m_vMin + vHalfExtents;
143
144 const Type f = plMath::Max(vHalfExtents.x, vHalfExtents.y, vHalfExtents.z);
146 m_vMin = vCenter - plVec3Template<Type>(f);
147 m_vMax = vCenter + plVec3Template<Type>(f);
148}
149
150template <typename Type>
152{
153 PL_ASSERT_DEBUG(IsValid(), "Cannot grow a box that is invalid.");
154
155 m_vMax += vDiff;
156 m_vMin -= vDiff;
157
158 PL_ASSERT_DEBUG(IsValid(), "The grown box has become invalid.");
159}
160
161template <typename Type>
162PL_FORCE_INLINE bool plBoundingBoxTemplate<Type>::Contains(const plVec3Template<Type>& vPoint) const
163{
164 PL_NAN_ASSERT(this);
165 PL_NAN_ASSERT(&vPoint);
166
167 return (plMath::IsInRange(vPoint.x, m_vMin.x, m_vMax.x) && plMath::IsInRange(vPoint.y, m_vMin.y, m_vMax.y) &&
168 plMath::IsInRange(vPoint.z, m_vMin.z, m_vMax.z));
169}
170
171template <typename Type>
173{
174 return Contains(rhs.m_vMin) && Contains(rhs.m_vMax);
175}
176
177template <typename Type>
178bool plBoundingBoxTemplate<Type>::Contains(const plVec3Template<Type>* pPoints, plUInt32 uiNumPoints, plUInt32 uiStride /* = sizeof(plVec3Template<Type>) */) const
179{
180 PL_ASSERT_DEBUG(pPoints != nullptr, "Array must not be NuLL.");
181 PL_ASSERT_DEBUG(uiStride >= sizeof(plVec3Template<Type>), "Data must not overlap.");
182
183 const plVec3Template<Type>* pCur = &pPoints[0];
184
185 for (plUInt32 i = 0; i < uiNumPoints; ++i)
186 {
187 if (!Contains(*pCur))
188 return false;
189
190 pCur = plMemoryUtils::AddByteOffset(pCur, uiStride);
191 }
192
193 return true;
194}
195
196template <typename Type>
198{
199 PL_NAN_ASSERT(this);
200 PL_NAN_ASSERT(&rhs);
201
202 if (rhs.m_vMin.x >= m_vMax.x)
203 return false;
204 if (rhs.m_vMin.y >= m_vMax.y)
205 return false;
206 if (rhs.m_vMin.z >= m_vMax.z)
207 return false;
208
209 if (m_vMin.x >= rhs.m_vMax.x)
210 return false;
211 if (m_vMin.y >= rhs.m_vMax.y)
212 return false;
213 if (m_vMin.z >= rhs.m_vMax.z)
214 return false;
215
216 return true;
217}
218
219template <typename Type>
220bool plBoundingBoxTemplate<Type>::Overlaps(const plVec3Template<Type>* pPoints, plUInt32 uiNumPoints, plUInt32 uiStride /* = sizeof(plVec3Template<Type>) */) const
221{
222 PL_ASSERT_DEBUG(pPoints != nullptr, "Array must not be NuLL.");
223 PL_ASSERT_DEBUG(uiStride >= sizeof(plVec3Template<Type>), "Data must not overlap.");
224
225 const plVec3Template<Type>* pCur = &pPoints[0];
226
227 for (plUInt32 i = 0; i < uiNumPoints; ++i)
228 {
229 if (Contains(*pCur))
230 return true;
231
232 pCur = plMemoryUtils::AddByteOffset(pCur, uiStride);
233 }
234
235 return false;
236}
237
238template <typename Type>
240{
241 return (m_vMin == rhs.m_vMin && m_vMax == rhs.m_vMax);
242}
243
244template <typename Type>
246{
247 return (m_vMin.IsEqual(rhs.m_vMin, fEpsilon) && m_vMax.IsEqual(rhs.m_vMax, fEpsilon));
248}
249
250template <typename Type>
251PL_ALWAYS_INLINE bool operator==(const plBoundingBoxTemplate<Type>& lhs, const plBoundingBoxTemplate<Type>& rhs)
252{
253 return lhs.IsIdentical(rhs);
254}
255
256template <typename Type>
257PL_ALWAYS_INLINE bool operator!=(const plBoundingBoxTemplate<Type>& lhs, const plBoundingBoxTemplate<Type>& rhs)
258{
259 return !lhs.IsIdentical(rhs);
260}
261
262template <typename Type>
264{
265 m_vMin += vDiff;
266 m_vMax += vDiff;
267}
268
269template <typename Type>
271{
272 const plVec3Template<Type> vCenter = GetCenter();
273 const plVec3 vNewMin = vCenter + (m_vMin - vCenter).CompMul(vScale);
274 const plVec3 vNewMax = vCenter + (m_vMax - vCenter).CompMul(vScale);
275
276 // this is necessary for negative scalings to work as expected
277 m_vMin = vNewMin.CompMin(vNewMax);
278 m_vMax = vNewMin.CompMax(vNewMax);
279}
280
281template <typename Type>
283{
284 const plVec3 vNewMin = m_vMin.CompMul(vScale);
285 const plVec3 vNewMax = m_vMax.CompMul(vScale);
286
287 // this is necessary for negative scalings to work as expected
288 m_vMin = vNewMin.CompMin(vNewMax);
289 m_vMax = vNewMin.CompMax(vNewMax);
290}
291
292template <typename Type>
294{
295 plVec3Template<Type> vCorners[8];
296 GetCorners(vCorners);
297
298 const plVec3Template<Type> vCenter = GetCenter();
299 *this = MakeInvalid();
300
301 for (plUInt32 i = 0; i < 8; ++i)
302 ExpandToInclude(vCenter + mTransform.TransformPosition(vCorners[i] - vCenter));
303}
304
305template <typename Type>
307{
308 plVec3Template<Type> vCorners[8];
309 GetCorners(vCorners);
310
311 mTransform.TransformPosition(vCorners, 8);
312
313 *this = MakeInvalid();
314 ExpandToInclude(vCorners, 8);
315}
316
317template <typename Type>
319{
320 return vPoint.CompMin(m_vMax).CompMax(m_vMin);
321}
322
323template <typename Type>
325{
326 const plVec3Template<Type> vClamped = GetClampedPoint(vPoint);
327
328 return (vPoint - vClamped).GetLength();
329}
330
331template <typename Type>
333{
334 const plVec3Template<Type> vClamped = GetClampedPoint(vPoint);
335
336 return (vPoint - vClamped).GetLengthSquared();
337}
338
339template <typename Type>
341{
342 // This will return zero for overlapping boxes
343
344 PL_NAN_ASSERT(this);
345 PL_NAN_ASSERT(&rhs);
346
347 Type fDistSQR = 0.0f;
348
349 {
350 if (rhs.m_vMin.x > m_vMax.x)
351 {
352 fDistSQR += plMath::Square(rhs.m_vMin.x - m_vMax.x);
353 }
354 else if (rhs.m_vMax.x < m_vMin.x)
355 {
356 fDistSQR += plMath::Square(m_vMin.x - rhs.m_vMax.x);
357 }
358 }
359
360 {
361 if (rhs.m_vMin.y > m_vMax.y)
362 {
363 fDistSQR += plMath::Square(rhs.m_vMin.y - m_vMax.y);
364 }
365 else if (rhs.m_vMax.y < m_vMin.y)
366 {
367 fDistSQR += plMath::Square(m_vMin.y - rhs.m_vMax.y);
368 }
369 }
370
371 {
372 if (rhs.m_vMin.z > m_vMax.z)
373 {
374 fDistSQR += plMath::Square(rhs.m_vMin.z - m_vMax.z);
375 }
376 else if (rhs.m_vMax.z < m_vMin.z)
377 {
378 fDistSQR += plMath::Square(m_vMin.z - rhs.m_vMax.z);
379 }
380 }
381
382 return fDistSQR;
383}
384
385template <typename Type>
387{
388 return plMath::Sqrt(GetDistanceSquaredTo(rhs));
389}
390
391template <typename Type>
392bool plBoundingBoxTemplate<Type>::GetRayIntersection(const plVec3Template<Type>& vStartPos, const plVec3Template<Type>& vRayDir, Type* out_pIntersectionDistance, plVec3Template<Type>* out_pIntersection) const
393{
394 // This code was taken from: http://people.csail.mit.edu/amy/papers/box-jgt.pdf
395 // "An Efficient and Robust Ray-Box Intersection Algorithm"
396 // Contrary to previous implementation, this one actually works with ray/box configurations
397 // that produce division by zero and multiplication with infinity (which can produce NaNs).
398
399 PL_ASSERT_DEBUG(plMath::SupportsInfinity<Type>(), "This type does not support infinite values, which is required for this algorithm.");
400 PL_ASSERT_DEBUG(vStartPos.IsValid(), "Ray start position must be valid.");
401 PL_ASSERT_DEBUG(vRayDir.IsValid(), "Ray direction must be valid.");
402
403 PL_NAN_ASSERT(this);
404
405 float tMin, tMax;
406
407 // Compare along X and Z axis, find intersection point
408 {
409 float tMinY, tMaxY;
410
411 const float fDivX = 1.0f / vRayDir.x;
412 const float fDivY = 1.0f / vRayDir.y;
413
414 if (vRayDir.x >= 0.0f)
415 {
416 tMin = (m_vMin.x - vStartPos.x) * fDivX;
417 tMax = (m_vMax.x - vStartPos.x) * fDivX;
418 }
419 else
420 {
421 tMin = (m_vMax.x - vStartPos.x) * fDivX;
422 tMax = (m_vMin.x - vStartPos.x) * fDivX;
423 }
424
425 if (vRayDir.y >= 0.0f)
426 {
427 tMinY = (m_vMin.y - vStartPos.y) * fDivY;
428 tMaxY = (m_vMax.y - vStartPos.y) * fDivY;
429 }
430 else
431 {
432 tMinY = (m_vMax.y - vStartPos.y) * fDivY;
433 tMaxY = (m_vMin.y - vStartPos.y) * fDivY;
434 }
435
436 if (tMin > tMaxY || tMinY > tMax)
437 return false;
438
439 if (tMinY > tMin)
440 tMin = tMinY;
441 if (tMaxY < tMax)
442 tMax = tMaxY;
443 }
444
445 // Compare along Z axis and previous result, find intersection point
446 {
447 float tMinZ, tMaxZ;
448
449 const float fDivZ = 1.0f / vRayDir.z;
450
451 if (vRayDir.z >= 0.0f)
452 {
453 tMinZ = (m_vMin.z - vStartPos.z) * fDivZ;
454 tMaxZ = (m_vMax.z - vStartPos.z) * fDivZ;
455 }
456 else
457 {
458 tMinZ = (m_vMax.z - vStartPos.z) * fDivZ;
459 tMaxZ = (m_vMin.z - vStartPos.z) * fDivZ;
460 }
461
462 if (tMin > tMaxZ || tMinZ > tMax)
463 return false;
464
465 if (tMinZ > tMin)
466 tMin = tMinZ;
467 if (tMaxZ < tMax)
468 tMax = tMaxZ;
469 }
470
471 // rays that start inside the box are considered as not hitting the box
472 if (tMax <= 0.0f)
473 return false;
474
475 if (out_pIntersectionDistance)
476 *out_pIntersectionDistance = tMin;
477
478 if (out_pIntersection)
479 *out_pIntersection = vStartPos + tMin * vRayDir;
480
481 return true;
482}
483
484template <typename Type>
485bool plBoundingBoxTemplate<Type>::GetLineSegmentIntersection(const plVec3Template<Type>& vStartPos, const plVec3Template<Type>& vEndPos, Type* out_pLineFraction, plVec3Template<Type>* out_pIntersection) const
486{
487 const plVec3Template<Type> vRayDir = vEndPos - vStartPos;
488
489 Type fIntersection = 0.0f;
490 if (!GetRayIntersection(vStartPos, vRayDir, &fIntersection, out_pIntersection))
491 return false;
492
493 if (out_pLineFraction)
494 *out_pLineFraction = fIntersection;
495
496 return fIntersection <= 1.0f;
497}
498
499
500
501#include <Foundation/Math/Implementation/AllClasses_inl.h>
An axis-aligned bounding box implementation.
Definition BoundingBox.h:12
void Translate(const plVec3Template< Type > &vDiff)
Moves the box by the given vector.
Definition BoundingBox_inl.h:263
Type GetDistanceSquaredTo(const plVec3Template< Type > &vPoint) const
Returns the squared minimum distance from the box's surface to the point. Zero if the point is inside...
Definition BoundingBox_inl.h:332
const plVec3Template< Type > GetCenter() const
Returns the center position of the box.
Definition BoundingBox_inl.h:78
void ExpandToCube()
If the box is not cubic all extents are set to the value of the maximum extent, such that the box bec...
Definition BoundingBox_inl.h:139
const plVec3Template< Type > GetExtents() const
Returns the extents of the box along each axis.
Definition BoundingBox_inl.h:84
void ExpandToInclude(const plVec3Template< Type > &vPoint)
Expands the box such that the given point is inside it.
Definition BoundingBox_inl.h:108
bool IsNaN() const
Checks whether any component is NaN.
Definition BoundingBox_inl.h:102
Type GetDistanceTo(const plVec3Template< Type > &vPoint) const
Returns the minimum distance from the box's surface to the point. Zero if the point is inside the box...
Definition BoundingBox_inl.h:324
void TransformFromCenter(const plMat4Template< Type > &mTransform)
Transforms the corners of the box in its local space. The center of the box does not change,...
Definition BoundingBox_inl.h:293
static plBoundingBoxTemplate< Type > MakeFromPoints(const plVec3Template< Type > *pPoints, plUInt32 uiNumPoints, plUInt32 uiStride=sizeof(plVec3Template< Type >))
Creates a box around the given set of points. If uiNumPoints is zero, the returned box is invalid (sa...
Definition BoundingBox_inl.h:54
void GetCorners(plVec3Template< Type > *out_pCorners) const
Writes the 8 different corners of the box to the given array.
Definition BoundingBox_inl.h:62
plBoundingBoxTemplate()
Default constructor does not initialize anything.
bool IsValid() const
Checks whether the box is in an invalid state.
Definition BoundingBox_inl.h:96
void ScaleFromCenter(const plVec3Template< Type > &vScale)
Scales the box along each axis, but keeps its center constant.
Definition BoundingBox_inl.h:270
static plBoundingBoxTemplate< Type > MakeFromMinMax(const plVec3Template< Type > &vMin, const plVec3Template< Type > &vMax)
Creates a box with the given minimum and maximum values.
Definition BoundingBox_inl.h:42
void TransformFromOrigin(const plMat4Template< Type > &mTransform)
Transforms the corners of the box and recomputes the AABB of those transformed points....
Definition BoundingBox_inl.h:306
const plVec3Template< Type > GetClampedPoint(const plVec3Template< Type > &vPoint) const
The given point is clamped to the volume of the box, i.e. it will be either inside the box or on its ...
Definition BoundingBox_inl.h:318
bool IsEqual(const plBoundingBoxTemplate &rhs, Type fEpsilon=plMath::DefaultEpsilon< Type >()) const
Checks whether this box and the other box are equal within some threshold.
Definition BoundingBox_inl.h:245
const plVec3Template< Type > GetHalfExtents() const
Returns the half extents of the box along each axis.
Definition BoundingBox_inl.h:90
static plBoundingBoxTemplate< Type > MakeZero()
Creates a box that is located at the origin and has zero size. This is a 'valid' box.
Definition BoundingBox_inl.h:15
bool Contains(const plVec3Template< Type > &vPoint) const
Checks whether the given point is inside the box.
Definition BoundingBox_inl.h:162
bool Overlaps(const plBoundingBoxTemplate &rhs) const
Checks whether this box overlaps with the given box.
Definition BoundingBox_inl.h:197
void Grow(const plVec3Template< Type > &vDiff)
Will increase the size of the box in all directions by the given amount (per axis).
Definition BoundingBox_inl.h:151
static plBoundingBoxTemplate< Type > MakeInvalid()
Creates a box that is in an invalid state. ExpandToInclude can then be used to make it into a boundin...
Definition BoundingBox_inl.h:24
bool GetRayIntersection(const plVec3Template< Type > &vStartPos, const plVec3Template< Type > &vRayDir, Type *out_pIntersectionDistance=nullptr, plVec3Template< Type > *out_pIntersection=nullptr) const
Returns whether the given ray intersects the box. Optionally returns the intersection distance and po...
Definition BoundingBox_inl.h:392
void ScaleFromOrigin(const plVec3Template< Type > &vScale)
Scales the box's corners by the given factors, thus also moves the box around.
Definition BoundingBox_inl.h:282
bool IsIdentical(const plBoundingBoxTemplate &rhs) const
Checks whether this box and the other box are exactly identical.
Definition BoundingBox_inl.h:239
bool GetLineSegmentIntersection(const plVec3Template< Type > &vStartPos, const plVec3Template< Type > &vEndPos, Type *out_pLineFraction=nullptr, plVec3Template< Type > *out_pIntersection=nullptr) const
Checks whether the line segment intersects the box. Optionally returns the intersection point and the...
Definition BoundingBox_inl.h:485
static plBoundingBoxTemplate< Type > MakeFromCenterAndHalfExtents(const plVec3Template< Type > &vCenter, const plVec3Template< Type > &vHalfExtents)
Creates a box from a center point and half-extents for each axis.
Definition BoundingBox_inl.h:33
A 4x4 component matrix class.
Definition Mat4.h:11
const plVec3Template< Type > TransformPosition(const plVec3Template< Type > &v) const
Matrix-vector multiplication, assuming the 4th component of the vector is one (default behavior).
Definition Mat4_inl.h:347
static T * AddByteOffset(T *pPtr, std::ptrdiff_t offset)
Returns the address stored in ptr plus the given byte offset iOffset, cast to type T.
A 3-component vector class.
Definition Vec3.h:9
static plVec3Template< Type > MakeZero()
Returns a vector with all components set to zero.
Definition Vec3.h:38
void Set(Type xyz)
Sets all 3 components to this value.
Definition Vec3_inl.h:32
bool IsNaN() const
Returns true, if any of x, y or z is NaN.
Definition Vec3_inl.h:144
const plVec3Template< Type > CompMin(const plVec3Template< Type > &rhs) const
Returns the component-wise minimum of *this and rhs.
Definition Vec3_inl.h:317
bool IsValid() const
Checks that all components are finite numbers.
Definition Vec3_inl.h:157
const plVec3Template< Type > CompMax(const plVec3Template< Type > &rhs) const
Returns the component-wise maximum of *this and rhs.
Definition Vec3_inl.h:326
const plVec3Template< Type > CompMul(const plVec3Template< Type > &rhs) const
Returns the component-wise multiplication of *this and rhs.
Definition Vec3_inl.h:345
constexpr PL_ALWAYS_INLINE T Square(T f)
Returns f * f.
Definition Math_inl.h:8
constexpr bool SupportsInfinity()
Returns whether the template type supports specialized values to represent Infinity.
Definition Constants_inl.h:90
constexpr TYPE MaxValue()
Returns the largest possible positive value (that is not infinity).
constexpr bool IsInRange(T value, T minVal, T maxVal)
Checks whether the value of the first parameter lies between the value of the second and third.
Definition Math_inl.h:282
PL_ALWAYS_INLINE double Sqrt(double f)
Returns the square root of f.
Definition MathDouble_inl.h:99
constexpr PL_ALWAYS_INLINE T Max(T f1, T f2)
Returns the greater value, f1 or f2.
Definition Math_inl.h:39
Definition FormatStringArgs.h:48