Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
BoxSphereBounds.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreTypes.h"
6#include "Math/UnrealMathUtility.h"
7#include "Containers/UnrealString.h"
8//#include "Logging/LogMacros.h"
9#include "Math/Vector.h"
10#include "Math/Sphere.h"
11#include "Math/Box.h"
12#include "Misc/LargeWorldCoordinatesSerializer.h"
13
14/**
15 * Structure for a combined axis aligned bounding box and bounding sphere with the same origin. (28 bytes).
16 */
17namespace UE
18{
19namespace Math
20{
21
22template<typename T, typename TExtent>
23struct TBoxSphereBounds
24{
25 using FReal = T;
26
27 /** Holds the origin of the bounding box and sphere. */
28 TVector<T> Origin;
29
30 /** Holds the extent of the bounding box. */
31 TVector<TExtent> BoxExtent;
32
33 /** Holds the radius of the bounding sphere. */
34 TExtent SphereRadius;
35
36public:
37
38 /** Default constructor. */
39 TBoxSphereBounds() { }
40
41 /**
42 * Creates and initializes a new instance.
43 *
44 * @param EForceInit Force Init Enum.
45 */
46 explicit FORCEINLINE TBoxSphereBounds( EForceInit )
47 : Origin(ForceInit)
48 , BoxExtent(ForceInit)
49 , SphereRadius(0)
50 {
51 DiagnosticCheckNaN();
52 }
53
54 /**
55 * Creates and initializes a new instance from the specified parameters.
56 *
57 * @param InOrigin origin of the bounding box and sphere.
58 * @param InBoxExtent half size of box.
59 * @param InSphereRadius radius of the sphere.
60 */
61 TBoxSphereBounds( const TVector<T>& InOrigin, const TVector<TExtent>& InBoxExtent, TExtent InSphereRadius )
62 : Origin(InOrigin)
63 , BoxExtent(InBoxExtent)
64 , SphereRadius(InSphereRadius)
65 {
66 DiagnosticCheckNaN();
67 }
68
69 /**
70 * Creates and initializes a new instance from the given Box and Sphere.
71 *
72 * @param Box The bounding box.
73 * @param Sphere The bounding sphere.
74 */
75 TBoxSphereBounds( const TBox<T>& Box, const TSphere<T>& Sphere )
76 {
77 TVector<T> LocalExtent;
78 Box.GetCenterAndExtents(Origin, LocalExtent);
79 BoxExtent = TVector<TExtent>(LocalExtent);
80
81 SphereRadius = (TExtent)FMath::Min(LocalExtent.Size(), (Sphere.Center - Origin).Size() + Sphere.W);
82
83 DiagnosticCheckNaN();
84 }
85
86 /**
87 * Creates and initializes a new instance the given Box.
88 *
89 * The sphere radius is taken from the extent of the box.
90 *
91 * @param Box The bounding box.
92 */
93 TBoxSphereBounds( const TBox<T>& Box )
94 {
95 TVector<T> LocalExtent;
96 Box.GetCenterAndExtents(Origin, LocalExtent);
97 BoxExtent = TVector<TExtent>(LocalExtent);
98
99 SphereRadius = BoxExtent.Size();
100
101 DiagnosticCheckNaN();
102 }
103
104 /**
105 * Creates and initializes a new instance for the given sphere.
106 */
107 TBoxSphereBounds( const TSphere<T>& Sphere )
108 {
109 Origin = Sphere.Center;
110 SphereRadius = Sphere.W;
111 BoxExtent = TVector<TExtent>(SphereRadius);
112
113 DiagnosticCheckNaN();
114 }
115
116 /**
117 * Creates and initializes a new instance from the given set of points.
118 *
119 * The sphere radius is taken from the extent of the box.
120 *
121 * @param Points The points to be considered for the bounding box.
122 * @param NumPoints Number of points in the Points array.
123 */
124 TBoxSphereBounds( const TVector<T>* Points, uint32 NumPoints );
125
126 // Conversion to other type.
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) {}
129
130public:
131
132 bool Serialize(FArchive &Ar);
133 bool SerializeFromMismatchedTag(FName StructTag, FArchive &Ar);
134
135 /**
136 * Constructs a bounding volume containing both this and B.
137 *
138 * @param Other The other bounding volume.
139 * @return The combined bounding volume.
140 */
141 FORCEINLINE TBoxSphereBounds<T, TExtent> operator+( const TBoxSphereBounds<T, TExtent>& Other ) const;
142
143 /**
144 * Compare bounding volume this and Other.
145 *
146 * @param Other The other bounding volume.
147 * @return true of they match.
148 */
149 FORCEINLINE bool operator==(const TBoxSphereBounds<T, TExtent>& Other) const;
150
151 /**
152 * Compare bounding volume this and Other.
153 *
154 * @param Other The other bounding volume.
155 * @return true of they do not match.
156 */
157 FORCEINLINE bool operator!=(const TBoxSphereBounds<T, TExtent>& Other) const;
158
159public:
160
161 /**
162 * Calculates the squared distance from a point to a bounding box
163 *
164 * @param Point The point.
165 * @return The distance.
166 */
167 FORCEINLINE T ComputeSquaredDistanceFromBoxToPoint( const TVector<T>& Point ) const
168 {
169 TVector<T> Mins = Origin - BoxExtent;
170 TVector<T> Maxs = Origin + BoxExtent;
171
172 return ::ComputeSquaredDistanceFromBoxToPoint(Mins, Maxs, Point);
173 }
174
175 /**
176 * Test whether the spheres from two BoxSphereBounds intersect/overlap.
177 *
178 * @param A First BoxSphereBounds to test.
179 * @param B Second BoxSphereBounds to test.
180 * @param Tolerance Error tolerance added to test distance.
181 * @return true if spheres intersect, false otherwise.
182 */
183 FORCEINLINE static bool SpheresIntersect(const TBoxSphereBounds<T, TExtent>& A, const TBoxSphereBounds<T, TExtent>& B, TExtent Tolerance = UE_KINDA_SMALL_NUMBER)
184 {
185 return (A.Origin - B.Origin).SizeSquared() <= FMath::Square(FMath::Max<TExtent>(0, A.SphereRadius + B.SphereRadius + Tolerance));
186 }
187
188 /**
189 * Test whether the boxes from two BoxSphereBounds intersect/overlap.
190 *
191 * @param A First BoxSphereBounds to test.
192 * @param B Second BoxSphereBounds to test.
193 * @return true if boxes intersect, false otherwise.
194 */
195 FORCEINLINE static bool BoxesIntersect(const TBoxSphereBounds<T, TExtent>& A, const TBoxSphereBounds<T, TExtent>& B)
196 {
197 return A.GetBox().Intersect(B.GetBox());
198 }
199
200 /**
201 * Gets the bounding box.
202 *
203 * @return The bounding box.
204 */
205 FORCEINLINE TBox<T> GetBox() const
206 {
207 return TBox<T>(Origin - BoxExtent,Origin + BoxExtent);
208 }
209
210 /**
211 * Gets the extrema for the bounding box.
212 *
213 * @param Extrema 1 for positive extrema from the origin, else negative
214 * @return The boxes extrema
215 */
216 TVector<T> GetBoxExtrema( uint32 Extrema ) const
217 {
218 if (Extrema)
219 {
220 return Origin + BoxExtent;
221 }
222
223 return Origin - BoxExtent;
224 }
225
226 /**
227 * Gets the bounding sphere.
228 *
229 * @return The bounding sphere.
230 */
231 FORCEINLINE TSphere<T> GetSphere() const
232 {
233 return TSphere<T>(Origin,SphereRadius);
234 }
235
236 /**
237 * Increase the size of the box and sphere by a given size.
238 *
239 * @param ExpandAmount The size to increase by.
240 * @return A new box with the expanded size.
241 */
242 FORCEINLINE TBoxSphereBounds<T, TExtent> ExpandBy(TExtent ExpandAmount ) const
243 {
244 return TBoxSphereBounds(Origin, BoxExtent + ExpandAmount, SphereRadius + ExpandAmount);
245 }
246
247 /**
248 * Gets a bounding volume transformed by a matrix.
249 *
250 * @param M The matrix.
251 * @return The transformed volume.
252 */
253 TBoxSphereBounds<T, TExtent> TransformBy( const TMatrix<T>& M ) const;
254
255 /**
256 * Gets a bounding volume transformed by a FTransform object.
257 *
258 * @param M The FTransform object.
259 * @return The transformed volume.
260 */
261 TBoxSphereBounds<T, TExtent> TransformBy( const TTransform<T>& M ) const;
262
263 /**
264 * Get a textual representation of this bounding box.
265 *
266 * @return Text describing the bounding box.
267 */
268 FString ToString() const;
269
270 /**
271 * Constructs a bounding volume containing both A and B.
272 *
273 * This is a legacy version of the function used to compute primitive bounds, to avoid the need to rebuild lighting after the change.
274 */
275 friend TBoxSphereBounds<T, TExtent> Union( const TBoxSphereBounds<T, TExtent>& A,const TBoxSphereBounds<T, TExtent>& B )
276 {
277 return A + B;
278 }
279
281 FORCEINLINE void DiagnosticCheckNaN() const
282 {
283 if (Origin.ContainsNaN())
284 {
285 logOrEnsureNanError(TEXT("Origin contains NaN: %s"), *Origin.ToString());
286 const_cast<TBoxSphereBounds*>(this)->Origin = TVector<T>::ZeroVector;
287 }
288 if (BoxExtent.ContainsNaN())
289 {
290 logOrEnsureNanError(TEXT("BoxExtent contains NaN: %s"), *BoxExtent.ToString());
291 const_cast<TBoxSphereBounds*>(this)->BoxExtent = TVector<TExtent>::ZeroVector;
292 }
293 if (FMath::IsNaN(SphereRadius) || !FMath::IsFinite(SphereRadius))
294 {
295 logOrEnsureNanError(TEXT("SphereRadius contains NaN: %f"), SphereRadius);
296 const_cast<TBoxSphereBounds*>(this)->SphereRadius = 0.f;
297 }
298 }
299#else
300 FORCEINLINE void DiagnosticCheckNaN() const {}
301#endif
302
303 inline bool ContainsNaN() const
304 {
305 return Origin.ContainsNaN() || BoxExtent.ContainsNaN() || !FMath::IsFinite(SphereRadius);
306 }
307};
308
309
310/* TBoxSphereBounds<T, TExtent> inline functions
311 *****************************************************************************/
312
313/**
314 * Serializes the given bounding volume from or into the specified archive.
315 *
316 * @param Ar The archive to serialize from or into.
317 * @param Bounds The bounding volume to serialize.
318 * @return The archive..
319 */
320inline FArchive& operator<<(FArchive& Ar, TBoxSphereBounds<float, float>& Bounds)
321{
322 Ar << Bounds.Origin << Bounds.BoxExtent << Bounds.SphereRadius;
323 return Ar;
324}
325
326/**
327 * Serializes the given bounding volume from or into the specified archive.
328 *
329 * @param Ar The archive to serialize from or into.
330 * @param Bounds The bounding volume to serialize.
331 * @return The archive..
332 */
333inline FArchive& operator<<(FArchive& Ar, TBoxSphereBounds<double, double>& Bounds)
334{
335 Ar << Bounds.Origin << Bounds.BoxExtent;
336 if (Ar.UEVer() >= EUnrealEngineObjectUE5Version::LARGE_WORLD_COORDINATES)
337 {
338 Ar << Bounds.SphereRadius;
339 }
340 else
341 {
342 checkf(Ar.IsLoading(), TEXT("float -> double conversion applied outside of load!"));
343 // Stored as floats, so serialize float and copy.
344 float Radius;
345 Ar << Radius;
346 Bounds.SphereRadius = Radius;
347 }
348
349 return Ar;
350}
351
352template<typename T, typename TExtent>
353FORCEINLINE TBoxSphereBounds<T, TExtent>::TBoxSphereBounds( const TVector<T>* Points, uint32 NumPoints )
354{
355 TBox<T> BoundingBox(ForceInit);
356
357 // find an axis aligned bounding box for the points.
358 for (uint32 PointIndex = 0; PointIndex < NumPoints; PointIndex++)
359 {
360 BoundingBox += Points[PointIndex];
361 }
362
363 TVector<T> LocalExtent;
364 BoundingBox.GetCenterAndExtents(Origin, LocalExtent);
365 BoxExtent = TVector<TExtent>(LocalExtent);
366
367 // using the center of the bounding box as the origin of the sphere, find the radius of the bounding sphere.
368 TExtent SquaredSphereRadius = 0;
369
370 for (uint32 PointIndex = 0; PointIndex < NumPoints; PointIndex++)
371 {
372 SquaredSphereRadius = FMath::Max<TExtent>(SquaredSphereRadius, (Points[PointIndex] - Origin).SizeSquared()); // LWC_TODO: Precision loss
373 }
374
375 SphereRadius = FMath::Sqrt(SquaredSphereRadius);
376
377 DiagnosticCheckNaN();
378}
379
380template<typename T, typename TExtent>
381FORCEINLINE TBoxSphereBounds<T, TExtent> TBoxSphereBounds<T, TExtent>::operator+( const TBoxSphereBounds<T, TExtent>& Other ) const
382{
383 TBox<T> BoundingBox(ForceInit);
384
385 BoundingBox += (this->Origin - this->BoxExtent);
386 BoundingBox += (this->Origin + this->BoxExtent);
387 BoundingBox += (Other.Origin - Other.BoxExtent);
388 BoundingBox += (Other.Origin + Other.BoxExtent);
389
390 // build a bounding sphere from the bounding box's origin and the radii of A and B.
391 TBoxSphereBounds<T, TExtent> Result(BoundingBox);
392
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();
395
396 return Result;
397}
398
399template<typename T, typename TExtent>
400FORCEINLINE bool TBoxSphereBounds<T, TExtent>::operator==(const TBoxSphereBounds<T, TExtent>& Other) const
401{
402 return Origin == Other.Origin && BoxExtent == Other.BoxExtent && SphereRadius == Other.SphereRadius;
403}
404
405template<typename T, typename TExtent>
406FORCEINLINE bool TBoxSphereBounds<T, TExtent>::operator!=(const TBoxSphereBounds<T, TExtent>& Other) const
407{
408 return !(*this == Other);
409}
410
411template<typename T, typename TExtent>
412FORCEINLINE bool TBoxSphereBounds<T, TExtent>::Serialize(FArchive &Ar)
413{
414 Ar << *this;
415 return true;
416}
417
418template<typename T, typename TExtent>
419FORCEINLINE FString TBoxSphereBounds<T, TExtent>::ToString() const
420{
421 return FString::Printf(TEXT("Origin=%s, BoxExtent=(%s), SphereRadius=(%f)"), *Origin.ToString(), *BoxExtent.ToString(), SphereRadius);
422}
423
424template<typename T, typename TExtent>
425TBoxSphereBounds<T, TExtent> TBoxSphereBounds<T, TExtent>::TransformBy(const TMatrix<T>& M) const
426{
428 if (M.ContainsNaN())
429 {
430 logOrEnsureNanError(TEXT("Input Matrix contains NaN/Inf! %s"), *M.ToString());
431 (const_cast<TMatrix<T>*>(&M))->SetIdentity();
432 }
433#endif
434
435 TBoxSphereBounds<T> Result;
436
437 const TVectorRegisterType<T> VecOrigin = VectorLoadFloat3(&Origin);
438 const TVectorRegisterType<T> VecExtent = VectorLoadFloat3(&BoxExtent);
439
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]);
444
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);
449
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)));
453
454 VectorStoreFloat3(NewExtent, &(Result.BoxExtent.X));
455 VectorStoreFloat3(NewOrigin, &(Result.Origin.X));
456
457 TVectorRegisterType<T> MaxRadius = VectorMultiply(m0, m0);
458 MaxRadius = VectorMultiplyAdd(m1, m1, MaxRadius);
459 MaxRadius = VectorMultiplyAdd(m2, m2, MaxRadius);
460 MaxRadius = VectorMax(VectorMax(MaxRadius, VectorReplicate(MaxRadius, 1)), VectorReplicate(MaxRadius, 2));
461 Result.SphereRadius = FMath::Sqrt(VectorGetComponent(MaxRadius, 0)) * SphereRadius;
462
463 // For non-uniform scaling, computing sphere radius from a box results in a smaller sphere.
464 T const BoxExtentMagnitude = FMath::Sqrt(VectorDot3Scalar(NewExtent, NewExtent));
465 Result.SphereRadius = FMath::Min(Result.SphereRadius, BoxExtentMagnitude);
466
467 Result.DiagnosticCheckNaN();
468 return TBoxSphereBounds<T, TExtent>(Result);
469}
470
471/**
472 * Gets a bounding volume transformed by a FTransform object.
473 *
474 * @param M The FTransform object.
475 * @return The transformed volume.
476 */
477 template<typename T, typename TExtent>
478TBoxSphereBounds<T, TExtent> TBoxSphereBounds<T, TExtent>::TransformBy(const TTransform<T>& M) const
479{
481 M.DiagnosticCheckNaN_All();
482#endif
483
484 const TMatrix<T> Mat = M.ToMatrixWithScale();
485 TBoxSphereBounds<T, TExtent> Result = TransformBy(Mat);
486 return Result;
487}
488
489} // namespace UE::Math
490} // namespace UE
491
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 }; };
497
498template<>
499inline bool FBoxSphereBounds3f::SerializeFromMismatchedTag(FName StructTag, FArchive& Ar)
500{
501 // Falls back to UseSerializeItem to convert per property.
502 return false;
503}
504
505template<>
506inline bool FBoxSphereBounds3d::SerializeFromMismatchedTag(FName StructTag, FArchive& Ar)
507{
508 // Falls back to UseSerializeItem to convert per property.
509 return false;
510}
#define checkf(expr, format,...)
#define TEXT(x)
Definition Platform.h:1108
#define FORCEINLINE
Definition Platform.h:644
#define VectorReplicate(Vec, ElementIndex)
#define VectorGetComponent(Vec, ComponentIndex)
#define ENABLE_NAN_DIAGNOSTIC
#define UE_KINDA_SMALL_NUMBER
#define TEMPLATE_REQUIRES(...)