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