UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
MeshAABBTree3.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3// Port of geometry3cpp TMeshAABBTree3
4
5#pragma once
6
11#include "MeshQueries.h"
14
15
17{
18 using namespace UE::Geometry;
19
34 {
35 int TriangleID[2];
36 FVector3d Point[6]; // Coplanar tri-tri intersection forms a polygon of at most six points
37 int Quantity; // number of points actually used
38 };
45}
46
47
48namespace UE
49{
50namespace Geometry
51{
52
53using namespace UE::Math;
54
55template <class TriangleMeshType>
57
58
59template <class TriangleMeshType>
61{
63
64 constexpr static bool bValidatePerAccess = (bool)DO_GUARD_SLOW;
65
66public:
69
70protected:
74
76 {
77 return [](int Depth, const FAxisAlignedBox3d&)
78 {
79 return Depth % 3;
80 };
81 }
82
84
85public:
86 static constexpr double DOUBLE_MAX = TNumericLimits<double>::Max();
87
89 {
90 Mesh = nullptr;
91 }
92
93 TMeshAABBTree3(const TriangleMeshType* SourceMesh, bool bAutoBuild = true)
94 {
95 SetMesh(SourceMesh, bAutoBuild);
96 }
97
98 void SetMesh(const TriangleMeshType* SourceMesh, bool bAutoBuild = true)
99 {
100 Mesh = SourceMesh;
101 MeshChangeStamp = 0;
102
103 if (bAutoBuild)
104 {
105 Build();
106 }
107 }
108
110 {
111 return Mesh;
112 }
113
118 bool IsValid(bool bAllowUnsafeModifiedMeshQueries) const
119 {
120 checkSlow(RootIndex >= 0);
121 if (RootIndex < 0)
122 {
123 return false;
124 }
125 if (! bAllowUnsafeModifiedMeshQueries)
126 {
127 return (MeshChangeStamp == Mesh->GetChangeStamp());
128 }
129 return true;
130 }
131
137
138 void Build()
139 {
140 BuildTopDown(false);
141 MeshChangeStamp = Mesh->GetChangeStamp();
142 }
143
145 {
147 MeshChangeStamp = Mesh->GetChangeStamp();
148 }
149
150 virtual bool SupportsNearestTriangle() const override
151 {
152 return true;
153 }
154
160 const FVector3d& P, double& NearestDistSqr,
161 const FQueryOptions& Options = FQueryOptions()
162 ) const override
163 {
164 if constexpr (bValidatePerAccess)
165 {
166 if (ensure(IsValid(Options.bAllowUnsafeModifiedMeshQueries)) == false)
167 {
169 }
170 }
171
172 NearestDistSqr = (Options.MaxDistance < DOUBLE_MAX) ? Options.MaxDistance * Options.MaxDistance : DOUBLE_MAX;
175 return tNearID;
176 }
177
182 {
183 if (!ensure(RootIndex >= 0))
184 {
186 }
187 else
188 {
189 return GetBox(RootIndex);
190 }
191 }
192
198 const FVector3d& Point, const FQueryOptions& Options = FQueryOptions()
199 ) const
200 {
201 double NearestDistSqr;
203 if (NearTriID >= 0)
204 {
206 return Query.ClosestTrianglePoint;
207 }
208 return Point;
209 }
210
218 const FVector3d& Point, double ThresholdDistanceSqr, int& OutTriangleID, const FQueryOptions& Options = FQueryOptions()
219 ) const
220 {
221 if constexpr (bValidatePerAccess)
222 {
223 if (ensure(IsValid(Options.bAllowUnsafeModifiedMeshQueries)) == false)
224 {
225 return false;
226 }
227 }
228
232 }
233
234protected:
235 // bEarlyStop causes the traversal to stop as soon as any triangle closer than NearestDistSqr is found
236 // @return true if an early stop triangle was found
237 template<bool bEarlyStop = false>
238 bool find_nearest_tri(int IBox, const FVector3d& P, double& NearestDistSqr, int& TID, const FQueryOptions& Options) const
239 {
240 int idx = BoxToIndex[IBox];
241 if (idx < TrianglesEnd)
242 { // triangle-list case, array is [N t1 t2 ... tN]
243 int num_tris = IndexList[idx];
244 for (int i = 1; i <= num_tris; ++i)
245 {
246 int ti = IndexList[idx + i];
247 if (Options.TriangleFilterF != nullptr && Options.TriangleFilterF(ti) == false)
248 {
249 continue;
250 }
253 {
255 TID = ti;
256 if constexpr (bEarlyStop)
257 {
258 return true;
259 }
260 }
261 }
262 }
263 else
264 { // internal node, either 1 or 2 child boxes
265 int iChild1 = IndexList[idx];
266 if (iChild1 < 0)
267 { // 1 child, descend if nearer than cur min-dist
268 iChild1 = (-iChild1) - 1;
271 {
273 if (bEarlyStop && bFoundEarly)
274 {
275 return true;
276 }
277 }
278 }
279 else
280 { // 2 children, descend closest first
281 iChild1 = iChild1 - 1;
282 int iChild2 = IndexList[idx + 1] - 1;
283
287 {
289 {
292 {
293 return true;
294 }
296 {
299 {
300 return true;
301 }
302 }
303 }
304 }
305 else
306 {
308 {
311 {
312 return true;
313 }
315 {
318 {
319 return true;
320 }
321 }
322 }
323 }
324 }
325 }
326 return false;
327 }
328
329
330
331
332public:
336 virtual int FindNearestVertex(const FVector3d& P, double& NearestDistSqr,
337 double MaxDist = TNumericLimits<double>::Max(), const FQueryOptions& Options = FQueryOptions())
338 {
339 if constexpr (bValidatePerAccess)
340 {
341 if (ensure(IsValid(Options.bAllowUnsafeModifiedMeshQueries)) == false)
342 {
344 }
345 }
346
350 return NearestVertexID;
351 }
352
353
354protected:
356 int& NearestVertexID, const FQueryOptions& Options)
357 {
358 int idx = BoxToIndex[IBox];
359 if (idx < TrianglesEnd)
360 { // triangle-list case, array is [N t1 t2 ... tN]
361 int num_tris = IndexList[idx];
362 for (int i = 1; i <= num_tris; ++i)
363 {
364 int ti = IndexList[idx + i];
365 if (Options.TriangleFilterF != nullptr && Options.TriangleFilterF(ti) == false)
366 {
367 continue;
368 }
369 FIndex3i Triangle = Mesh->GetTriangle(ti);
370 for (int j = 0; j < 3; ++j)
371 {
372 double VertexDistSqr = DistanceSquared(Mesh->GetVertex(Triangle[j]), P);
374 {
377 }
378 }
379 }
380 }
381 else
382 { // internal node, either 1 or 2 child boxes
383 int iChild1 = IndexList[idx];
384 if (iChild1 < 0)
385 { // 1 child, descend if nearer than cur min-dist
386 iChild1 = (-iChild1) - 1;
389 {
391 }
392 }
393 else
394 { // 2 children, descend closest first
395 iChild1 = iChild1 - 1;
396 int iChild2 = IndexList[idx + 1] - 1;
397
401 {
403 {
406 {
408 }
409 }
410 }
411 else
412 {
414 {
417 {
419 }
420 }
421 }
422 }
423 }
424 }
425
426
427
428
429
430public:
431 virtual bool SupportsTriangleRayIntersection() const override
432 {
433 return true;
434 }
435
436 inline virtual int FindNearestHitTriangle(
437 const FRay3d& Ray, const FQueryOptions& Options = FQueryOptions()) const override
438 {
439 double NearestT;
440 int TID;
441 FVector3d BaryCoords;
442 FindNearestHitTriangleImpl<FRay3d>(Ray, NearestT, TID, BaryCoords, Options);
443 return TID;
444 }
445
446 virtual bool FindNearestHitTriangle(const FRay3d& Ray, double& NearestT, int& TID, const FQueryOptions& Options = FQueryOptions()) const override
447 {
448 FVector3d BaryCoords;
449 return FindNearestHitTriangleImpl<FRay3d>(Ray, NearestT, TID, BaryCoords, Options);
450 }
451
453 const FRay3d& Ray, double& NearestT, int& TID, FVector3d& BaryCoords,
454 const FQueryOptions& Options = FQueryOptions()) const override
455 {
456 return FindNearestHitTriangleImpl<FRay3d>(Ray, NearestT, TID, BaryCoords, Options);
457 }
458
460 const FWatertightRay3d& Ray, double& NearestT, int& TID, FVector3d& BaryCoords,
461 const FQueryOptions& Options = FQueryOptions()) const
462 {
463 return FindNearestHitTriangleImpl<FWatertightRay3d>(Ray, NearestT, TID, BaryCoords, Options);
464 }
465
468 const FQueryOptions& Options = FQueryOptions()) const override
469 {
470 return FindAllHitTrianglesImpl<FRay3d>(Ray, OutHits, Options);
471 }
472
475 const FQueryOptions& Options = FQueryOptions()) const
476 {
477 return FindAllHitTrianglesImpl<FWatertightRay3d>(Ray, OutHits, Options);
478 }
479private:
480
481 template<typename RayType>
482 bool FindNearestHitTriangleImpl(
483 const RayType& Ray, double& NearestT, int& TID, FVector3d& BaryCoords,
484 const FQueryOptions& Options = FQueryOptions()) const
485 {
487 BaryCoords = FVector3d::Zero();
488
489 // Note: using TNumericLimits<float>::Max() here because we need to use <= to compare Box hit
490 // to NearestT, and Box hit returns TNumericLimits<double>::Max() on no-hit. So, if we set
491 // nearestT to TNumericLimits<double>::Max(), then we will test all boxes (!)
492 NearestT = (Options.MaxDistance < TNumericLimits<float>::Max()) ? Options.MaxDistance : TNumericLimits<float>::Max();
493
494 if constexpr (bValidatePerAccess)
495 {
496 if (ensure(IsValid(Options.bAllowUnsafeModifiedMeshQueries)) == false)
497 {
498 return false;
499 }
500 }
501
502 FindHitTriangle(RootIndex, Ray, NearestT, TID, BaryCoords, Options);
504 }
505
506 template<typename RayType>
507 bool FindAllHitTrianglesImpl(
509 const FQueryOptions& Options = FQueryOptions()) const
510 {
511 if constexpr (bValidatePerAccess)
512 {
513 if (ensure(IsValid(Options.bAllowUnsafeModifiedMeshQueries)) == false)
514 {
515 return false;
516 }
517 }
518
520
521 FindHitTriangles(RootIndex, Ray, OutHits, Options);
522
523 if (OutHits.IsEmpty())
524 {
525 return false;
526 }
527
528 // sort all hits by distance
529 OutHits.Sort([](const HitResult& Hit0, const HitResult& Hit1)
530 {
531 return Hit0.Distance < Hit1.Distance;
532 });
533
534 return true;
535 }
536
537protected:
538 template<typename RayType = FRay3d>
540 int IBox, const RayType& Ray, double& NearestT, int& TID, FVector3d& BaryCoords,
541 const FQueryOptions& Options = FQueryOptions()) const
542 {
543 int idx = BoxToIndex[IBox];
544 if (idx < TrianglesEnd)
545 { // triangle-list case, array is [N t1 t2 ... tN]
547 int num_tris = IndexList[idx];
548 for (int i = 1; i <= num_tris; ++i)
549 {
550 int ti = IndexList[idx + i];
551 if (Options.TriangleFilterF != nullptr && Options.TriangleFilterF(ti) == false)
552 {
553 continue;
554 }
555
556 Mesh->GetTriVertices(ti, Triangle.V[0], Triangle.V[1], Triangle.V[2]);
558 if (Query.Find())
559 {
560 if (Query.RayParameter < NearestT)
561 {
562 NearestT = Query.RayParameter;
563 TID = ti;
564 BaryCoords = Query.TriangleBaryCoords;
565 }
566 }
567 }
568 }
569 else
570 { // internal node, either 1 or 2 child boxes
571 double e = FMathd::ZeroTolerance;
572
573 int iChild1 = IndexList[idx];
574 if (iChild1 < 0)
575 { // 1 child, descend if nearer than cur min-dist
576 iChild1 = (-iChild1) - 1;
577 double fChild1T = box_ray_intersect_t(iChild1, Ray);
578 if (fChild1T <= NearestT + e)
579 {
580 FindHitTriangle(iChild1, Ray, NearestT, TID, BaryCoords, Options);
581 }
582 }
583 else
584 { // 2 children, descend closest first
585 iChild1 = iChild1 - 1;
586 int iChild2 = IndexList[idx + 1] - 1;
587
588 double fChild1T = box_ray_intersect_t(iChild1, Ray);
589 double fChild2T = box_ray_intersect_t(iChild2, Ray);
590 if (fChild1T < fChild2T)
591 {
592 if (fChild1T <= NearestT + e)
593 {
594 FindHitTriangle(iChild1, Ray, NearestT, TID, BaryCoords, Options);
595 if (fChild2T <= NearestT + e)
596 {
597 FindHitTriangle(iChild2, Ray, NearestT, TID, BaryCoords, Options);
598 }
599 }
600 }
601 else
602 {
603 if (fChild2T <= NearestT + e)
604 {
605 FindHitTriangle(iChild2, Ray, NearestT, TID, BaryCoords, Options);
606 if (fChild1T <= NearestT + e)
607 {
608 FindHitTriangle(iChild1, Ray, NearestT, TID, BaryCoords, Options);
609 }
610 }
611 }
612 }
613 }
614 }
615
616 template<typename RayType = FRay3d>
618 int IBox, const RayType& Ray, TArray<MeshIntersection::FHitIntersectionResult>& Intersections,
619 const FQueryOptions& Options = FQueryOptions()) const
620 {
621 // Note: using TNumericLimits<float>::Max() here because we need to use <= to compare Box hit
622 // to MaxDistance, and Box hit returns TNumericLimits<double>::Max() on no-hit. So, if we set
623 // MaxDistance to TNumericLimits<double>::Max(), then we will test all boxes (!)
624 const double MaxDistance = (Options.MaxDistance < TNumericLimits<float>::Max()) ? Options.MaxDistance : TNumericLimits<float>::Max();
625 static constexpr double e = FMathd::ZeroTolerance;
626
627 int idx = BoxToIndex[IBox];
628 if (idx < TrianglesEnd)
629 { // triangle-list case, array is [N t1 t2 ... tN]
631 int num_tris = IndexList[idx];
632 for (int i = 1; i <= num_tris; ++i)
633 {
634 int ti = IndexList[idx + i];
635 if (Options.TriangleFilterF != nullptr && Options.TriangleFilterF(ti) == false)
636 {
637 continue;
638 }
639
640 Mesh->GetTriVertices(ti, Triangle.V[0], Triangle.V[1], Triangle.V[2]);
642 if (Query.Find() && Query.RayParameter <= MaxDistance + e)
643 {
644 MeshIntersection::FHitIntersectionResult NewIntersection({ti, Query.RayParameter, Query.TriangleBaryCoords});
645 Intersections.Emplace(MoveTemp(NewIntersection));
646 }
647 }
648 }
649 else
650 { // internal node, either 1 or 2 child boxes
651 int iChild1 = IndexList[idx];
652 if (iChild1 < 0)
653 { // 1 child, descend if nearer than cur min-dist
654 iChild1 = (-iChild1) - 1;
655 double fChild1T = box_ray_intersect_t(iChild1, Ray);
656 if (fChild1T <= MaxDistance + e)
657 {
658 FindHitTriangles(iChild1, Ray, Intersections, Options);
659 }
660 }
661 else
662 { // 2 children, descend closest first
663 iChild1 = iChild1 - 1;
664 int iChild2 = IndexList[idx + 1] - 1;
665
666 double fChild1T = box_ray_intersect_t(iChild1, Ray);
667 double fChild2T = box_ray_intersect_t(iChild2, Ray);
668 if (fChild1T < fChild2T)
669 {
670 if (fChild1T <= MaxDistance + e)
671 {
672 FindHitTriangles(iChild1, Ray, Intersections, Options);
673 if (fChild2T <= MaxDistance + e)
674 {
675 FindHitTriangles(iChild2, Ray, Intersections, Options);
676 }
677 }
678 }
679 else
680 {
681 if (fChild2T <= MaxDistance + e)
682 {
683 FindHitTriangles(iChild2, Ray, Intersections, Options);
684 if (fChild1T <= MaxDistance + e)
685 {
686 FindHitTriangles(iChild1, Ray, Intersections, Options);
687 }
688 }
689 }
690 }
691 }
692 }
693
694public:
698 virtual bool TestAnyHitTriangle(const FRay3d& Ray, const FQueryOptions& Options = FQueryOptions()) const
699 {
700 if constexpr (bValidatePerAccess)
701 {
702 if (ensure(IsValid(Options.bAllowUnsafeModifiedMeshQueries)) == false)
703 {
704 return false;
705 }
706 }
707
708 double MaxDistance = (Options.MaxDistance < TNumericLimits<float>::Max()) ? Options.MaxDistance : TNumericLimits<float>::Max();
711 return bFoundHit;
712 }
713
714protected:
716 int IBox, const FRay3d& Ray, int32& HitTIDOut, double MaxDistance,
717 const FQueryOptions& Options = FQueryOptions()) const
718 {
719 int idx = BoxToIndex[IBox];
720 if (idx < TrianglesEnd)
721 { // triangle-list case, array is [N t1 t2 ... tN]
722 FVector3d A, B, C;
723 int num_tris = IndexList[idx];
724 for (int i = 1; i <= num_tris; ++i)
725 {
726 int ti = IndexList[idx + i];
727 if (Options.TriangleFilterF != nullptr && Options.TriangleFilterF(ti) == false)
728 {
729 continue;
730 }
731 Mesh->GetTriVertices(ti, A, B, C);
732 // TODO: RayTriangleTest does most of the work of Query.Find(); test if it's faster to just do Query.Find() directly.
734 {
736 if (Query.Find() && Query.RayParameter < Options.MaxDistance)
737 {
738 return true;
739 }
740 }
741 }
742 }
743 else
744 { // internal node, either 1 or 2 child boxes
745 double e = FMathd::ZeroTolerance;
746 int iChild1 = IndexList[idx];
747 if (iChild1 < 0)
748 { // 1 child, descend if nearer than cur min-dist
749 iChild1 = (-iChild1) - 1;
750 double fChild1T = box_ray_intersect_t(iChild1, Ray);
751 if (fChild1T <= MaxDistance + e)
752 {
753 if (TestAnyHitTriangle(iChild1, Ray, HitTIDOut, MaxDistance, Options))
754 {
755 return true;
756 }
757 }
758 }
759 else
760 { // 2 children, descend closest first
761 iChild1 = iChild1 - 1;
762 int iChild2 = IndexList[idx + 1] - 1;
763
764 double fChild1T = box_ray_intersect_t(iChild1, Ray);
765 double fChild2T = box_ray_intersect_t(iChild2, Ray);
766 if (fChild1T < fChild2T)
767 {
768 if (fChild1T <= MaxDistance + e)
769 {
770 if (TestAnyHitTriangle(iChild1, Ray, HitTIDOut, MaxDistance, Options))
771 {
772 return true;
773 }
774 if (fChild2T <= MaxDistance + e)
775 {
776 if (TestAnyHitTriangle(iChild2, Ray, HitTIDOut, MaxDistance, Options))
777 {
778 return true;
779 }
780 }
781 }
782 }
783 else
784 {
785 if (fChild2T <= MaxDistance + e)
786 {
787 if (TestAnyHitTriangle(iChild2, Ray, HitTIDOut, MaxDistance, Options))
788 {
789 return true;
790 }
791 if (fChild1T <= MaxDistance + e)
792 {
793 if (TestAnyHitTriangle(iChild1, Ray, HitTIDOut, MaxDistance, Options))
794 {
795 return true;
796 }
797 }
798 }
799 }
800 }
801 }
802 return false;
803 }
804
805
806
807
808public:
819 )
820 {
821 if constexpr (bValidatePerAccess)
822 {
823 if (ensure(IsValid(Options.bAllowUnsafeModifiedMeshQueries)) == false)
824 {
825 return FIndex2i::Invalid();
826 }
827 }
828
829 double NearestSqr = FMathd::MaxReal;
830 if (Options.MaxDistance < FMathd::MaxReal)
831 {
832 NearestSqr = Options.MaxDistance * Options.MaxDistance;
833 }
835
837 Distance = (NearestSqr < FMathd::MaxReal) ? FMathd::Sqrt(NearestSqr) : FMathd::MaxReal;
838 return NearestPair;
839 }
840
841
842
843 virtual bool SupportsPointContainment() const override
844 {
845 return false;
846 }
847
848 virtual bool IsInside(const FVector3d& P) const override
849 {
850 return false;
851 }
852
854 {
855 public:
856 // The traversal is terminated at the current node if this function returns false
857 TFunction<bool(const FAxisAlignedBox3d&, int)> NextBoxF = [](const FAxisAlignedBox3d& Box, int Depth) { return true; };
858
859 // These functions are called in sequence if NextBoxF returned true and the current node is a leaf
860 TFunction<void(int, int)> BeginBoxTrianglesF = [](int BoxID, int Depth) {};
861 TFunction<void(int)> NextTriangleF = [](int TriangleID) {}; // Call may be skipped by TriangleFilterF
863 };
864
868 virtual void DoTraversal(FTreeTraversal& Traversal, const FQueryOptions& Options = FQueryOptions()) const
869 {
870 if constexpr (bValidatePerAccess)
871 {
872 if (ensure(IsValid(Options.bAllowUnsafeModifiedMeshQueries)) == false)
873 {
874 return;
875 }
876 }
877
878 if (Traversal.NextBoxF(GetBox(RootIndex), 0))
879 {
881 }
882 }
883
884protected:
885 // Traversal implementation. you can override to customize this if necessary.
886 virtual void TreeTraversalImpl(
887 int IBox, int Depth, FTreeTraversal& Traversal, const FQueryOptions& Options
888 ) const
889 {
890 int idx = BoxToIndex[IBox];
891
892 if (idx < TrianglesEnd)
893 {
894 Traversal.BeginBoxTrianglesF(IBox, Depth);
895
896 // triangle-list case, array is [N t1 t2 ... tN]
897 int n = IndexList[idx];
898 for (int i = 1; i <= n; ++i)
899 {
900 int ti = IndexList[idx + i];
901 if (Options.TriangleFilterF != nullptr && Options.TriangleFilterF(ti) == false)
902 {
903 continue;
904 }
905 Traversal.NextTriangleF(ti);
906 }
907
908 Traversal.EndBoxTrianglesF(IBox);
909 }
910 else
911 {
912 int i0 = IndexList[idx];
913 if (i0 < 0)
914 {
915 // negative index means we only have one 'child' Box to descend into
916 i0 = (-i0) - 1;
917 if (Traversal.NextBoxF(GetBox(i0), Depth + 1))
918 {
919 TreeTraversalImpl(i0, Depth + 1, Traversal, Options);
920 }
921 }
922 else
923 {
924 // positive index, two sequential child Box indices to descend into
925 i0 = i0 - 1;
926 if (Traversal.NextBoxF(GetBox(i0), Depth + 1))
927 {
928 TreeTraversalImpl(i0, Depth + 1, Traversal, Options);
929 }
930
931 int i1 = IndexList[idx + 1] - 1;
932 if (Traversal.NextBoxF(GetBox(i1), Depth + 1))
933 {
934 TreeTraversalImpl(i1, Depth + 1, Traversal, Options);
935 }
936 }
937 }
938 }
939
940
941public:
947 virtual bool TestIntersection(
949 const TFunction<FVector3d(const FVector3d&)>& TransformF = nullptr,
950 const FQueryOptions& Options = FQueryOptions()
951 ) const
952 {
953 if constexpr (bValidatePerAccess)
954 {
955 if (ensure(IsValid(Options.bAllowUnsafeModifiedMeshQueries)) == false)
956 {
957 return false;
958 }
959 }
960
961 if (!TestMeshBounds.IsEmpty())
962 {
963 if (TransformF != nullptr)
964 {
966 [&](const FVector3d& P) { return TransformF(P); });
967 }
969 {
970 return false;
971 }
972 }
973
975 for (int TID = 0, N = TestMesh->MaxTriangleID(); TID < N; TID++)
976 {
977 if (TransformF != nullptr)
978 {
979 FIndex3i Tri = TestMesh->GetTriangle(TID);
980 TestTri.V[0] = TransformF(TestMesh->GetVertex(Tri.A));
981 TestTri.V[1] = TransformF(TestMesh->GetVertex(Tri.B));
982 TestTri.V[2] = TransformF(TestMesh->GetVertex(Tri.C));
983 }
984 else
985 {
986 TestMesh->GetTriVertices(TID, TestTri.V[0], TestTri.V[1], TestTri.V[2]);
987 }
988 if (TestIntersection(TestTri, Options))
989 {
990 return true;
991 }
992 }
993 return false;
994 }
995
996
1001 virtual bool TestIntersection(
1003 const TFunction<FVector3d(const FVector3d&)>& TransformF = nullptr,
1005 ) const
1006 {
1007 if constexpr (bValidatePerAccess)
1008 {
1009 if (ensure(IsValid(Options.bAllowUnsafeModifiedMeshQueries)) == false)
1010 {
1011 return false;
1012 }
1013 }
1014
1016 [this](const FTriangle3d& A, const FTriangle3d& B)
1017 {
1018 return TMeshAABBTree3<TriangleMeshType>::TriangleIntersectionFilter(A, B);
1019 }, Options, OtherTreeOptions))
1020 {
1021 return true;
1022 }
1023
1024 return false;
1025 }
1026
1030 virtual bool TestIntersection(
1031 const FTriangle3d& Triangle,
1032 const FQueryOptions& Options = FQueryOptions()
1033 ) const
1034 {
1035 if constexpr (bValidatePerAccess)
1036 {
1037 if (ensure(IsValid(Options.bAllowUnsafeModifiedMeshQueries)) == false)
1038 {
1039 return false;
1040 }
1041 }
1042
1045 [](const FTriangle3d& A, const FTriangle3d& B)
1046 {
1048 },
1049 Options);
1050 return (interTri >= 0);
1051 }
1052
1053
1061 const TMeshAABBTree3& OtherTree, const TFunction<FVector3d(const FVector3d&)>& TransformF = nullptr,
1064 ) const
1065 {
1066 if (!IntersectionFn)
1067 {
1069 {
1071 };
1072 }
1073
1075
1076 if ( ensure(IsValid(Options.bAllowUnsafeModifiedMeshQueries)) == false )
1077 {
1078 return result;
1079 }
1080
1083
1084 return result;
1085 }
1086
1095 bool bIgnoreTopoConnected = true,
1096 const FQueryOptions& Options = FQueryOptions(),
1098 ) const
1099 {
1100 if (!IntersectionFn)
1101 {
1103 {
1105 };
1106 }
1107
1109
1110 if constexpr (bValidatePerAccess)
1111 {
1112 if (ensure(IsValid(Options.bAllowUnsafeModifiedMeshQueries)) == false)
1113 {
1114 return Result;
1115 }
1116 }
1117
1119
1120 return Result;
1121 }
1122
1123 virtual bool TestSelfIntersection(bool bIgnoreTopoConnected = true, const FQueryOptions& Options = FQueryOptions()) const
1124 {
1125 if constexpr (bValidatePerAccess)
1126 {
1127 if (ensure(IsValid(Options.bAllowUnsafeModifiedMeshQueries)) == false)
1128 {
1129 return false;
1130 }
1131 }
1132
1135 {
1136 // only compute the boolean test value, and manually set result, to skip computing the actual intersection
1138 Intr.SetResult(bIsIntersecting);
1139 return bIsIntersecting;
1140 },
1141 Options);
1142 }
1143
1144
1145protected:
1146 //
1147 // Internals - data structures, construction, etc
1148 //
1149
1151 {
1152 const FVector3d& c = BoxCenters[IBox];
1153 const FVector3d& e = BoxExtents[IBox];
1154 FVector3d Min = c - e, Max = c + e;
1155 return FAxisAlignedBox3d(Min, Max);
1156 }
1158 {
1159 if (TransformF != nullptr)
1160 {
1162 return FAxisAlignedBox3d(box,
1163 [&](const FVector3d& P) { return TransformF(P); });
1164 }
1165 else
1166 {
1167 return GetBox(iBox);
1168 }
1169 }
1170
1171 FAxisAlignedBox3d GetBoxEps(int IBox, double Epsilon = FMathd::ZeroTolerance) const
1172 {
1173 const FVector3d& c = BoxCenters[IBox];
1175 e[0] += Epsilon;
1176 e[1] += Epsilon;
1177 e[2] += Epsilon;
1178 FVector3d Min = c - e, Max = c + e;
1179 return FAxisAlignedBox3d(Min, Max);
1180 }
1181
1182protected:
1183 // TODO: move BoxEps to IMeshSpatial::FQueryOptions
1184 double BoxEps = FMathd::ZeroTolerance;
1185public:
1186
1191 void SetTolerance(double Tolerance)
1192 {
1193 BoxEps = Tolerance;
1194 }
1195
1196 double BoxDistanceSqr(int IBox, const FVector3d& V) const
1197 {
1198 const FVector3d& c = BoxCenters[IBox];
1199 const FVector3d& e = BoxExtents[IBox];
1200
1201 // per-axis delta is max(abs(P-c) - e, 0)... ?
1202 double dx = FMath::Max(fabs(V.X - c.X) - e.X, 0.0);
1203 double dy = FMath::Max(fabs(V.Y - c.Y) - e.Y, 0.0);
1204 double dz = FMath::Max(fabs(V.Z - c.Z) - e.Z, 0.0);
1205 return dx * dx + dy * dy + dz * dz;
1206 }
1207
1208 bool box_contains(int IBox, const FVector3d& P) const
1209 {
1211 return Box.Contains(P);
1212 }
1213
1214 template<typename RayType>
1215 double box_ray_intersect_t(int IBox, const RayType& Ray) const
1216 {
1217 const FVector3d& c = BoxCenters[IBox];
1219 FAxisAlignedBox3d Box(c - e, c + e);
1220
1222 if (FIntrRay3AxisAlignedBox3d::FindIntersection(Ray.Origin, Ray.Direction, Box, ray_t))
1223 {
1224 return ray_t;
1225 }
1226 else
1227 {
1229 }
1230 }
1231
1233 {
1234 // [TODO] could compute this w/o constructing box
1236
1237 return Box.Intersects(TestBox);
1238 }
1239
1241 {
1242 return BoxToIndex.GetByteCount() + BoxCenters.GetByteCount() + BoxExtents.GetByteCount() + IndexList.GetByteCount();
1243 }
1244
1245 // storage for Box Nodes.
1246 // - BoxToIndex is a pointer into IndexList
1247 // - BoxCenters and BoxExtents are the Centers/extents of the bounding boxes
1251
1252 // list of indices for a given Box. There is *no* marker/sentinel between
1253 // boxes, you have to get the starting index from BoxToIndex[]
1254 //
1255 // There are three kinds of records:
1256 // - if i < TrianglesEnd, then the list is a number of Triangles,
1257 // stored as [N t1 t2 t3 ... tN]
1258 // - if i > TrianglesEnd and IndexList[i] < 0, this is a single-child
1259 // internal Box, with index (-IndexList[i])-1 (shift-by-one in case actual value is 0!)
1260 // - if i > TrianglesEnd and IndexList[i] > 0, this is a two-child
1261 // internal Box, with indices IndexList[i]-1 and IndexList[i+1]-1
1263
1264 // IndexList[i] for i < TrianglesEnd is a triangle-index list, otherwise Box-index pair/single
1266
1267 // BoxToIndex[RootIndex] is the root node of the tree
1268 int RootIndex = -1;
1269
1284
1285
1286 void BuildTopDown(bool bSorted)
1287 {
1288 // build list of valid Triangles & Centers. We skip any
1289 // Triangles that have infinite/garbage vertices...
1290 TArray<int> Triangles;
1291 Triangles.Reserve(Mesh->TriangleCount());
1293 Centers.Reserve(Mesh->TriangleCount());
1294 for (int ti = 0; ti < Mesh->MaxTriangleID(); ti++)
1295 {
1296 if (Mesh->IsTriangle(ti) == false)
1297 {
1298 continue;
1299 }
1301 double d2 = centroid.SquaredLength();
1302 bool bInvalid = FMathd::IsNaN(d2) || (FMathd::IsFinite(d2) == false);
1303 if (bInvalid == false)
1304 {
1305 Triangles.Add(ti);
1307 } // otherwise skip this Tri
1308 }
1309 checkSlow(Triangles.Num() == Centers.Num());
1310
1311 BuildTopDown(Triangles, Centers, Triangles.Num());
1312 }
1313
1314
1315 template<typename TriIndexEnumerable>
1316 void BuildTopDown(bool bSorted, TriIndexEnumerable TriangleList, int32 NumTriangles)
1317 {
1318 // build list of valid Triangles & Centers. We skip any
1319 // Triangles that have infinite/garbage vertices...
1320 TArray<int32> Triangles;
1321 Triangles.Reserve(NumTriangles);
1323 Centers.Reserve(NumTriangles);
1324 for (int32 ti : TriangleList)
1325 {
1326 if ( Mesh->IsTriangle(ti) == false)
1327 {
1328 continue;
1329 }
1331 double d2 = centroid.SquaredLength();
1332 bool bInvalid = FMathd::IsNaN(d2) || (FMathd::IsFinite(d2) == false);
1333 if (bInvalid == false)
1334 {
1335 Triangles.Add(ti);
1337 } // otherwise skip this Tri
1338 }
1339 checkSlow(Triangles.Num() == Centers.Num());
1340
1341 BuildTopDown(Triangles, Centers, Triangles.Num());
1342 }
1343
1344
1345 void BuildTopDown(TArray<int>& Triangles, TArray<FVector3d>& Centers, int32 NumTriangles)
1346 {
1348 FBoxesSet Nodes;
1350 int rootnode =
1351 //(bSorted) ? split_tri_set_sorted(Triangles, Centers, 0, NumTriangles, 0, TopDownLeafMaxTriCount, Tris, Nodes, out rootBox) :
1352 SplitTriSetMidpoint(Triangles, Centers, 0, NumTriangles, 0, TopDownLeafMaxTriCount, Tris, Nodes, rootBox);
1353
1354 BoxToIndex = Tris.BoxToIndex;
1355 BoxCenters = Tris.BoxCenters;
1356 BoxExtents = Tris.BoxExtents;
1357 IndexList = Tris.IndexList;
1358 TrianglesEnd = Tris.IIndicesCur;
1360 int iBoxShift = Tris.IBoxCur;
1361
1362 // ok now append internal node boxes & index ptrs
1363 for (int32 i = 0; i < Nodes.IBoxCur; ++i)
1364 {
1365 FVector3d NodeBoxCenter = Nodes.BoxCenters[i]; // cannot pass as argument in case a resize happens
1366 BoxCenters.InsertAt(NodeBoxCenter, iBoxShift + i);
1368 BoxExtents.InsertAt(NodeBoxExtents, iBoxShift + i);
1369 // internal node indices are shifted
1370 int NodeBoxIndex = Nodes.BoxToIndex[i];
1372 }
1373
1374 // now append index list
1375 for (int32 i = 0; i < Nodes.IIndicesCur; ++i)
1376 {
1377 int child_box = Nodes.IndexList[i];
1378 if (child_box < 0)
1379 { // this is a Triangles Box
1380 child_box = (-child_box) - 1;
1381 }
1382 else
1383 {
1385 }
1386 child_box = child_box + 1;
1388 }
1389
1391 }
1392
1393
1395 TArray<int>& Triangles,
1397 int IStart, int ICount, int Depth, int MinTriCount,
1399 {
1400 Box = (Triangles.Num() > 0) ?
1402 int IBox = -1;
1403
1404 if (ICount <= MinTriCount)
1405 {
1406 // append new Triangles Box
1407 IBox = Tris.IBoxCur++;
1408 Tris.BoxToIndex.InsertAt(Tris.IIndicesCur, IBox);
1409
1410 Tris.IndexList.InsertAt(ICount, Tris.IIndicesCur++);
1411 for (int i = 0; i < ICount; ++i)
1412 {
1413 Tris.IndexList.InsertAt(Triangles[IStart + i], Tris.IIndicesCur++);
1415 }
1416
1417 Tris.BoxCenters.InsertAt(Box.Center(), IBox);
1418 Tris.BoxExtents.InsertAt(Box.Extents(), IBox);
1419
1420 return -(IBox + 1);
1421 }
1422
1423 //compute interval along an axis and find midpoint
1424 int axis = GetSplitAxis(Depth, Box);
1426 for (int i = 0; i < ICount; ++i)
1427 {
1428 interval.Contain(Centers[IStart + i][axis]);
1429 }
1430 double midpoint = interval.Center();
1431
1432 int n0, n1;
1433 if (interval.Length() > FMathd::ZeroTolerance)
1434 {
1435 // we have to re-sort the Centers & Triangles lists so that Centers < midpoint
1436 // are first, so that we can recurse on the two subsets. We walk in from each side,
1437 // until we find two out-of-order locations, then we swap them.
1438 int l = 0;
1439 int r = ICount - 1;
1440 while (l < r)
1441 {
1442 // TODO: is <= right here? if V.axis == midpoint, then this loop
1443 // can get stuck unless one of these has an equality test. But
1444 // I did not think enough about if this is the right thing to do...
1445 while (Centers[IStart + l][axis] <= midpoint)
1446 {
1447 l++;
1448 }
1449 while (Centers[IStart + r][axis] > midpoint)
1450 {
1451 r--;
1452 }
1453 if (l >= r)
1454 {
1455 break; //done!
1456 //swap
1457 }
1459 Centers[IStart + l] = Centers[IStart + r];
1460 Centers[IStart + r] = tmpc;
1461 int tmpt = Triangles[IStart + l];
1462 Triangles[IStart + l] = Triangles[IStart + r];
1463 Triangles[IStart + r] = tmpt;
1464 }
1465
1466 n0 = l;
1467 n1 = ICount - n0;
1468 checkSlow(n0 >= 1 && n1 >= 1);
1469 }
1470 else
1471 {
1472 // interval is near-empty, so no point trying to do sorting, just split half and half
1473 n0 = ICount / 2;
1474 n1 = ICount - n0;
1475 }
1476
1477 // create child boxes
1479 int child0 = SplitTriSetMidpoint(Triangles, Centers, IStart, n0, Depth + 1, MinTriCount, Tris, Nodes, Box);
1480 int child1 = SplitTriSetMidpoint(Triangles, Centers, IStart + n0, n1, Depth + 1, MinTriCount, Tris, Nodes, box1);
1481 Box.Contain(box1);
1482
1483 // append new Box
1484 IBox = Nodes.IBoxCur++;
1485 Nodes.BoxToIndex.InsertAt(Nodes.IIndicesCur, IBox);
1486
1487 Nodes.IndexList.InsertAt(child0, Nodes.IIndicesCur++);
1488 Nodes.IndexList.InsertAt(child1, Nodes.IIndicesCur++);
1489
1490 Nodes.BoxCenters.InsertAt(Box.Center(), IBox);
1491 Nodes.BoxExtents.InsertAt(Box.Extents(), IBox);
1492
1493 return IBox;
1494 }
1495
1496
1499 int oBox, int depth, double &nearest_sqr, FIndex2i &nearest_pair,
1500 const FQueryOptions& Options, const FQueryOptions& OtherTreeOptions
1501 ) const
1502 {
1503 int idx = BoxToIndex[iBox];
1504 int odx = OtherTree.BoxToIndex[oBox];
1505
1506 if (idx < TrianglesEnd && odx < OtherTree.TrianglesEnd)
1507 {
1508 // ok we are at triangles for both trees, do triangle-level testing
1509 FTriangle3d Tri, otri;
1510 int num_tris = IndexList[idx], onum_tris = OtherTree.IndexList[odx];
1511
1513
1514 // outer iteration is "other" tris that need to be transformed (more expensive)
1515 for (int j = 1; j <= onum_tris; ++j)
1516 {
1517 int tj = OtherTree.IndexList[odx + j];
1518 if (OtherTreeOptions.TriangleFilterF != nullptr && OtherTreeOptions.TriangleFilterF(tj) == false)
1519 {
1520 continue;
1521 }
1522 OtherTree.Mesh->GetTriVertices(tj, otri.V[0], otri.V[1], otri.V[2]);
1523 if (TransformF != nullptr)
1524 {
1525 otri.V[0] = TransformF(otri.V[0]);
1526 otri.V[1] = TransformF(otri.V[1]);
1527 otri.V[2] = TransformF(otri.V[2]);
1528 }
1529 dist.SetTriangle(0, otri);
1530
1531 // inner iteration over "our" triangles
1532 for (int i = 1; i <= num_tris; ++i)
1533 {
1534 int ti = IndexList[idx + i];
1535 if (Options.TriangleFilterF != nullptr && Options.TriangleFilterF(ti) == false)
1536 {
1537 continue;
1538 }
1539 Mesh->GetTriVertices(ti, Tri.V[0], Tri.V[1], Tri.V[2]);
1540 dist.SetTriangle(1, Tri);
1541 double dist_sqr = dist.GetSquared();
1542 if (dist_sqr < nearest_sqr)
1543 {
1545 nearest_pair = FIndex2i(ti, tj);
1546 }
1547 }
1548 }
1549
1550 return;
1551 }
1552
1553 // we either descend "our" tree or the other tree
1554 // - if we have hit triangles on "our" tree, we have to descend other
1555 // - if we hit triangles on "other", we have to descend ours
1556 // - otherwise, we alternate at each depth. This produces wider
1557 // branching but is significantly faster (~10x) for both hits and misses
1558 bool bDescendOther = (idx < TrianglesEnd || depth % 2 == 0);
1559 if (bDescendOther && odx < OtherTree.TrianglesEnd)
1560 {
1561 bDescendOther = false; // can't
1562 }
1563
1564 if (bDescendOther)
1565 {
1566 // ok we reached triangles on our side but we need to still reach triangles on
1567 // the other side, so we descend "their" children
1569
1570 int oChild1 = OtherTree.IndexList[odx];
1571 if (oChild1 < 0) // 1 child, descend if nearer than cur min-dist
1572 {
1573 oChild1 = (-oChild1) - 1;
1575 if (oChild1Box.DistanceSquared(bounds) < nearest_sqr)
1576 {
1578 }
1579 }
1580 else // 2 children
1581 {
1582 oChild1 = oChild1 - 1;
1583 int oChild2 = OtherTree.IndexList[odx + 1] - 1;
1584
1587
1588 // descend closer box first
1590 double d2Sqr = oChild2Box.DistanceSquared(bounds);
1591 if (d2Sqr < d1Sqr)
1592 {
1593 if (d2Sqr < nearest_sqr)
1594 {
1596 }
1597 if (d1Sqr < nearest_sqr)
1598 {
1600 }
1601 }
1602 else
1603 {
1604 if (d1Sqr < nearest_sqr)
1605 {
1607 }
1608 if (d2Sqr < nearest_sqr)
1609 {
1611 }
1612 }
1613 }
1614 }
1615 else
1616 {
1617 // descend our tree nodes if they intersect w/ current bounds of other tree
1619
1620 int iChild1 = IndexList[idx];
1621 if (iChild1 < 0) // 1 child, descend if nearer than cur min-dist
1622 {
1623 iChild1 = (-iChild1) - 1;
1625 {
1627 }
1628 }
1629 else // 2 children
1630 {
1631 iChild1 = iChild1 - 1;
1632 int iChild2 = IndexList[idx + 1] - 1;
1633
1634 // descend closer box first
1637 if (d2Sqr < d1Sqr)
1638 {
1639 if (d2Sqr < nearest_sqr)
1640 {
1642 }
1643 if (d1Sqr < nearest_sqr)
1644 {
1646 }
1647 }
1648 else
1649 {
1650 if (d1Sqr < nearest_sqr)
1651 {
1653 }
1654 if (d2Sqr < nearest_sqr)
1655 {
1657 }
1658 }
1659 }
1660 }
1661 }
1662
1664 {
1665 // [TODO] could compute this w/o constructing box
1667 return box.DistanceSquared(testBox);
1668 }
1669
1670
1671
1676 {
1678 }
1685 {
1686 // Note: Test() is much faster than Find() so it makes sense to call it first, as most
1687 // triangles will not intersect (right? TODO: actually test this somehow, though it is very data dependent)
1688 bool bFound = Intr.Test();
1689 if (bFound)
1690 {
1691 Intr.Find();
1692 return Intr.Result == EIntersectionResult::Intersects;
1693 }
1694 else
1695 {
1696 return false;
1697 }
1698 }
1699
1700
1704 const FQueryOptions& Options
1705 ) const
1706 {
1707 int idx = BoxToIndex[iBox];
1708 if (idx < TrianglesEnd) // triangle-list case, array is [N t1 t2 ... tN]
1709 {
1711 int num_tris = IndexList[idx];
1712 for (int i = 1; i <= num_tris; ++i)
1713 {
1714 int ti = IndexList[idx + i];
1715 if (Options.TriangleFilterF != nullptr && Options.TriangleFilterF(ti) == false)
1716 {
1717 continue;
1718 }
1719 Mesh->GetTriVertices(ti, box_tri.V[0], box_tri.V[1], box_tri.V[2]);
1721 {
1722 return ti;
1723 }
1724 }
1725 }
1726 else // internal node, either 1 or 2 child boxes
1727 {
1728 int iChild1 = IndexList[idx];
1729 if (iChild1 < 0) // 1 child, descend if nearer than cur min-dist
1730 {
1731 iChild1 = (-iChild1) - 1;
1733 {
1735 }
1736
1737 }
1738 else // 2 children, descend closest first
1739 {
1740 iChild1 = iChild1 - 1;
1741 int iChild2 = IndexList[idx + 1] - 1;
1742
1743 int interTri = -1;
1745 {
1747 }
1749 {
1751 }
1752 return interTri;
1753 }
1754 }
1755
1756 return -1;
1757 }
1758
1759
1761 int iBox, const TMeshAABBTree3& OtherTree, const TFunction<FVector3d(const FVector3d&)>& TransformF, int oBox, int depth,
1763 const FQueryOptions& Options, const FQueryOptions& OtherTreeOptions
1764 ) const
1765 {
1766 int idx = BoxToIndex[iBox];
1767 int odx = OtherTree.BoxToIndex[oBox];
1768
1769 if (idx < TrianglesEnd && odx < OtherTree.TrianglesEnd)
1770 {
1771 // ok we are at triangles for both trees, do triangle-level testing
1772 FTriangle3d Tri, otri;
1773 int num_tris = IndexList[idx], onum_tris = OtherTree.IndexList[odx];
1774
1775 // outer iteration is "other" tris that need to be transformed (more expensive)
1776 for (int j = 1; j <= onum_tris; ++j)
1777 {
1778 int tj = OtherTree.IndexList[odx + j];
1779 if (OtherTreeOptions.TriangleFilterF != nullptr && OtherTreeOptions.TriangleFilterF(tj) == false)
1780 {
1781 continue;
1782 }
1783 OtherTree.Mesh->GetTriVertices(tj, otri.V[0], otri.V[1], otri.V[2]);
1784 if (TransformF != nullptr)
1785 {
1786 otri.V[0] = TransformF(otri.V[0]);
1787 otri.V[1] = TransformF(otri.V[1]);
1788 otri.V[2] = TransformF(otri.V[2]);
1789 }
1790
1791 // inner iteration over "our" triangles
1792 for (int i = 1; i <= num_tris; ++i)
1793 {
1794 int ti = IndexList[idx + i];
1795 if (Options.TriangleFilterF != nullptr && Options.TriangleFilterF(ti) == false)
1796 {
1797 continue;
1798 }
1799 Mesh->GetTriVertices(ti, Tri.V[0], Tri.V[1], Tri.V[2]);
1801 {
1802 return true;
1803 }
1804 }
1805 }
1806 return false;
1807 }
1808
1809 // we either descend "our" tree or the other tree
1810 // - if we have hit triangles on "our" tree, we have to descend other
1811 // - if we hit triangles on "other", we have to descend ours
1812 // - otherwise, we alternate at each depth. This produces wider
1813 // branching but is significantly faster (~10x) for both hits and misses
1814 bool bDescendOther = (idx < TrianglesEnd || depth % 2 == 0);
1815 if (bDescendOther && odx < OtherTree.TrianglesEnd)
1816 {
1817 bDescendOther = false; // can't
1818 }
1819
1820 if (bDescendOther)
1821 {
1822 // ok we hit triangles on our side but we need to still reach triangles on
1823 // the other side, so we descend "their" children
1824
1825 // [TODO] could we do efficient box.intersects(transform(box)) test?
1826 // ( Contains() on each xformed point? )
1828
1829 int oChild1 = OtherTree.IndexList[odx];
1830 if (oChild1 < 0) // 1 child, descend if nearer than cur min-dist
1831 {
1832 oChild1 = (-oChild1) - 1;
1834 if (oChild1Box.Intersects(bounds))
1835 {
1837 }
1838
1839 }
1840 else // 2 children
1841 {
1842 oChild1 = oChild1 - 1; // [TODO] could descend one w/ larger overlap volume first??
1843 int oChild2 = OtherTree.IndexList[odx + 1] - 1;
1844
1845 bool intersects = false;
1847 if (oChild1Box.Intersects(bounds))
1848 {
1850 }
1851
1852 if (intersects == false)
1853 {
1855 if (oChild2Box.Intersects(bounds))
1856 {
1858 }
1859 }
1860 return intersects;
1861 }
1862 }
1863 else
1864 {
1865 // descend our tree nodes if they intersect w/ current bounds of other tree
1867
1868 int iChild1 = IndexList[idx];
1869 if (iChild1 < 0) // 1 child, descend if nearer than cur min-dist
1870 {
1871 iChild1 = (-iChild1) - 1;
1873 {
1875 }
1876 }
1877 else // 2 children
1878 {
1879 iChild1 = iChild1 - 1; // [TODO] could descend one w/ larger overlap volume first??
1880 int iChild2 = IndexList[idx + 1] - 1;
1881
1882 bool intersects = false;
1884 {
1886 }
1887 if (intersects == false && box_box_intersect(iChild2, oBounds))
1888 {
1890 }
1891 return intersects;
1892 }
1893
1894 }
1895 return false;
1896 }
1897
1898
1899 // helper for find_self_intersections that checks intersections between triangles from separate boxes
1902 bool bIgnoreTopoConnected, int depth,
1904 const FQueryOptions& Options
1905 ) const
1906 {
1907 bool bFound = false;
1908 if (Box1 < 0)
1909 {
1910 return false;
1911 }
1912
1913 int Box1Idx = BoxToIndex[Box1];
1914 int Box2Idx = Box2 > -1 ? BoxToIndex[Box2] : -1; // Box2Idx allowed to be invalid
1915
1916 // at leaf
1918 {
1919 if (Box2 == -1)
1920 {
1921 return false;
1922 }
1923
1924 for (int IdxA = Box1Idx + 1, Box1End = Box1Idx + 1 + IndexList[Box1Idx]; IdxA < Box1End; IdxA++)
1925 {
1926 int TID_A = IndexList[IdxA];
1928 if (!Result && bFound)
1929 {
1930 return true;
1931 }
1932 }
1933 return bFound;
1934 }
1935
1936 // alternate which box we descend, while still making sure Box1 is not a leaf
1937 // (the alternating part is just a heuristic that I guess may help performance; it's not necessary)
1938 if (Box1Idx < TrianglesEnd || (Box2Idx >= TrianglesEnd && depth % 2 == 1))
1939 {
1940 Swap(Box1, Box2);
1942 }
1943
1944
1945 // if Box2 is present, we *only* care about the intersection of Box1's children w/ Box2
1946 // if Box2 is not present, we handle all the other cases (descending into the children of box1, and checking if the children intersect)
1947 if (Box2 > -1)
1948 {
1950
1951 // Descend through Box1
1952 int iChild1 = IndexList[Box1Idx];
1953 if (iChild1 < 0) // 1 child
1954 {
1955 iChild1 = (-iChild1) - 1;
1956
1957 if (Box2 > -1 && box_box_intersect(iChild1, Box2Box))
1958 {
1960 if (!Result && bFound)
1961 {
1962 return true;
1963 }
1964 }
1965 }
1966 else // 2 children
1967 {
1968 iChild1 = iChild1 - 1;
1969 int iChild2 = IndexList[Box1Idx + 1] - 1;
1970
1971 if (Box2 > -1 && box_box_intersect(iChild1, Box2Box))
1972 {
1974 if (!Result && bFound)
1975 {
1976 return true;
1977 }
1978 }
1979 if (Box2 > -1 && box_box_intersect(iChild2, Box2Box))
1980 {
1982 if (!Result && bFound)
1983 {
1984 return true;
1985 }
1986 }
1987 }
1988 }
1989 else // Box2 is not present
1990 {
1991 // Descend through Box1
1992 int iChild1 = IndexList[Box1Idx];
1993 if (iChild1 < 0) // 1 child
1994 {
1995 iChild1 = (-iChild1) - 1;
1996
1998 if (!Result && bFound)
1999 {
2000 return true;
2001 }
2002 }
2003 else // 2 children
2004 {
2005 iChild1 = iChild1 - 1;
2006 int iChild2 = IndexList[Box1Idx + 1] - 1;
2007
2009 if (!Result && bFound)
2010 {
2011 return true;
2012 }
2014 if (!Result && bFound)
2015 {
2016 return true;
2017 }
2018
2020
2022 {
2024 if (!Result && bFound)
2025 {
2026 return true;
2027 }
2028 }
2029 }
2030 }
2031
2032 return bFound;
2033 }
2034
2035 // helper for find_self_intersections that intersects a single triangle vs a range of triangles
2040 const FQueryOptions& Options
2041 ) const
2042 {
2043 if (Options.TriangleFilterF != nullptr && Options.TriangleFilterF(TID_A) == false)
2044 {
2045 return false;
2046 }
2047
2048 bool bFound = false;
2050 Mesh->GetTriVertices(TID_A, TriA.V[0], TriA.V[1], TriA.V[2]);
2053 FIndex3i TriA_VID = Mesh->GetTriangle(TID_A);
2054
2055 for (int IdxB = IdxRangeStart; IdxB < IdxRangeEnd; IdxB++)
2056 {
2057 int TID_B = IndexList[IdxB];
2058 if (Options.TriangleFilterF != nullptr && Options.TriangleFilterF(TID_B) == false)
2059 {
2060 continue;
2061 }
2062
2063 FIndex3i TriB_VID = Mesh->GetTriangle(TID_B);
2065 {
2066 // ignore triangles that share a vertex
2067 bool bTopoConnected = false;
2068 for (int AIdx = 0; AIdx < 3 && !bTopoConnected; AIdx++)
2069 {
2070 int VID_A = TriA_VID[AIdx];
2071 for (int BIdx = 0; BIdx < 3; BIdx++)
2072 {
2073 if (VID_A == TriB_VID[BIdx])
2074 {
2075 bTopoConnected = true;
2076 break;
2077 }
2078 }
2079 }
2080 if (bTopoConnected)
2081 {
2082 continue;
2083 }
2084 }
2085
2086 Mesh->GetTriVertices(TID_B, TriB.V[0], TriB.V[1], TriB.V[2]);
2087 Intr.SetTriangle1(TriB);
2089 if (bFound)
2090 {
2091 if (!Result)
2092 {
2093 return true;
2094 }
2095 else
2096 {
2098 }
2099 }
2100 }
2101
2102 return bFound;
2103 }
2104
2109 {
2110 if (Intr.Quantity == 1)
2111 {
2112 Result.Points.Add(MeshIntersection::FPointIntersection{ {TID_A, TID_B}, Intr.Points[0] });
2113 }
2114 else if (Intr.Quantity == 2)
2115 {
2116 Result.Segments.Add(MeshIntersection::FSegmentIntersection{ {TID_A, TID_B}, {Intr.Points[0], Intr.Points[1]} });
2117 }
2118 else if (Intr.Quantity > 2)
2119 {
2121 {
2122 Result.Segments.Add(MeshIntersection::FSegmentIntersection{ {TID_A, TID_B}, {Intr.Points[0], Intr.Points[1]} });
2123 Result.Segments.Add(MeshIntersection::FSegmentIntersection{ {TID_A, TID_B}, {Intr.Points[2], Intr.Points[3]} });
2124 if (Intr.Quantity > 4)
2125 {
2126 Result.Segments.Add(MeshIntersection::FSegmentIntersection{ {TID_A, TID_B}, {Intr.Points[4], Intr.Points[5]} });
2127 }
2128 }
2129 else
2130 {
2131 Result.Polygons.Add(MeshIntersection::FPolygonIntersection{ {TID_A, TID_B},
2132 {Intr.Points[0],Intr.Points[1],Intr.Points[2],Intr.Points[3],Intr.Points[4],Intr.Points[5]}, Intr.Quantity });
2133 }
2134 }
2135 }
2136
2137
2141 const FQueryOptions & Options
2142 ) const
2143 {
2144 // Check each leaf-box for intersecting triangles within the same box
2145 bool bFound = false;
2146 for (int StartIdx = 0; StartIdx < TrianglesEnd; )
2147 {
2148 int NumTris = IndexList[StartIdx];
2149 int EndIdx = StartIdx + NumTris + 1;
2150 for (int IdxA = StartIdx + 1; IdxA + 1 < EndIdx; IdxA++)
2151 {
2152 int TID_A = IndexList[IdxA];
2154 if (!Result && bFound) // early out if not filling Result
2155 {
2156 return bFound;
2157 }
2158 }
2159 StartIdx = EndIdx;
2160 }
2161
2162 // Recursively check across boxes
2164 }
2165
2166
2169 int oBox, int depth, MeshIntersection::FIntersectionsQueryResult& result,
2171 const FQueryOptions& Options, const FQueryOptions& OtherTreeOptions
2172 ) const
2173 {
2174 int idx = BoxToIndex[iBox];
2175 int odx = OtherTree.BoxToIndex[oBox];
2177
2178 if (idx < TrianglesEnd && odx < OtherTree.TrianglesEnd)
2179 {
2180 // ok we are at triangles for both trees, do triangle-level testing
2181 FTriangle3d Tri, otri;
2182 int num_tris = IndexList[idx], onum_tris = OtherTree.IndexList[odx];
2183
2184 // outer iteration is "other" tris that need to be transformed (more expensive)
2185 for (int j = 1; j <= onum_tris; ++j)
2186 {
2187 int tj = OtherTree.IndexList[odx + j];
2188 if (OtherTreeOptions.TriangleFilterF != nullptr && OtherTreeOptions.TriangleFilterF(tj) == false)
2189 {
2190 continue;
2191 }
2192 OtherTree.Mesh->GetTriVertices(tj, otri.V[0], otri.V[1], otri.V[2]);
2193 if (TransformF != nullptr)
2194 {
2195 otri.V[0] = TransformF(otri.V[0]);
2196 otri.V[1] = TransformF(otri.V[1]);
2197 otri.V[2] = TransformF(otri.V[2]);
2198 }
2199 Intr.SetTriangle0(otri);
2200
2201 // inner iteration over "our" triangles
2202 for (int i = 1; i <= num_tris; ++i)
2203 {
2204 int ti = IndexList[idx + i];
2205 if (Options.TriangleFilterF != nullptr && Options.TriangleFilterF(ti) == false)
2206 {
2207 continue;
2208 }
2209 Mesh->GetTriVertices(ti, Tri.V[0], Tri.V[1], Tri.V[2]);
2210 Intr.SetTriangle1(Tri);
2211
2212
2213 if (IntersectFn(Intr))
2214 {
2215 AddTriTriIntersectionResult(Intr, ti, tj, result);
2216 }
2217 }
2218 }
2219
2220 // done these nodes
2221 return;
2222 }
2223
2224 // we either descend "our" tree or the other tree
2225 // - if we have hit triangles on "our" tree, we have to descend other
2226 // - if we hit triangles on "other", we have to descend ours
2227 // - otherwise, we alternate at each depth. This produces wider
2228 // branching but is significantly faster (~10x) for both hits and misses
2229 bool bDescendOther = (idx < TrianglesEnd || depth % 2 == 0);
2230 if (bDescendOther && odx < OtherTree.TrianglesEnd)
2231 bDescendOther = false; // can't
2232
2233 if (bDescendOther) {
2234 // ok we hit triangles on our side but we need to still reach triangles on
2235 // the other side, so we descend "their" children
2236
2237 // [TODO] could we do efficient box.intersects(transform(box)) test?
2238 // ( Contains() on each xformed point? )
2240
2241 int oChild1 = OtherTree.IndexList[odx];
2242 if (oChild1 < 0) // 1 child, descend if nearer than cur min-dist
2243 {
2244 oChild1 = (-oChild1) - 1;
2246 if (oChild1Box.Intersects(bounds))
2248
2249 }
2250 else // 2 children
2251 {
2252 oChild1 = oChild1 - 1;
2253
2255 if (oChild1Box.Intersects(bounds))
2256 {
2258 }
2259
2260 int oChild2 = OtherTree.IndexList[odx + 1] - 1;
2262 if (oChild2Box.Intersects(bounds))
2263 {
2265 }
2266 }
2267
2268 }
2269 else
2270 {
2271 // descend our tree nodes if they intersect w/ current bounds of other tree
2273
2274 int iChild1 = IndexList[idx];
2275 if (iChild1 < 0) // 1 child, descend if nearer than cur min-dist
2276 {
2277 iChild1 = (-iChild1) - 1;
2279 {
2281 }
2282
2283 }
2284 else // 2 children
2285 {
2286 iChild1 = iChild1 - 1;
2288 {
2290 }
2291
2292 int iChild2 = IndexList[idx + 1] - 1;
2294 {
2296 }
2297 }
2298
2299 }
2300 }
2301
2302
2303
2304
2305public:
2306 // 1) make sure we can reach every Tri in Mesh through tree (also demo of how to traverse tree...)
2307 // 2) make sure that Triangles are contained in parent boxes
2309 {
2311 tri_counts.SetNumZeroed(Mesh->MaxTriangleID());
2312
2315
2316 test_coverage(tri_counts, parent_indices, RootIndex);
2317
2318 for (int ti = 0; ti < Mesh->MaxTriangleID(); ti++)
2319 {
2320 if (!Mesh->IsTriangle(ti))
2321 {
2322 continue;
2323 }
2324 checkSlow(tri_counts[ti] == 1);
2325 }
2326 }
2327
2332 {
2333 double volSum = 0;
2335 t.NextBoxF = [&](const FAxisAlignedBox3d& Box, int)
2336 {
2337 volSum += Box.Volume();
2338 return true;
2339 };
2340 DoTraversal(t);
2341 return volSum;
2342 }
2343
2344private:
2345 // accumulate triangle counts and track each Box-parent index.
2346 // also checks that Triangles are contained in boxes
2347 void test_coverage(TArray<int>& tri_counts, TArray<int>& parent_indices, int IBox)
2348 {
2349 int idx = BoxToIndex[IBox];
2350
2351 debug_check_child_tris_in_box(IBox);
2352
2353 if (idx < TrianglesEnd)
2354 {
2355 // triangle-list case, array is [N t1 t2 ... tN]
2356 int n = IndexList[idx];
2358 for (int i = 1; i <= n; ++i)
2359 {
2360 int ti = IndexList[idx + i];
2361 tri_counts[ti]++;
2362
2363 FIndex3i tv = Mesh->GetTriangle(ti);
2364 for (int j = 0; j < 3; ++j)
2365 {
2366 FVector3d V = Mesh->GetVertex(tv[j]);
2367 checkSlow(Box.Contains(V));
2368 }
2369 }
2370 }
2371 else
2372 {
2373 int i0 = IndexList[idx];
2374 if (i0 < 0)
2375 {
2376 // negative index means we only have one 'child' Box to descend into
2377 i0 = (-i0) - 1;
2379 test_coverage(tri_counts, parent_indices, i0);
2380 }
2381 else
2382 {
2383 // positive index, two sequential child Box indices to descend into
2384 i0 = i0 - 1;
2386 test_coverage(tri_counts, parent_indices, i0);
2387 int i1 = IndexList[idx + 1];
2388 i1 = i1 - 1;
2390 test_coverage(tri_counts, parent_indices, i1);
2391 }
2392 }
2393 }
2394 // do full tree Traversal below IBox and make sure that all Triangles are further
2395 // than Box-distance-sqr
2396 void debug_check_child_tri_distances(int IBox, const FVector3d& P)
2397 {
2398 double fBoxDistSqr = BoxDistanceSqr(IBox, P);
2399
2400 // [TODO]
2401 FTreeTraversal t;
2402 t.NextTriangleF = [&](int TID)
2403 {
2406 {
2407 checkSlow(fabs(fTriDistSqr - fBoxDistSqr) <= FMathd::ZeroTolerance * 100);
2408 }
2409 };
2410 TreeTraversalImpl(IBox, 0, t, FQueryOptions());
2411 }
2412
2413 // do full tree Traversal below IBox to make sure that all child Triangles are contained
2414 void debug_check_child_tris_in_box(int IBox)
2415 {
2417 FTreeTraversal t;
2418 t.NextTriangleF = [&](int TID)
2419 {
2420 FIndex3i tv = Mesh->GetTriangle(TID);
2421 for (int j = 0; j < 3; ++j)
2422 {
2423 FVector3d V = Mesh->GetVertex(tv[j]);
2424 checkSlow(Box.Contains(V));
2425 }
2426 };
2427 TreeTraversalImpl(IBox, 0, t, FQueryOptions());
2428 }
2429};
2430
2431
2432} // end namespace UE::Geometry
2433} // end namespace UE
OODEFFUNC typedef void(OODLE_CALLBACK t_fp_OodleCore_Plugin_Free)(void *ptr)
#define checkSlow(expr)
Definition AssertionMacros.h:332
#define ensure( InExpression)
Definition AssertionMacros.h:464
FPlatformTypes::SIZE_T SIZE_T
An unsigned integer the same size as a pointer, the same as UPTRINT.
Definition Platform.h:1150
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
FPlatformTypes::uint64 uint64
A 64-bit unsigned integer.
Definition Platform.h:1117
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
UE::Math::TVector< double > FVector3d
Definition MathFwd.h:60
const bool
Definition NetworkReplayStreaming.h:178
USkinnedMeshComponent float
Definition SkinnedMeshComponent.h:60
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
void SetNumZeroed(SizeType NewNum, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2340
UE_REWRITE bool IsEmpty() const
Definition Array.h:1133
UE_FORCEINLINE_HINT SizeType Emplace(ArgsType &&... Args)
Definition Array.h:2561
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(ElementType &&Item)
Definition Array.h:2696
UE_NODEBUG void Sort()
Definition Array.h:3418
UE_FORCEINLINE_HINT void Reserve(SizeType Number)
Definition Array.h:3016
Definition AssetRegistryState.h:50
Definition AndroidPlatformMisc.h:14
static bool IsFinite(const RealType Value)
Definition MathUtil.h:208
static bool IsNaN(const RealType Value)
Definition MathUtil.h:201
static RealType Sqrt(const RealType Value)
Definition MathUtil.h:342
Definition SpatialInterfaces.h:51
Definition DistPoint3Triangle3.h:23
Definition DistTriangle3Triangle3.h:27
Real GetSquared()
Definition DistTriangle3Triangle3.h:55
void SetTriangle(int WhichTriangle, const TTriangle3< Real > &TriangleIn)
Definition DistTriangle3Triangle3.h:44
Definition DynamicVector.h:27
size_t GetByteCount() const
Definition DynamicVector.h:149
void InsertAt(const Type &Data, unsigned int Index)
Definition DynamicVector.h:747
size_t GetLength() const
Definition DynamicVector.h:146
Definition FastWinding.h:316
static bool FindIntersection(const TRay< RealType > &Ray, const TAxisAlignedBox3< RealType > &Box, RealType &RayParamOut)
Definition IntrRay3AxisAlignedBox3.h:110
Definition IntrRay3Triangle3.h:67
Definition IntrTriangle3Triangle3.h:33
void SetTriangle0(const TTriangle3< Real > &Triangle0In)
Definition IntrTriangle3Triangle3.h:112
static bool Intersects(const TTriangle3< Real > &Triangle0, const TTriangle3< Real > &Triangle1, Real Tolerance=TMathUtil< Real >::ZeroTolerance)
Definition IntrTriangle3Triangle3.h:386
Definition MeshAABBTree3.h:854
TFunction< bool(const FAxisAlignedBox3d &, int)> NextBoxF
Definition MeshAABBTree3.h:857
TFunction< void(int, int)> BeginBoxTrianglesF
Definition MeshAABBTree3.h:860
TFunction< void(int)> NextTriangleF
Definition MeshAABBTree3.h:861
TFunction< void(int)> EndBoxTrianglesF
Definition MeshAABBTree3.h:862
Definition MeshAABBTree3.h:61
void find_intersections(int iBox, const TMeshAABBTree3 &OtherTree, const TFunction< FVector3d(const FVector3d &)> &TransformF, int oBox, int depth, MeshIntersection::FIntersectionsQueryResult &result, TFunctionRef< bool(FIntrTriangle3Triangle3d &)> IntersectFn, const FQueryOptions &Options, const FQueryOptions &OtherTreeOptions) const
Definition MeshAABBTree3.h:2167
bool FindAllHitTriangles(const FWatertightRay3d &Ray, TArray< MeshIntersection::FHitIntersectionResult > &OutHits, const FQueryOptions &Options=FQueryOptions()) const
Definition MeshAABBTree3.h:473
TriangleMeshType MeshType
Definition MeshAABBTree3.h:67
void TestCoverage()
Definition MeshAABBTree3.h:2308
virtual bool FindAllHitTriangles(const FRay3d &Ray, TArray< MeshIntersection::FHitIntersectionResult > &OutHits, const FQueryOptions &Options=FQueryOptions()) const override
Definition MeshAABBTree3.h:466
FAxisAlignedBox3d GetBox(int IBox) const
Definition MeshAABBTree3.h:1150
double BoxDistanceSqr(int IBox, const FVector3d &V) const
Definition MeshAABBTree3.h:1196
virtual bool TestIntersection(const FTriangle3d &Triangle, const FQueryOptions &Options=FQueryOptions()) const
Definition MeshAABBTree3.h:1030
double TotalVolume()
Definition MeshAABBTree3.h:2331
bool find_nearest_tri(int IBox, const FVector3d &P, double &NearestDistSqr, int &TID, const FQueryOptions &Options) const
Definition MeshAABBTree3.h:238
int SplitTriSetMidpoint(TArray< int > &Triangles, TArray< FVector3d > &Centers, int IStart, int ICount, int Depth, int MinTriCount, FBoxesSet &Tris, FBoxesSet &Nodes, FAxisAlignedBox3d &Box)
Definition MeshAABBTree3.h:1394
void SetBuildOptions(int32 MaxBoxTriCount, GetSplitAxisFunc &&GetSplitAxisIn=MakeDefaultSplitAxisFunc())
Definition MeshAABBTree3.h:132
virtual bool TestAnyHitTriangle(const FRay3d &Ray, const FQueryOptions &Options=FQueryOptions()) const
Definition MeshAABBTree3.h:698
static bool TriangleIntersectionFilter(const FTriangle3d &A, const FTriangle3d &B)
Definition MeshAABBTree3.h:1675
virtual MeshIntersection::FIntersectionsQueryResult FindAllSelfIntersections(bool bIgnoreTopoConnected=true, const FQueryOptions &Options=FQueryOptions(), TFunction< bool(FIntrTriangle3Triangle3d &)> IntersectionFn=nullptr) const
Definition MeshAABBTree3.h:1094
const TriangleMeshType * Mesh
Definition MeshAABBTree3.h:71
virtual bool TestSelfIntersection(bool bIgnoreTopoConnected=true, const FQueryOptions &Options=FQueryOptions()) const
Definition MeshAABBTree3.h:1123
void BuildTopDown(bool bSorted, TriIndexEnumerable TriangleList, int32 NumTriangles)
Definition MeshAABBTree3.h:1316
void FindHitTriangle(int IBox, const RayType &Ray, double &NearestT, int &TID, FVector3d &BaryCoords, const FQueryOptions &Options=FQueryOptions()) const
Definition MeshAABBTree3.h:539
int find_any_intersection(int iBox, const FTriangle3d &Triangle, const FAxisAlignedBox3d &triBounds, TFunctionRef< bool(const FTriangle3d &A, const FTriangle3d &B)> TriangleIntersectionTest, const FQueryOptions &Options) const
Definition MeshAABBTree3.h:1701
void SetMesh(const TriangleMeshType *SourceMesh, bool bAutoBuild=true)
Definition MeshAABBTree3.h:98
TMeshAABBTree3()
Definition MeshAABBTree3.h:88
bool find_self_intersections(MeshIntersection::FIntersectionsQueryResult *Result, bool bIgnoreTopoConnected, TFunctionRef< bool(FIntrTriangle3Triangle3d &)> IntersectFn, const FQueryOptions &Options) const
Definition MeshAABBTree3.h:2138
double box_ray_intersect_t(int IBox, const RayType &Ray) const
Definition MeshAABBTree3.h:1215
bool box_box_intersect(int IBox, const FAxisAlignedBox3d &TestBox) const
Definition MeshAABBTree3.h:1232
bool FindNearestHitTriangle(const FWatertightRay3d &Ray, double &NearestT, int &TID, FVector3d &BaryCoords, const FQueryOptions &Options=FQueryOptions()) const
Definition MeshAABBTree3.h:459
void BuildTopDown(bool bSorted)
Definition MeshAABBTree3.h:1286
virtual bool IsInside(const FVector3d &P) const override
Definition MeshAABBTree3.h:848
void FindHitTriangles(int IBox, const RayType &Ray, TArray< MeshIntersection::FHitIntersectionResult > &Intersections, const FQueryOptions &Options=FQueryOptions()) const
Definition MeshAABBTree3.h:617
void Build(const TArray< int32 > &TriangleList)
Definition MeshAABBTree3.h:144
virtual bool FindNearestHitTriangle(const FRay3d &Ray, double &NearestT, int &TID, FVector3d &BaryCoords, const FQueryOptions &Options=FQueryOptions()) const override
Definition MeshAABBTree3.h:452
bool TestAnyHitTriangle(int IBox, const FRay3d &Ray, int32 &HitTIDOut, double MaxDistance, const FQueryOptions &Options=FQueryOptions()) const
Definition MeshAABBTree3.h:715
TDynamicVector< int > BoxToIndex
Definition MeshAABBTree3.h:1248
GetSplitAxisFunc GetSplitAxis
Definition MeshAABBTree3.h:83
TDynamicVector< int > IndexList
Definition MeshAABBTree3.h:1262
void Build()
Definition MeshAABBTree3.h:138
virtual bool SupportsPointContainment() const override
Definition MeshAABBTree3.h:843
static GetSplitAxisFunc MakeDefaultSplitAxisFunc()
Definition MeshAABBTree3.h:75
int TrianglesEnd
Definition MeshAABBTree3.h:1265
virtual MeshIntersection::FIntersectionsQueryResult FindAllIntersections(const TMeshAABBTree3 &OtherTree, const TFunction< FVector3d(const FVector3d &)> &TransformF=nullptr, const FQueryOptions &Options=FQueryOptions(), const FQueryOptions &OtherTreeOptions=FQueryOptions(), TFunction< bool(FIntrTriangle3Triangle3d &)> IntersectionFn=nullptr) const
Definition MeshAABBTree3.h:1060
virtual bool SupportsTriangleRayIntersection() const override
Definition MeshAABBTree3.h:431
virtual FIndex2i FindNearestTriangles(TMeshAABBTree3 &OtherTree, const TFunction< FVector3d(const FVector3d &)> &TransformF, double &Distance, const FQueryOptions &Options=FQueryOptions(), const FQueryOptions &OtherTreeOptions=FQueryOptions())
Definition MeshAABBTree3.h:816
virtual int FindNearestVertex(const FVector3d &P, double &NearestDistSqr, double MaxDist=TNumericLimits< double >::Max(), const FQueryOptions &Options=FQueryOptions())
Definition MeshAABBTree3.h:336
const TriangleMeshType * GetMesh() const
Definition MeshAABBTree3.h:109
double box_box_distsqr(int iBox, const FAxisAlignedBox3d &testBox) const
Definition MeshAABBTree3.h:1663
FAxisAlignedBox3d GetBox(int iBox, const TFunction< FVector3d(const FVector3d &)> &TransformF) const
Definition MeshAABBTree3.h:1157
static constexpr double DOUBLE_MAX
Definition MeshAABBTree3.h:86
void SetTolerance(double Tolerance)
Definition MeshAABBTree3.h:1191
bool IsValid(bool bAllowUnsafeModifiedMeshQueries) const
Definition MeshAABBTree3.h:118
virtual void TreeTraversalImpl(int IBox, int Depth, FTreeTraversal &Traversal, const FQueryOptions &Options) const
Definition MeshAABBTree3.h:886
int TopDownLeafMaxTriCount
Definition MeshAABBTree3.h:73
virtual int FindNearestTriangle(const FVector3d &P, double &NearestDistSqr, const FQueryOptions &Options=FQueryOptions()) const override
Definition MeshAABBTree3.h:159
virtual void DoTraversal(FTreeTraversal &Traversal, const FQueryOptions &Options=FQueryOptions()) const
Definition MeshAABBTree3.h:868
bool find_tri_tri_intersections(int TID_A, int IdxRangeStart, int IdxRangeEnd, MeshIntersection::FIntersectionsQueryResult *Result, bool bIgnoreTopoConnected, TFunctionRef< bool(FIntrTriangle3Triangle3d &)> IntersectFn, const FQueryOptions &Options) const
Definition MeshAABBTree3.h:2036
TMeshAABBTree3(const TriangleMeshType *SourceMesh, bool bAutoBuild=true)
Definition MeshAABBTree3.h:93
int RootIndex
Definition MeshAABBTree3.h:1268
TDynamicVector< FVector3d > BoxCenters
Definition MeshAABBTree3.h:1249
SIZE_T GetByteCount() const
Definition MeshAABBTree3.h:1240
virtual FVector3d FindNearestPoint(const FVector3d &Point, const FQueryOptions &Options=FQueryOptions()) const
Definition MeshAABBTree3.h:197
uint64 MeshChangeStamp
Definition MeshAABBTree3.h:72
virtual int FindNearestHitTriangle(const FRay3d &Ray, const FQueryOptions &Options=FQueryOptions()) const override
Definition MeshAABBTree3.h:436
void find_nearest_triangles(int iBox, TMeshAABBTree3 &OtherTree, const TFunction< FVector3d(const FVector3d &)> &TransformF, int oBox, int depth, double &nearest_sqr, FIndex2i &nearest_pair, const FQueryOptions &Options, const FQueryOptions &OtherTreeOptions) const
Definition MeshAABBTree3.h:1497
void find_nearest_vertex(int IBox, const FVector3d &P, double &NearestDistSqr, int &NearestVertexID, const FQueryOptions &Options)
Definition MeshAABBTree3.h:355
void BuildTopDown(TArray< int > &Triangles, TArray< FVector3d > &Centers, int32 NumTriangles)
Definition MeshAABBTree3.h:1345
virtual bool IsWithinDistanceSquared(const FVector3d &Point, double ThresholdDistanceSqr, int &OutTriangleID, const FQueryOptions &Options=FQueryOptions()) const
Definition MeshAABBTree3.h:217
FAxisAlignedBox3d GetBoundingBox() const
Definition MeshAABBTree3.h:181
double BoxEps
Definition MeshAABBTree3.h:1184
virtual bool SupportsNearestTriangle() const override
Definition MeshAABBTree3.h:150
virtual bool TestIntersection(const TMeshAABBTree3 &OtherTree, const TFunction< FVector3d(const FVector3d &)> &TransformF=nullptr, const FQueryOptions &Options=FQueryOptions(), const FQueryOptions &OtherTreeOptions=FQueryOptions()) const
Definition MeshAABBTree3.h:1001
bool box_contains(int IBox, const FVector3d &P) const
Definition MeshAABBTree3.h:1208
static bool TriangleIntersection(FIntrTriangle3Triangle3d &Intr)
Definition MeshAABBTree3.h:1684
static void AddTriTriIntersectionResult(const FIntrTriangle3Triangle3d &Intr, int TID_A, int TID_B, MeshIntersection::FIntersectionsQueryResult &Result)
Definition MeshAABBTree3.h:2108
bool find_self_intersections_acrossboxes(int Box1, int Box2, MeshIntersection::FIntersectionsQueryResult *Result, bool bIgnoreTopoConnected, int depth, TFunctionRef< bool(FIntrTriangle3Triangle3d &)> IntersectFn, const FQueryOptions &Options) const
Definition MeshAABBTree3.h:1900
TDynamicVector< FVector3d > BoxExtents
Definition MeshAABBTree3.h:1250
FAxisAlignedBox3d GetBoxEps(int IBox, double Epsilon=FMathd::ZeroTolerance) const
Definition MeshAABBTree3.h:1171
virtual bool FindNearestHitTriangle(const FRay3d &Ray, double &NearestT, int &TID, const FQueryOptions &Options=FQueryOptions()) const override
Definition MeshAABBTree3.h:446
bool find_any_intersection(int iBox, const TMeshAABBTree3 &OtherTree, const TFunction< FVector3d(const FVector3d &)> &TransformF, int oBox, int depth, TFunctionRef< bool(const FTriangle3d &A, const FTriangle3d &B)> TriangleIntersectionTest, const FQueryOptions &Options, const FQueryOptions &OtherTreeOptions) const
Definition MeshAABBTree3.h:1760
virtual bool TestIntersection(const TriangleMeshType *TestMesh, FAxisAlignedBox3d TestMeshBounds=FAxisAlignedBox3d::Empty(), const TFunction< FVector3d(const FVector3d &)> &TransformF=nullptr, const FQueryOptions &Options=FQueryOptions()) const
Definition MeshAABBTree3.h:947
Definition MeshQueries.h:21
static FVector3d GetTriCentroid(const TriangleMeshType &Mesh, int TriIdx)
Definition MeshQueries.h:57
static FDistPoint3Triangle3d TriangleDistance(const TriangleMeshType &Mesh, int TriIdx, FVector3d Point)
Definition MeshQueries.h:28
static double TriDistanceSqr(const TriangleMeshType &Mesh, int TriIdx, const FVector3d &Point)
Definition MeshQueries.h:361
constexpr int InvalidID
Definition IndexTypes.h:13
bool RayTriangleTest(const TVector< RealType > &RayOrigin, const TVector< RealType > &RayDirection, const TVector< RealType > &V0, const TVector< RealType > &V1, const TVector< RealType > &V2)
Definition IntersectionUtil.h:38
Definition MeshAABBTree3.h:17
Definition ParametricSurfaceData.h:18
TIntrRay3Triangle3< double > FIntrRay3Triangle3d
Definition IntrRay3Triangle3.h:319
T DistanceSquared(const UE::Math::TVector2< T > &V1, const UE::Math::TVector2< T > &V2)
Definition VectorTypes.h:82
TAxisAlignedBox3< double > FAxisAlignedBox3d
Definition BoxTypes.h:885
TTriangle3< double > FTriangle3d
Definition TriangleTypes.h:325
Definition Sphere.cpp:10
Definition AdvancedWidgetsModule.cpp:13
Definition SpatialInterfaces.h:13
Definition MeshAABBTree3.h:40
TArray< FSegmentIntersection > Segments
Definition MeshAABBTree3.h:42
TArray< FPolygonIntersection > Polygons
Definition MeshAABBTree3.h:43
TArray< FPointIntersection > Points
Definition MeshAABBTree3.h:41
Definition MeshAABBTree3.h:24
int TriangleID[2]
Definition MeshAABBTree3.h:25
FVector3d Point
Definition MeshAABBTree3.h:26
Definition MeshAABBTree3.h:34
int Quantity
Definition MeshAABBTree3.h:37
int TriangleID[2]
Definition MeshAABBTree3.h:35
FVector3d Point[6]
Definition MeshAABBTree3.h:36
Definition MeshAABBTree3.h:29
FVector3d Point[2]
Definition MeshAABBTree3.h:31
int TriangleID[2]
Definition MeshAABBTree3.h:30
Definition NumericLimits.h:41
Definition IndexTypes.h:27
static constexpr FIndex2i Invalid()
Definition IndexTypes.h:52
Definition IndexTypes.h:158
int B
Definition IndexTypes.h:164
int A
Definition IndexTypes.h:163
int C
Definition IndexTypes.h:165
Definition SpatialInterfaces.h:57
TFunction< bool(int)> TriangleFilterF
Definition SpatialInterfaces.h:66
static TAxisAlignedBox3< double > Empty()
Definition BoxTypes.h:382
RealType DistanceSquared(const TVector< RealType > &V) const
Definition BoxTypes.h:531
static TInterval1< double > Empty()
Definition BoxTypes.h:34
Definition MeshAABBTree3.h:1271
TDynamicVector< FVector3d > BoxCenters
Definition MeshAABBTree3.h:1273
int IBoxCur
Definition MeshAABBTree3.h:1276
TDynamicVector< int > BoxToIndex
Definition MeshAABBTree3.h:1272
TDynamicVector< FVector3d > BoxExtents
Definition MeshAABBTree3.h:1274
FBoxesSet()
Definition MeshAABBTree3.h:1278
TDynamicVector< int > IndexList
Definition MeshAABBTree3.h:1275
int IIndicesCur
Definition MeshAABBTree3.h:1277
Definition TriangleTypes.h:263
TVector< RealType > V[3]
Definition TriangleTypes.h:264
Definition IntrRay3Triangle3.h:24
TVector< T > Origin
Definition Ray.h:24
TVector< T > Direction
Definition Ray.h:27
T Z
Definition Vector.h:68
static TVector< double > Zero()
Definition Vector.h:112
T Y
Definition Vector.h:65
T X
Definition Vector.h:62
T SquaredLength() const
Definition Vector.h:1734