6#include "Math/UnrealMathUtility.h"
7#include "Containers/UnrealString.h"
9#include "Math/Vector.h"
10#include "Math/Sphere.h"
12#include "Misc/LargeWorldCoordinatesSerializer.h"
15
16
22template<
typename T,
typename TExtent>
23struct TBoxSphereBounds
31 TVector<TExtent> BoxExtent;
39 TBoxSphereBounds() { }
42
43
44
45
48 , BoxExtent(ForceInit)
55
56
57
58
59
60
61 TBoxSphereBounds(
const TVector<T>& InOrigin,
const TVector<TExtent>& InBoxExtent, TExtent InSphereRadius )
63 , BoxExtent(InBoxExtent)
64 , SphereRadius(InSphereRadius)
70
71
72
73
74
75 TBoxSphereBounds(
const TBox<T>& Box,
const TSphere<T>& Sphere )
77 TVector<T> LocalExtent;
78 Box.GetCenterAndExtents(Origin, LocalExtent);
79 BoxExtent = TVector<TExtent>(LocalExtent);
81 SphereRadius = (TExtent)FMath::Min(LocalExtent.Size(), (Sphere.Center - Origin).Size() + Sphere.W);
87
88
89
90
91
92
93 TBoxSphereBounds(
const TBox<T>& Box )
95 TVector<T> LocalExtent;
96 Box.GetCenterAndExtents(Origin, LocalExtent);
97 BoxExtent = TVector<TExtent>(LocalExtent);
99 SphereRadius = BoxExtent.Size();
101 DiagnosticCheckNaN();
105
106
107 TBoxSphereBounds(
const TSphere<T>& Sphere )
109 Origin = Sphere.Center;
110 SphereRadius = Sphere.W;
111 BoxExtent = TVector<TExtent>(SphereRadius);
113 DiagnosticCheckNaN();
117
118
119
120
121
122
123
124 TBoxSphereBounds(
const TVector<T>* Points, uint32 NumPoints );
127 template<
typename TFrom,
typename TExtentFrom,
TEMPLATE_REQUIRES(!(std::is_same_v<T, TFrom> && std::is_same_v<TExtent, TExtentFrom>))>
128 explicit TBoxSphereBounds(
const TBoxSphereBounds<TFrom, TExtentFrom>& From) : TBoxSphereBounds<T, TExtent>(TVector<T>(From.Origin), TVector<TExtent>(From.BoxExtent), (TExtent)From.SphereRadius) {}
132 bool Serialize(FArchive &Ar);
133 bool SerializeFromMismatchedTag(FName StructTag, FArchive &Ar);
136
137
138
139
140
141 FORCEINLINE TBoxSphereBounds<T, TExtent> operator+(
const TBoxSphereBounds<T, TExtent>& Other )
const;
144
145
146
147
148
149 FORCEINLINE bool operator==(
const TBoxSphereBounds<T, TExtent>& Other)
const;
152
153
154
155
156
157 FORCEINLINE bool operator!=(
const TBoxSphereBounds<T, TExtent>& Other)
const;
162
163
164
165
166
167 FORCEINLINE T ComputeSquaredDistanceFromBoxToPoint(
const TVector<T>& Point )
const
169 TVector<T> Mins = Origin - BoxExtent;
170 TVector<T> Maxs = Origin + BoxExtent;
172 return ::ComputeSquaredDistanceFromBoxToPoint(Mins, Maxs, Point);
176
177
178
179
180
181
182
185 return (A.Origin - B.Origin).SizeSquared() <= FMath::Square(FMath::Max<TExtent>(0, A.SphereRadius + B.SphereRadius + Tolerance));
189
190
191
192
193
194
195 FORCEINLINE static bool BoxesIntersect(
const TBoxSphereBounds<T, TExtent>& A,
const TBoxSphereBounds<T, TExtent>& B)
197 return A.GetBox().Intersect(B.GetBox());
201
202
203
204
207 return TBox<T>(Origin - BoxExtent,Origin + BoxExtent);
211
212
213
214
215
216 TVector<T> GetBoxExtrema( uint32 Extrema )
const
220 return Origin + BoxExtent;
223 return Origin - BoxExtent;
227
228
229
230
233 return TSphere<T>(Origin,SphereRadius);
237
238
239
240
241
242 FORCEINLINE TBoxSphereBounds<T, TExtent> ExpandBy(TExtent ExpandAmount )
const
244 return TBoxSphereBounds(Origin, BoxExtent + ExpandAmount, SphereRadius + ExpandAmount);
248
249
250
251
252
253 TBoxSphereBounds<T, TExtent> TransformBy(
const TMatrix<T>& M )
const;
256
257
258
259
260
261 TBoxSphereBounds<T, TExtent> TransformBy(
const TTransform<T>& M )
const;
264
265
266
267
268 FString ToString()
const;
271
272
273
274
275 friend TBoxSphereBounds<T, TExtent> Union(
const TBoxSphereBounds<T, TExtent>& A,
const TBoxSphereBounds<T, TExtent>& B )
281 FORCEINLINE
void DiagnosticCheckNaN()
const
283 if (Origin.ContainsNaN())
285 logOrEnsureNanError(TEXT(
"Origin contains NaN: %s"), *Origin.ToString());
286 const_cast<TBoxSphereBounds*>(
this)->Origin = TVector<T>::ZeroVector;
288 if (BoxExtent.ContainsNaN())
290 logOrEnsureNanError(TEXT(
"BoxExtent contains NaN: %s"), *BoxExtent.ToString());
291 const_cast<TBoxSphereBounds*>(
this)->BoxExtent = TVector<TExtent>::ZeroVector;
293 if (FMath::IsNaN(SphereRadius) || !FMath::IsFinite(SphereRadius))
295 logOrEnsureNanError(TEXT(
"SphereRadius contains NaN: %f"), SphereRadius);
296 const_cast<TBoxSphereBounds*>(
this)->SphereRadius = 0.f;
303 inline bool ContainsNaN()
const
305 return Origin.ContainsNaN() || BoxExtent.ContainsNaN() || !FMath::IsFinite(SphereRadius);
311
314
315
316
317
318
319
320inline FArchive& operator<<(FArchive& Ar, TBoxSphereBounds<
float,
float>& Bounds)
322 Ar << Bounds.Origin << Bounds.BoxExtent << Bounds.SphereRadius;
327
328
329
330
331
332
333inline FArchive& operator<<(FArchive& Ar, TBoxSphereBounds<
double,
double>& Bounds)
335 Ar << Bounds.Origin << Bounds.BoxExtent;
336 if (Ar.UEVer() >= EUnrealEngineObjectUE5Version::LARGE_WORLD_COORDINATES)
338 Ar << Bounds.SphereRadius;
342 checkf(Ar.IsLoading(), TEXT(
"float -> double conversion applied outside of load!"));
346 Bounds.SphereRadius = Radius;
352template<
typename T,
typename TExtent>
353FORCEINLINE TBoxSphereBounds<T, TExtent>::TBoxSphereBounds(
const TVector<T>* Points, uint32 NumPoints )
355 TBox<T> BoundingBox(ForceInit);
358 for (uint32 PointIndex = 0; PointIndex < NumPoints; PointIndex++)
360 BoundingBox += Points[PointIndex];
363 TVector<T> LocalExtent;
364 BoundingBox.GetCenterAndExtents(Origin, LocalExtent);
365 BoxExtent = TVector<TExtent>(LocalExtent);
368 TExtent SquaredSphereRadius = 0;
370 for (uint32 PointIndex = 0; PointIndex < NumPoints; PointIndex++)
372 SquaredSphereRadius = FMath::Max<TExtent>(SquaredSphereRadius, (Points[PointIndex] - Origin).SizeSquared());
375 SphereRadius = FMath::Sqrt(SquaredSphereRadius);
377 DiagnosticCheckNaN();
380template<
typename T,
typename TExtent>
381FORCEINLINE TBoxSphereBounds<T, TExtent> TBoxSphereBounds<T, TExtent>::operator+(
const TBoxSphereBounds<T, TExtent>& Other )
const
383 TBox<T> BoundingBox(ForceInit);
385 BoundingBox += (
this->Origin -
this->BoxExtent);
386 BoundingBox += (
this->Origin +
this->BoxExtent);
387 BoundingBox += (Other.Origin - Other.BoxExtent);
388 BoundingBox += (Other.Origin + Other.BoxExtent);
391 TBoxSphereBounds<T, TExtent> Result(BoundingBox);
393 Result.SphereRadius = FMath::Min<TExtent>(Result.SphereRadius, FMath::Max<TExtent>((Origin - Result.Origin).Size() + SphereRadius, (Other.Origin - Result.Origin).Size() + Other.SphereRadius));
394 Result.DiagnosticCheckNaN();
399template<
typename T,
typename TExtent>
400FORCEINLINE bool TBoxSphereBounds<T, TExtent>::operator==(
const TBoxSphereBounds<T, TExtent>& Other)
const
402 return Origin == Other.Origin && BoxExtent == Other.BoxExtent && SphereRadius == Other.SphereRadius;
405template<
typename T,
typename TExtent>
406FORCEINLINE bool TBoxSphereBounds<T, TExtent>::operator!=(
const TBoxSphereBounds<T, TExtent>& Other)
const
408 return !(*
this == Other);
411template<
typename T,
typename TExtent>
412FORCEINLINE bool TBoxSphereBounds<T, TExtent>::Serialize(FArchive &Ar)
418template<
typename T,
typename TExtent>
421 return FString::Printf(
TEXT(
"Origin=%s, BoxExtent=(%s), SphereRadius=(%f)"), *Origin.ToString(), *BoxExtent.ToString(), SphereRadius);
424template<
typename T,
typename TExtent>
425TBoxSphereBounds<T, TExtent> TBoxSphereBounds<T, TExtent>::TransformBy(
const TMatrix<T>& M)
const
430 logOrEnsureNanError(TEXT(
"Input Matrix contains NaN/Inf! %s"), *M.ToString());
431 (
const_cast<TMatrix<T>*>(&M))->SetIdentity();
435 TBoxSphereBounds<T> Result;
437 const TVectorRegisterType<T> VecOrigin = VectorLoadFloat3(&Origin);
438 const TVectorRegisterType<T> VecExtent = VectorLoadFloat3(&BoxExtent);
440 const TVectorRegisterType<T> m0 = VectorLoadAligned(M.M[0]);
441 const TVectorRegisterType<T> m1 = VectorLoadAligned(M.M[1]);
442 const TVectorRegisterType<T> m2 = VectorLoadAligned(M.M[2]);
443 const TVectorRegisterType<T> m3 = VectorLoadAligned(M.M[3]);
445 TVectorRegisterType<T> NewOrigin = VectorMultiply(
VectorReplicate(VecOrigin, 0), m0);
446 NewOrigin = VectorMultiplyAdd(
VectorReplicate(VecOrigin, 1), m1, NewOrigin);
447 NewOrigin = VectorMultiplyAdd(
VectorReplicate(VecOrigin, 2), m2, NewOrigin);
448 NewOrigin = VectorAdd(NewOrigin, m3);
450 TVectorRegisterType<T> NewExtent = VectorAbs(VectorMultiply(
VectorReplicate(VecExtent, 0), m0));
451 NewExtent = VectorAdd(NewExtent, VectorAbs(VectorMultiply(
VectorReplicate(VecExtent, 1), m1)));
452 NewExtent = VectorAdd(NewExtent, VectorAbs(VectorMultiply(
VectorReplicate(VecExtent, 2), m2)));
454 VectorStoreFloat3(NewExtent, &(Result.BoxExtent.X));
455 VectorStoreFloat3(NewOrigin, &(Result.Origin.X));
457 TVectorRegisterType<T> MaxRadius = VectorMultiply(m0, m0);
458 MaxRadius = VectorMultiplyAdd(m1, m1, MaxRadius);
459 MaxRadius = VectorMultiplyAdd(m2, m2, MaxRadius);
464 T
const BoxExtentMagnitude = FMath::Sqrt(VectorDot3Scalar(NewExtent, NewExtent));
465 Result.SphereRadius = FMath::Min(Result.SphereRadius, BoxExtentMagnitude);
467 Result.DiagnosticCheckNaN();
468 return TBoxSphereBounds<T, TExtent>(Result);
472
473
474
475
476
477 template<
typename T,
typename TExtent>
478TBoxSphereBounds<T, TExtent> TBoxSphereBounds<T, TExtent>::TransformBy(
const TTransform<T>& M)
const
481 M.DiagnosticCheckNaN_All();
484 const TMatrix<T> Mat = M.ToMatrixWithScale();
485 TBoxSphereBounds<T, TExtent> Result = TransformBy(Mat);
492template <>
struct TIsPODType<FBoxSphereBounds3f> {
enum { Value =
true }; };
493template <>
struct TIsPODType<FBoxSphereBounds3d> {
enum {
Value =
true }; };
494template <>
struct TIsUECoreVariant<FBoxSphereBounds3f> {
enum { Value =
true }; };
495template <>
struct TIsUECoreVariant<FBoxSphereBounds3d> {
enum { Value =
true }; };
496template <>
struct TIsUECoreVariant<FCompactBoxSphereBounds3d> {
enum { Value =
true }; };
499inline bool FBoxSphereBounds3f::SerializeFromMismatchedTag(FName StructTag, FArchive& Ar)
506inline bool FBoxSphereBounds3d::SerializeFromMismatchedTag(FName StructTag, FArchive& Ar)
#define checkf(expr, format,...)
#define VectorReplicate(Vec, ElementIndex)
#define VectorGetComponent(Vec, ComponentIndex)
#define ENABLE_NAN_DIAGNOSTIC
#define UE_KINDA_SMALL_NUMBER
#define TEMPLATE_REQUIRES(...)