Plasma Engine  2.0
Loading...
Searching...
No Matches
BoundingSphere_inl.h
1#pragma once
2
3#include <Foundation/Math/Mat4.h>
4
5template <typename Type>
7{
8#if PL_ENABLED(PL_MATH_CHECK_FOR_NAN)
9 // Initialize all data to NaN in debug mode to find problems with uninitialized data easier.
10 // m_vCenter is already initialized to NaN by its own constructor.
11 const Type TypeNaN = plMath::NaN<Type>();
12 m_fRadius = TypeNaN;
13#endif
14}
15
16template <typename Type>
18{
20 res.m_vCenter.SetZero();
21 res.m_fRadius = 0.0f;
22 return res;
23}
25template <typename Type>
27{
29 res.m_vCenter = vCenter;
30 res.m_fRadius = -plMath::SmallEpsilon<Type>(); // has to be very small for ExpandToInclude to work
31 return res;
32}
34template <typename Type>
36{
38 res.m_vCenter = vCenter;
39 res.m_fRadius = fRadius;
40 PL_ASSERT_DEBUG(res.IsValid(), "The sphere was created with invalid values.");
41 return res;
42}
43
44template <typename Type>
45PL_FORCE_INLINE plBoundingSphereTemplate<Type> plBoundingSphereTemplate<Type>::MakeFromPoints(const plVec3Template<Type>* pPoints, plUInt32 uiNumPoints, plUInt32 uiStride /*= sizeof(plVec3Template<Type>)*/)
46{
47 PL_ASSERT_DEBUG(pPoints != nullptr, "The array must not be empty.");
48 PL_ASSERT_DEBUG(uiStride >= sizeof(plVec3Template<Type>), "The data must not overlap.");
49 PL_ASSERT_DEBUG(uiNumPoints > 0, "The array must contain at least one point.");
51 const plVec3Template<Type>* pCur = &pPoints[0];
52
53 plVec3Template<Type> vCenter(0.0f);
54
55 for (plUInt32 i = 0; i < uiNumPoints; ++i)
56 {
57 vCenter += *pCur;
58 pCur = plMemoryUtils::AddByteOffset(pCur, uiStride);
59 }
61 vCenter /= (Type)uiNumPoints;
62
63 Type fMaxDistSQR = 0.0f;
65 pCur = &pPoints[0];
66 for (plUInt32 i = 0; i < uiNumPoints; ++i)
67 {
68 const Type fDistSQR = (*pCur - vCenter).GetLengthSquared();
69 fMaxDistSQR = plMath::Max(fMaxDistSQR, fDistSQR);
70
71 pCur = plMemoryUtils::AddByteOffset(pCur, uiStride);
72 }
75 res.m_vCenter = vCenter;
76 res.m_fRadius = plMath::Sqrt(fMaxDistSQR);
77
78 PL_ASSERT_DEBUG(res.IsValid(), "The point cloud contained corrupted data.");
80 return res;
81}
83template <typename Type>
84bool plBoundingSphereTemplate<Type>::IsZero(Type fEpsilon /* = plMath::DefaultEpsilon<Type>() */) const
86 return m_vCenter.IsZero(fEpsilon) && plMath::IsZero(m_fRadius, fEpsilon);
87}
89template <typename Type>
92 return (m_vCenter.IsValid() && m_fRadius >= 0.0f);
93}
94
95template <typename Type>
97{
98 return (m_vCenter.IsNaN() || plMath::IsNaN(m_fRadius));
99}
100
101template <typename Type>
103{
104 const Type fDistSQR = (vPoint - m_vCenter).GetLengthSquared();
105
106 if (plMath::Square(m_fRadius) < fDistSQR)
107 m_fRadius = plMath::Sqrt(fDistSQR);
109
110template <typename Type>
112{
113 const Type fReqRadius = (rhs.m_vCenter - m_vCenter).GetLength() + rhs.m_fRadius;
115 m_fRadius = plMath::Max(m_fRadius, fReqRadius);
116}
118template <typename Type>
119PL_FORCE_INLINE void plBoundingSphereTemplate<Type>::Grow(Type fDiff)
120{
121 PL_ASSERT_DEBUG(IsValid(), "Cannot grow a sphere that is invalid.");
122
123 m_fRadius += fDiff;
124
125 PL_ASSERT_DEBUG(IsValid(), "The grown sphere has become invalid.");
127
128template <typename Type>
130{
131 return (m_vCenter.IsIdentical(rhs.m_vCenter) && m_fRadius == rhs.m_fRadius);
132}
133
134template <typename Type>
137 return (m_vCenter.IsEqual(rhs.m_vCenter, fEpsilon) && plMath::IsEqual(m_fRadius, rhs.m_fRadius, fEpsilon));
138}
139
140template <typename Type>
141PL_ALWAYS_INLINE bool operator==(const plBoundingSphereTemplate<Type>& lhs, const plBoundingSphereTemplate<Type>& rhs)
142{
143 return lhs.IsIdentical(rhs);
144}
146template <typename Type>
147PL_ALWAYS_INLINE bool operator!=(const plBoundingSphereTemplate<Type>& lhs, const plBoundingSphereTemplate<Type>& rhs)
148{
149 return !lhs.IsIdentical(rhs);
150}
151
152template <typename Type>
153PL_ALWAYS_INLINE void plBoundingSphereTemplate<Type>::Translate(const plVec3Template<Type>& vTranslation)
154{
155 m_vCenter += vTranslation;
156}
157
158template <typename Type>
159PL_FORCE_INLINE void plBoundingSphereTemplate<Type>::ScaleFromCenter(Type fScale)
160{
161 PL_ASSERT_DEBUG(fScale >= 0.0f, "Cannot invert the sphere.");
162
163 m_fRadius *= fScale;
164
165 PL_NAN_ASSERT(this);
166}
167
168template <typename Type>
170{
171 PL_ASSERT_DEBUG(vScale.x >= 0.0f, "Cannot invert the sphere.");
172 PL_ASSERT_DEBUG(vScale.y >= 0.0f, "Cannot invert the sphere.");
173 PL_ASSERT_DEBUG(vScale.z >= 0.0f, "Cannot invert the sphere.");
174
175 m_vCenter = m_vCenter.CompMul(vScale);
176
177 // scale the radius by the maximum scaling factor (the sphere cannot become an ellipsoid,
178 // so to be a 'bounding' sphere, it should be as large as possible
179 m_fRadius *= plMath::Max(vScale.x, vScale.y, vScale.z);
180}
181
182template <typename Type>
184{
185 m_vCenter = mTransform.TransformPosition(m_vCenter);
186
187 const plVec3Template<Type> Scale = mTransform.GetScalingFactors();
188 m_fRadius *= plMath::Max(Scale.x, Scale.y, Scale.z);
189}
190
191template <typename Type>
193{
194 m_vCenter += mTransform.GetTranslationVector();
195
196 const plVec3Template<Type> Scale = mTransform.GetScalingFactors();
197 m_fRadius *= plMath::Max(Scale.x, Scale.y, Scale.z);
198}
199
200template <typename Type>
202{
203 return (vPoint - m_vCenter).GetLength() - m_fRadius;
204}
205
206template <typename Type>
208{
209 return (rhs.m_vCenter - m_vCenter).GetLength() - m_fRadius - rhs.m_fRadius;
210}
211
212template <typename Type>
214{
215 return (vPoint - m_vCenter).GetLengthSquared() <= plMath::Square(m_fRadius);
216}
217
218template <typename Type>
220{
221 return (rhs.m_vCenter - m_vCenter).GetLength() + rhs.m_fRadius <= m_fRadius;
222}
223
224template <typename Type>
226{
227 return (rhs.m_vCenter - m_vCenter).GetLengthSquared() < plMath::Square(rhs.m_fRadius + m_fRadius);
228}
229
230template <typename Type>
232{
233 const plVec3Template<Type> vDir = vPoint - m_vCenter;
234 const Type fDistSQR = vDir.GetLengthSquared();
235
236 // return the point, if it is already inside the sphere
237 if (fDistSQR <= plMath::Square(m_fRadius))
238 return vPoint;
239
240 // otherwise return a point on the surface of the sphere
241
242 const Type fLength = plMath::Sqrt(fDistSQR);
243
244 return m_vCenter + m_fRadius * (vDir / fLength);
245}
246
247template <typename Type>
248bool plBoundingSphereTemplate<Type>::Contains(const plVec3Template<Type>* pPoints, plUInt32 uiNumPoints, plUInt32 uiStride /* = sizeof(plVec3Template) */) const
249{
250 PL_ASSERT_DEBUG(pPoints != nullptr, "The array must not be empty.");
251 PL_ASSERT_DEBUG(uiNumPoints > 0, "The array must contain at least one point.");
252 PL_ASSERT_DEBUG(uiStride >= sizeof(plVec3Template<Type>), "The data must not overlap.");
253
254 const Type fRadiusSQR = plMath::Square(m_fRadius);
255
256 const plVec3Template<Type>* pCur = &pPoints[0];
257
258 for (plUInt32 i = 0; i < uiNumPoints; ++i)
259 {
260 if ((*pCur - m_vCenter).GetLengthSquared() > fRadiusSQR)
261 return false;
262
263 pCur = plMemoryUtils::AddByteOffset(pCur, uiStride);
264 }
265
266 return true;
267}
268
269template <typename Type>
270bool plBoundingSphereTemplate<Type>::Overlaps(const plVec3Template<Type>* pPoints, plUInt32 uiNumPoints, plUInt32 uiStride /* = sizeof(plVec3Template) */) const
271{
272 PL_ASSERT_DEBUG(pPoints != nullptr, "The array must not be empty.");
273 PL_ASSERT_DEBUG(uiNumPoints > 0, "The array must contain at least one point.");
274 PL_ASSERT_DEBUG(uiStride >= sizeof(plVec3Template<Type>), "The data must not overlap.");
275
276 const Type fRadiusSQR = plMath::Square(m_fRadius);
277
278 const plVec3Template<Type>* pCur = &pPoints[0];
279
280 for (plUInt32 i = 0; i < uiNumPoints; ++i)
281 {
282 if ((*pCur - m_vCenter).GetLengthSquared() <= fRadiusSQR)
283 return true;
284
285 pCur = plMemoryUtils::AddByteOffset(pCur, uiStride);
286 }
287
288 return false;
289}
290
291template <typename Type>
292void plBoundingSphereTemplate<Type>::ExpandToInclude(const plVec3Template<Type>* pPoints, plUInt32 uiNumPoints, plUInt32 uiStride /* = sizeof(plVec3Template) */)
293{
294 PL_ASSERT_DEBUG(pPoints != nullptr, "The array must not be empty.");
295 PL_ASSERT_DEBUG(uiStride >= sizeof(plVec3Template<Type>), "The data must not overlap.");
296
297 const plVec3Template<Type>* pCur = &pPoints[0];
298
299 Type fMaxDistSQR = 0.0f;
300
301 for (plUInt32 i = 0; i < uiNumPoints; ++i)
302 {
303 const Type fDistSQR = (*pCur - m_vCenter).GetLengthSquared();
304 fMaxDistSQR = plMath::Max(fMaxDistSQR, fDistSQR);
305
306 pCur = plMemoryUtils::AddByteOffset(pCur, uiStride);
307 }
308
309 if (plMath::Square(m_fRadius) < fMaxDistSQR)
310 m_fRadius = plMath::Sqrt(fMaxDistSQR);
311}
312
313template <typename Type>
314Type plBoundingSphereTemplate<Type>::GetDistanceTo(const plVec3Template<Type>* pPoints, plUInt32 uiNumPoints, plUInt32 uiStride /* = sizeof(plVec3Template) */) const
315{
316 PL_ASSERT_DEBUG(pPoints != nullptr, "The array must not be empty.");
317 PL_ASSERT_DEBUG(uiNumPoints > 0, "The array must contain at least one point.");
318 PL_ASSERT_DEBUG(uiStride >= sizeof(plVec3Template<Type>), "The data must not overlap.");
319
320 const plVec3Template<Type>* pCur = &pPoints[0];
321
322 Type fMinDistSQR = plMath::MaxValue<Type>();
323
324 for (plUInt32 i = 0; i < uiNumPoints; ++i)
325 {
326 const Type fDistSQR = (*pCur - m_vCenter).GetLengthSquared();
327
328 fMinDistSQR = plMath::Min(fMinDistSQR, fDistSQR);
329
330 pCur = plMemoryUtils::AddByteOffset(pCur, uiStride);
331 }
332
333 return plMath::Sqrt(fMinDistSQR);
334}
335
336template <typename Type>
338 Type* out_pIntersectionDistance /* = nullptr */, plVec3Template<Type>* out_pIntersection /* = nullptr */) const
339{
340 PL_ASSERT_DEBUG(vRayDirNormalized.IsNormalized(), "The ray direction must be normalized.");
341
342 // Ugly Code taken from 'Real Time Rendering First Edition' Page 299
343
344 const Type fRadiusSQR = plMath::Square(m_fRadius);
345 const plVec3Template<Type> vRelPos = m_vCenter - vRayStartPos;
346
347 const Type d = vRelPos.Dot(vRayDirNormalized);
348 const Type fRelPosLenSQR = vRelPos.GetLengthSquared();
349
350 if (d < 0.0f && fRelPosLenSQR > fRadiusSQR)
351 return false;
352
353 const Type m2 = fRelPosLenSQR - plMath::Square(d);
354
355 if (m2 > fRadiusSQR)
356 return false;
357
358 const Type q = plMath::Sqrt(fRadiusSQR - m2);
359
360 Type fIntersectionTime;
361
362 if (fRelPosLenSQR > fRadiusSQR)
363 fIntersectionTime = d - q;
364 else
365 fIntersectionTime = d + q;
366
367 if (out_pIntersectionDistance)
368 *out_pIntersectionDistance = fIntersectionTime;
369 if (out_pIntersection)
370 *out_pIntersection = vRayStartPos + vRayDirNormalized * fIntersectionTime;
371
372 return true;
373}
374
375template <typename Type>
377 Type* out_pHitFraction /* = nullptr */, plVec3Template<Type>* out_pIntersection /* = nullptr */) const
378{
379 Type fIntersection = 0.0f;
380
381 const plVec3Template<Type> vDir = vLineEndPos - vLineStartPos;
382 plVec3Template<Type> vDirNorm = vDir;
383 const Type fLen = vDirNorm.GetLengthAndNormalize();
384
385 if (!GetRayIntersection(vLineStartPos, vDirNorm, &fIntersection))
386 return false;
387
388 if (fIntersection > fLen)
389 return false;
390
391 if (out_pHitFraction)
392 *out_pHitFraction = fIntersection / fLen;
393
394 if (out_pIntersection)
395 *out_pIntersection = vLineStartPos + vDirNorm * fIntersection;
396
397 return true;
398}
399
400#include <Foundation/Math/Implementation/AllClasses_inl.h>
An implementation of a bounding sphere.
Definition BoundingSphere.h:11
void Translate(const plVec3Template< Type > &vTranslation)
Moves the sphere by the given vector.
Definition BoundingSphere_inl.h:153
void Grow(Type fDiff)
Increases the size of the sphere by the given amount.
Definition BoundingSphere_inl.h:119
static plBoundingSphereTemplate< Type > MakeFromCenterAndRadius(const plVec3Template< Type > &vCenter, Type fRadius)
Creates a sphere with the provided center and radius.
Definition BoundingSphere_inl.h:35
void TransformFromCenter(const plMat4Template< Type > &mTransform)
Transforms the sphere with the given matrix from its own center. I.e. rotations have no effect,...
Definition BoundingSphere_inl.h:192
bool IsZero(Type fEpsilon=plMath::DefaultEpsilon< Type >()) const
Checks whether the sphere is all zero.
Definition BoundingSphere_inl.h:84
void TransformFromOrigin(const plMat4Template< Type > &mTransform)
Transforms the sphere with the given matrix from the world origin. I.e. scalings and rotations will i...
Definition BoundingSphere_inl.h:183
bool IsIdentical(const plBoundingSphereTemplate &rhs) const
Tests whether two spheres are identical.
Definition BoundingSphere_inl.h:129
void ScaleFromCenter(Type fScale)
Scales the sphere's size, does not change its center position.
Definition BoundingSphere_inl.h:159
bool GetLineSegmentIntersection(const plVec3Template< Type > &vLineStartPos, const plVec3Template< Type > &vLineEndPos, Type *out_pHitFraction=nullptr, plVec3Template< Type > *out_pIntersection=nullptr) const
Returns true if the line segment intersects the sphere.
Definition BoundingSphere_inl.h:376
bool IsValid() const
Returns whether the sphere has valid values.
Definition BoundingSphere_inl.h:90
Type GetDistanceTo(const plVec3Template< Type > &vPoint) const
Computes the distance of the point to the sphere's surface. Returns negative values for points inside...
Definition BoundingSphere_inl.h:201
static plBoundingSphereTemplate< Type > MakeFromPoints(const plVec3Template< Type > *pPoints, plUInt32 uiNumPoints, plUInt32 uiStride=sizeof(plVec3Template< Type >))
Creates a bounding sphere around the provided points.
Definition BoundingSphere_inl.h:45
void ScaleFromOrigin(const plVec3Template< Type > &vScale)
Scales the sphere in world unites, meaning its center position will change as well.
Definition BoundingSphere_inl.h:169
const plVec3Template< Type > GetClampedPoint(const plVec3Template< Type > &vPoint)
Clamps the given position to the volume of the sphere. The resulting point will always be inside the ...
Definition BoundingSphere_inl.h:231
bool Overlaps(const plVec3Template< Type > *pPoints, plUInt32 uiNumPoints, plUInt32 uiStride=sizeof(plVec3Template< Type >)) const
Checks whether any of the given points is inside the sphere.
Definition BoundingSphere_inl.h:270
void ExpandToInclude(const plVec3Template< Type > &vPoint)
Increases the sphere's radius to include this point. Does NOT change its position,...
Definition BoundingSphere_inl.h:102
static plBoundingSphereTemplate< Type > MakeZero()
Creates a sphere at the origin with radius zero.
Definition BoundingSphere_inl.h:17
static plBoundingSphereTemplate< Type > MakeInvalid(const plVec3Template< Type > &vCenter=plVec3Template< Type >::MakeZero())
Creates an 'invalid' sphere, with its center at the given position and a negative radius.
Definition BoundingSphere_inl.h:26
bool IsNaN() const
Returns whether any value is NaN.
Definition BoundingSphere_inl.h:96
bool GetRayIntersection(const plVec3Template< Type > &vRayStartPos, const plVec3Template< Type > &vRayDir, Type *out_pIntersectionDistance=nullptr, plVec3Template< Type > *out_pIntersection=nullptr) const
Computes the intersection of a ray with this sphere. Returns true if there was an intersection....
Definition BoundingSphere_inl.h:337
plBoundingSphereTemplate()
Default constructor does not initialize any data.
Definition BoundingSphere_inl.h:6
bool IsEqual(const plBoundingSphereTemplate &rhs, Type fEpsilon=plMath::DefaultEpsilon< Type >()) const
Tests whether two spheres are equal within some threshold.
Definition BoundingSphere_inl.h:135
bool Contains(const plVec3Template< Type > &vPoint) const
Returns true if the given point is inside the sphere.
Definition BoundingSphere_inl.h:213
A 4x4 component matrix class.
Definition Mat4.h:11
const plVec3Template< Type > GetTranslationVector() const
Returns the first 3 components of the last column.
Definition Mat4_inl.h:430
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
const plVec3Template< Type > GetScalingFactors() const
Returns the 3 scaling factors that are encoded in the matrix.
Definition Mat4_inl.h:737
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
PL_DECLARE_IF_FLOAT_TYPE bool IsNormalized(Type fEpsilon=plMath::HugeEpsilon< Type >()) const
Returns, whether the squared length of this vector is between 0.999f and 1.001f.
Definition Vec3_inl.h:121
Type GetLengthSquared() const
Returns the squared length. Faster, since no square-root is taken. Useful, if one only wants to compa...
Definition Vec3_inl.h:70
PL_DECLARE_IF_FLOAT_TYPE Type GetLengthAndNormalize()
Normalizes this vector and returns its previous length in one operation. More efficient than calling ...
Definition Vec3_inl.h:78
Type Dot(const plVec3Template< Type > &rhs) const
Returns the Dot-product of the two vectors (commutative, order does not matter)
Definition Vec3_inl.h:290
constexpr PL_ALWAYS_INLINE T Square(T f)
Returns f * f.
Definition Math_inl.h:8
constexpr PL_ALWAYS_INLINE T Min(T f1, T f2)
Returns the smaller value, f1 or f2.
Definition Math_inl.h:27
constexpr TYPE MaxValue()
Returns the largest possible positive value (that is not infinity).
constexpr TYPE NaN()
Returns the value for NaN as the template type. Returns zero, if the type does not support NaN.
Definition Constants_inl.h:58
PL_ALWAYS_INLINE double Sqrt(double f)
Returns the square root of f.
Definition MathDouble_inl.h:99
bool IsZero(Type f, Type fEpsilon)
Checks whether the given number is close to zero.
Definition Math_inl.h:288
constexpr bool IsEqual(Type lhs, Type rhs, Type fEpsilon)
Checks, whether fValue is in the range [fDesired - fMaxImprecision; fDesired + fMaxImprecision].
Definition Math_inl.h:276
constexpr PL_ALWAYS_INLINE T Max(T f1, T f2)
Returns the greater value, f1 or f2.
Definition Math_inl.h:39