KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dynamic_rtree_cow.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_COW_H
21#define DYNAMIC_RTREE_COW_H
22
23#include <atomic>
24#include <memory>
25#include <vector>
26
29
30namespace KIRTREE
31{
32
50template <class DATATYPE, class ELEMTYPE = int, int NUMDIMS = 2, int TMAXNODES = 16>
52{
53public:
56
57private:
58 // Persistent immutable linked list of parent allocators.
60 {
61 std::shared_ptr<ALLOC> allocator;
62 std::shared_ptr<ALLOC_CHAIN> next;
63 };
64
65public:
66
67 COW_RTREE() : m_root( nullptr ), m_count( 0 ),
68 m_allocator( std::make_shared<ALLOC>() )
69 {
70 }
71
73 {
75 }
76
77 // Move semantics
78 COW_RTREE( COW_RTREE&& aOther ) noexcept :
79 m_root( aOther.m_root ),
80 m_count( aOther.m_count ),
81 m_allocator( std::move( aOther.m_allocator ) ),
82 m_parentChain( std::move( aOther.m_parentChain ) )
83 {
84 aOther.m_root = nullptr;
85 aOther.m_count = 0;
86 }
87
88 COW_RTREE& operator=( COW_RTREE&& aOther ) noexcept
89 {
90 if( this != &aOther )
91 {
93 m_root = aOther.m_root;
94 m_count = aOther.m_count;
95 m_allocator = std::move( aOther.m_allocator );
96 m_parentChain = std::move( aOther.m_parentChain );
97 aOther.m_root = nullptr;
98 aOther.m_count = 0;
99 }
100
101 return *this;
102 }
103
104 // Non-copyable (use Clone() for intentional sharing)
105 COW_RTREE( const COW_RTREE& ) = delete;
106 COW_RTREE& operator=( const COW_RTREE& ) = delete;
107
115 {
116 COW_RTREE clone;
117 clone.m_root = m_root;
118 clone.m_count = m_count;
119
120 if( m_root )
121 m_root->refcount.fetch_add( 1, std::memory_order_relaxed );
122
123 // Clone gets its own allocator for any nodes it copies
124 clone.m_allocator = std::make_shared<ALLOC>();
125
126 // Prepend our allocator to the parent chain (O(1), shared with siblings)
127 clone.m_parentChain = std::make_shared<ALLOC_CHAIN>(
128 ALLOC_CHAIN{ m_allocator, m_parentChain } );
129
130 return clone;
131 }
132
136 void Insert( const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS],
137 const DATATYPE& aData )
138 {
139 if( !m_root )
140 {
141 m_root = m_allocator->Allocate();
142 m_root->level = 0;
143 }
144 else
145 {
147 }
148
149 // Use a simplified insertion for CoW (no forced reinsert to avoid complexity)
150 insertSimple( m_root, aMin, aMax, aData );
151 m_count++;
152 }
153
157 bool Remove( const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS],
158 const DATATYPE& aData )
159 {
160 if( !m_root )
161 return false;
162
164
165 if( removeImpl( m_root, aMin, aMax, aData ) )
166 {
167 m_count--;
168
169 // Condense root
170 while( m_root && m_root->IsInternal() && m_root->count == 1 )
171 {
172 NODE* oldRoot = m_root;
173 m_root = m_root->children[0];
174
175 if( m_root )
176 m_root->refcount.fetch_add( 1, std::memory_order_relaxed );
177
178 releaseNode( oldRoot );
179 }
180
181 if( m_root && m_root->count == 0 )
182 {
184 m_root = nullptr;
185 }
186
187 return true;
188 }
189
190 return false;
191 }
192
197 template <class VISITOR>
198 int Search( const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS],
199 VISITOR& aVisitor ) const
200 {
201 int found = 0;
202
203 if( m_root )
204 searchImpl( m_root, aMin, aMax, aVisitor, found );
205
206 return found;
207 }
208
210 {
212 m_root = nullptr;
213 m_count = 0;
214 }
215
221
222 void BulkLoad( std::vector<BULK_ENTRY>& aEntries )
223 {
224 RemoveAll();
225
226 if( aEntries.empty() )
227 return;
228
229 m_count = aEntries.size();
230
231 // Find global bounds for Hilbert normalization
232 ELEMTYPE globalMin[NUMDIMS], globalMax[NUMDIMS];
233
234 for( int d = 0; d < NUMDIMS; ++d )
235 {
236 globalMin[d] = aEntries[0].min[d];
237 globalMax[d] = aEntries[0].max[d];
238 }
239
240 for( const auto& e : aEntries )
241 {
242 for( int d = 0; d < NUMDIMS; ++d )
243 {
244 if( e.min[d] < globalMin[d] ) globalMin[d] = e.min[d];
245 if( e.max[d] > globalMax[d] ) globalMax[d] = e.max[d];
246 }
247 }
248
249 double scale[NUMDIMS];
250
251 for( int d = 0; d < NUMDIMS; ++d )
252 {
253 double range = static_cast<double>( globalMax[d] ) - globalMin[d];
254 scale[d] = ( range > 0 ) ? ( 65535.0 / range ) : 0.0;
255 }
256
257 // Compute Hilbert index for each entry and sort
258 struct SORTED_ENTRY
259 {
260 uint64_t hilbert;
261 size_t origIdx;
262 };
263
264 std::vector<SORTED_ENTRY> sorted( aEntries.size() );
265
266 for( size_t i = 0; i < aEntries.size(); ++i )
267 {
268 const auto& e = aEntries[i];
269 double cx = ( static_cast<double>( e.min[0] ) + e.max[0] ) * 0.5;
270 double cy = ( static_cast<double>( e.min[1] ) + e.max[1] ) * 0.5;
271 uint32_t hx = static_cast<uint32_t>( ( cx - globalMin[0] ) * scale[0] );
272 uint32_t hy = static_cast<uint32_t>( ( cy - globalMin[1] ) * scale[1] );
273 sorted[i] = { KIRTREE::HilbertXY2D( 16, hx, hy ), i };
274 }
275
276 std::sort( sorted.begin(), sorted.end(),
277 []( const SORTED_ENTRY& a, const SORTED_ENTRY& b )
278 {
279 return a.hilbert < b.hilbert;
280 } );
281
282 // Reorder entries in-place by Hilbert index
283 std::vector<BULK_ENTRY> reordered;
284 reordered.reserve( aEntries.size() );
285
286 for( const auto& s : sorted )
287 reordered.push_back( std::move( aEntries[s.origIdx] ) );
288
289 aEntries = std::move( reordered );
290
291 // Pack into leaf nodes
292 std::vector<NODE*> currentLevel;
293 size_t idx = 0;
294
295 while( idx < aEntries.size() )
296 {
297 NODE* leaf = m_allocator->Allocate();
298 leaf->level = 0;
299
300 int fill = std::min( static_cast<int>( TMAXNODES ),
301 static_cast<int>( aEntries.size() - idx ) );
302
303 for( int i = 0; i < fill; ++i, ++idx )
304 {
305 leaf->SetChildBounds( i, aEntries[idx].min, aEntries[idx].max );
306 leaf->SetInsertBounds( i, aEntries[idx].min, aEntries[idx].max );
307 leaf->data[i] = aEntries[idx].data;
308 }
309
310 leaf->count = fill;
311 currentLevel.push_back( leaf );
312 }
313
314 // Build internal levels bottom-up
315 int level = 1;
316
317 while( currentLevel.size() > 1 )
318 {
319 std::vector<NODE*> nextLevel;
320 size_t ci = 0;
321
322 while( ci < currentLevel.size() )
323 {
324 NODE* parent = m_allocator->Allocate();
325 parent->level = level;
326
327 int fill = std::min( static_cast<int>( TMAXNODES ),
328 static_cast<int>( currentLevel.size() - ci ) );
329
330 for( int i = 0; i < fill; ++i, ++ci )
331 {
332 NODE* child = currentLevel[ci];
333 ELEMTYPE cmin[NUMDIMS], cmax[NUMDIMS];
334 child->ComputeEnclosingBounds( cmin, cmax );
335 parent->SetChildBounds( i, cmin, cmax );
336 parent->children[i] = child;
337 }
338
339 parent->count = fill;
340 nextLevel.push_back( parent );
341 }
342
343 currentLevel = std::move( nextLevel );
344 level++;
345 }
346
347 m_root = currentLevel[0];
348 }
349
350 size_t size() const { return m_count; }
351 bool empty() const { return m_count == 0; }
352
358 {
359 public:
360 Iterator() : m_atEnd( true ) {}
361
362 explicit Iterator( NODE* aRoot )
363 {
364 if( aRoot && aRoot->count > 0 )
365 {
366 m_stack.push_back( { aRoot, 0 } );
367 advance();
368 }
369 else
370 {
371 m_atEnd = true;
372 }
373 }
374
375 const DATATYPE& operator*() const { return m_current; }
376
378 {
379 advance();
380 return *this;
381 }
382
383 bool operator==( const Iterator& aOther ) const
384 {
385 return m_atEnd == aOther.m_atEnd;
386 }
387
388 bool operator!=( const Iterator& aOther ) const
389 {
390 return !( *this == aOther );
391 }
392
393 private:
395 {
398 };
399
400 void advance()
401 {
402 while( !m_stack.empty() )
403 {
404 STACK_ENTRY& top = m_stack.back();
405
406 if( top.node->IsLeaf() )
407 {
408 if( top.childIdx < top.node->count )
409 {
410 m_current = top.node->data[top.childIdx];
411 top.childIdx++;
412 m_atEnd = false;
413 return;
414 }
415
416 m_stack.pop_back();
417 }
418 else
419 {
420 if( top.childIdx < top.node->count )
421 {
422 NODE* child = top.node->children[top.childIdx];
423 top.childIdx++;
424 m_stack.push_back( { child, 0 } );
425 }
426 else
427 {
428 m_stack.pop_back();
429 }
430 }
431 }
432
433 m_atEnd = true;
434 }
435
436 std::vector<STACK_ENTRY> m_stack;
437 DATATYPE m_current = {};
438 bool m_atEnd = true;
439 };
440
441 Iterator begin() const { return Iterator( m_root ); }
442 Iterator end() const { return Iterator(); }
443
444private:
449 void ensureWritable( NODE*& aNode )
450 {
451 if( !aNode )
452 return;
453
454 if( aNode->refcount.load( std::memory_order_relaxed ) > 1 )
455 {
456 NODE* copy = m_allocator->Allocate();
457 copy->count = aNode->count;
458 copy->level = aNode->level;
459 std::memcpy( copy->bounds, aNode->bounds, sizeof( aNode->bounds ) );
460 std::memcpy( copy->insertBounds, aNode->insertBounds,
461 sizeof( aNode->insertBounds ) );
462
463 if( aNode->IsLeaf() )
464 {
465 for( int i = 0; i < aNode->count; ++i )
466 copy->data[i] = aNode->data[i];
467 }
468 else
469 {
470 for( int i = 0; i < aNode->count; ++i )
471 {
472 copy->children[i] = aNode->children[i];
473
474 // Children are now shared between old and new node
475 if( copy->children[i] )
476 {
477 copy->children[i]->refcount.fetch_add( 1,
478 std::memory_order_relaxed );
479 }
480 }
481 }
482
483 copy->refcount.store( 1, std::memory_order_relaxed );
484
485 // Release our reference to the old node
486 releaseNode( aNode );
487 aNode = copy;
488 }
489 }
490
495 void releaseNode( NODE* aNode )
496 {
497 if( !aNode )
498 return;
499
500 if( aNode->refcount.fetch_sub( 1, std::memory_order_acq_rel ) == 1 )
501 {
502 if( aNode->IsInternal() )
503 {
504 for( int i = 0; i < aNode->count; ++i )
505 releaseNode( aNode->children[i] );
506 }
507
508 freeToOwningAllocator( aNode );
509 }
510 }
511
518 {
519 if( m_allocator->Owns( aNode ) )
520 {
521 m_allocator->Free( aNode );
522 return;
523 }
524
525 for( auto chain = m_parentChain; chain; chain = chain->next )
526 {
527 if( chain->allocator->Owns( aNode ) )
528 {
529 chain->allocator->Free( aNode );
530 return;
531 }
532 }
533
534 assert( false && "R-tree node not owned by any allocator in chain" );
535 }
536
540 void releaseTree( NODE* aNode )
541 {
542 releaseNode( aNode );
543 }
544
549 void insertSimple( NODE* aNode, const ELEMTYPE aMin[NUMDIMS],
550 const ELEMTYPE aMax[NUMDIMS], const DATATYPE& aData )
551 {
552 if( aNode->IsLeaf() )
553 {
554 if( !aNode->IsFull() )
555 {
556 int slot = aNode->count;
557 aNode->SetChildBounds( slot, aMin, aMax );
558 aNode->SetInsertBounds( slot, aMin, aMax );
559 aNode->data[slot] = aData;
560 aNode->count++;
561 }
562 else
563 {
564 // Simple split: sort by center of longest axis, split in half
565 simpleSplit( aNode, aMin, aMax, aData );
566 }
567 }
568 else
569 {
570 // Choose child with minimum area enlargement
571 int bestIdx = 0;
572 int64_t bestAreaInc = std::numeric_limits<int64_t>::max();
573
574 for( int i = 0; i < aNode->count; ++i )
575 {
576 int64_t areaInc = aNode->ChildEnlargement( i, aMin, aMax );
577
578 if( areaInc < bestAreaInc )
579 {
580 bestIdx = i;
581 bestAreaInc = areaInc;
582 }
583 }
584
585 NODE* child = aNode->children[bestIdx];
586 ensureWritable( child );
587 aNode->children[bestIdx] = child;
588
589 int oldCount = child->count;
590 insertSimple( child, aMin, aMax, aData );
591
592 // Update child bbox in parent
593 ELEMTYPE childMin[NUMDIMS], childMax[NUMDIMS];
594 child->ComputeEnclosingBounds( childMin, childMax );
595 aNode->SetChildBounds( bestIdx, childMin, childMax );
596
597 // Check if child split (count decreased means it was split and a sibling created)
598 if( child->count < oldCount && child->IsInternal() )
599 {
600 // The split created a new root subtree, handle it
601 // For simplicity in CoW, we just accept the tree as-is
602 }
603 }
604 }
605
609 void simpleSplit( NODE* aNode, const ELEMTYPE aMin[NUMDIMS],
610 const ELEMTYPE aMax[NUMDIMS], const DATATYPE& aData )
611 {
612 struct ENTRY
613 {
614 ELEMTYPE min[NUMDIMS];
615 ELEMTYPE max[NUMDIMS];
616 ELEMTYPE insertMin[NUMDIMS];
617 ELEMTYPE insertMax[NUMDIMS];
618 DATATYPE data;
619 int64_t sortKey;
620 };
621
622 int total = aNode->count + 1;
623 std::vector<ENTRY> entries( total );
624
625 // Find longest axis
626 ELEMTYPE nodeMin[NUMDIMS], nodeMax[NUMDIMS];
627 aNode->ComputeEnclosingBounds( nodeMin, nodeMax );
628
629 int bestAxis = 0;
630 ELEMTYPE bestExtent = 0;
631
632 for( int d = 0; d < NUMDIMS; ++d )
633 {
634 ELEMTYPE lo = std::min( nodeMin[d], aMin[d] );
635 ELEMTYPE hi = std::max( nodeMax[d], aMax[d] );
636 ELEMTYPE extent = hi - lo;
637
638 if( extent > bestExtent )
639 {
640 bestExtent = extent;
641 bestAxis = d;
642 }
643 }
644
645 // Gather entries
646 for( int i = 0; i < aNode->count; ++i )
647 {
648 aNode->GetChildBounds( i, entries[i].min, entries[i].max );
649 aNode->GetInsertBounds( i, entries[i].insertMin, entries[i].insertMax );
650 entries[i].data = aNode->data[i];
651 entries[i].sortKey = static_cast<int64_t>( entries[i].min[bestAxis] )
652 + entries[i].max[bestAxis];
653 }
654
655 for( int d = 0; d < NUMDIMS; ++d )
656 {
657 entries[aNode->count].min[d] = aMin[d];
658 entries[aNode->count].max[d] = aMax[d];
659 entries[aNode->count].insertMin[d] = aMin[d];
660 entries[aNode->count].insertMax[d] = aMax[d];
661 }
662
663 entries[aNode->count].data = aData;
664 entries[aNode->count].sortKey = static_cast<int64_t>( aMin[bestAxis] )
665 + aMax[bestAxis];
666
667 std::sort( entries.begin(), entries.end(),
668 []( const ENTRY& a, const ENTRY& b )
669 {
670 return a.sortKey < b.sortKey;
671 } );
672
673 int splitIdx = total / 2;
674
675 // Rebuild this node with first half
676 aNode->count = 0;
677
678 for( int i = 0; i < splitIdx; ++i )
679 {
680 int slot = aNode->count;
681 aNode->SetChildBounds( slot, entries[i].min, entries[i].max );
682 aNode->SetInsertBounds( slot, entries[i].insertMin, entries[i].insertMax );
683 aNode->data[slot] = entries[i].data;
684 aNode->count++;
685 }
686
687 // Create sibling with second half
688 NODE* sibling = m_allocator->Allocate();
689 sibling->level = 0;
690
691 for( int i = splitIdx; i < total; ++i )
692 {
693 int slot = sibling->count;
694 sibling->SetChildBounds( slot, entries[i].min, entries[i].max );
695 sibling->SetInsertBounds( slot, entries[i].insertMin, entries[i].insertMax );
696 sibling->data[slot] = entries[i].data;
697 sibling->count++;
698 }
699
700 // Need to propagate the sibling up. For the CoW case, if there's no room in the
701 // parent we need to handle it. Since we modify the root on Insert, we handle
702 // root splits here.
703 ELEMTYPE sibMin[NUMDIMS], sibMax[NUMDIMS];
704 sibling->ComputeEnclosingBounds( sibMin, sibMax );
705
706 if( aNode == m_root )
707 {
708 NODE* newRoot = m_allocator->Allocate();
709 newRoot->level = 1;
710
711 ELEMTYPE nMin[NUMDIMS], nMax[NUMDIMS];
712 aNode->ComputeEnclosingBounds( nMin, nMax );
713
714 newRoot->SetChildBounds( 0, nMin, nMax );
715 newRoot->children[0] = aNode;
716 newRoot->SetChildBounds( 1, sibMin, sibMax );
717 newRoot->children[1] = sibling;
718 newRoot->count = 2;
719 m_root = newRoot;
720 }
721 else
722 {
723 // For non-root splits in CoW trees, we need to find the parent.
724 // This is a limitation of the simplified CoW approach -- the parent
725 // should be tracked during traversal. For now, create a new root.
726 NODE* newRoot = m_allocator->Allocate();
727 newRoot->level = m_root->level + 1;
728
729 ELEMTYPE rMin[NUMDIMS], rMax[NUMDIMS];
730 m_root->ComputeEnclosingBounds( rMin, rMax );
731
732 // Incorporate sibling bbox into root bbox
733 for( int d = 0; d < NUMDIMS; ++d )
734 {
735 if( sibMin[d] < rMin[d] )
736 rMin[d] = sibMin[d];
737
738 if( sibMax[d] > rMax[d] )
739 rMax[d] = sibMax[d];
740 }
741
742 newRoot->SetChildBounds( 0, rMin, rMax );
743 newRoot->children[0] = m_root;
744 newRoot->SetChildBounds( 1, sibMin, sibMax );
745 newRoot->children[1] = sibling;
746 newRoot->count = 2;
747 m_root = newRoot;
748 }
749 }
750
751 bool removeImpl( NODE* aNode, const ELEMTYPE aMin[NUMDIMS],
752 const ELEMTYPE aMax[NUMDIMS], const DATATYPE& aData )
753 {
754 if( aNode->IsLeaf() )
755 {
756 for( int i = 0; i < aNode->count; ++i )
757 {
758 if( aNode->data[i] == aData
759 && aNode->ChildOverlaps( i, aMin, aMax ) )
760 {
761 aNode->RemoveChild( i );
762 return true;
763 }
764 }
765
766 return false;
767 }
768
769 for( int i = 0; i < aNode->count; ++i )
770 {
771 if( !aNode->ChildOverlaps( i, aMin, aMax ) )
772 continue;
773
774 NODE* child = aNode->children[i];
775 ensureWritable( child );
776 aNode->children[i] = child;
777
778 if( removeImpl( child, aMin, aMax, aData ) )
779 {
780 if( child->count > 0 )
781 {
782 ELEMTYPE childMin[NUMDIMS], childMax[NUMDIMS];
783 child->ComputeEnclosingBounds( childMin, childMax );
784 aNode->SetChildBounds( i, childMin, childMax );
785 }
786 else
787 {
788 releaseNode( child );
789 aNode->RemoveChild( i );
790 }
791
792 return true;
793 }
794 }
795
796 return false;
797 }
798
799 template <class VISITOR>
800 void searchImpl( NODE* aNode, const ELEMTYPE aMin[NUMDIMS],
801 const ELEMTYPE aMax[NUMDIMS], VISITOR& aVisitor, int& aFound ) const
802 {
803 if( aNode->IsLeaf() )
804 {
805 for( int i = 0; i < aNode->count; ++i )
806 {
807 if( aNode->ChildOverlaps( i, aMin, aMax ) )
808 {
809 aFound++;
810
811 if( !aVisitor( aNode->data[i] ) )
812 return;
813 }
814 }
815 }
816 else
817 {
818 for( int i = 0; i < aNode->count; ++i )
819 {
820 if( aNode->ChildOverlaps( i, aMin, aMax ) )
821 searchImpl( aNode->children[i], aMin, aMax, aVisitor, aFound );
822 }
823 }
824 }
825
826 NODE* m_root = nullptr;
827 size_t m_count = 0;
828 std::shared_ptr<ALLOC> m_allocator;
829 std::shared_ptr<ALLOC_CHAIN> m_parentChain;
830};
831
832} // namespace KIRTREE
833
834#endif // DYNAMIC_RTREE_COW_H
bool operator!=(const Iterator &aOther) const
bool operator==(const Iterator &aOther) const
std::vector< STACK_ENTRY > m_stack
const DATATYPE & operator*() const
COW_RTREE & operator=(const COW_RTREE &)=delete
void searchImpl(NODE *aNode, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], VISITOR &aVisitor, int &aFound) const
typename DYNAMIC_RTREE< DATATYPE, ELEMTYPE, NUMDIMS, TMAXNODES >::BULK_ENTRY BULK_ENTRY
Bulk load entries using Hilbert curve sorting and bottom-up packing.
COW_RTREE(const COW_RTREE &)=delete
SLAB_ALLOCATOR< NODE > ALLOC
void BulkLoad(std::vector< BULK_ENTRY > &aEntries)
COW_RTREE & operator=(COW_RTREE &&aOther) noexcept
void simpleSplit(NODE *aNode, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], const DATATYPE &aData)
Simple split for CoW insertion: median split along longest axis.
int Search(const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], VISITOR &aVisitor) const
Search for items whose bounding boxes overlap the query rectangle.
void ensureWritable(NODE *&aNode)
Ensure a node is exclusively owned (refcount == 1).
Iterator end() const
std::shared_ptr< ALLOC_CHAIN > m_parentChain
COW_RTREE(COW_RTREE &&aOther) noexcept
void Insert(const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], const DATATYPE &aData)
Insert an item.
COW_RTREE Clone() const
Create a clone that shares the tree structure with this tree.
RTREE_NODE< DATATYPE, ELEMTYPE, NUMDIMS, TMAXNODES > NODE
bool removeImpl(NODE *aNode, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], const DATATYPE &aData)
void insertSimple(NODE *aNode, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], const DATATYPE &aData)
Simplified insertion (no forced reinsert, just split on overflow).
void releaseNode(NODE *aNode)
Release a reference to a node.
std::shared_ptr< ALLOC > m_allocator
bool Remove(const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], const DATATYPE &aData)
Remove an item.
void releaseTree(NODE *aNode)
Release the entire tree rooted at aNode.
Iterator begin() const
void freeToOwningAllocator(NODE *aNode)
Free a node through the allocator that actually owns its memory.
Pool allocator for R-tree nodes.
Definition rtree_node.h:548
uint64_t HilbertXY2D(int aOrder, uint32_t aX, uint32_t aY)
Compute a 64-bit Hilbert curve index from 2D unsigned coordinates.
Definition rtree_node.h:53
STL namespace.
const int scale
std::shared_ptr< ALLOC_CHAIN > next
std::shared_ptr< ALLOC > allocator
int childIdx
NODE * node
Entry type for bulk loading.
R-tree node with Structure-of-Arrays bounding box layout.
Definition rtree_node.h:295
bool IsInternal() const
Definition rtree_node.h:325
ELEMTYPE insertBounds[NUMDIMS *2][MAXNODES]
Definition rtree_node.h:313
ELEMTYPE bounds[NUMDIMS *2][MAXNODES]
Definition rtree_node.h:303
std::atomic< int > refcount
Definition rtree_node.h:315
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
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
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
KIBIS top(path, &reporter)
const SHAPE_LINE_CHAIN chain