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