KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dynamic_rtree.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#ifndef DYNAMIC_RTREE_H
21#define DYNAMIC_RTREE_H
22
23#include <algorithm>
24#include <bit>
25#include <cassert>
26#include <climits>
27#include <cstdint>
28#include <cstring>
29#include <functional>
30#include <limits>
31#include <queue>
32#include <utility>
33#include <vector>
34
36
37namespace KIRTREE
38{
39
58template <class DATATYPE, class ELEMTYPE = int, int NUMDIMS = 2, int TMAXNODES = 16>
60{
61public:
63
64 static constexpr int MAXNODES = TMAXNODES;
65 static constexpr int MINNODES = NODE::MINNODES;
66
67 // Fraction of entries to reinsert on overflow (30% per R*-tree paper)
68 static constexpr int REINSERT_COUNT = MAXNODES * 3 / 10;
69
70 DYNAMIC_RTREE() = default;
71
73 {
75 m_root = nullptr;
76 m_count = 0;
77 }
78
79 // Move semantics
80 DYNAMIC_RTREE( DYNAMIC_RTREE&& aOther ) noexcept :
81 m_root( aOther.m_root ),
82 m_count( aOther.m_count ),
83 m_allocator( std::move( aOther.m_allocator ) )
84 {
85 aOther.m_root = nullptr;
86 aOther.m_count = 0;
87 }
88
90 {
91 if( this != &aOther )
92 {
94 m_root = aOther.m_root;
95 m_count = aOther.m_count;
96 m_allocator = std::move( aOther.m_allocator );
97 aOther.m_root = nullptr;
98 aOther.m_count = 0;
99 }
100
101 return *this;
102 }
103
104 // Non-copyable
105 DYNAMIC_RTREE( const DYNAMIC_RTREE& ) = delete;
107
111 void Insert( const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS],
112 const DATATYPE& aData )
113 {
114 if( !m_root )
115 {
116 m_root = allocNode();
117 m_root->level = 0;
118 }
119
120 // Bitmask tracking which levels have had forced reinsert this insertion.
121 // 32 bits handles tree depth up to 31, which covers > 16^31 items.
122 uint32_t reinsertedLevels = 0;
123
124 insertImpl( aMin, aMax, aData, reinsertedLevels );
125 m_count++;
126 }
127
133 bool Remove( const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS],
134 const DATATYPE& aData )
135 {
136 if( !m_root )
137 return false;
138
139 // Try removal using the provided bbox first
140 std::vector<NODE*> reinsertList;
141
142 if( removeImpl( m_root, aMin, aMax, aData, reinsertList ) )
143 {
144 m_count--;
145 reinsertOrphans( reinsertList );
146 condenseRoot();
147 return true;
148 }
149
150 // Fall back to full-tree search using stored insertion bboxes
151 ELEMTYPE fullMin[NUMDIMS];
152 ELEMTYPE fullMax[NUMDIMS];
153
154 for( int d = 0; d < NUMDIMS; ++d )
155 {
156 fullMin[d] = std::numeric_limits<ELEMTYPE>::lowest();
157 fullMax[d] = std::numeric_limits<ELEMTYPE>::max();
158 }
159
160 reinsertList.clear();
161
162 if( removeImpl( m_root, fullMin, fullMax, aData, reinsertList ) )
163 {
164 m_count--;
165 reinsertOrphans( reinsertList );
166 condenseRoot();
167 return true;
168 }
169
170 return false;
171 }
172
181 template <class VISITOR>
182 int Search( const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS],
183 VISITOR& aVisitor ) const
184 {
185 int found = 0;
186
187 if( m_root )
188 searchImpl( m_root, aMin, aMax, aVisitor, found );
189
190 return found;
191 }
192
197 {
199 m_root = nullptr;
200 m_count = 0;
201 }
202
207 {
208 ELEMTYPE min[NUMDIMS];
209 ELEMTYPE max[NUMDIMS];
210 DATATYPE data;
211 };
212
224 void BulkLoad( std::vector<BULK_ENTRY>& aEntries )
225 {
226 if( aEntries.empty() )
227 {
229 m_root = nullptr;
230 m_count = 0;
231 return;
232 }
233
234 // Find global bounds for Hilbert normalization
235 ELEMTYPE globalMin[NUMDIMS], globalMax[NUMDIMS];
236
237 for( int d = 0; d < NUMDIMS; ++d )
238 {
239 globalMin[d] = std::numeric_limits<ELEMTYPE>::max();
240 globalMax[d] = std::numeric_limits<ELEMTYPE>::lowest();
241 }
242
243 for( const auto& entry : aEntries )
244 {
245 for( int d = 0; d < NUMDIMS; ++d )
246 {
247 if( entry.min[d] < globalMin[d] )
248 globalMin[d] = entry.min[d];
249
250 if( entry.max[d] > globalMax[d] )
251 globalMax[d] = entry.max[d];
252 }
253 }
254
255 // Sort entries by Hilbert index of bbox center
256 double range[NUMDIMS];
257
258 for( int d = 0; d < NUMDIMS; ++d )
259 {
260 range[d] = static_cast<double>( globalMax[d] ) - globalMin[d];
261
262 if( range[d] <= 0.0 )
263 range[d] = 1.0;
264 }
265
266 // Derive each curve index once. A comparator that derives them re-derives both
267 // operands on every comparison, which for three axes costs more than the load
268 size_t n = aEntries.size();
269 std::vector<std::pair<uint64_t, size_t>> order( n );
270
271 for( size_t i = 0; i < n; ++i )
272 {
273 const BULK_ENTRY& entry = aEntries[i];
274 uint32_t coords[NUMDIMS];
275
276 for( int d = 0; d < NUMDIMS; ++d )
277 {
278 double center = ( static_cast<double>( entry.min[d] ) + entry.max[d] ) / 2.0;
279
280 coords[d] = static_cast<uint32_t>( ( ( center - globalMin[d] ) / range[d] )
281 * static_cast<double>( UINT32_MAX ) );
282 }
283
284 order[i] = { HilbertND2D<NUMDIMS>( 32, coords ), i };
285 }
286
287 std::sort( order.begin(), order.end() );
288
289 // Drop the old tree only after the last large allocation, so a caller that runs out
290 // of memory keeps its index instead of an empty tree that reports a size
292 m_root = nullptr;
293 m_count = n;
294
295 // Pack entries into leaf nodes
296 std::vector<NODE*> currentLevel;
297 currentLevel.reserve( ( n + MAXNODES - 1 ) / MAXNODES );
298
299 for( size_t i = 0; i < n; i += MAXNODES )
300 {
301 NODE* leaf = allocNode();
302 leaf->level = 0;
303 int cnt = static_cast<int>( std::min<size_t>( MAXNODES, n - i ) );
304
305 for( int j = 0; j < cnt; ++j )
306 {
307 const auto& entry = aEntries[order[i + j].second];
308 leaf->SetChildBounds( j, entry.min, entry.max );
309 leaf->SetInsertBounds( j, entry.min, entry.max );
310 leaf->data[j] = entry.data;
311 }
312
313 leaf->count = cnt;
314 currentLevel.push_back( leaf );
315 }
316
317 // Build internal levels bottom-up
318 int level = 1;
319
320 while( currentLevel.size() > 1 )
321 {
322 size_t levelSize = currentLevel.size();
323 std::vector<NODE*> nextLevel;
324 nextLevel.reserve( ( levelSize + MAXNODES - 1 ) / MAXNODES );
325
326 for( size_t i = 0; i < levelSize; i += MAXNODES )
327 {
328 NODE* internal = allocNode();
329 internal->level = level;
330 int cnt = static_cast<int>( std::min<size_t>( MAXNODES, levelSize - i ) );
331
332 for( int j = 0; j < cnt; ++j )
333 {
334 NODE* child = currentLevel[i + j];
335 ELEMTYPE childMin[NUMDIMS], childMax[NUMDIMS];
336 child->ComputeEnclosingBounds( childMin, childMax );
337 internal->SetChildBounds( j, childMin, childMax );
338 internal->children[j] = child;
339 }
340
341 internal->count = cnt;
342 nextLevel.push_back( internal );
343 }
344
345 currentLevel = std::move( nextLevel );
346 level++;
347 }
348
349 m_root = currentLevel[0];
350 }
351
352 size_t size() const { return m_count; }
353 bool empty() const { return m_count == 0; }
354
358 size_t MemoryUsage() const
359 {
360 return m_allocator.MemoryUsage();
361 }
362
367 {
368 public:
369 using iterator_category = std::forward_iterator_tag;
370 using value_type = DATATYPE;
371 using difference_type = ptrdiff_t;
372 using pointer = const DATATYPE*;
373 using reference = const DATATYPE&;
374
375 Iterator() : m_atEnd( true ) {}
376
377 explicit Iterator( NODE* aRoot )
378 {
379 if( aRoot && aRoot->count > 0 )
380 {
381 m_stack.push_back( { aRoot, 0 } );
382 advance();
383 }
384 else
385 {
386 m_atEnd = true;
387 }
388 }
389
390 const DATATYPE& operator*() const { return m_current; }
391 const DATATYPE* operator->() const { return &m_current; }
392
394 {
395 advance();
396 return *this;
397 }
398
399 bool operator==( const Iterator& aOther ) const
400 {
401 return m_atEnd == aOther.m_atEnd;
402 }
403
404 bool operator!=( const Iterator& aOther ) const
405 {
406 return !( *this == aOther );
407 }
408
409 private:
411 {
414 };
415
416 void advance()
417 {
418 while( !m_stack.empty() )
419 {
420 STACK_ENTRY& top = m_stack.back();
421
422 if( top.node->IsLeaf() )
423 {
424 if( top.childIdx < top.node->count )
425 {
426 m_current = top.node->data[top.childIdx];
427 top.childIdx++;
428 m_atEnd = false;
429 return;
430 }
431
432 m_stack.pop_back();
433 }
434 else
435 {
436 if( top.childIdx < top.node->count )
437 {
438 NODE* child = top.node->children[top.childIdx];
439 top.childIdx++;
440 m_stack.push_back( { child, 0 } );
441 }
442 else
443 {
444 m_stack.pop_back();
445 }
446 }
447 }
448
449 m_atEnd = true;
450 }
451
452 std::vector<STACK_ENTRY> m_stack;
453 DATATYPE m_current = {};
454 bool m_atEnd = true;
455 };
456
457 Iterator begin() const { return Iterator( m_root ); }
458 Iterator end() const { return Iterator(); }
459
465 {
466 public:
467 using iterator_category = std::input_iterator_tag;
468 using value_type = DATATYPE;
469 using difference_type = ptrdiff_t;
470 using pointer = const DATATYPE*;
471 using reference = const DATATYPE&;
472
473 SearchIterator() : m_atEnd( true ) {}
474
475 SearchIterator( NODE* aRoot, const ELEMTYPE aMin[NUMDIMS],
476 const ELEMTYPE aMax[NUMDIMS] )
477 {
478 for( int d = 0; d < NUMDIMS; ++d )
479 {
480 m_min[d] = aMin[d];
481 m_max[d] = aMax[d];
482 }
483
484 if( aRoot && aRoot->count > 0 )
485 {
486 m_stack.push_back( { aRoot, 0 } );
487 advance();
488 }
489 else
490 {
491 m_atEnd = true;
492 }
493 }
494
495 const DATATYPE& operator*() const { return m_current; }
496
498 {
499 advance();
500 return *this;
501 }
502
503 bool operator==( const SearchIterator& aOther ) const
504 {
505 return m_atEnd == aOther.m_atEnd;
506 }
507
508 bool operator!=( const SearchIterator& aOther ) const
509 {
510 return !( *this == aOther );
511 }
512
513 private:
515 {
518 };
519
520 void advance()
521 {
522 while( !m_stack.empty() )
523 {
524 STACK_ENTRY& top = m_stack.back();
525
526 if( top.node->IsLeaf() )
527 {
528 while( top.childIdx < top.node->count )
529 {
530 if( top.node->ChildOverlaps( top.childIdx, m_min, m_max ) )
531 {
532 m_current = top.node->data[top.childIdx];
533 top.childIdx++;
534 m_atEnd = false;
535 return;
536 }
537
538 top.childIdx++;
539 }
540
541 m_stack.pop_back();
542 }
543 else
544 {
545 bool descended = false;
546
547 while( top.childIdx < top.node->count )
548 {
549 if( top.node->ChildOverlaps( top.childIdx, m_min, m_max ) )
550 {
551 NODE* child = top.node->children[top.childIdx];
552 top.childIdx++;
553 m_stack.push_back( { child, 0 } );
554 descended = true;
555 break;
556 }
557
558 top.childIdx++;
559 }
560
561 if( !descended )
562 m_stack.pop_back();
563 }
564 }
565
566 m_atEnd = true;
567 }
568
569 std::vector<STACK_ENTRY> m_stack;
570 ELEMTYPE m_min[NUMDIMS];
571 ELEMTYPE m_max[NUMDIMS];
572 DATATYPE m_current = {};
573 bool m_atEnd = true;
574 };
575
581 {
582 public:
583 SearchRange( NODE* aRoot, const ELEMTYPE aMin[NUMDIMS],
584 const ELEMTYPE aMax[NUMDIMS] ) :
585 m_root( aRoot )
586 {
587 for( int d = 0; d < NUMDIMS; ++d )
588 {
589 m_min[d] = aMin[d];
590 m_max[d] = aMax[d];
591 }
592 }
593
595 SearchIterator end() const { return SearchIterator(); }
596 bool empty() const { return begin() == end(); }
597
598 private:
600 ELEMTYPE m_min[NUMDIMS];
601 ELEMTYPE m_max[NUMDIMS];
602 };
603
609 SearchRange Overlapping( const ELEMTYPE aMin[NUMDIMS],
610 const ELEMTYPE aMax[NUMDIMS] ) const
611 {
612 return SearchRange( m_root, aMin, aMax );
613 }
614
622 void NearestNeighbors( const ELEMTYPE aPoint[NUMDIMS], int aK,
623 std::vector<std::pair<int64_t, DATATYPE>>& aResults ) const
624 {
625 aResults.clear();
626
627 if( !m_root || aK <= 0 )
628 return;
629
630 using QueueEntry = std::pair<int64_t, std::pair<NODE*, int>>;
631 // Min-heap: smallest distance first
632 auto cmp = []( const QueueEntry& a, const QueueEntry& b )
633 {
634 return a.first > b.first;
635 };
636 std::priority_queue<QueueEntry, std::vector<QueueEntry>, decltype( cmp )> pq( cmp );
637
638 // Seed with root's children
639 for( int i = 0; i < m_root->count; ++i )
640 {
641 int64_t dist = minDistSq( m_root, i, aPoint );
642 pq.push( { dist, { m_root, i } } );
643 }
644
645 while( !pq.empty() && static_cast<int>( aResults.size() ) < aK )
646 {
647 auto [dist, entry] = pq.top();
648 pq.pop();
649 NODE* node = entry.first;
650 int slot = entry.second;
651
652 if( node->IsLeaf() )
653 {
654 aResults.push_back( { dist, node->data[slot] } );
655 }
656 else
657 {
658 NODE* child = node->children[slot];
659
660 for( int i = 0; i < child->count; ++i )
661 {
662 int64_t childDist = minDistSq( child, i, aPoint );
663 pq.push( { childDist, { child, i } } );
664 }
665 }
666 }
667 }
668
669private:
670 // Entry type used by both leaf and internal node split algorithms
672 {
673 ELEMTYPE min[NUMDIMS];
674 ELEMTYPE max[NUMDIMS];
675 ELEMTYPE insertMin[NUMDIMS];
676 ELEMTYPE insertMax[NUMDIMS];
677 DATATYPE data;
679 };
680
682 {
683 return m_allocator.Allocate();
684 }
685
686 void freeNode( NODE* aNode )
687 {
688 m_allocator.Free( aNode );
689 }
690
691 void removeAllNodes( NODE* aNode )
692 {
693 if( !aNode )
694 return;
695
696 if( aNode->IsInternal() )
697 {
698 for( int i = 0; i < aNode->count; ++i )
699 removeAllNodes( aNode->children[i] );
700 }
701
702 freeNode( aNode );
703 }
704
708 void insertImpl( const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS],
709 const DATATYPE& aData, uint32_t& aReinsertedLevels )
710 {
711 // ChooseSubtree to find the leaf
712 std::vector<NODE*> path;
713 NODE* leaf = chooseSubtree( m_root, aMin, aMax, path );
714
715 // Insert into leaf
716 if( !leaf->IsFull() )
717 {
718 int slot = leaf->count;
719 leaf->SetChildBounds( slot, aMin, aMax );
720 leaf->SetInsertBounds( slot, aMin, aMax );
721 leaf->data[slot] = aData;
722 leaf->count++;
723
724 adjustPath( path, leaf );
725 }
726 else
727 {
728 overflowTreatment( leaf, aMin, aMax, aData, path, aReinsertedLevels );
729 }
730 }
731
738 NODE* chooseSubtree( NODE* aNode, const ELEMTYPE aMin[NUMDIMS],
739 const ELEMTYPE aMax[NUMDIMS], std::vector<NODE*>& aPath )
740 {
741 aPath.clear();
742 NODE* node = aNode;
743
744 while( node->IsInternal() )
745 {
746 aPath.push_back( node );
747
748 if( node->level == 1 )
749 {
750 // At the level just above leaves: minimize overlap increase
751 int bestIdx = 0;
752 int64_t bestOverlapInc = std::numeric_limits<int64_t>::max();
753 int64_t bestAreaInc = std::numeric_limits<int64_t>::max();
754 int64_t bestArea = std::numeric_limits<int64_t>::max();
755
756 for( int i = 0; i < node->count; ++i )
757 {
758 int64_t overlapBefore = computeOverlap( node, i );
759 int64_t overlapAfter = computeOverlapEnlarged( node, i, aMin, aMax );
760 int64_t overlapInc = overlapAfter - overlapBefore;
761 int64_t areaInc = node->ChildEnlargement( i, aMin, aMax );
762 int64_t area = node->ChildArea( i );
763
764 if( overlapInc < bestOverlapInc
765 || ( overlapInc == bestOverlapInc && areaInc < bestAreaInc )
766 || ( overlapInc == bestOverlapInc && areaInc == bestAreaInc
767 && area < bestArea ) )
768 {
769 bestIdx = i;
770 bestOverlapInc = overlapInc;
771 bestAreaInc = areaInc;
772 bestArea = area;
773 }
774 }
775
776 node = node->children[bestIdx];
777 }
778 else
779 {
780 // Higher levels: minimize area increase, tie-break by smallest area
781 int bestIdx = 0;
782 int64_t bestAreaInc = std::numeric_limits<int64_t>::max();
783 int64_t bestArea = std::numeric_limits<int64_t>::max();
784
785 for( int i = 0; i < node->count; ++i )
786 {
787 int64_t areaInc = node->ChildEnlargement( i, aMin, aMax );
788 int64_t area = node->ChildArea( i );
789
790 if( areaInc < bestAreaInc
791 || ( areaInc == bestAreaInc && area < bestArea ) )
792 {
793 bestIdx = i;
794 bestAreaInc = areaInc;
795 bestArea = area;
796 }
797 }
798
799 node = node->children[bestIdx];
800 }
801 }
802
803 return node;
804 }
805
809 void overflowTreatment( NODE* aNode, const ELEMTYPE aMin[NUMDIMS],
810 const ELEMTYPE aMax[NUMDIMS], const DATATYPE& aData,
811 std::vector<NODE*>& aPath, uint32_t& aReinsertedLevels )
812 {
813 int level = aNode->level;
814
815 // Guard against UB from shifting by >= 32. At fanout 16 this would
816 // require > 16^32 items, but protect the generic template regardless.
817 if( level >= 32 )
818 {
819 splitNode( aNode, aMin, aMax, aData, aPath, aReinsertedLevels );
820 return;
821 }
822
823 const uint32_t levelMask = 1U << level;
824
825 if( !( aReinsertedLevels & levelMask ) )
826 {
827 aReinsertedLevels |= levelMask;
828 forcedReinsert( aNode, aMin, aMax, aData, aPath, aReinsertedLevels );
829 }
830 else
831 {
832 splitNode( aNode, aMin, aMax, aData, aPath, aReinsertedLevels );
833 }
834 }
835
842 void forcedReinsert( NODE* aNode, const ELEMTYPE aMin[NUMDIMS],
843 const ELEMTYPE aMax[NUMDIMS], const DATATYPE& aData,
844 std::vector<NODE*>& aPath, uint32_t& aReinsertedLevels )
845 {
846 // Collect all entries including the new one
847 struct ENTRY
848 {
849 ELEMTYPE min[NUMDIMS];
850 ELEMTYPE max[NUMDIMS];
851 ELEMTYPE insertMin[NUMDIMS];
852 ELEMTYPE insertMax[NUMDIMS];
853 DATATYPE data;
854 NODE* child; // Only for internal nodes
855 int64_t distSq;
856 };
857
858 int totalEntries = aNode->count + 1;
859 std::vector<ENTRY> entries( totalEntries );
860
861 // Compute node center
862 ELEMTYPE nodeMin[NUMDIMS];
863 ELEMTYPE nodeMax[NUMDIMS];
864 aNode->ComputeEnclosingBounds( nodeMin, nodeMax );
865
866 double center[NUMDIMS];
867
868 for( int d = 0; d < NUMDIMS; ++d )
869 center[d] = ( static_cast<double>( nodeMin[d] ) + nodeMax[d] ) / 2.0;
870
871 // Gather existing entries
872 for( int i = 0; i < aNode->count; ++i )
873 {
874 aNode->GetChildBounds( i, entries[i].min, entries[i].max );
875
876 if( aNode->IsLeaf() )
877 {
878 aNode->GetInsertBounds( i, entries[i].insertMin, entries[i].insertMax );
879 entries[i].data = aNode->data[i];
880 entries[i].child = nullptr;
881 }
882 else
883 {
884 entries[i].child = aNode->children[i];
885 }
886
887 // Distance from entry center to node center
888 int64_t distSq = 0;
889
890 for( int d = 0; d < NUMDIMS; ++d )
891 {
892 double entryCenter = ( static_cast<double>( entries[i].min[d] )
893 + entries[i].max[d] ) / 2.0;
894 double diff = entryCenter - center[d];
895 distSq += static_cast<int64_t>( diff * diff );
896 }
897
898 entries[i].distSq = distSq;
899 }
900
901 // Add the new entry
902 ENTRY& newEntry = entries[aNode->count];
903
904 for( int d = 0; d < NUMDIMS; ++d )
905 {
906 newEntry.min[d] = aMin[d];
907 newEntry.max[d] = aMax[d];
908 newEntry.insertMin[d] = aMin[d];
909 newEntry.insertMax[d] = aMax[d];
910 }
911
912 newEntry.data = aData;
913 newEntry.child = nullptr;
914
915 int64_t distSq = 0;
916
917 for( int d = 0; d < NUMDIMS; ++d )
918 {
919 double entryCenter = ( static_cast<double>( aMin[d] ) + aMax[d] ) / 2.0;
920 double diff = entryCenter - center[d];
921 distSq += static_cast<int64_t>( diff * diff );
922 }
923
924 newEntry.distSq = distSq;
925
926 // Sort by distance descending to find the farthest
927 std::sort( entries.begin(), entries.end(),
928 []( const ENTRY& a, const ENTRY& b )
929 {
930 return a.distSq > b.distSq;
931 } );
932
933 // Keep close entries in the node, reinsert far ones
934 int reinsertCount = std::min( REINSERT_COUNT, totalEntries - MINNODES );
935
936 if( reinsertCount <= 0 )
937 {
938 // Can't reinsert without underflow, fall back to split
939 splitNode( aNode, aMin, aMax, aData, aPath, aReinsertedLevels );
940 return;
941 }
942
943 // Rebuild the node with the close entries
944 aNode->count = 0;
945
946 for( int i = reinsertCount; i < totalEntries; ++i )
947 {
948 int slot = aNode->count;
949 aNode->SetChildBounds( slot, entries[i].min, entries[i].max );
950
951 if( aNode->IsLeaf() )
952 {
953 aNode->SetInsertBounds( slot, entries[i].insertMin, entries[i].insertMax );
954 aNode->data[slot] = entries[i].data;
955 }
956 else
957 {
958 aNode->children[slot] = entries[i].child;
959 }
960
961 aNode->count++;
962 }
963
964 adjustPath( aPath, aNode );
965
966 // Reinsert the far entries
967 for( int i = 0; i < reinsertCount; ++i )
968 {
969 if( aNode->IsLeaf() )
970 {
971 insertImpl( entries[i].insertMin, entries[i].insertMax,
972 entries[i].data, aReinsertedLevels );
973 }
974 else
975 {
976 reinsertNode( entries[i].child, entries[i].min, entries[i].max,
977 aNode->level - 1, aReinsertedLevels );
978 }
979 }
980 }
981
985 void reinsertNode( NODE* aChild, const ELEMTYPE aMin[NUMDIMS],
986 const ELEMTYPE aMax[NUMDIMS], int aLevel,
987 uint32_t& aReinsertedLevels )
988 {
989 // Find a node at the correct level
990 std::vector<NODE*> path;
991 NODE* target = chooseSubtreeAtLevel( m_root, aMin, aMax, aLevel + 1, path );
992
993 if( !target->IsFull() )
994 {
995 int slot = target->count;
996 target->SetChildBounds( slot, aMin, aMax );
997 target->children[slot] = aChild;
998 target->count++;
999 adjustPath( path, target );
1000 }
1001 else
1002 {
1003 splitNodeInternal( target, aMin, aMax, aChild, path, aReinsertedLevels );
1004 }
1005 }
1006
1010 NODE* chooseSubtreeAtLevel( NODE* aNode, const ELEMTYPE aMin[NUMDIMS],
1011 const ELEMTYPE aMax[NUMDIMS], int aTargetLevel,
1012 std::vector<NODE*>& aPath )
1013 {
1014 aPath.clear();
1015 NODE* node = aNode;
1016
1017 while( node->level > aTargetLevel )
1018 {
1019 aPath.push_back( node );
1020
1021 int bestIdx = 0;
1022 int64_t bestAreaInc = std::numeric_limits<int64_t>::max();
1023 int64_t bestArea = std::numeric_limits<int64_t>::max();
1024
1025 for( int i = 0; i < node->count; ++i )
1026 {
1027 int64_t areaInc = node->ChildEnlargement( i, aMin, aMax );
1028 int64_t area = node->ChildArea( i );
1029
1030 if( areaInc < bestAreaInc
1031 || ( areaInc == bestAreaInc && area < bestArea ) )
1032 {
1033 bestIdx = i;
1034 bestAreaInc = areaInc;
1035 bestArea = area;
1036 }
1037 }
1038
1039 node = node->children[bestIdx];
1040 }
1041
1042 return node;
1043 }
1044
1053 void splitNode( NODE* aNode, const ELEMTYPE aMin[NUMDIMS],
1054 const ELEMTYPE aMax[NUMDIMS], const DATATYPE& aData,
1055 std::vector<NODE*>& aPath, uint32_t& aReinsertedLevels )
1056 {
1057 // Collect all entries including the overflow entry
1058 int totalEntries = aNode->count + 1;
1059 std::vector<SPLIT_ENTRY> entries( totalEntries );
1060
1061 for( int i = 0; i < aNode->count; ++i )
1062 {
1063 aNode->GetChildBounds( i, entries[i].min, entries[i].max );
1064
1065 if( aNode->IsLeaf() )
1066 {
1067 aNode->GetInsertBounds( i, entries[i].insertMin, entries[i].insertMax );
1068 entries[i].data = aNode->data[i];
1069 entries[i].child = nullptr;
1070 }
1071 else
1072 {
1073 entries[i].child = aNode->children[i];
1074 }
1075 }
1076
1077 // The overflow entry
1078 for( int d = 0; d < NUMDIMS; ++d )
1079 {
1080 entries[aNode->count].min[d] = aMin[d];
1081 entries[aNode->count].max[d] = aMax[d];
1082 entries[aNode->count].insertMin[d] = aMin[d];
1083 entries[aNode->count].insertMax[d] = aMax[d];
1084 }
1085
1086 entries[aNode->count].data = aData;
1087 entries[aNode->count].child = nullptr;
1088
1089 // ChooseSplitAxis: minimize sum of perimeters
1090 int bestAxis = 0;
1091 int64_t bestPerimeterSum = std::numeric_limits<int64_t>::max();
1092
1093 for( int axis = 0; axis < NUMDIMS; ++axis )
1094 {
1095 int64_t perimeterSum = 0;
1096
1097 // Sort by min bound on this axis
1098 std::sort( entries.begin(), entries.end(),
1099 [axis]( const SPLIT_ENTRY& a, const SPLIT_ENTRY& b )
1100 {
1101 return a.min[axis] < b.min[axis]
1102 || ( a.min[axis] == b.min[axis]
1103 && a.max[axis] < b.max[axis] );
1104 } );
1105
1106 perimeterSum += computeSplitPerimeters( entries, totalEntries );
1107
1108 // Sort by max bound on this axis
1109 std::sort( entries.begin(), entries.end(),
1110 [axis]( const SPLIT_ENTRY& a, const SPLIT_ENTRY& b )
1111 {
1112 return a.max[axis] < b.max[axis]
1113 || ( a.max[axis] == b.max[axis]
1114 && a.min[axis] < b.min[axis] );
1115 } );
1116
1117 perimeterSum += computeSplitPerimeters( entries, totalEntries );
1118
1119 if( perimeterSum < bestPerimeterSum )
1120 {
1121 bestPerimeterSum = perimeterSum;
1122 bestAxis = axis;
1123 }
1124 }
1125
1126 // ChooseSplitIndex along bestAxis: minimize overlap
1127 // Re-sort by min on best axis
1128 std::sort( entries.begin(), entries.end(),
1129 [bestAxis]( const SPLIT_ENTRY& a, const SPLIT_ENTRY& b )
1130 {
1131 return a.min[bestAxis] < b.min[bestAxis]
1132 || ( a.min[bestAxis] == b.min[bestAxis]
1133 && a.max[bestAxis] < b.max[bestAxis] );
1134 } );
1135
1136 int bestSplit = findBestSplitIndex( entries, totalEntries );
1137
1138 // Also try sorting by max
1139 std::vector<SPLIT_ENTRY> entriesByMax = entries;
1140
1141 std::sort( entriesByMax.begin(), entriesByMax.end(),
1142 [bestAxis]( const SPLIT_ENTRY& a, const SPLIT_ENTRY& b )
1143 {
1144 return a.max[bestAxis] < b.max[bestAxis]
1145 || ( a.max[bestAxis] == b.max[bestAxis]
1146 && a.min[bestAxis] < b.min[bestAxis] );
1147 } );
1148
1149 int bestSplitMax = findBestSplitIndex( entriesByMax, totalEntries );
1150 int64_t overlapMin = computeSplitOverlap( entries, bestSplit, totalEntries );
1151 int64_t overlapMax = computeSplitOverlap( entriesByMax, bestSplitMax, totalEntries );
1152
1153 if( overlapMax < overlapMin )
1154 {
1155 entries = std::move( entriesByMax );
1156 bestSplit = bestSplitMax;
1157 }
1158
1159 // Create new sibling node
1160 NODE* sibling = allocNode();
1161 sibling->level = aNode->level;
1162
1163 // Distribute entries
1164 aNode->count = 0;
1165
1166 for( int i = 0; i < bestSplit; ++i )
1167 {
1168 int slot = aNode->count;
1169 aNode->SetChildBounds( slot, entries[i].min, entries[i].max );
1170
1171 if( aNode->IsLeaf() )
1172 {
1173 aNode->SetInsertBounds( slot, entries[i].insertMin, entries[i].insertMax );
1174 aNode->data[slot] = entries[i].data;
1175 }
1176 else
1177 {
1178 aNode->children[slot] = entries[i].child;
1179 }
1180
1181 aNode->count++;
1182 }
1183
1184 for( int i = bestSplit; i < totalEntries; ++i )
1185 {
1186 int slot = sibling->count;
1187 sibling->SetChildBounds( slot, entries[i].min, entries[i].max );
1188
1189 if( aNode->IsLeaf() )
1190 {
1191 sibling->SetInsertBounds( slot, entries[i].insertMin,
1192 entries[i].insertMax );
1193 sibling->data[slot] = entries[i].data;
1194 }
1195 else
1196 {
1197 sibling->children[slot] = entries[i].child;
1198 }
1199
1200 sibling->count++;
1201 }
1202
1203 // Propagate the split upward
1204 ELEMTYPE sibMin[NUMDIMS], sibMax[NUMDIMS];
1205 sibling->ComputeEnclosingBounds( sibMin, sibMax );
1206
1207 if( aPath.empty() )
1208 {
1209 // Splitting the root: create new root
1210 NODE* newRoot = allocNode();
1211 newRoot->level = m_root->level + 1;
1212
1213 ELEMTYPE nodeMin[NUMDIMS], nodeMax[NUMDIMS];
1214 aNode->ComputeEnclosingBounds( nodeMin, nodeMax );
1215
1216 newRoot->SetChildBounds( 0, nodeMin, nodeMax );
1217 newRoot->children[0] = aNode;
1218 newRoot->SetChildBounds( 1, sibMin, sibMax );
1219 newRoot->children[1] = sibling;
1220 newRoot->count = 2;
1221 m_root = newRoot;
1222 }
1223 else
1224 {
1225 NODE* parent = aPath.back();
1226
1227 // Update the existing child's bbox in parent
1228 int childSlot = findChildSlot( parent, aNode );
1229
1230 if( childSlot >= 0 )
1231 {
1232 ELEMTYPE nodeMin[NUMDIMS], nodeMax[NUMDIMS];
1233 aNode->ComputeEnclosingBounds( nodeMin, nodeMax );
1234 parent->SetChildBounds( childSlot, nodeMin, nodeMax );
1235 }
1236
1237 // Insert sibling into parent
1238 if( !parent->IsFull() )
1239 {
1240 int slot = parent->count;
1241 parent->SetChildBounds( slot, sibMin, sibMax );
1242 parent->children[slot] = sibling;
1243 parent->count++;
1244
1245 aPath.pop_back();
1246 adjustPath( aPath, parent );
1247 }
1248 else
1249 {
1250 aPath.pop_back();
1251 splitNodeInternal( parent, sibMin, sibMax, sibling, aPath, aReinsertedLevels );
1252 }
1253 }
1254 }
1255
1259 void splitNodeInternal( NODE* aNode, const ELEMTYPE aMin[NUMDIMS],
1260 const ELEMTYPE aMax[NUMDIMS], NODE* aChild,
1261 std::vector<NODE*>& aPath,
1262 uint32_t& aReinsertedLevels )
1263 {
1264 int totalEntries = aNode->count + 1;
1265 std::vector<SPLIT_ENTRY> entries( totalEntries );
1266
1267 for( int i = 0; i < aNode->count; ++i )
1268 {
1269 aNode->GetChildBounds( i, entries[i].min, entries[i].max );
1270 entries[i].child = aNode->children[i];
1271 }
1272
1273 for( int d = 0; d < NUMDIMS; ++d )
1274 {
1275 entries[aNode->count].min[d] = aMin[d];
1276 entries[aNode->count].max[d] = aMax[d];
1277 }
1278
1279 entries[aNode->count].child = aChild;
1280
1281 // Choose best axis
1282 int bestAxis = 0;
1283 int64_t bestPerimeterSum = std::numeric_limits<int64_t>::max();
1284
1285 for( int axis = 0; axis < NUMDIMS; ++axis )
1286 {
1287 std::sort( entries.begin(), entries.end(),
1288 [axis]( const SPLIT_ENTRY& a, const SPLIT_ENTRY& b )
1289 {
1290 return a.min[axis] < b.min[axis];
1291 } );
1292
1293 int64_t perimSum = computeSplitPerimeters( entries, totalEntries );
1294
1295 if( perimSum < bestPerimeterSum )
1296 {
1297 bestPerimeterSum = perimSum;
1298 bestAxis = axis;
1299 }
1300 }
1301
1302 // Re-sort on best axis, find best split
1303 std::sort( entries.begin(), entries.end(),
1304 [bestAxis]( const SPLIT_ENTRY& a, const SPLIT_ENTRY& b )
1305 {
1306 return a.min[bestAxis] < b.min[bestAxis];
1307 } );
1308
1309 int bestSplit = findBestSplitIndex( entries, totalEntries );
1310
1311 // Create sibling
1312 NODE* sibling = allocNode();
1313 sibling->level = aNode->level;
1314
1315 aNode->count = 0;
1316
1317 for( int i = 0; i < bestSplit; ++i )
1318 {
1319 int slot = aNode->count;
1320 aNode->SetChildBounds( slot, entries[i].min, entries[i].max );
1321 aNode->children[slot] = entries[i].child;
1322 aNode->count++;
1323 }
1324
1325 for( int i = bestSplit; i < totalEntries; ++i )
1326 {
1327 int slot = sibling->count;
1328 sibling->SetChildBounds( slot, entries[i].min, entries[i].max );
1329 sibling->children[slot] = entries[i].child;
1330 sibling->count++;
1331 }
1332
1333 ELEMTYPE sibMin[NUMDIMS], sibMax[NUMDIMS];
1334 sibling->ComputeEnclosingBounds( sibMin, sibMax );
1335
1336 if( aPath.empty() )
1337 {
1338 NODE* newRoot = allocNode();
1339 newRoot->level = m_root->level + 1;
1340
1341 ELEMTYPE nodeMin[NUMDIMS], nodeMax[NUMDIMS];
1342 aNode->ComputeEnclosingBounds( nodeMin, nodeMax );
1343
1344 newRoot->SetChildBounds( 0, nodeMin, nodeMax );
1345 newRoot->children[0] = aNode;
1346 newRoot->SetChildBounds( 1, sibMin, sibMax );
1347 newRoot->children[1] = sibling;
1348 newRoot->count = 2;
1349 m_root = newRoot;
1350 }
1351 else
1352 {
1353 NODE* parent = aPath.back();
1354 int childSlot = findChildSlot( parent, aNode );
1355
1356 if( childSlot >= 0 )
1357 {
1358 ELEMTYPE nodeMin[NUMDIMS], nodeMax[NUMDIMS];
1359 aNode->ComputeEnclosingBounds( nodeMin, nodeMax );
1360 parent->SetChildBounds( childSlot, nodeMin, nodeMax );
1361 }
1362
1363 if( !parent->IsFull() )
1364 {
1365 int slot = parent->count;
1366 parent->SetChildBounds( slot, sibMin, sibMax );
1367 parent->children[slot] = sibling;
1368 parent->count++;
1369 aPath.pop_back();
1370 adjustPath( aPath, parent );
1371 }
1372 else
1373 {
1374 aPath.pop_back();
1375 splitNodeInternal( parent, sibMin, sibMax, sibling, aPath,
1376 aReinsertedLevels );
1377 }
1378 }
1379 }
1380
1384 template <class ENTRY_VEC>
1385 int64_t computeSplitPerimeters( const ENTRY_VEC& aEntries, int aTotalEntries ) const
1386 {
1387 int64_t sum = 0;
1388
1389 for( int k = MINNODES; k <= aTotalEntries - MINNODES; ++k )
1390 {
1391 // Group 1: entries [0, k)
1392 // Group 2: entries [k, totalEntries)
1393 for( int grp = 0; grp < 2; ++grp )
1394 {
1395 int start = ( grp == 0 ) ? 0 : k;
1396 int end = ( grp == 0 ) ? k : aTotalEntries;
1397
1398 int64_t perimeter = 0;
1399
1400 for( int d = 0; d < NUMDIMS; ++d )
1401 {
1402 ELEMTYPE mn = std::numeric_limits<ELEMTYPE>::max();
1403 ELEMTYPE mx = std::numeric_limits<ELEMTYPE>::lowest();
1404
1405 for( int i = start; i < end; ++i )
1406 {
1407 if( aEntries[i].min[d] < mn )
1408 mn = aEntries[i].min[d];
1409
1410 if( aEntries[i].max[d] > mx )
1411 mx = aEntries[i].max[d];
1412 }
1413
1414 perimeter += static_cast<int64_t>( mx ) - mn;
1415 }
1416
1417 sum += 2 * perimeter;
1418 }
1419 }
1420
1421 return sum;
1422 }
1423
1427 template <class ENTRY_VEC>
1428 int findBestSplitIndex( const ENTRY_VEC& aEntries, int aTotalEntries ) const
1429 {
1430 int bestSplit = MINNODES;
1431 int64_t bestOverlap = std::numeric_limits<int64_t>::max();
1432 int64_t bestAreaSum = std::numeric_limits<int64_t>::max();
1433
1434 for( int k = MINNODES; k <= aTotalEntries - MINNODES; ++k )
1435 {
1436 int64_t overlap = computeSplitOverlap( aEntries, k, aTotalEntries );
1437
1438 // Compute area sum for tie-breaking
1439 int64_t areaSum = 0;
1440
1441 for( int grp = 0; grp < 2; ++grp )
1442 {
1443 int start = ( grp == 0 ) ? 0 : k;
1444 int end = ( grp == 0 ) ? k : aTotalEntries;
1445 int64_t area = 1;
1446
1447 for( int d = 0; d < NUMDIMS; ++d )
1448 {
1449 ELEMTYPE mn = std::numeric_limits<ELEMTYPE>::max();
1450 ELEMTYPE mx = std::numeric_limits<ELEMTYPE>::lowest();
1451
1452 for( int i = start; i < end; ++i )
1453 {
1454 if( aEntries[i].min[d] < mn )
1455 mn = aEntries[i].min[d];
1456
1457 if( aEntries[i].max[d] > mx )
1458 mx = aEntries[i].max[d];
1459 }
1460
1461 area *= static_cast<int64_t>( mx ) - mn;
1462 }
1463
1464 areaSum += area;
1465 }
1466
1467 if( overlap < bestOverlap
1468 || ( overlap == bestOverlap && areaSum < bestAreaSum ) )
1469 {
1470 bestSplit = k;
1471 bestOverlap = overlap;
1472 bestAreaSum = areaSum;
1473 }
1474 }
1475
1476 return bestSplit;
1477 }
1478
1482 template <class ENTRY_VEC>
1483 int64_t computeSplitOverlap( const ENTRY_VEC& aEntries, int aSplitIdx,
1484 int aTotalEntries ) const
1485 {
1486 ELEMTYPE g1Min[NUMDIMS], g1Max[NUMDIMS];
1487 ELEMTYPE g2Min[NUMDIMS], g2Max[NUMDIMS];
1488
1489 for( int d = 0; d < NUMDIMS; ++d )
1490 {
1491 g1Min[d] = g2Min[d] = std::numeric_limits<ELEMTYPE>::max();
1492 g1Max[d] = g2Max[d] = std::numeric_limits<ELEMTYPE>::lowest();
1493 }
1494
1495 for( int i = 0; i < aSplitIdx; ++i )
1496 {
1497 for( int d = 0; d < NUMDIMS; ++d )
1498 {
1499 if( aEntries[i].min[d] < g1Min[d] )
1500 g1Min[d] = aEntries[i].min[d];
1501
1502 if( aEntries[i].max[d] > g1Max[d] )
1503 g1Max[d] = aEntries[i].max[d];
1504 }
1505 }
1506
1507 for( int i = aSplitIdx; i < aTotalEntries; ++i )
1508 {
1509 for( int d = 0; d < NUMDIMS; ++d )
1510 {
1511 if( aEntries[i].min[d] < g2Min[d] )
1512 g2Min[d] = aEntries[i].min[d];
1513
1514 if( aEntries[i].max[d] > g2Max[d] )
1515 g2Max[d] = aEntries[i].max[d];
1516 }
1517 }
1518
1519 // Compute overlap volume
1520 int64_t overlap = 1;
1521
1522 for( int d = 0; d < NUMDIMS; ++d )
1523 {
1524 ELEMTYPE lo = std::max( g1Min[d], g2Min[d] );
1525 ELEMTYPE hi = std::min( g1Max[d], g2Max[d] );
1526
1527 if( lo >= hi )
1528 return 0;
1529
1530 overlap *= static_cast<int64_t>( hi ) - lo;
1531 }
1532
1533 return overlap;
1534 }
1535
1539 int64_t computeOverlap( NODE* aNode, int aIdx ) const
1540 {
1541 int64_t total = 0;
1542 ELEMTYPE iMin[NUMDIMS], iMax[NUMDIMS];
1543 aNode->GetChildBounds( aIdx, iMin, iMax );
1544
1545 for( int j = 0; j < aNode->count; ++j )
1546 {
1547 if( j == aIdx )
1548 continue;
1549
1550 total += aNode->ChildOverlapArea( j, iMin, iMax );
1551 }
1552
1553 return total;
1554 }
1555
1559 int64_t computeOverlapEnlarged( NODE* aNode, int aIdx, const ELEMTYPE aMin[NUMDIMS],
1560 const ELEMTYPE aMax[NUMDIMS] ) const
1561 {
1562 ELEMTYPE enlargedMin[NUMDIMS], enlargedMax[NUMDIMS];
1563 aNode->GetChildBounds( aIdx, enlargedMin, enlargedMax );
1564
1565 for( int d = 0; d < NUMDIMS; ++d )
1566 {
1567 if( aMin[d] < enlargedMin[d] )
1568 enlargedMin[d] = aMin[d];
1569
1570 if( aMax[d] > enlargedMax[d] )
1571 enlargedMax[d] = aMax[d];
1572 }
1573
1574 int64_t total = 0;
1575
1576 for( int j = 0; j < aNode->count; ++j )
1577 {
1578 if( j == aIdx )
1579 continue;
1580
1581 total += aNode->ChildOverlapArea( j, enlargedMin, enlargedMax );
1582 }
1583
1584 return total;
1585 }
1586
1594 void adjustPath( const std::vector<NODE*>& aPath, NODE* aBottomChild = nullptr )
1595 {
1596 NODE* childToUpdate = aBottomChild;
1597
1598 for( int i = static_cast<int>( aPath.size() ) - 1; i >= 0; --i )
1599 {
1600 NODE* parent = aPath[i];
1601
1602 if( childToUpdate )
1603 {
1604 int slot = findChildSlot( parent, childToUpdate );
1605
1606 if( slot >= 0 )
1607 {
1608 ELEMTYPE childMin[NUMDIMS], childMax[NUMDIMS];
1609 childToUpdate->ComputeEnclosingBounds( childMin, childMax );
1610 parent->SetChildBounds( slot, childMin, childMax );
1611 }
1612 }
1613
1614 childToUpdate = parent;
1615 }
1616 }
1617
1618 int findChildSlot( NODE* aParent, NODE* aChild ) const
1619 {
1620 for( int i = 0; i < aParent->count; ++i )
1621 {
1622 if( aParent->children[i] == aChild )
1623 return i;
1624 }
1625
1626 return -1;
1627 }
1628
1632 bool removeImpl( NODE* aNode, const ELEMTYPE aMin[NUMDIMS],
1633 const ELEMTYPE aMax[NUMDIMS], const DATATYPE& aData,
1634 std::vector<NODE*>& aReinsertList )
1635 {
1636 if( aNode->IsLeaf() )
1637 {
1638 for( int i = 0; i < aNode->count; ++i )
1639 {
1640 if( aNode->data[i] == aData
1641 && aNode->ChildOverlaps( i, aMin, aMax ) )
1642 {
1643 aNode->RemoveChild( i );
1644 return true;
1645 }
1646 }
1647
1648 return false;
1649 }
1650
1651 // Internal node: recurse into children whose bbox overlaps the query
1652 for( int i = 0; i < aNode->count; ++i )
1653 {
1654 if( !aNode->ChildOverlaps( i, aMin, aMax ) )
1655 continue;
1656
1657 NODE* child = aNode->children[i];
1658
1659 if( removeImpl( child, aMin, aMax, aData, aReinsertList ) )
1660 {
1661 // Update child's bbox in parent
1662 if( child->count > 0 )
1663 {
1664 ELEMTYPE childMin[NUMDIMS], childMax[NUMDIMS];
1665 child->ComputeEnclosingBounds( childMin, childMax );
1666 aNode->SetChildBounds( i, childMin, childMax );
1667
1668 // Check for underflow
1669 if( child->count < MINNODES && aNode != m_root )
1670 {
1671 aReinsertList.push_back( child );
1672 aNode->RemoveChild( i );
1673 }
1674 }
1675 else
1676 {
1677 freeNode( child );
1678 aNode->RemoveChild( i );
1679 }
1680
1681 return true;
1682 }
1683 }
1684
1685 return false;
1686 }
1687
1691 void reinsertOrphans( std::vector<NODE*>& aReinsertList )
1692 {
1693 for( NODE* orphan : aReinsertList )
1694 {
1695 if( orphan->IsLeaf() )
1696 {
1697 for( int i = 0; i < orphan->count; ++i )
1698 {
1699 ELEMTYPE mn[NUMDIMS], mx[NUMDIMS];
1700 orphan->GetInsertBounds( i, mn, mx );
1701
1702 uint32_t reinsertedLevels = 0;
1703 insertImpl( mn, mx, orphan->data[i], reinsertedLevels );
1704 }
1705 }
1706 else
1707 {
1708 for( int i = 0; i < orphan->count; ++i )
1709 {
1710 ELEMTYPE mn[NUMDIMS], mx[NUMDIMS];
1711 orphan->GetChildBounds( i, mn, mx );
1712
1713 uint32_t reinsertedLevels = 0;
1714 reinsertNode( orphan->children[i], mn, mx, orphan->level - 1,
1715 reinsertedLevels );
1716 }
1717 }
1718
1719 freeNode( orphan );
1720 }
1721 }
1722
1727 {
1728 while( m_root && m_root->IsInternal() && m_root->count == 1 )
1729 {
1730 NODE* oldRoot = m_root;
1731 m_root = m_root->children[0];
1732 freeNode( oldRoot );
1733 }
1734
1735 if( m_root && m_root->count == 0 )
1736 {
1737 freeNode( m_root );
1738 m_root = nullptr;
1739 }
1740 }
1741
1745 template <class VISITOR>
1746 bool searchImpl( NODE* aNode, const ELEMTYPE aMin[NUMDIMS],
1747 const ELEMTYPE aMax[NUMDIMS], VISITOR& aVisitor, int& aFound ) const
1748 {
1749 uint32_t mask = aNode->ChildOverlapMask( aMin, aMax );
1750
1751 if( aNode->IsLeaf() )
1752 {
1753 while( mask )
1754 {
1755 int i = std::countr_zero( mask );
1756 mask &= mask - 1;
1757 aFound++;
1758
1759 if( !aVisitor( aNode->data[i] ) )
1760 return false;
1761 }
1762 }
1763 else
1764 {
1765 while( mask )
1766 {
1767 int i = std::countr_zero( mask );
1768 mask &= mask - 1;
1769
1770 if( !searchImpl( aNode->children[i], aMin, aMax, aVisitor, aFound ) )
1771 return false;
1772 }
1773 }
1774
1775 return true;
1776 }
1777
1781 int64_t minDistSq( NODE* aNode, int aSlot, const ELEMTYPE aPoint[NUMDIMS] ) const
1782 {
1783 int64_t dist = 0;
1784
1785 for( int d = 0; d < NUMDIMS; ++d )
1786 {
1787 ELEMTYPE lo = aNode->bounds[d * 2][aSlot];
1788 ELEMTYPE hi = aNode->bounds[d * 2 + 1][aSlot];
1789
1790 if( aPoint[d] < lo )
1791 {
1792 int64_t diff = static_cast<int64_t>( lo ) - aPoint[d];
1793 dist += diff * diff;
1794 }
1795 else if( aPoint[d] > hi )
1796 {
1797 int64_t diff = static_cast<int64_t>( aPoint[d] ) - hi;
1798 dist += diff * diff;
1799 }
1800 }
1801
1802 return dist;
1803 }
1804
1805 NODE* m_root = nullptr;
1806 size_t m_count = 0;
1808};
1809
1810} // namespace KIRTREE
1811
1812#endif // DYNAMIC_RTREE_H
const DATATYPE * operator->() const
std::forward_iterator_tag iterator_category
bool operator!=(const Iterator &aOther) const
bool operator==(const Iterator &aOther) const
std::vector< STACK_ENTRY > m_stack
const DATATYPE & operator*() const
Lazy iterator that traverses only nodes overlapping a query rectangle.
std::vector< STACK_ENTRY > m_stack
SearchIterator(NODE *aRoot, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS])
std::input_iterator_tag iterator_category
bool operator!=(const SearchIterator &aOther) const
bool operator==(const SearchIterator &aOther) const
SearchRange(NODE *aRoot, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS])
Iterator begin() const
int64_t computeSplitPerimeters(const ENTRY_VEC &aEntries, int aTotalEntries) const
Compute sum of perimeters for all valid split distributions.
void NearestNeighbors(const ELEMTYPE aPoint[NUMDIMS], int aK, std::vector< std::pair< int64_t, DATATYPE > > &aResults) const
Nearest-neighbor search using Hjaltason & Samet's algorithm.
void reinsertOrphans(std::vector< NODE * > &aReinsertList)
Reinsert all entries from orphaned underflowing nodes.
bool removeImpl(NODE *aNode, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], const DATATYPE &aData, std::vector< NODE * > &aReinsertList)
Remove an item from the tree, collecting underflowing nodes for reinsertion.
bool searchImpl(NODE *aNode, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], VISITOR &aVisitor, int &aFound) const
Recursive search.
int Search(const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], VISITOR &aVisitor) const
Search for items whose bounding boxes overlap the query rectangle.
NODE * chooseSubtree(NODE *aNode, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], std::vector< NODE * > &aPath)
R*-tree ChooseSubtree.
SLAB_ALLOCATOR< NODE > m_allocator
void adjustPath(const std::vector< NODE * > &aPath, NODE *aBottomChild=nullptr)
Adjust bounding boxes for all nodes in the path (root to leaf).
DYNAMIC_RTREE & operator=(DYNAMIC_RTREE &&aOther) noexcept
void removeAllNodes(NODE *aNode)
int64_t computeOverlap(NODE *aNode, int aIdx) const
Compute total overlap of child i with all other children in the node.
Iterator end() const
size_t MemoryUsage() const
Return approximate memory usage in bytes.
bool Remove(const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], const DATATYPE &aData)
Remove an item using its stored insertion bounding box.
void Insert(const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], const DATATYPE &aData)
Insert an item with the given bounding box.
int findBestSplitIndex(const ENTRY_VEC &aEntries, int aTotalEntries) const
Find the split index that minimizes overlap between the two groups.
int64_t computeSplitOverlap(const ENTRY_VEC &aEntries, int aSplitIdx, int aTotalEntries) const
Compute the overlap area between two split groups.
DYNAMIC_RTREE(const DYNAMIC_RTREE &)=delete
void splitNodeInternal(NODE *aNode, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], NODE *aChild, std::vector< NODE * > &aPath, uint32_t &aReinsertedLevels)
Split an internal node to insert a new child.
void reinsertNode(NODE *aChild, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], int aLevel, uint32_t &aReinsertedLevels)
Reinsert an internal node's child at its correct level.
int findChildSlot(NODE *aParent, NODE *aChild) const
DYNAMIC_RTREE & operator=(const DYNAMIC_RTREE &)=delete
void splitNode(NODE *aNode, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], const DATATYPE &aData, std::vector< NODE * > &aPath, uint32_t &aReinsertedLevels)
R*-tree split.
DYNAMIC_RTREE(DYNAMIC_RTREE &&aOther) noexcept
void overflowTreatment(NODE *aNode, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], const DATATYPE &aData, std::vector< NODE * > &aPath, uint32_t &aReinsertedLevels)
Handle overflow: forced reinsert or split.
RTREE_NODE< SCH_ITEM *, int, NUMDIMS, 16 > NODE
int64_t minDistSq(NODE *aNode, int aSlot, const ELEMTYPE aPoint[NUMDIMS]) const
Compute minimum squared distance from a point to a child's bounding box.
int64_t computeOverlapEnlarged(NODE *aNode, int aIdx, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS]) const
Compute total overlap of child i (enlarged to include query box) with other children.
void forcedReinsert(NODE *aNode, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], const DATATYPE &aData, std::vector< NODE * > &aPath, uint32_t &aReinsertedLevels)
R*-tree forced reinsert.
void insertImpl(const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], const DATATYPE &aData, uint32_t &aReinsertedLevels)
Core insertion with forced reinsert tracking.
void freeNode(NODE *aNode)
SearchRange Overlapping(const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS]) const
Return a lazy range of items overlapping the query rectangle.
void BulkLoad(std::vector< BULK_ENTRY > &aEntries)
Build the tree from a batch of entries using Hilbert-curve packed bulk loading.
NODE * chooseSubtreeAtLevel(NODE *aNode, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], int aTargetLevel, std::vector< NODE * > &aPath)
ChooseSubtree targeting a specific level.
void condenseRoot()
If the root has only one child, replace it with that child.
void RemoveAll()
Remove all items from the tree.
Pool allocator for R-tree nodes.
Definition rtree_node.h:555
uint64_t HilbertND2D(int aOrder, const uint32_t aCoords[NUMDIMS])
Compute Hilbert index for N-dimensional coordinates.
Definition rtree_node.h:98
Entry type for bulk loading.
ELEMTYPE max[NUMDIMS]
ELEMTYPE min[NUMDIMS]
DATATYPE data
int childIdx
NODE * node
NODE * child
ELEMTYPE insertMin[NUMDIMS]
ELEMTYPE min[NUMDIMS]
DATATYPE data
ELEMTYPE max[NUMDIMS]
ELEMTYPE insertMax[NUMDIMS]
int childIdx
NODE * node
R-tree node with Structure-of-Arrays bounding box layout.
Definition rtree_node.h:302
static constexpr int MINNODES
Definition rtree_node.h:303
int64_t ChildOverlapArea(int i, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS]) const
Compute the overlap area between child slot i and the given box.
Definition rtree_node.h:416
bool IsInternal() const
Definition rtree_node.h:332
ELEMTYPE bounds[NUMDIMS *2][MAXNODES]
Definition rtree_node.h:310
int64_t ChildEnlargement(int i, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS]) const
Compute how much child slot i's area would increase if it were enlarged to include the given bounding...
Definition rtree_node.h:439
int64_t ChildArea(int i) const
Compute the area (or volume for 3D) of child slot i's bounding box.
Definition rtree_node.h:363
void GetChildBounds(int i, ELEMTYPE aMin[NUMDIMS], ELEMTYPE aMax[NUMDIMS]) const
Get the bounding box for child slot i.
Definition rtree_node.h:484
bool IsFull() const
Definition rtree_node.h:333
RTREE_NODE * children[MAXNODES]
Definition rtree_node.h:314
uint32_t ChildOverlapMask(const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS]) const
Bitmask of children whose bounding boxes overlap the query rectangle.
Definition rtree_node.h:391
bool ChildOverlaps(int i, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS]) const
Test whether child slot i's bounding box overlaps with the given query box.
Definition rtree_node.h:376
bool IsLeaf() const
Definition rtree_node.h:331
void SetChildBounds(int i, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS])
Set the bounding box for child slot i.
Definition rtree_node.h:472
void SetInsertBounds(int i, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS])
Store the insertion bounding box for leaf entry i.
Definition rtree_node.h:496
void GetInsertBounds(int i, ELEMTYPE aMin[NUMDIMS], ELEMTYPE aMax[NUMDIMS]) const
Get the stored insertion bounding box for leaf entry i.
Definition rtree_node.h:508
void ComputeEnclosingBounds(ELEMTYPE aMin[NUMDIMS], ELEMTYPE aMax[NUMDIMS]) const
Compute the bounding box that encloses all children in this node.
Definition rtree_node.h:339
DATATYPE data[MAXNODES]
Definition rtree_node.h:315
void RemoveChild(int i)
Remove child at slot i by swapping with last entry.
Definition rtree_node.h:520
std::string path
KIBIS top(path, &reporter)
VECTOR2I center