UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
StaticSpatialIndex.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2#pragma once
3
4#include "CoreMinimal.h"
5#include "Algo/ForEach.h"
6#include "Algo/Transform.h"
7#include "Misc/TVariant.h"
8#include "UObject/ObjectPtr.h"
11
13{
15 {
16 enum { Is3D = 0 };
20 using FBox = FBox2D;
21 };
22
24 {
25 enum { Is3D = 1 };
29 using FBox = FBox;
30 };
31
32 template <typename Profile>
33 inline bool FastSphereAABBIntersection(const typename Profile::FVector& InCenter, const typename Profile::FReal InRadiusSquared, const typename Profile::FBox& InBox)
34 {
35 const typename Profile::FVector ClosestPoint = Profile::FVector::Max(InBox.Min, Profile::FVector::Min(InCenter, InBox.Max));
36 return (ClosestPoint - InCenter).SizeSquared() <= InRadiusSquared;
37 }
38
49
61
62 template <typename Profile>
63 inline bool FastConeAABBIntersection(const typename Profile::FVector& InCenter, const typename Profile::FReal InRadiusSquared, const typename Profile::FVector& InAxis, const typename Profile::FReal InAngle, const typename Profile::FReal InSinHalfAngle, const typename Profile::FReal InCosHalfAngle, const typename Profile::FBox& InBox)
64 {
66 {
67 if constexpr (Profile::Is3D)
68 {
69 const typename Profile::FVector BoxExtent = InBox.GetExtent();
70 const typename Profile::FReal BoxExtentSizeSqr = BoxExtent.SizeSquared();
71 const typename Profile::FReal BoxExtentSize = FMath::Sqrt(BoxExtentSizeSqr);
72 const typename Profile::FVector U = InCenter - (BoxExtentSize / InSinHalfAngle) * InAxis;
73
74 typename Profile::FVector D = InBox.GetCenter() - U;
75 typename Profile::FReal DSqr = D | D;
76 typename Profile::FReal E = InAxis | D;
77
78 if(E > 0.0f && E * E >= DSqr * FMath::Square(InCosHalfAngle))
79 {
80 D = InBox.GetCenter() - InCenter;
81 DSqr = D | D;
82 E = -(InAxis | D);
83 if(E > 0.0f && E * E >= DSqr * FMath::Square(InSinHalfAngle))
84 {
85 return DSqr <= BoxExtentSizeSqr;
86 }
87
88 return true;
89 }
90
91 return false;
92 }
93 else
94 {
95 const FVector2D CenterToMinXMinY((FVector2D(InBox.Min.X, InBox.Min.Y) - InCenter).GetSafeNormal());
96 const FVector2D CenterToMaxXMinY((FVector2D(InBox.Max.X, InBox.Min.Y) - InCenter).GetSafeNormal());
97 const FVector2D CenterToMaxXMaxY((FVector2D(InBox.Max.X, InBox.Max.Y) - InCenter).GetSafeNormal());
98 const FVector2D CenterToMinXMaxY((FVector2D(InBox.Min.X, InBox.Max.Y) - InCenter).GetSafeNormal());
99
100 if (InAngle <= 180.0f)
101 {
102 const typename Profile::FReal SinAngleMinXMinY = FVector2D::CrossProduct(InAxis, CenterToMinXMinY);
103 const typename Profile::FReal SinAngleMaxXMinY = FVector2D::CrossProduct(InAxis, CenterToMaxXMinY);
104 const typename Profile::FReal SinAngleMaxXMaxY = FVector2D::CrossProduct(InAxis, CenterToMaxXMaxY);
105 const typename Profile::FReal SinAngleMinXMaxY = FVector2D::CrossProduct(InAxis, CenterToMinXMaxY);
106
108 {
109 return false;
110 }
111
113 {
114 return false;
115 }
116
117 const typename Profile::FReal CosAngleMinXMinY = FVector2D::DotProduct(InAxis, CenterToMinXMinY);
118 const typename Profile::FReal CosAngleMaxXMinY = FVector2D::DotProduct(InAxis, CenterToMaxXMinY);
119 const typename Profile::FReal CosAngleMaxXMaxY = FVector2D::DotProduct(InAxis, CenterToMaxXMaxY);
120 const typename Profile::FReal CosAngleMinXMaxY = FVector2D::DotProduct(InAxis, CenterToMinXMaxY);
121
123 {
124 return false;
125 }
126
127 return true;
128 }
129 else
130 {
131 const typename Profile::FReal CosAngleMinXMinY = FVector2D::DotProduct(InAxis,CenterToMinXMinY);
132 const typename Profile::FReal CosAngleMaxXMinY = FVector2D::DotProduct(InAxis,CenterToMaxXMinY);
133 const typename Profile::FReal CosAngleMaxXMaxY = FVector2D::DotProduct(InAxis,CenterToMaxXMaxY);
134 const typename Profile::FReal CosAngleMinXMaxY = FVector2D::DotProduct(InAxis,CenterToMinXMaxY);
135
137 {
138 return true;
139 }
140
141 const typename Profile::FReal InvInSinHalfAngle = FMath::Sin((360.0 - InAngle) * 0.5 * UE_PI / 180.0);
142 const typename Profile::FReal InvSinAngleMinXMinY = FVector2D::CrossProduct(-InAxis, CenterToMinXMinY);
143 const typename Profile::FReal InvSinAngleMaxXMinY = FVector2D::CrossProduct(-InAxis, CenterToMaxXMinY);
144 const typename Profile::FReal InvSinAngleMaxXMaxY = FVector2D::CrossProduct(-InAxis, CenterToMaxXMaxY);
145 const typename Profile::FReal InvSinAngleMinXMaxY = FVector2D::CrossProduct(-InAxis, CenterToMinXMaxY);
146
149 {
150 return false;
151 }
152
153 return true;
154 }
155 }
156 }
157
158 return false;
159 }
160}
161
162template <typename Profile>
164{
166 virtual int32 GetNumBox() const = 0;
167 virtual const typename Profile::FBox& GetBox(uint32 InIndex) const = 0;
168 virtual const typename Profile::FBox* GetBoxes(uint32 InIndex, uint32& OutStride) const = 0;
169 virtual uint32 GetAllocatedSize() const = 0;
170};
171
172template <typename ValueType, typename Profile, class SpatialIndexType, class ElementsSorter>
174{
175 using FBox = typename Profile::FBox;
176
177public:
179 : SpatialIndex(*this)
180 {}
181
183 {
184 Elements = InElements;
185 InitSpatialIndex();
186 }
187
189 {
190 Elements = MoveTemp(InElements);
191 InitSpatialIndex();
192 }
193
194 template <class Func>
195 void ForEachElement(Func InFunc) const
196 {
198
199 SpatialIndex.ForEachElement([this, &Invoker](uint32 ValueIndex)
200 {
201 return Invoker(Elements[ValueIndex].Value);
202 });
203 }
204
205 template <class Func>
206 void ForEachIntersectingElement(const FBox& InBox, Func InFunc) const
207 {
209
210 SpatialIndex.ForEachIntersectingElement(InBox, [this, &Invoker](uint32 ValueIndex)
211 {
212 return Invoker(Elements[ValueIndex].Value);
213 });
214 }
215
216 template <class Func>
218 {
220
221 SpatialIndex.ForEachIntersectingElement(InSphere, [this, &Invoker](uint32 ValueIndex)
222 {
223 return Invoker(Elements[ValueIndex].Value);
224 });
225 }
226
227 template <class Func>
229 {
231
232 SpatialIndex.ForEachIntersectingElement(InCone, [this, &Invoker](uint32 ValueIndex)
233 {
234 return Invoker(Elements[ValueIndex].Value);
235 });
236 }
237
239 {
241 {
242 for (TPair<FBox, ValueType>& Element : Elements)
243 {
244 Collector.AddReferencedObject(Element.Value);
245 }
246 }
247 }
248
249 // TStaticSpatialIndexDataInterface interface
250 virtual int32 GetNumBox() const override
251 {
252 return Elements.Num();
253 }
254
255 virtual const FBox& GetBox(uint32 InIndex) const override
256 {
257 return Elements[InIndex].Key;
258 }
259
260 virtual const FBox* GetBoxes(uint32 InIndex, uint32& OutStride) const override
261 {
262 OutStride = Elements.GetTypeSize();
263 return &Elements[InIndex].Key;
264 }
265
266 virtual uint32 GetAllocatedSize() const override
267 {
268 return sizeof(*this) + Elements.GetAllocatedSize() + SpatialIndex.GetAllocatedSize();
269 }
270
271private:
272 void InitSpatialIndex()
273 {
274 // Sort elements to maximize cache coherency during queries
275 if (ElementsSorter::NeedSort)
276 {
278 Algo::ForEach(Elements, [&ElementsBox](const TPair<FBox, ValueType>& Element) { ElementsBox += Element.Key; });
279
282 Elements.Sort([&Sorter](const TPair<FBox, ValueType>& A, const TPair<FBox, ValueType>B) { return Sorter.Sort(A.Key, B.Key); });
283 }
284
285 // Initialize spatial index implementation
286 SpatialIndex.Init();
287 }
288
290 SpatialIndexType SpatialIndex;
291};
292
293namespace FStaticSpatialIndex
294{
295 template <typename Profile>
296 class TImpl
297 {
298 public:
300 : DataInterface(InDataInterface)
301 {}
302
303 protected:
305 };
306
307 template <typename Profile>
308 class TListImpl : public TImpl<Profile>
309 {
310 using FVector = typename Profile::FVector;
311 using FBox = typename Profile::FBox;
312
313 public:
315 : TImpl<Profile>(InDataInterface)
316 {}
317
318 void Init() {}
319
320 bool ForEachElement(TFunctionRef<bool(uint32 InValueIndex)> InFunc) const
321 {
322 for (int32 ValueIndex = 0; ValueIndex < this->DataInterface.GetNumBox(); ValueIndex++)
323 {
324 if (!InFunc(ValueIndex))
325 {
326 return false;
327 }
328 }
329 return true;
330 }
331
332 bool ForEachIntersectingElement(const FBox& InBox, TFunctionRef<bool(uint32 InValueIndex)> InFunc) const
333 {
335 const FBox* Box = this->DataInterface.GetBoxes(0, BoxStride);
336 for (int32 ValueIndex = 0; ValueIndex < this->DataInterface.GetNumBox(); ValueIndex++, *(uint8**)&Box += BoxStride)
337 {
338 if (Box->Intersect(InBox))
339 {
340 if (!InFunc(ValueIndex))
341 {
342 return false;
343 }
344 }
345 }
346 return true;
347
348 }
349
350 bool ForEachIntersectingElement(const FStaticSpatialIndex::FSphere& InSphere, TFunctionRef<bool(uint32 InValueIndex)> InFunc) const
351 {
352 const typename Profile::FReal RadiusSquared = FMath::Square(InSphere.Radius);
353
355 const FBox* Box = this->DataInterface.GetBoxes(0, BoxStride);
356 for (int32 ValueIndex = 0; ValueIndex < this->DataInterface.GetNumBox(); ValueIndex++, *(uint8**)&Box += BoxStride)
357 {
359 {
360 if (!InFunc(ValueIndex))
361 {
362 return false;
363 }
364 }
365 }
366 return true;
367 }
368
369 bool ForEachIntersectingElement(const FStaticSpatialIndex::FCone& InCone, TFunctionRef<bool(uint32 InValueIndex)> InFunc) const
370 {
371 const typename Profile::FReal RadiusSquared = FMath::Square(InCone.Radius);
372 const typename Profile::FReal HalfSinAngle = FMath::Sin(InCone.Angle * 0.5 * UE_PI / 180.0);
373 const typename Profile::FReal HalfCosAngle = FMath::Cos(InCone.Angle * 0.5 * UE_PI / 180.0);
374
376 const FBox* Box = this->DataInterface.GetBoxes(0, BoxStride);
377 for (int32 ValueIndex = 0; ValueIndex < this->DataInterface.GetNumBox(); ValueIndex++, *(uint8**)&Box += BoxStride)
378 {
380 {
381 if (!InFunc(ValueIndex))
382 {
383 return false;
384 }
385 }
386 }
387 return true;
388 }
389
391 {
392 return sizeof(*this);
393 }
394 };
395
396 template <typename Profile, int32 MaxNumElementsPerNode = 16, int32 MaxNumElementsPerLeaf = 64>
397 class TRTreeImpl : public TImpl<Profile>
398 {
399 using FVector = typename Profile::FVector;
400 using FBox = typename Profile::FBox;
401
402 public:
404 : TImpl<Profile>(InDataInterface)
405 {}
406
407 void Init()
408 {
409 if (this->DataInterface.GetNumBox())
410 {
411 // Build leaves
412 FNode* CurrentNode = nullptr;
414 TArray<FNode> Nodes;
415
416 for (int32 ElementIndex = 0; ElementIndex < this->DataInterface.GetNumBox(); ElementIndex++)
417 {
418 const FBox& Element = this->DataInterface.GetBox(ElementIndex);
419
420 if (!CurrentNode || (CurrentNode->Content.template Get<typename FNode::FLeafType>().Num() >= MaxNumElementsPerLeaf))
421 {
422 if (CurrentNode)
423 {
424 CurrentNode->BoxMin = CurrentNodeBox.Min;
425 CurrentNode->BoxMax = CurrentNodeBox.Max;
426 CurrentNodeBox.Init();
427 }
428
429 CurrentNode = &Nodes.Emplace_GetRef();
430 CurrentNode->Content.template Emplace<typename FNode::FLeafType>();
431 }
432
434 CurrentNode->Content.template Get<typename FNode::FLeafType>().Add(ElementIndex);
435 }
436
437 check(CurrentNode);
438
439 CurrentNode->BoxMin = CurrentNodeBox.Min;
440 CurrentNode->BoxMax = CurrentNodeBox.Max;
441 CurrentNodeBox.Init();
442
443 // Build nodes
444 while (Nodes.Num() > 1)
445 {
446 CurrentNode = nullptr;
448
449 for (FNode& Node : Nodes)
450 {
451 if (!CurrentNode || (CurrentNode->Content.template Get<typename FNode::FNodeType>().Num() >= MaxNumElementsPerNode))
452 {
453 if (CurrentNode)
454 {
455 CurrentNode->BoxMin = CurrentNodeBox.Min;
456 CurrentNode->BoxMax = CurrentNodeBox.Max;
457 CurrentNode->Content.template Get<typename FNode::FNodeType>().Shrink();
458 CurrentNodeBox.Init();
459 }
460
461 CurrentNode = &TopNodes.Emplace_GetRef();
462 CurrentNode->Content.template Emplace<typename FNode::FNodeType>();
463 }
464
465 CurrentNodeBox += Node.GetBox();
466 CurrentNode->Content.template Get<typename FNode::FNodeType>().Add(MoveTemp(Node));
467 }
468
469 check(CurrentNode);
470
471 CurrentNode->BoxMin = CurrentNodeBox.Min;
472 CurrentNode->BoxMax = CurrentNodeBox.Max;
473 CurrentNode->Content.template Get<typename FNode::FNodeType>().Shrink();
474 CurrentNodeBox.Init();
475
476 Nodes = MoveTemp(TopNodes);
477 }
478
479 check(Nodes.Num() == 1);
480 RootNode = MoveTemp(Nodes[0]);
481 }
482 }
483
484 bool ForEachElement(TFunctionRef<bool(uint32 InValueIndex)> InFunc) const
485 {
486 return ForEachElementRecursive(&RootNode, InFunc);
487 }
488
489 bool ForEachIntersectingElement(const FBox& InBox, TFunctionRef<bool(uint32 InValueIndex)> InFunc) const
490 {
491 return ForEachIntersectingElementRecursive(&RootNode, InBox, InFunc);
492 }
493
494 bool ForEachIntersectingElement(const FStaticSpatialIndex::FSphere& InSphere, TFunctionRef<bool(uint32 InValueIndex)> InFunc) const
495 {
496 const typename Profile::FReal RadiusSquared = FMath::Square(InSphere.Radius);
497 return ForEachIntersectingElementRecursive(&RootNode, FVector(InSphere.Center), RadiusSquared, InFunc);
498 }
499
500 bool ForEachIntersectingElement(const FStaticSpatialIndex::FCone& InCone, TFunctionRef<bool(uint32 InValueIndex)> InFunc) const
501 {
502 const typename Profile::FReal RadiusSquared = FMath::Square(InCone.Radius);
503 const typename Profile::FReal HalfSinAngle = FMath::Sin(InCone.Angle * 0.5 * UE_PI / 180.0);
504 const typename Profile::FReal HalfCosAngle = FMath::Cos(InCone.Angle * 0.5 * UE_PI / 180.0);
505 return ForEachIntersectingElementRecursive(&RootNode, FVector(InCone.Center), RadiusSquared, FVector(InCone.Axis), InCone.Angle, HalfSinAngle, HalfCosAngle, InFunc);
506 }
507
509 {
510 TFunction<uint32(const FNode*, uint32)> GetAllocatedSizeRecursive = [this, &GetAllocatedSizeRecursive](const FNode* Node, uint32 BaseSize)
511 {
512 uint32 AllocatedSize = BaseSize;
513
514 if (Node->Content.template IsType<typename FNode::FNodeType>())
515 {
516 AllocatedSize += Node->Content.template Get<typename FNode::FNodeType>().GetAllocatedSize();
517
518 for (auto& ChildNode : Node->Content.template Get<typename FNode::FNodeType>())
519 {
520 AllocatedSize += GetAllocatedSizeRecursive(&ChildNode, sizeof(FNode));
521 }
522 }
523 else
524 {
525 AllocatedSize += Node->Content.template Get<typename FNode::FLeafType>().GetAllocatedSize();
526 }
527
528 return AllocatedSize;
529 };
530
531 return GetAllocatedSizeRecursive(&RootNode, sizeof(*this));
532 }
533
534 protected:
535 struct FNode
536 {
539 {
542
543 inline FLeafType()
544 : StartIndex(0)
545 , NumElements(0)
546 {}
547
548 inline void Add(uint32 InIndex)
549 {
550 if (!NumElements)
551 {
553 }
554
556 NumElements++;
557 }
558
559 inline uint32 Num() const { return NumElements; }
560 inline uint32 GetAllocatedSize() const { return sizeof(*this); }
561
563 {
565 inline uint32 operator++() { return Value++; }
566 inline uint32 operator*() const { return Value; }
567 inline bool operator!=(const TIterator& Other) const { return Value != Other.Value; }
569 };
570
571 inline TIterator begin() { return TIterator(StartIndex); }
572 inline TIterator begin() const { return TIterator(StartIndex); }
574 inline TIterator end() const { return TIterator(StartIndex + NumElements); }
575 };
576 using FVectorType = typename Profile::FVector;
577 using FBoxType = typename Profile::FBox;
578
579 inline FBoxType GetBox() const { return FBoxType(BoxMin, BoxMax); }
580
583
585 };
586
587 bool ForEachElementRecursive(const FNode* InNode, TFunctionRef<bool(uint32 InValueIndex)> InFunc) const
588 {
589 if (InNode->Content.template IsType<typename FNode::FNodeType>())
590 {
591 for (auto& ChildNode : InNode->Content.template Get<typename FNode::FNodeType>())
592 {
593 if (!ForEachElementRecursive(&ChildNode, InFunc))
594 {
595 return false;
596 }
597 }
598 }
599 else
600 {
601 for (uint32 ValueIndex : InNode->Content.template Get<typename FNode::FLeafType>())
602 {
603 if (!InFunc(ValueIndex))
604 {
605 return false;
606 }
607 }
608 }
609 return true;
610
611 }
612
613 bool ForEachIntersectingElementRecursive(const FNode* InNode, const FBox& InBox, TFunctionRef<bool(uint32 InValueIndex)> InFunc) const
614 {
615 if (InNode->Content.template IsType<typename FNode::FNodeType>())
616 {
617 for (auto& ChildNode : InNode->Content.template Get<typename FNode::FNodeType>())
618 {
619 if (ChildNode.GetBox().Intersect(InBox))
620 {
621 if (!ForEachIntersectingElementRecursive(&ChildNode, InBox, InFunc))
622 {
623 return false;
624 }
625 }
626 }
627 }
628 else
629 {
631 const FBox* Box = this->DataInterface.GetBoxes(InNode->Content.template Get<typename FNode::FLeafType>().StartIndex, BoxStride);
632
633 for (uint32 ValueIndex : InNode->Content.template Get<typename FNode::FLeafType>())
634 {
635 if (Box->Intersect(InBox))
636 {
637 if (!InFunc(ValueIndex))
638 {
639 return false;
640 }
641 }
642
643 *(uint8**)&Box += BoxStride;
644 }
645 }
646 return true;
647 }
648
649 bool ForEachIntersectingElementRecursive(const FNode* InNode, const FVector& InSphereCenter, typename Profile::FReal InRadiusSquared, TFunctionRef<bool(uint32 InValueIndex)> InFunc) const
650 {
651 if (InNode->Content.template IsType<typename FNode::FNodeType>())
652 {
653 for (auto& ChildNode : InNode->Content.template Get<typename FNode::FNodeType>())
654 {
656 {
657 if (!ForEachIntersectingElementRecursive(&ChildNode, InSphereCenter, InRadiusSquared, InFunc))
658 {
659 return false;
660 }
661 }
662 }
663 }
664 else
665 {
667 const FBox* Box = this->DataInterface.GetBoxes(InNode->Content.template Get<typename FNode::FLeafType>().StartIndex, BoxStride);
668
669 for (uint32 ValueIndex : InNode->Content.template Get<typename FNode::FLeafType>())
670 {
672 {
673 if (!InFunc(ValueIndex))
674 {
675 return false;
676 }
677 }
678
679 *(uint8**)&Box += BoxStride;
680 }
681 }
682 return true;
683 }
684
685 bool ForEachIntersectingElementRecursive(const FNode* InNode, const FVector& InConeCenter, typename Profile::FReal InRadiusSquared, const FVector& InAxis, float InAngle, float InSinHalfAngle, float InCosHalfAngle, TFunctionRef<bool(uint32 InValueIndex)> InFunc) const
686 {
687 if (InNode->Content.template IsType<typename FNode::FNodeType>())
688 {
689 for (auto& ChildNode : InNode->Content.template Get<typename FNode::FNodeType>())
690 {
692 {
693 if (!ForEachIntersectingElementRecursive(&ChildNode, InConeCenter, InRadiusSquared, InAxis, InAngle, InSinHalfAngle, InCosHalfAngle, InFunc))
694 {
695 return false;
696 }
697 }
698 }
699 }
700 else
701 {
703 const FBox* Box = this->DataInterface.GetBoxes(InNode->Content.template Get<typename FNode::FLeafType>().StartIndex, BoxStride);
704
705 for (uint32 ValueIndex : InNode->Content.template Get<typename FNode::FLeafType>())
706 {
708 {
709 if (!InFunc(ValueIndex))
710 {
711 return false;
712 }
713 }
714
715 *(uint8**)&Box += BoxStride;
716 }
717 }
718 return true;
719 }
720 FNode RootNode;
721 };
722
723 template <typename Profile>
724 class TNodeSorterNoSort
725 {
726 public:
727 enum { NeedSort = 0 };
728 using FBox = typename Profile::FBox;
729 void Init(const FBox& SortBox) {}
730 bool Sort(const FBox& A, const FBox& B) { return false; }
731 };
732
733 template <typename Profile>
734 class TNodeSorterMinX
735 {
736 public:
737 enum { NeedSort = 1 };
738 using FBox = typename Profile::FBox;
739 void Init(const FBox& SortBox) {}
740 bool Sort(const FBox& A, const FBox& B) { return A.Min.X < B.Min.X; }
741 };
742
743 template <typename Profile, int32 BucketSize>
744 class TNodeSorterMorton
745 {
746 public:
747 enum { NeedSort = 1 };
748 using FBox = typename Profile::FBox;
749 using FReal = typename Profile::FReal;
750 using FIntPoint = typename Profile::FIntPoint;
751
752 void Init(const FBox& SortBox)
753 {}
754
755 bool Sort(const FBox& A, const FBox& B)
756 {
758 CellPosA.X = int32(A.GetCenter().X / (FReal)BucketSize);
759 CellPosA.Y = int32(A.GetCenter().Y / (FReal)BucketSize);
760 if constexpr (Profile::Is3D)
761 {
762 CellPosA.Z = int32(A.GetCenter().Z / (FReal)BucketSize);
763 }
764 const uint32 MortonCodeA = MortonEncode(CellPosA);
765
767 CellPosB.X = int32(B.GetCenter().X / (FReal)BucketSize);
768 CellPosB.Y = int32(B.GetCenter().Y / (FReal)BucketSize);
769 if constexpr (Profile::Is3D)
770 {
771 CellPosB.Z = int32(B.GetCenter().Z / (FReal)BucketSize);
772 }
773 const uint32 MortonCodeB = MortonEncode(CellPosB);
774
775 return MortonCodeA < MortonCodeB;
776 }
777
778 private:
779 inline uint32 MortonEncode(const FIntPoint& Point)
780 {
781 if constexpr (Profile::Is3D)
782 {
783 return FMath::MortonCode3(Point.X) | (FMath::MortonCode3(Point.Y) << 1) | (FMath::MortonCode3(Point.Z) << 2);
784 }
785 else
786 {
787 return FMath::MortonCode2(Point.X) | (FMath::MortonCode2(Point.Y) << 1);
788 }
789 }
790 };
791
792 template <typename Profile, int32 BucketSize>
793 class TNodeSorterHilbert
794 {
795 public:
796 enum { NeedSort = 1 };
797 using FBox = typename Profile::FBox;
798 using FReal = typename Profile::FReal;
799 using FIntPoint = typename Profile::FIntPoint;
800
801 void Init(const FBox& SortBox)
802 {
803 const FReal MaxExtent = SortBox.GetExtent().GetMax();
804 const uint32 NumBuckets = FMath::CeilToInt32(MaxExtent / (FReal)BucketSize);
805 HilbertOrder = 1 + FMath::CeilLogTwo(NumBuckets);
806 }
807
808 bool Sort(const FBox& A, const FBox& B)
809 {
810 const int32 HilbertCodeA = HilbertEncode({ int32(A.GetCenter().X / (FReal)BucketSize), int32(A.GetCenter().Y / (FReal)BucketSize) }, HilbertOrder);
811 const int32 HilbertCodeB = HilbertEncode({ int32(B.GetCenter().X / (FReal)BucketSize), int32(B.GetCenter().Y / (FReal)BucketSize) }, HilbertOrder);
812 return HilbertCodeA < HilbertCodeB;
813 }
814
815 private:
816 uint32 HilbertEncode(const FIntVector2& Point, uint32 Order)
817 {
818 uint32 Result = 0;
819
820 uint32 State = 0;
821 for (int32 i = Order - 1; i >= 0; i--)
822 {
823 uint32 Row = 4 * State | 2 * ((Point.X >> i) & 1) | ((Point.Y >> i) & 1);
824 Result = (Result << 2) | ((0x361e9cb4 >> 2 * Row) & 3);
825 State = (0x8fe65831 >> 2 * Row) & 3;
826 }
827
828 return Result;
829 }
830
831 uint32 HilbertOrder;
832 };
833}
834
835template <typename ValueType, typename NodeSorter, typename Profile>
836class TStaticSpatialIndexList : public TStaticSpatialIndex<ValueType, Profile, FStaticSpatialIndex::TListImpl<Profile>, NodeSorter>
837{};
838
839template <typename ValueType, typename NodeSorter, typename Profile>
840class TStaticSpatialIndexRTree : public TStaticSpatialIndex<ValueType, Profile, FStaticSpatialIndex::TRTreeImpl<Profile>, NodeSorter>
841{};
#define check(expr)
Definition AssertionMacros.h:314
@ ForceInit
Definition CoreMiscDefines.h:155
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
void Init()
Definition LockFreeList.h:4
UE::Math::TIntVector2< int32 > FIntVector2
Definition MathFwd.h:91
UE::Math::TVector2< double > FVector2D
Definition MathFwd.h:48
FInt32Vector3 FIntVector
Definition MathFwd.h:115
UE::Math::TBox2< double > FBox2D
Definition MathFwd.h:56
#define UE_PI
Definition UnrealMathUtility.h:129
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
uint8_t uint8
Definition binka_ue_file_header.h:8
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition UObjectGlobals.h:2492
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
UE_REWRITE SizeType Max() const
Definition Array.h:1161
UE_FORCEINLINE_HINT ElementType & Emplace_GetRef(ArgsType &&... Args) UE_LIFETIMEBOUND
Definition Array.h:2613
Definition AssetRegistryState.h:50
Definition AndroidPlatformMisc.h:14
Definition StaticSpatialIndex.h:837
Definition StaticSpatialIndex.h:841
Definition StaticSpatialIndex.h:174
void Init(const TArray< TPair< FBox, ValueType > > &InElements)
Definition StaticSpatialIndex.h:182
void AddReferencedObjects(FReferenceCollector &Collector)
Definition StaticSpatialIndex.h:238
virtual int32 GetNumBox() const override
Definition StaticSpatialIndex.h:250
void ForEachIntersectingElement(const FStaticSpatialIndex::FCone &InCone, Func InFunc) const
Definition StaticSpatialIndex.h:228
void ForEachIntersectingElement(const FStaticSpatialIndex::FSphere &InSphere, Func InFunc) const
Definition StaticSpatialIndex.h:217
virtual const FBox & GetBox(uint32 InIndex) const override
Definition StaticSpatialIndex.h:255
void ForEachElement(Func InFunc) const
Definition StaticSpatialIndex.h:195
void Init(TArray< TPair< FBox, ValueType > > &&InElements)
Definition StaticSpatialIndex.h:188
void ForEachIntersectingElement(const FBox &InBox, Func InFunc) const
Definition StaticSpatialIndex.h:206
virtual uint32 GetAllocatedSize() const override
Definition StaticSpatialIndex.h:266
TStaticSpatialIndex()
Definition StaticSpatialIndex.h:178
virtual const FBox * GetBoxes(uint32 InIndex, uint32 &OutStride) const override
Definition StaticSpatialIndex.h:260
Definition TVariant.h:48
UE_REWRITE void Sort(RangeType &&Range)
Definition Sort.h:16
void ForEach(InT &&Input, CallableT Callable)
Definition ForEach.h:36
void Init()
Definition LaunchIOS.cpp:473
Definition StaticSpatialIndex.h:13
bool FastSphereAABBIntersection(const typename Profile::FVector &InCenter, const typename Profile::FReal InRadiusSquared, const typename Profile::FBox &InBox)
Definition StaticSpatialIndex.h:33
bool FastConeAABBIntersection(const typename Profile::FVector &InCenter, const typename Profile::FReal InRadiusSquared, const typename Profile::FVector &InAxis, const typename Profile::FReal InAngle, const typename Profile::FReal InSinHalfAngle, const typename Profile::FReal InCosHalfAngle, const typename Profile::FBox &InBox)
Definition StaticSpatialIndex.h:63
Chaos::FReal FReal
Definition ImmediatePhysicsCore_Chaos.h:33
SIZE_T GetAllocatedSize(const T &Value)
Definition ManagedArray.h:93
FORCEINLINE T * Get(const FObjectPtr &ObjectPtr)
Definition ObjectPtr.h:426
@ Element
Definition Visu.h:18
double InSphere(const double *PA, const double *PB, const double *PC, const double *PD, const double *PE)
Definition ExactPredicates.cpp:79
State
Definition PacketHandler.h:88
UE_STRING_CLASS Result(Forward< LhsType >(Lhs), RhsLen)
Definition String.cpp.inl:732
static constexpr UE_FORCEINLINE_HINT T Square(const T A)
Definition UnrealMathUtility.h:578
Definition StaticSpatialIndex.h:51
FVector::FReal Angle
Definition StaticSpatialIndex.h:59
FCone(const FVector &InCenter, const FVector &InAxis, const FVector::FReal InRadius, const FVector::FReal InAngle)
Definition StaticSpatialIndex.h:52
FVector Axis
Definition StaticSpatialIndex.h:58
Definition StaticSpatialIndex.h:15
@ Is3D
Definition StaticSpatialIndex.h:16
FVector2D::FReal FReal
Definition StaticSpatialIndex.h:17
Definition StaticSpatialIndex.h:24
FVector::FReal FReal
Definition StaticSpatialIndex.h:26
FVector FVector
Definition StaticSpatialIndex.h:27
@ Is3D
Definition StaticSpatialIndex.h:25
FBox FBox
Definition StaticSpatialIndex.h:29
Definition StaticSpatialIndex.h:40
FVector::FReal Radius
Definition StaticSpatialIndex.h:47
FSphere(const FVector &InCenter, const FVector::FReal InRadius)
Definition StaticSpatialIndex.h:41
FVector Center
Definition StaticSpatialIndex.h:46
uint32 Value
Definition StaticSpatialIndex.h:568
uint32 operator*() const
Definition StaticSpatialIndex.h:566
bool operator!=(const TIterator &Other) const
Definition StaticSpatialIndex.h:567
uint32 operator++()
Definition StaticSpatialIndex.h:565
TIterator(uint32 InValue)
Definition StaticSpatialIndex.h:564
Definition StaticSpatialIndex.h:539
uint32 Num() const
Definition StaticSpatialIndex.h:559
uint32 GetAllocatedSize() const
Definition StaticSpatialIndex.h:560
uint32 StartIndex
Definition StaticSpatialIndex.h:540
FLeafType()
Definition StaticSpatialIndex.h:543
uint32 NumElements
Definition StaticSpatialIndex.h:541
TIterator begin()
Definition StaticSpatialIndex.h:571
void Add(uint32 InIndex)
Definition StaticSpatialIndex.h:548
TIterator end()
Definition StaticSpatialIndex.h:573
TIterator begin() const
Definition StaticSpatialIndex.h:572
TIterator end() const
Definition StaticSpatialIndex.h:574
Definition StaticSpatialIndex.h:536
FVectorType BoxMax
Definition StaticSpatialIndex.h:582
FVectorType BoxMin
Definition StaticSpatialIndex.h:581
FBoxType GetBox() const
Definition StaticSpatialIndex.h:579
TVariant< FNodeType, FLeafType > Content
Definition StaticSpatialIndex.h:584
typename Profile::FVector FVectorType
Definition StaticSpatialIndex.h:576
typename Profile::FBox FBoxType
Definition StaticSpatialIndex.h:577
Definition ObjectPtr.h:1323
Definition OverrideVoidReturnInvoker.h:16
Definition StaticSpatialIndex.h:164
virtual ~TStaticSpatialIndexDataInterface()
Definition StaticSpatialIndex.h:165
virtual int32 GetNumBox() const =0
virtual const Profile::FBox * GetBoxes(uint32 InIndex, uint32 &OutStride) const =0
virtual const Profile::FBox & GetBox(uint32 InIndex) const =0
virtual uint32 GetAllocatedSize() const =0
Definition Tuple.h:652
void Init()
Definition Box.h:441
Definition IntPoint.h:25
IntType X
Definition IntPoint.h:34
static UE_FORCEINLINE_HINT double DotProduct(const TVector2< double > &A, const TVector2< double > &B)
Definition Vector2D.h:929
static UE_FORCEINLINE_HINT double CrossProduct(const TVector2< double > &A, const TVector2< double > &B)
Definition Vector2D.h:947
double FReal
Definition Vector2D.h:42
double FReal
Definition Vector.h:55