@@ -316,13 +316,13 @@ namespace OrthoTree
316316 concept HasReserve = requires (TContainer container) { container.reserve (0 ); };
317317
318318 template <HasReserve TContainer>
319- constexpr void reserve (TContainer& c, std::size_t n) noexcept
319+ inline constexpr void reserve (TContainer& c, std::size_t n) noexcept
320320 {
321321 c.reserve (n);
322322 };
323323
324324 template <typename TContainer>
325- constexpr void reserve (TContainer& c, std::size_t n) noexcept {};
325+ inline constexpr void reserve (TContainer& c, std::size_t n) noexcept {};
326326
327327 template <uint8_t e, typename TOut = std::size_t >
328328 consteval TOut pow2_ce ()
@@ -333,7 +333,7 @@ namespace OrthoTree
333333 }
334334
335335 template <typename TIn, typename TOut = std::size_t >
336- constexpr TOut pow2 (TIn e) noexcept
336+ inline constexpr TOut pow2 (TIn e) noexcept
337337 {
338338 assert (e >= 0 && e < (sizeof (TOut) * CHAR_BIT));
339339 return TOut{ 1 } << e;
@@ -2021,11 +2021,13 @@ namespace OrthoTree
20212021 }
20222022
20232023 protected:
2024- inline Node& CreateChild (Node& parentNode, MortonNodeIDCR childKey) noexcept
2024+ inline constexpr Node CreateChild (Node const & parentNode, MortonNodeIDCR childKey) const noexcept
20252025 {
2026- auto & nodeChild = m_nodes[childKey];
2026+ #ifdef ORTHOTREE__DISABLED_NODECENTER
2027+ return Node{};
2028+ #else
2029+ Node nodeChild;
20272030
2028- #ifndef ORTHOTREE__DISABLED_NODECENTER
20292031 auto const depthID = SI::GetDepthID (childKey);
20302032 auto const & halfSizes = this ->GetNodeSize (depthID + 1 );
20312033 auto const & parentCenter = parentNode.GetCenter ();
@@ -2040,8 +2042,8 @@ namespace OrthoTree
20402042 }
20412043
20422044 nodeChild.SetCenter (std::move (childCenter));
2043- #endif // ORTHOTREE__DISABLED_NODECENTER
20442045 return nodeChild;
2046+ #endif // ORTHOTREE__DISABLED_NODECENTER
20452047 }
20462048
20472049 template <bool HANDLE_OUT_OF_TREE_GEOMETRY = false >
@@ -2120,8 +2122,8 @@ namespace OrthoTree
21202122 auto const childNodeKey = childGenerator.GetChildNodeKey (childID);
21212123
21222124 parentNode.AddChildInOrder (childNodeKey);
2123- auto & childNode = this ->CreateChild (parentNode, childNodeKey);
2124- childNode.AddEntity (newEntityID);
2125+ auto [ childNode, _] = this ->m_nodes . emplace (childNodeKey, this -> CreateChild (parentNode, childNodeKey) );
2126+ childNode-> second .AddEntity (newEntityID);
21252127
21262128 break ;
21272129 }
@@ -2135,8 +2137,8 @@ namespace OrthoTree
21352137 auto const childNodeKey = childGenerator.GetChildNodeKey (childID);
21362138
21372139 parentNode.AddChildInOrder (childNodeKey);
2138- auto & childNode = this ->CreateChild (parentNode, childNodeKey);
2139- childNode.AddEntity (newEntityID);
2140+ auto [ childNode, _] = this ->m_nodes . emplace (childNodeKey, this -> CreateChild (parentNode, childNodeKey) );
2141+ childNode-> second .AddEntity (newEntityID);
21402142 }
21412143
21422144 auto parentEntities = std::vector<TEntityID>{}; // Box entities could be stuck in the parent node.
@@ -2162,8 +2164,8 @@ namespace OrthoTree
21622164 else
21632165 {
21642166 parentNode.AddChildInOrder (childNodeKey);
2165- auto & childNode = this ->CreateChild (parentNode, childNodeKey);
2166- childNode.AddEntity (entityID);
2167+ auto [ childNode, _] = this ->m_nodes . emplace (childNodeKey, this -> CreateChild (parentNode, childNodeKey) );
2168+ childNode-> second .AddEntity (entityID);
21672169 }
21682170 }
21692171
@@ -2224,8 +2226,8 @@ namespace OrthoTree
22242226 auto const childNodeKey = childGenerator.GetChildNodeKey (childID);
22252227
22262228 parentNode.AddChildInOrder (childNodeKey);
2227- auto & nodeChild = this ->CreateChild (parentNode, childNodeKey);
2228- nodeChild .AddEntity (entityID);
2229+ auto [childNode, _] = this ->m_nodes . emplace (childNodeKey, this -> CreateChild (parentNode, childNodeKey) );
2230+ childNode-> second .AddEntity (entityID);
22292231 }
22302232 else
22312233 parentNode.AddEntity (entityID);
@@ -2273,7 +2275,7 @@ namespace OrthoTree
22732275 auto const nElementInNodeAvg = static_cast <float >(elementNo) / static_cast <float >(maxElementNo);
22742276 auto const nDepthEstimated = std::min (maxDepthNo, static_cast <depth_t >(ceil ((log2f (nElementInNodeAvg) + 1.0 ) / static_cast <float >(DIMENSION_NO))));
22752277 if (nDepthEstimated * DIMENSION_NO < 64 )
2276- return static_cast <std::size_t >(rMult * detail::pow2 (nDepthEstimated * DIMENSION_NO));
2278+ return static_cast <std::size_t >(1.05 * detail::pow2 (nDepthEstimated * std::min< depth_t >( 6 , DIMENSION_NO) ));
22772279
22782280 return static_cast <std::size_t >(rMult * nElementInNodeAvg);
22792281 }
@@ -2965,46 +2967,6 @@ namespace OrthoTree
29652967 this ->template Create <false >(*this , points, maxDepthNoIn, std::move (boxSpaceOptional), maxElementNoInNode);
29662968 }
29672969
2968- private: // Aid functions
2969- struct Location
2970- {
2971- TEntityID EntityID;
2972- MortonLocationID LocationID;
2973- };
2974-
2975- using LocationIterator = typename std::vector<Location>::iterator;
2976- void CreateChildNodes (
2977- Node& parentNode, MortonNodeIDCR parentKey, LocationIterator& locationBeginIterator, LocationIterator const & locationEndIterator, depth_t remainingDepth) noexcept
2978- {
2979- std::size_t const elementNo = std::distance (locationBeginIterator, locationEndIterator);
2980- if (elementNo < this ->m_maxElementNo || remainingDepth == 0 )
2981- {
2982- auto & entityIDs = parentNode.GetEntities ();
2983- entityIDs.resize (elementNo);
2984-
2985- LOOPIVDEP
2986- for (std::size_t i = 0 ; locationBeginIterator != locationEndIterator; ++locationBeginIterator, ++i)
2987- entityIDs[i] = locationBeginIterator->EntityID ;
2988-
2989- return ;
2990- }
2991-
2992- --remainingDepth;
2993- auto const keyGenerator = typename SI::ChildKeyGenerator (parentKey);
2994-
2995- while (locationBeginIterator != locationEndIterator)
2996- {
2997- auto const childChecker = typename SI::ChildCheckerFixedDepth (remainingDepth, locationBeginIterator->LocationID );
2998- auto const actualEndIterator =
2999- std::partition_point (locationBeginIterator, locationEndIterator, [&](auto const & location) { return childChecker.Test (location.LocationID ); });
3000-
3001- auto const childKey = keyGenerator.GetChildNodeKey (childChecker.GetChildID (remainingDepth));
3002- parentNode.AddChild (childKey);
3003- auto & childNode = this ->CreateChild (parentNode, childKey);
3004- this ->CreateChildNodes (childNode, childKey, locationBeginIterator, actualEndIterator, remainingDepth);
3005- }
3006- }
3007-
30082970 public: // Create
30092971 // Create
30102972 template <bool IS_PARALLEL_EXEC = false >
@@ -3023,24 +2985,89 @@ namespace OrthoTree
30232985 if (points.empty ())
30242986 return ;
30252987
3026- detail::reserve (tree. m_nodes , Base::EstimateNodeNumber (pointNo, maxDepthNo, maxElementNoInNode));
2988+ // Calculate and sort the Morton location ids
30272989
2990+ struct Location
2991+ {
2992+ TEntityID EntityID;
2993+ MortonLocationID LocationID;
2994+ };
30282995 auto pointLocations = std::vector<Location>(pointNo);
30292996 EXEC_POL_DEF (ept); // GCC 11.3
30302997 std::transform (EXEC_POL_ADD (ept) points.begin (), points.end (), pointLocations.begin (), [&](auto const & point) {
30312998 return Location{ detail::getKeyPart (points, point), tree.GetLocationID (detail::getValuePart (point)) };
30322999 });
30333000
3034- EXEC_POL_DEF (eps); // GCC 11.3
3035- std::sort (EXEC_POL_ADD (eps) pointLocations.begin (), pointLocations.end (), [&](auto const & leftLocation, auto const & rightLocation) {
3036- return leftLocation.LocationID < rightLocation.LocationID ;
3037- });
3001+ if constexpr (IS_PARALLEL_EXEC)
3002+ {
3003+ EXEC_POL_DEF (eps); // GCC 11.3
3004+ std::sort (EXEC_POL_ADD (eps) pointLocations.begin (), pointLocations.end (), [&](auto const & leftLocation, auto const & rightLocation) {
3005+ return leftLocation.LocationID < rightLocation.LocationID ;
3006+ });
3007+ }
30383008
3039- auto constexpr rootKey = SI::GetRootKey ();
3040- auto & nodeRoot = detail::at (tree.m_nodes , rootKey);
3009+ // Build the tree in depth-first search order
3010+
3011+ struct NodeData
3012+ {
3013+ std::pair<MortonNodeID, Node> NodeInstance;
3014+ typename std::vector<Location>::iterator LocationEndIterator;
3015+ };
3016+ std::array<NodeData, SI::MAX_THEORETICAL_DEPTH> nodeStack;
3017+ nodeStack[0 ] = NodeData{ *tree.m_nodes .find (SI::GetRootKey ()), pointLocations.end () };
3018+ tree.m_nodes .clear (); // Root will be inserted again via the nodeStack, unspecified behavior
3019+
3020+ auto locationBeginIterator = pointLocations.begin ();
3021+ for (int depthID = 0 ; depthID >= 0 ;)
3022+ {
3023+ auto & [node, locationEndIterator] = nodeStack[depthID];
3024+ std::size_t const elementNo = std::distance (locationBeginIterator, locationEndIterator);
3025+ if (elementNo == 0 )
3026+ {
3027+ tree.m_nodes .emplace (std::move (node));
3028+ --depthID;
3029+ continue ;
3030+ }
3031+
3032+ if (((elementNo < tree.m_maxElementNo ) && !node.second .IsAnyChildExist ()) || depthID == maxDepthNo)
3033+ {
3034+ auto & entityIDs = node.second .GetEntities ();
3035+ entityIDs.resize (elementNo);
3036+
3037+ LOOPIVDEP
3038+ for (std::size_t i = 0 ; i < elementNo; ++i)
3039+ {
3040+ entityIDs[i] = locationBeginIterator->EntityID ;
3041+ ++locationBeginIterator;
3042+ }
30413043
3042- auto beginIterator = pointLocations.begin ();
3043- tree.CreateChildNodes (nodeRoot, rootKey, beginIterator, pointLocations.end (), maxDepthNo);
3044+ tree.m_nodes .emplace (std::move (node));
3045+ --depthID;
3046+ continue ;
3047+ }
3048+
3049+ ++depthID;
3050+ auto const examinedLevel = tree.GetDepthMax () - depthID;
3051+ auto const keyGenerator = typename SI::ChildKeyGenerator (node.first );
3052+ auto const childChecker = typename SI::ChildCheckerFixedDepth (examinedLevel, locationBeginIterator->LocationID );
3053+ auto childKey = keyGenerator.GetChildNodeKey (childChecker.GetChildID (examinedLevel));
3054+ if constexpr (IS_PARALLEL_EXEC)
3055+ {
3056+ nodeStack[depthID].LocationEndIterator = std::partition_point (locationBeginIterator, locationEndIterator, [&](auto const & location) {
3057+ return childChecker.Test (location.LocationID );
3058+ });
3059+ node.second .AddChild (childKey);
3060+ }
3061+ else
3062+ {
3063+ nodeStack[depthID].LocationEndIterator =
3064+ std::partition (locationBeginIterator, locationEndIterator, [&](auto const & location) { return childChecker.Test (location.LocationID ); });
3065+ node.second .AddChildInOrder (childKey);
3066+ }
3067+
3068+ nodeStack[depthID].NodeInstance .first = std::move (childKey);
3069+ nodeStack[depthID].NodeInstance .second = tree.CreateChild (node.second , childKey);
3070+ }
30443071 }
30453072
30463073 public: // Edit functions
@@ -3496,9 +3523,11 @@ namespace OrthoTree
34963523 entityIDs.resize (elementNo);
34973524
34983525 LOOPIVDEP
3499- for (std::size_t i = 0 ; beginLocationIterator != endLocationIterator; ++beginLocationIterator, ++i)
3526+ for (std::size_t i = 0 ; i < elementNo; ++i)
3527+ {
35003528 entityIDs[i] = beginLocationIterator->EntityID ;
3501-
3529+ ++beginLocationIterator;
3530+ }
35023531 return ;
35033532 }
35043533
@@ -3515,8 +3544,11 @@ namespace OrthoTree
35153544 entityIDs.resize (stuckedElementNo);
35163545
35173546 LOOPIVDEP
3518- for (std::size_t i = 0 ; beginLocationIterator != stuckedEndLocationIterator; ++beginLocationIterator, ++i)
3547+ for (std::size_t i = 0 ; i < stuckedElementNo; ++i)
3548+ {
35193549 entityIDs[i] = beginLocationIterator->EntityID ;
3550+ ++beginLocationIterator;
3551+ }
35203552 }
35213553
35223554 ++currentDepthID;
@@ -3533,8 +3565,8 @@ namespace OrthoTree
35333565 auto const childKey = keyGenerator.GetChildNodeKey (childChecker.GetChildID (remainingDepthNo));
35343566
35353567 parentNode.AddChild (childKey);
3536- auto & nodeChild = this ->CreateChild (parentNode, childKey);
3537- this ->CreateChildNodes (nodeChild , childKey, beginLocationIterator, actualEndLocationIterator, remainingDepthNo);
3568+ auto [childNode, _] = this ->m_nodes . emplace (childKey, this -> CreateChild (parentNode, childKey) );
3569+ this ->CreateChildNodes (childNode-> second , childKey, beginLocationIterator, actualEndLocationIterator, remainingDepthNo);
35383570 }
35393571 }
35403572
0 commit comments