Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
Box.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 "Misc/AssertionMacros.h"
7#include "Math/UnrealMathUtility.h"
8#include "Containers/UnrealString.h"
9#include "Math/Vector.h"
10#include "Math/Sphere.h"
11#include "Misc/LargeWorldCoordinatesSerializer.h"
12
13/**
14 * Implements an axis-aligned box.
15 *
16 * Boxes describe an axis-aligned extent in three dimensions. They are used for many different things in the
17 * Engine and in games, such as bounding volumes, collision detection and visibility calculation.
18 */
19namespace UE {
20namespace Math {
21
22struct TBoxConstInit {};
23
24template<typename T>
25struct TBox
26{
27public:
28 using FReal = T;
29
30 /** Holds the box's minimum point. */
31 TVector<T> Min;
32
33 /** Holds the box's maximum point. */
34 TVector<T> Max;
35
36 /** Holds a flag indicating whether this box is valid. */
37 uint8 IsValid;
38
39public:
40
41 /** Default constructor (no initialization). */
42 TBox() { }
43
44 /**
45 * Creates and initializes a new box with zero extent and marks it as invalid.
46 *
47 * Use enum value EForceInit::ForceInit to force box initialization.
48 */
49 explicit TBox( EForceInit )
50 {
51 Init();
52 }
53
54 constexpr TBox(EForceInit, TBoxConstInit)
55 : Min(0, TVectorConstInit{}), Max(0, TVectorConstInit{}), IsValid(0)
56 {
57 }
58
59 /**
60 * Creates and initializes a new box from the specified extents.
61 *
62 * @param InMin The box's minimum point.
63 * @param InMax The box's maximum point.
64 */
65 template<typename FArg>
66 TBox(const TVector<FArg>& InMin, const TVector<FArg>& InMax)
67 : Min(InMin)
68 , Max(InMax)
69 , IsValid(1)
70 {
71 // Intended to catch TBox<float>(TVector<double>(), TVector<double>())
72 static_assert(sizeof(FArg) <= sizeof(T), "Losing precision when constructing a box of floats from vectors of doubles");
73 }
74
75 TBox(const TVector4<T>& InMin, const TVector4<T>& InMax)
76 : Min(InMin)
77 , Max(InMax)
78 , IsValid(1)
79 { }
80
81 /**
82 * Creates and initializes a new box from the given set of points.
83 *
84 * @param Points Array of Points to create for the bounding volume.
85 * @param Count The number of points.
86 */
87 TBox(const TVector<T>* Points, int32 Count) : Min(0, 0, 0), Max(0, 0, 0), IsValid(0)
88 {
89 for (int32 i = 0; i < Count; i++)
90 {
91 *this += Points[i];
92 }
93 }
94
95 /**
96 * Creates and initializes a new box from an array of points.
97 *
98 * @param Points Array of Points to create for the bounding volume.
99 */
100 TBox(const TArray<TVector<T>>& Points) : TBox<T>(&Points[0], Points.Num()) {};
101
102 // Conversion from other type.
103 template<typename FArg, TEMPLATE_REQUIRES(!std::is_same_v<T, FArg>)>
104 explicit TBox(const TBox<FArg>& From) : TBox<T>(TVector<T>(From.Min), TVector<T>(From.Max)) {}
105
106public:
107
108 /**
109 * Compares two boxes for equality.
110 *
111 * Returns true if both bounding boxes are invalid. Returns false if one of the bounding boxes is invalid.
112 *
113 * @return true if the boxes are equal, false otherwise.
114 */
115 FORCEINLINE bool operator==( const TBox<T>& Other ) const
116 {
117 return (!IsValid && !Other.IsValid) || ((IsValid && Other.IsValid) && (Min == Other.Min) && (Max == Other.Max));
118 }
119
120 /**
121 * Compares two boxes for inequality.
122 *
123 * @return false if the boxes are equal, true otherwise.
124 */
125 FORCEINLINE bool operator!=( const TBox<T>& Other) const
126 {
127 return !(*this == Other);
128 }
129
130 /**
131 * Check against another box for equality, within specified error limits.
132 *
133 * Returns true if both bounding boxes are invalid. Returns false if one of the bounding boxes is invalid.
134 *
135 * @param Other The box to check against.
136 * @param Tolerance Error tolerance.
137 * @return true if the boxes are equal within tolerance limits, false otherwise.
138 */
139 bool Equals(const TBox<T>& Other, T Tolerance=UE_KINDA_SMALL_NUMBER) const
140 {
141 return (!IsValid && !Other.IsValid) || ((IsValid && Other.IsValid) && Min.Equals(Other.Min, Tolerance) && Max.Equals(Other.Max, Tolerance));
142 }
143
144 /**
145 * Adds to this bounding box to include a given point.
146 *
147 * @param Other the point to increase the bounding volume to.
148 * @return Reference to this bounding box after resizing to include the other point.
149 */
150 FORCEINLINE TBox<T>& operator+=( const TVector<T> &Other );
151
152 /**
153 * Gets the result of addition to this bounding volume.
154 *
155 * @param Other The other point to add to this.
156 * @return A new bounding volume.
157 */
158 FORCEINLINE TBox<T> operator+( const TVector<T>& Other ) const
159 {
160 return TBox<T>(*this) += Other;
161 }
162
163 /**
164 * Adds to this bounding box to include a new bounding volume.
165 *
166 * @param Other the bounding volume to increase the bounding volume to.
167 * @return Reference to this bounding volume after resizing to include the other bounding volume.
168 */
169 FORCEINLINE TBox<T>& operator+=( const TBox<T>& Other );
170
171 /**
172 * Gets the result of addition to this bounding volume.
173 *
174 * @param Other The other volume to add to this.
175 * @return A new bounding volume.
176 */
177 FORCEINLINE TBox<T> operator+( const TBox<T>& Other ) const
178 {
179 return TBox<T>(*this) += Other;
180 }
181
182 /**
183 * Gets reference to the min or max of this bounding volume.
184 *
185 * @param Index the index into points of the bounding volume.
186 * @return a reference to a point of the bounding volume.
187 */
188 FORCEINLINE TVector<T>& operator[]( int32 Index )
189 {
190 check((Index >= 0) && (Index < 2));
191
192 if (Index == 0)
193 {
194 return Min;
195 }
196
197 return Max;
198 }
199
200public:
201
202 /**
203 * Calculates the distance of a point to this box.
204 *
205 * @param Point The point.
206 * @return The distance.
207 */
208 FORCEINLINE T ComputeSquaredDistanceToPoint( const TVector<T>& Point ) const
209 {
210 return ComputeSquaredDistanceFromBoxToPoint(Min, Max, Point);
211 }
212
213 /**
214 * Calculates squared distance between two boxes.
215 */
216 FORCEINLINE T ComputeSquaredDistanceToBox(const TBox<T>& Box) const
217 {
218 TVector<T> AxisDistances = (GetCenter() - Box.GetCenter()).GetAbs() - (GetExtent() + Box.GetExtent());
219 AxisDistances = TVector<T>::Max(AxisDistances, TVector<T>(0.0f, 0.0f, 0.0f));
220 return TVector<T>::DotProduct(AxisDistances, AxisDistances);
221 }
222
223 /**
224 * Returns a box of increased size.
225 *
226 * @param W The size to increase the volume by.
227 * @return A new bounding box.
228 */
229 UE_NODISCARD FORCEINLINE TBox<T> ExpandBy(T W) const
230 {
231 return TBox<T>(Min - TVector<T>(W, W, W), Max + TVector<T>(W, W, W));
232 }
233
234 /**
235 * Returns a box of increased size.
236 *
237 * @param V The size to increase the volume by.
238 * @return A new bounding box.
239 */
240 UE_NODISCARD FORCEINLINE TBox<T> ExpandBy(const TVector<T>& V) const
241 {
242 return TBox<T>(Min - V, Max + V);
243 }
244
245 /**
246 * Returns a box of increased size.
247 *
248 * @param Neg The size to increase the volume by in the negative direction (positive values move the bounds outwards)
249 * @param Pos The size to increase the volume by in the positive direction (positive values move the bounds outwards)
250 * @return A new bounding box.
251 */
252 UE_NODISCARD TBox<T> ExpandBy(const TVector<T>& Neg, const TVector<T>& Pos) const
253 {
254 return TBox<T>(Min - Neg, Max + Pos);
255 }
256
257 /**
258 * Returns a box with its position shifted.
259 *
260 * @param Offset The vector to shift the box by.
261 * @return A new bounding box.
262 */
263 UE_NODISCARD FORCEINLINE TBox<T> ShiftBy( const TVector<T>& Offset ) const
264 {
265 return TBox<T>(Min + Offset, Max + Offset);
266 }
267
268 /**
269 * Returns a box with its center moved to the new destination.
270 *
271 * @param Destination The destination point to move center of box to.
272 * @return A new bounding box.
273 */
274 UE_NODISCARD FORCEINLINE TBox<T> MoveTo( const TVector<T>& Destination ) const
275 {
276 const TVector<T> Offset = Destination - GetCenter();
277 return TBox<T>(Min + Offset, Max + Offset);
278 }
279
280 /**
281 * Gets the center point of this box.
282 *
283 * @return The center point.
284 * @see GetCenterAndExtents, GetExtent, GetSize, GetVolume
285 */
286 FORCEINLINE TVector<T> GetCenter() const
287 {
288 return TVector<T>((Min + Max) * 0.5f);
289 }
290
291 /**
292 * Gets the center and extents of this box.
293 *
294 * @param Center [out] Will contain the box center point.
295 * @param Extents [out] Will contain the extent around the center.
296 * @see GetCenter, GetExtent, GetSize, GetVolume
297 */
298 FORCEINLINE void GetCenterAndExtents( TVector<T>& Center, TVector<T>& Extents ) const
299 {
300 Extents = GetExtent();
301 Center = Min + Extents;
302 }
303
304 /**
305 * Calculates the closest point on or inside the box to a given point in space.
306 *
307 * @param Point The point in space.
308 * @return The closest point on or inside the box.
309 */
310 FORCEINLINE TVector<T> GetClosestPointTo( const TVector<T>& Point ) const;
311
312 /**
313 * Gets the extents of this box.
314 *
315 * @return The box extents.
316 * @see GetCenter, GetCenterAndExtents, GetSize, GetVolume
317 */
318 FORCEINLINE TVector<T> GetExtent() const
319 {
320 return 0.5f * (Max - Min);
321 }
322
323 UE_DEPRECATED(4.24, "This method performed unsafe operations and should be replaced with using .Min and .Max directly or using the [] operator on this class instead.")
324 FORCEINLINE TVector<T>& GetExtrema( int PointIndex )
325 {
326 return (&Min)[PointIndex];
327 }
328
329 UE_DEPRECATED(4.24, "This method performed unsafe operations and should be replaced with using .Min and .Max directly or using the [] operator on this class instead.")
330 FORCEINLINE const TVector<T>& GetExtrema( int PointIndex ) const
331 {
332 return (&Min)[PointIndex];
333 }
334
335 /**
336 * Gets the size of this box.
337 *
338 * @return The box size.
339 * @see GetCenter, GetCenterAndExtents, GetExtent, GetVolume
340 */
341 FORCEINLINE TVector<T> GetSize() const
342 {
343 return (Max - Min);
344 }
345
346 /**
347 * Gets the volume of this box.
348 *
349 * @return The box volume.
350 * @see GetCenter, GetCenterAndExtents, GetExtent, GetSize
351 */
352 FORCEINLINE T GetVolume() const
353 {
354 return (Max.X - Min.X) * (Max.Y - Min.Y) * (Max.Z - Min.Z);
355 }
356
357 /**
358 * Set the initial values of the bounding box to Zero.
359 */
360 FORCEINLINE void Init()
361 {
362 Min = Max = TVector<T>::ZeroVector;
363 IsValid = 0;
364 }
365
366 /**
367 * Checks whether the given bounding box intersects this bounding box.
368 *
369 * @param Other The bounding box to intersect with.
370 * @return true if the boxes intersect, false otherwise.
371 */
372 FORCEINLINE bool Intersect( const TBox<T>& Other ) const;
373
374 /**
375 * Checks whether the given bounding box intersects this bounding box in the XY plane.
376 *
377 * @param Other The bounding box to test intersection.
378 * @return true if the boxes intersect in the XY Plane, false otherwise.
379 */
380 FORCEINLINE bool IntersectXY( const TBox<T>& Other ) const;
381
382 /**
383 * Returns the overlap TBox<T> of two box
384 *
385 * @param Other The bounding box to test overlap
386 * @return the overlap box. It can be 0 if they don't overlap
387 */
388 UE_NODISCARD TBox<T> Overlap( const TBox<T>& Other ) const;
389
390 /**
391 * Gets a bounding volume transformed by an inverted TTransform<T> object.
392 *
393 * @param M The transformation object to perform the inversely transform this box with.
394 * @return The transformed box.
395 */
396 UE_NODISCARD TBox<T> InverseTransformBy( const TTransform<T>& M ) const;
397
398 /**
399 * Checks whether the given location is inside this box.
400 *
401 * @param In The location to test for inside the bounding volume.
402 * @return true if location is inside this volume.
403 * @see IsInsideXY
404 */
405 FORCEINLINE bool IsInside( const TVector<T>& In ) const
406 {
407 return ((In.X > Min.X) && (In.X < Max.X) && (In.Y > Min.Y) && (In.Y < Max.Y) && (In.Z > Min.Z) && (In.Z < Max.Z));
408 }
409
410 /**
411 * Checks whether the given location is inside or on this box.
412 *
413 * @param In The location to test for inside the bounding volume.
414 * @return true if location is inside this volume.
415 * @see IsInsideXY
416 */
417 FORCEINLINE bool IsInsideOrOn( const TVector<T>& In ) const
418 {
419 return ((In.X >= Min.X) && (In.X <= Max.X) && (In.Y >= Min.Y) && (In.Y <= Max.Y) && (In.Z >= Min.Z) && (In.Z <= Max.Z));
420 }
421
422 /**
423 * Checks whether a given box is fully encapsulated by this box.
424 *
425 * @param Other The box to test for encapsulation within the bounding volume.
426 * @return true if box is inside this volume.
427 */
428 FORCEINLINE bool IsInside( const TBox<T>& Other ) const
429 {
430 return (IsInside(Other.Min) && IsInside(Other.Max));
431 }
432
433 /**
434 * Checks whether the given location is inside this box in the XY plane.
435 *
436 * @param In The location to test for inside the bounding box.
437 * @return true if location is inside this box in the XY plane.
438 * @see IsInside
439 */
440 FORCEINLINE bool IsInsideXY( const TVector<T>& In ) const
441 {
442 return ((In.X > Min.X) && (In.X < Max.X) && (In.Y > Min.Y) && (In.Y < Max.Y));
443 }
444
445 /**
446 * Checks whether the given location is inside or on this box in the XY plane.
447 *
448 * @param In The location to test for inside the bounding volume.
449 * @return true if location is inside this box in the XY plane.
450 * @see IsInsideOrOn
451 */
452 FORCEINLINE bool IsInsideOrOnXY(const FVector& In) const
453 {
454 return ((In.X >= Min.X) && (In.X <= Max.X) && (In.Y >= Min.Y) && (In.Y <= Max.Y));
455 }
456
457 /**
458 * Checks whether the given box is fully encapsulated by this box in the XY plane.
459 *
460 * @param Other The box to test for encapsulation within the bounding box.
461 * @return true if box is inside this box in the XY plane.
462 */
463 FORCEINLINE bool IsInsideXY( const TBox<T>& Other ) const
464 {
465 return (IsInsideXY(Other.Min) && IsInsideXY(Other.Max));
466 }
467
468 /**
469 * Gets a bounding volume transformed by a matrix.
470 *
471 * @param M The matrix to transform by.
472 * @return The transformed box.
473 * @see TransformProjectBy
474 */
475 UE_NODISCARD TBox<T> TransformBy( const TMatrix<T>& M ) const;
476
477 /**
478 * Gets a bounding volume transformed by a TTransform<T> object.
479 *
480 * @param M The transformation object.
481 * @return The transformed box.
482 * @see TransformProjectBy
483 */
484 UE_NODISCARD TBox<T> TransformBy( const TTransform<T>& M ) const;
485
486 /**
487 * Returns the current world bounding box transformed and projected to screen space
488 *
489 * @param ProjM The projection matrix.
490 * @return The transformed box.
491 * @see TransformBy
492 */
493 UE_NODISCARD TBox<T> TransformProjectBy( const TMatrix<T>& ProjM ) const;
494
495 /**
496 * Get a textual representation of this box.
497 *
498 * @return A string describing the box.
499 */
500 FString ToString() const;
501
502 /**
503 * Get the vertices that make up this box.
504 *
505 *
506 */
507 void GetVertices( TVector<T> (&Vertices)[8] ) const;
508
509public:
510
511 /**
512 * Utility function to build an AABB from Origin and Extent
513 *
514 * @param Origin The location of the bounding box.
515 * @param Extent Half size of the bounding box.
516 * @return A new axis-aligned bounding box.
517 */
518 static TBox<T> BuildAABB( const TVector<T>& Origin, const TVector<T>& Extent )
519 {
520 TBox<T> NewBox(Origin - Extent, Origin + Extent);
521
522 return NewBox;
523 }
524
525public:
526
527 /**
528 * Serializes the bounding box.
529 *
530 * @param Ar The archive to serialize into.
531 * @param Box The box to serialize.
532 * @return Reference to the Archive after serialization.
533 */
534 friend FArchive& operator<<( FArchive& Ar, TBox<T>& Box )
535 {
536 return Ar << Box.Min << Box.Max << Box.IsValid;
537 }
538
539 /**
540 * Serializes the bounding box.
541 *
542 * @param Slot The structured archive slot to serialize into.
543 * @param Box The box to serialize.
544 */
545 friend void operator<<(FStructuredArchive::FSlot Slot, TBox<T>& Box)
546 {
547 FStructuredArchive::FRecord Record = Slot.EnterRecord();
548 Record << SA_VALUE(TEXT("Min"), Box.Min) << SA_VALUE(TEXT("Max"), Box.Max) << SA_VALUE(TEXT("IsValid"), Box.IsValid);
549 }
550
551 bool Serialize( FArchive& Ar )
552 {
553 Ar << *this;
554 return true;
555 }
556
557 bool Serialize( FStructuredArchive::FSlot Slot )
558 {
559 Slot << *this;
560 return true;
561 }
562
563 bool SerializeFromMismatchedTag(FName StructTag, FArchive& Ar);
564};
565
566/* TBox<T> inline functions
567 *****************************************************************************/
568
569template<typename T>
570FORCEINLINE TBox<T>& TBox<T>::operator+=( const TVector<T> &Other )
571{
572 if (IsValid)
573 {
574 Min.X = FMath::Min(Min.X, Other.X);
575 Min.Y = FMath::Min(Min.Y, Other.Y);
576 Min.Z = FMath::Min(Min.Z, Other.Z);
577
578 Max.X = FMath::Max(Max.X, Other.X);
579 Max.Y = FMath::Max(Max.Y, Other.Y);
580 Max.Z = FMath::Max(Max.Z, Other.Z);
581 }
582 else
583 {
584 Min = Max = Other;
585 IsValid = 1;
586 }
587
588 return *this;
589}
590
591
592template<typename T>
593FORCEINLINE TBox<T>& TBox<T>::operator+=( const TBox<T>& Other )
594{
595 if (IsValid && Other.IsValid)
596 {
597 Min.X = FMath::Min(Min.X, Other.Min.X);
598 Min.Y = FMath::Min(Min.Y, Other.Min.Y);
599 Min.Z = FMath::Min(Min.Z, Other.Min.Z);
600
601 Max.X = FMath::Max(Max.X, Other.Max.X);
602 Max.Y = FMath::Max(Max.Y, Other.Max.Y);
603 Max.Z = FMath::Max(Max.Z, Other.Max.Z);
604 }
605 else if (Other.IsValid)
606 {
607 *this = Other;
608 }
609
610 return *this;
611}
612
613template<typename T>
614FORCEINLINE TVector<T> TBox<T>::GetClosestPointTo( const TVector<T>& Point ) const
615{
616 // start by considering the point inside the box
617 TVector<T> ClosestPoint = Point;
618
619 // now clamp to inside box if it's outside
620 if (Point.X < Min.X)
621 {
622 ClosestPoint.X = Min.X;
623 }
624 else if (Point.X > Max.X)
625 {
626 ClosestPoint.X = Max.X;
627 }
628
629 // now clamp to inside box if it's outside
630 if (Point.Y < Min.Y)
631 {
632 ClosestPoint.Y = Min.Y;
633 }
634 else if (Point.Y > Max.Y)
635 {
636 ClosestPoint.Y = Max.Y;
637 }
638
639 // Now clamp to inside box if it's outside.
640 if (Point.Z < Min.Z)
641 {
642 ClosestPoint.Z = Min.Z;
643 }
644 else if (Point.Z > Max.Z)
645 {
646 ClosestPoint.Z = Max.Z;
647 }
648
649 return ClosestPoint;
650}
651
652
653template<typename T>
654FORCEINLINE bool TBox<T>::Intersect( const TBox<T>& Other ) const
655{
656 if ((Min.X > Other.Max.X) || (Other.Min.X > Max.X))
657 {
658 return false;
659 }
660
661 if ((Min.Y > Other.Max.Y) || (Other.Min.Y > Max.Y))
662 {
663 return false;
664 }
665
666 if ((Min.Z > Other.Max.Z) || (Other.Min.Z > Max.Z))
667 {
668 return false;
669 }
670
671 return true;
672}
673
674
675template<typename T>
676FORCEINLINE bool TBox<T>::IntersectXY( const TBox<T>& Other ) const
677{
678 if ((Min.X > Other.Max.X) || (Other.Min.X > Max.X))
679 {
680 return false;
681 }
682
683 if ((Min.Y > Other.Max.Y) || (Other.Min.Y > Max.Y))
684 {
685 return false;
686 }
687
688 return true;
689}
690
691
692template<typename T>
693FORCEINLINE FString TBox<T>::ToString() const
694{
695 return FString::Printf(TEXT("IsValid=%s, Min=(%s), Max=(%s)"), IsValid ? TEXT("true") : TEXT("false"), *Min.ToString(), *Max.ToString());
696}
697
698
699template<typename T>
700TBox<T> TBox<T>::TransformBy(const TMatrix<T>& M) const
701{
702 // if we are not valid, return another invalid box.
703 if (!IsValid)
704 {
705 return TBox<T>(ForceInit);
706 }
707
708 TBox<T> NewBox;
709
710 const TVectorRegisterType<T> VecMin = VectorLoadFloat3_W0(&Min);
711 const TVectorRegisterType<T> VecMax = VectorLoadFloat3_W0(&Max);
712
713 const TVectorRegisterType<T> m0 = VectorLoadAligned(M.M[0]);
714 const TVectorRegisterType<T> m1 = VectorLoadAligned(M.M[1]);
715 const TVectorRegisterType<T> m2 = VectorLoadAligned(M.M[2]);
716 const TVectorRegisterType<T> m3 = VectorLoadAligned(M.M[3]);
717
718 const TVectorRegisterType<T> Half = VectorSetFloat1((T)0.5f); // VectorSetFloat1() can be faster than SetFloat3(0.5, 0.5, 0.5, 0.0). Okay if 4th element is 0.5, it's multiplied by 0.0 below and we discard W anyway.
719 const TVectorRegisterType<T> Origin = VectorMultiply(VectorAdd(VecMax, VecMin), Half);
720 const TVectorRegisterType<T> Extent = VectorMultiply(VectorSubtract(VecMax, VecMin), Half);
721
722 TVectorRegisterType<T> NewOrigin = VectorMultiply(VectorReplicate(Origin, 0), m0);
723 NewOrigin = VectorMultiplyAdd(VectorReplicate(Origin, 1), m1, NewOrigin);
724 NewOrigin = VectorMultiplyAdd(VectorReplicate(Origin, 2), m2, NewOrigin);
725 NewOrigin = VectorAdd(NewOrigin, m3);
726
727 TVectorRegisterType<T> NewExtent = VectorAbs(VectorMultiply(VectorReplicate(Extent, 0), m0));
728 NewExtent = VectorAdd(NewExtent, VectorAbs(VectorMultiply(VectorReplicate(Extent, 1), m1)));
729 NewExtent = VectorAdd(NewExtent, VectorAbs(VectorMultiply(VectorReplicate(Extent, 2), m2)));
730
731 const TVectorRegisterType<T> NewVecMin = VectorSubtract(NewOrigin, NewExtent);
732 const TVectorRegisterType<T> NewVecMax = VectorAdd(NewOrigin, NewExtent);
733
734 VectorStoreFloat3(NewVecMin, &(NewBox.Min.X));
735 VectorStoreFloat3(NewVecMax, &(NewBox.Max.X));
736
737 NewBox.IsValid = 1;
738
739 return NewBox;
740}
741
742template<typename T>
743TBox<T> TBox<T>::TransformBy(const TTransform<T>& M) const
744{
745 return TransformBy(M.ToMatrixWithScale());
746}
747
748template<typename T>
749void TBox<T>::GetVertices(TVector<T>(&Vertices)[8]) const
750{
751 Vertices[0] = TVector<T>(Min);
752 Vertices[1] = TVector<T>(Min.X, Min.Y, Max.Z);
753 Vertices[2] = TVector<T>(Min.X, Max.Y, Min.Z);
754 Vertices[3] = TVector<T>(Max.X, Min.Y, Min.Z);
755 Vertices[4] = TVector<T>(Max.X, Max.Y, Min.Z);
756 Vertices[5] = TVector<T>(Max.X, Min.Y, Max.Z);
757 Vertices[6] = TVector<T>(Min.X, Max.Y, Max.Z);
758 Vertices[7] = TVector<T>(Max);
759}
760
761template<typename T>
762TBox<T> TBox<T>::InverseTransformBy(const TTransform<T>& M) const
763{
764 TVector<T> Vertices[8];
765 GetVertices(Vertices);
766
767 TBox<T> NewBox(ForceInit);
768
769 for (int32 VertexIndex = 0; VertexIndex < UE_ARRAY_COUNT(Vertices); VertexIndex++)
770 {
771 TVector<T> ProjectedVertex = M.InverseTransformPosition(Vertices[VertexIndex]);
772 NewBox += ProjectedVertex;
773 }
774
775 return NewBox;
776}
777
778template<typename T>
779TBox<T> TBox<T>::TransformProjectBy(const TMatrix<T>& ProjM) const
780{
781 TVector<T> Vertices[8];
782 GetVertices(Vertices);
783
784 TBox<T> NewBox(ForceInit);
785
786 for (int32 VertexIndex = 0; VertexIndex < UE_ARRAY_COUNT(Vertices); VertexIndex++)
787 {
788 TVector4<T> ProjectedVertex = ProjM.TransformPosition(Vertices[VertexIndex]);
789 NewBox += ((TVector<T>)ProjectedVertex) / ProjectedVertex.W;
790 }
791
792 return NewBox;
793}
794
795template<typename T>
796TBox<T> TBox<T>::Overlap(const TBox<T>& Other) const
797{
798 if (Intersect(Other) == false)
799 {
800 static TBox<T> EmptyBox(ForceInit);
801 return EmptyBox;
802 }
803
804 // otherwise they overlap
805 // so find overlapping box
806 TVector<T> MinVector, MaxVector;
807
808 MinVector.X = FMath::Max(Min.X, Other.Min.X);
809 MaxVector.X = FMath::Min(Max.X, Other.Max.X);
810
811 MinVector.Y = FMath::Max(Min.Y, Other.Min.Y);
812 MaxVector.Y = FMath::Min(Max.Y, Other.Max.Y);
813
814 MinVector.Z = FMath::Max(Min.Z, Other.Min.Z);
815 MaxVector.Z = FMath::Min(Max.Z, Other.Max.Z);
816
817 return TBox<T>(MinVector, MaxVector);
818}
819
820
821} // namespace Math
822} // namespace UE
823
825
826//template<> struct TCanBulkSerialize<FBox3f> { enum { Value = true }; };
827template<> struct TIsPODType<FBox3f> { enum { Value = true }; };
828template<> struct TIsUECoreVariant<FBox3f> { enum { Value = true }; };
829
830//template<> struct TCanBulkSerialize<FBox3d> { enum { Value = false }; }; // LWC_TODO: This can be done (via versioning) once LWC is fixed to on.
831template<> struct TIsPODType<FBox3d> { enum { Value = true }; };
832template<> struct TIsUECoreVariant<FBox3d> { enum { Value = true }; };
833
834template<>
835inline bool FBox3f::SerializeFromMismatchedTag(FName StructTag, FArchive& Ar)
836{
837 return UE_SERIALIZE_VARIANT_FROM_MISMATCHED_TAG(Ar, Box, Box3f, Box3d);
838}
839
840template<>
841inline bool FBox3d::SerializeFromMismatchedTag(FName StructTag, FArchive& Ar)
842{
843 return UE_SERIALIZE_VARIANT_FROM_MISMATCHED_TAG(Ar, Box, Box3d, Box3f);
844}
845
846/* FMath inline functions
847 *****************************************************************************/
848
849template<typename FReal>
850inline bool FMath::PointBoxIntersection
851 (
852 const UE::Math::TVector<FReal>& Point,
853 const UE::Math::TBox<FReal>& Box
854 )
855{
856 return (Point.X >= Box.Min.X && Point.X <= Box.Max.X &&
857 Point.Y >= Box.Min.Y && Point.Y <= Box.Max.Y &&
858 Point.Z >= Box.Min.Z && Point.Z <= Box.Max.Z);
859}
860
861template<typename FReal>
862inline bool FMath::LineBoxIntersection
863 (
864 const UE::Math::TBox<FReal>& Box,
865 const UE::Math::TVector<FReal>& Start,
866 const UE::Math::TVector<FReal>& End,
867 const UE::Math::TVector<FReal>& StartToEnd
868 )
869{
870 return LineBoxIntersection(Box, Start, End, StartToEnd, StartToEnd.Reciprocal());
871}
872
873template<typename FReal>
874inline bool FMath::LineBoxIntersection
875 (
876 const UE::Math::TBox<FReal>& Box,
877 const UE::Math::TVector<FReal>& Start,
878 const UE::Math::TVector<FReal>& End,
879 const UE::Math::TVector<FReal>& StartToEnd,
880 const UE::Math::TVector<FReal>& OneOverStartToEnd
881 )
882{
883 UE::Math::TVector<FReal> Time;
884 bool bStartIsOutside = false;
885
886 if(Start.X < Box.Min.X)
887 {
888 bStartIsOutside = true;
889 if(End.X >= Box.Min.X)
890 {
891 Time.X = (Box.Min.X - Start.X) * OneOverStartToEnd.X;
892 }
893 else
894 {
895 return false;
896 }
897 }
898 else if(Start.X > Box.Max.X)
899 {
900 bStartIsOutside = true;
901 if(End.X <= Box.Max.X)
902 {
903 Time.X = (Box.Max.X - Start.X) * OneOverStartToEnd.X;
904 }
905 else
906 {
907 return false;
908 }
909 }
910 else
911 {
912 Time.X = 0.0f;
913 }
914
915 if(Start.Y < Box.Min.Y)
916 {
917 bStartIsOutside = true;
918 if(End.Y >= Box.Min.Y)
919 {
920 Time.Y = (Box.Min.Y - Start.Y) * OneOverStartToEnd.Y;
921 }
922 else
923 {
924 return false;
925 }
926 }
927 else if(Start.Y > Box.Max.Y)
928 {
929 bStartIsOutside = true;
930 if(End.Y <= Box.Max.Y)
931 {
932 Time.Y = (Box.Max.Y - Start.Y) * OneOverStartToEnd.Y;
933 }
934 else
935 {
936 return false;
937 }
938 }
939 else
940 {
941 Time.Y = 0.0f;
942 }
943
944 if(Start.Z < Box.Min.Z)
945 {
946 bStartIsOutside = true;
947 if(End.Z >= Box.Min.Z)
948 {
949 Time.Z = (Box.Min.Z - Start.Z) * OneOverStartToEnd.Z;
950 }
951 else
952 {
953 return false;
954 }
955 }
956 else if(Start.Z > Box.Max.Z)
957 {
958 bStartIsOutside = true;
959 if(End.Z <= Box.Max.Z)
960 {
961 Time.Z = (Box.Max.Z - Start.Z) * OneOverStartToEnd.Z;
962 }
963 else
964 {
965 return false;
966 }
967 }
968 else
969 {
970 Time.Z = 0.0f;
971 }
972
973 if(bStartIsOutside)
974 {
975 const FReal MaxTime = Max3(Time.X,Time.Y,Time.Z);
976
977 if(MaxTime >= 0.0f && MaxTime <= 1.0f)
978 {
979 const UE::Math::TVector<FReal> Hit = Start + StartToEnd * MaxTime;
980 const FReal BOX_SIDE_THRESHOLD = 0.1f;
981 if( Hit.X > Box.Min.X - BOX_SIDE_THRESHOLD && Hit.X < Box.Max.X + BOX_SIDE_THRESHOLD &&
982 Hit.Y > Box.Min.Y - BOX_SIDE_THRESHOLD && Hit.Y < Box.Max.Y + BOX_SIDE_THRESHOLD &&
983 Hit.Z > Box.Min.Z - BOX_SIDE_THRESHOLD && Hit.Z < Box.Max.Z + BOX_SIDE_THRESHOLD)
984 {
985 return true;
986 }
987 }
988
989 return false;
990 }
991 else
992 {
993 return true;
994 }
995}
996
997/**
998 * Performs a sphere vs box intersection test using Arvo's algorithm:
999 *
1000 * for each i in (x, y, z)
1001 * if (SphereCenter(i) < BoxMin(i)) d2 += (SphereCenter(i) - BoxMin(i)) ^ 2
1002 * else if (SphereCenter(i) > BoxMax(i)) d2 += (SphereCenter(i) - BoxMax(i)) ^ 2
1003 *
1004 * @param SphereCenter the center of the sphere being tested against the AABB
1005 * @param RadiusSquared the size of the sphere being tested
1006 * @param AABB the box being tested against
1007 *
1008 * @return Whether the sphere/box intersect or not.
1009 */
1010template<typename FReal>
1011inline bool FMath::SphereAABBIntersection(const UE::Math::TVector<FReal>& SphereCenter, const FReal RadiusSquared, const UE::Math::TBox<FReal>& AABB)
1012{
1013 // Accumulates the distance as we iterate axis
1014 FReal DistSquared = 0.f;
1015 // Check each axis for min/max and add the distance accordingly
1016 // NOTE: Loop manually unrolled for > 2x speed up
1017 if (SphereCenter.X < AABB.Min.X)
1018 {
1019 DistSquared += FMath::Square(SphereCenter.X - AABB.Min.X);
1020 }
1021 else if (SphereCenter.X > AABB.Max.X)
1022 {
1023 DistSquared += FMath::Square(SphereCenter.X - AABB.Max.X);
1024 }
1025 if (SphereCenter.Y < AABB.Min.Y)
1026 {
1027 DistSquared += FMath::Square(SphereCenter.Y - AABB.Min.Y);
1028 }
1029 else if (SphereCenter.Y > AABB.Max.Y)
1030 {
1031 DistSquared += FMath::Square(SphereCenter.Y - AABB.Max.Y);
1032 }
1033 if (SphereCenter.Z < AABB.Min.Z)
1034 {
1035 DistSquared += FMath::Square(SphereCenter.Z - AABB.Min.Z);
1036 }
1037 else if (SphereCenter.Z > AABB.Max.Z)
1038 {
1039 DistSquared += FMath::Square(SphereCenter.Z - AABB.Max.Z);
1040 }
1041 // If the distance is less than or equal to the radius, they intersect
1042 return DistSquared <= RadiusSquared;
1043}
1044
1045/**
1046 * Converts a sphere into a point plus radius squared for the test above
1047 */
1048template<typename FReal>
1049inline bool FMath::SphereAABBIntersection(const UE::Math::TSphere<FReal>& Sphere, const UE::Math::TBox<FReal>& AABB)
1050{
1051 FReal RadiusSquared = FMath::Square(Sphere.W);
1052 // If the distance is less than or equal to the radius, they intersect
1053 return SphereAABBIntersection(Sphere.Center, RadiusSquared, AABB);
1054}
#define check(expr)
#define UE_DEPRECATED(Version, Message)
#define UE_DECLARE_LWC_TYPE(...)
#define UE_SERIALIZE_VARIANT_FROM_MISMATCHED_TAG(AR_OR_SLOT, ALIAS, TYPE, ALT_TYPE)
#define TEXT(x)
Definition Platform.h:1108
#define FORCEINLINE
Definition Platform.h:644
#define UE_NODISCARD
Definition Platform.h:660
#define SA_VALUE(Name, Value)
#define VectorReplicate(Vec, ElementIndex)
#define UE_KINDA_SMALL_NUMBER
#define UE_ARRAY_COUNT(array)
#define TEMPLATE_REQUIRES(...)