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