@@ -3194,7 +3194,11 @@ namespace OrthoTree
31943194
31953195 private: // K Nearest Neighbor helpers
31963196 static inline void CreateEntityDistance (
3197- std::vector<TEntityID> const & entities, TVector const & searchPoint, TContainer const & points, std::vector<EntityDistance>& neighborEntities, TGeometry maxDistance) noexcept
3197+ std::vector<TEntityID> const & entities,
3198+ TVector const & searchPoint,
3199+ TContainer const & points,
3200+ std::vector<EntityDistance>& neighborEntities,
3201+ TGeometry maxDistance) noexcept
31983202 {
31993203 for (auto const entityID : entities)
32003204 {
@@ -3992,7 +3996,24 @@ namespace OrthoTree
39923996 return this ->FrustumCullingBase (boundaryPlanes, tolerance, boxes);
39933997 }
39943998
3999+ private:
4000+ struct SweepAndPruneDatabase
4001+ {
4002+ inline constexpr SweepAndPruneDatabase (TContainer const & boxes, std::vector<TEntityID> const & entityIDs) noexcept
4003+ : m_sortedEntityIDs(entityIDs)
4004+ {
4005+ std::sort (m_sortedEntityIDs.begin (), m_sortedEntityIDs.end (), [&](auto const entityIDL, auto const entityIDR) {
4006+ return AD::GetBoxMinC (detail::at (boxes, entityIDL), 0 ) < AD::GetBoxMinC (detail::at (boxes, entityIDR), 0 );
4007+ });
4008+ }
4009+
4010+ inline constexpr std::vector<TEntityID> const & GetEntities () const noexcept { return m_sortedEntityIDs; }
4011+
4012+ private:
4013+ std::vector<TEntityID> m_sortedEntityIDs;
4014+ };
39954015
4016+ public:
39964017 // Client-defined Collision detector based on indices. AABB intersection is executed independently from this checker.
39974018 using FCollisionDetector = std::function<bool (TEntityID, TEntityID)>;
39984019
@@ -4020,6 +4041,18 @@ namespace OrthoTree
40204041 auto constexpr rootKey = SI::GetRootKey ();
40214042 auto const trees = std::array{ &leftTree, &rightTree };
40224043
4044+ auto entitiesInOrderCache = std::array<std::unordered_map<MortonNodeID, SweepAndPruneDatabase>, 2 >{};
4045+ auto const getOrCreateEntitiesInOrder = [&](bool side, NodeIterator const & it, TContainer const & boxes) -> std::vector<TEntityID> const & {
4046+ auto itKeyAndSPD = entitiesInOrderCache[side].find (it->first );
4047+ if (itKeyAndSPD == entitiesInOrderCache[side].end ())
4048+ {
4049+ bool isInserted = false ;
4050+ std::tie (itKeyAndSPD, isInserted) = entitiesInOrderCache[side].emplace (it->first , SweepAndPruneDatabase (boxes, it->second .Entities ));
4051+ }
4052+
4053+ return itKeyAndSPD->second .GetEntities ();
4054+ };
4055+
40234056 [[maybe_unused]] auto const pLeftTree = &leftTree;
40244057 [[maybe_unused]] auto const pRightTree = &rightTree;
40254058 auto nodePairToProceed = std::queue<ParentIteratorArray>{};
@@ -4032,11 +4065,28 @@ namespace OrthoTree
40324065 auto const & parentNodePair = nodePairToProceed.front ();
40334066
40344067 // Check the current ascendant content
4068+
4069+ auto const & leftEntitiesInOrder = getOrCreateEntitiesInOrder (Left, parentNodePair[Left].Iterator , leftBoxes);
4070+ auto const & rightEntitiesInOrder = getOrCreateEntitiesInOrder (Right, parentNodePair[Right].Iterator , rightBoxes);
4071+
4072+ auto const rightEntityNo = rightEntitiesInOrder.size ();
4073+ std::size_t iRightEntityBegin = 0 ;
4074+ for (auto const leftEntityID : leftEntitiesInOrder)
40354075 {
4036- for (auto const leftEntityID : parentNodePair[Left].Iterator ->second .Entities )
4037- for (auto const rightEntityID : parentNodePair[Right].Iterator ->second .Entities )
4038- if (AD::AreBoxesOverlapped (detail::at (leftBoxes, leftEntityID), detail::at (rightBoxes, rightEntityID), false ))
4039- results.emplace_back (leftEntityID, rightEntityID);
4076+ for (; iRightEntityBegin < rightEntityNo; ++iRightEntityBegin)
4077+ if (AD::GetBoxMaxC (detail::at (rightBoxes, rightEntitiesInOrder[iRightEntityBegin]), 0 ) >= AD::GetBoxMinC (detail::at (leftBoxes, leftEntityID), 0 ))
4078+ break ; // sweep and prune optimization
4079+
4080+ for (std::size_t iRightEntity = iRightEntityBegin; iRightEntity < rightEntityNo; ++iRightEntity)
4081+ {
4082+ auto const rightEntityID = rightEntitiesInOrder[iRightEntity];
4083+
4084+ if (AD::GetBoxMaxC (detail::at (leftBoxes, leftEntityID), 0 ) < AD::GetBoxMinC (detail::at (rightBoxes, rightEntityID), 0 ))
4085+ break ; // sweep and prune optimization
4086+
4087+ if (AD::AreBoxesOverlapped (detail::at (leftBoxes, leftEntityID), detail::at (rightBoxes, rightEntityID), false ))
4088+ results.emplace_back (leftEntityID, rightEntityID);
4089+ }
40404090 }
40414091
40424092 // Collect children
@@ -4091,22 +4141,6 @@ namespace OrthoTree
40914141 }
40924142
40934143 private:
4094- struct SweepAndPruneDatabase
4095- {
4096- inline constexpr SweepAndPruneDatabase (TContainer const & boxes, std::vector<TEntityID> const & entityIDs) noexcept
4097- : m_sortedEntityIDs(entityIDs)
4098- {
4099- std::sort (m_sortedEntityIDs.begin (), m_sortedEntityIDs.end (), [&](auto const entityIDL, auto const entityIDR) {
4100- return AD::GetBoxMinC (detail::at (boxes, entityIDL), 0 ) < AD::GetBoxMinC (detail::at (boxes, entityIDR), 0 );
4101- });
4102- }
4103-
4104- inline constexpr std::vector<TEntityID> const & GetEntities () const noexcept { return m_sortedEntityIDs; }
4105-
4106- private:
4107- std::vector<TEntityID> m_sortedEntityIDs;
4108- };
4109-
41104144 template <typename TCollisionDetectionContainer>
41114145 void InsertCollidedEntities (
41124146 TContainer const & boxes, std::pair<MortonNodeID, Node> const & pairKeyNode, TCollisionDetectionContainer& collidedEntityPairsInsideNode) const noexcept
@@ -4369,7 +4403,8 @@ namespace OrthoTree
43694403 TVector const & rayBasePoint, TVector const & rayHeading, TContainer const & boxes, TGeometry tolerance = {}) const noexcept
43704404 {
43714405 auto const & rootNode = this ->GetNode (SI::GetRootKey ());
4372- auto const distance = IGM::GetRayBoxDistanceAD (GetNodeCenterMacro (this , SI::GetRootKey (), rootNode), this ->GetNodeSize (1 ), rayBasePoint, rayHeading, tolerance);
4406+ auto const distance =
4407+ IGM::GetRayBoxDistanceAD (GetNodeCenterMacro (this , SI::GetRootKey (), rootNode), this ->GetNodeSize (1 ), rayBasePoint, rayHeading, tolerance);
43734408 if (!distance)
43744409 return std::nullopt ;
43754410
0 commit comments