20#ifndef DYNAMIC_RTREE_COW_H
21#define DYNAMIC_RTREE_COW_H
50template <
class DATATYPE,
class ELEMTYPE =
int,
int NUMDIMS = 2,
int TMAXNODES = 16>
62 std::shared_ptr<ALLOC_CHAIN>
next;
84 aOther.m_root =
nullptr;
97 aOther.m_root =
nullptr;
121 m_root->refcount.fetch_add( 1, std::memory_order_relaxed );
136 void Insert(
const ELEMTYPE aMin[NUMDIMS],
const ELEMTYPE aMax[NUMDIMS],
137 const DATATYPE& aData )
157 bool Remove(
const ELEMTYPE aMin[NUMDIMS],
const ELEMTYPE aMax[NUMDIMS],
158 const DATATYPE& aData )
176 m_root->refcount.fetch_add( 1, std::memory_order_relaxed );
197 template <
class VISITOR>
198 int Search(
const ELEMTYPE aMin[NUMDIMS],
const ELEMTYPE aMax[NUMDIMS],
199 VISITOR& aVisitor )
const
226 if( aEntries.empty() )
232 ELEMTYPE globalMin[NUMDIMS], globalMax[NUMDIMS];
234 for(
int d = 0; d < NUMDIMS; ++d )
236 globalMin[d] = aEntries[0].min[d];
237 globalMax[d] = aEntries[0].max[d];
240 for(
const auto& e : aEntries )
242 for(
int d = 0; d < NUMDIMS; ++d )
244 if( e.min[d] < globalMin[d] ) globalMin[d] = e.min[d];
245 if( e.max[d] > globalMax[d] ) globalMax[d] = e.max[d];
249 double scale[NUMDIMS];
251 for(
int d = 0; d < NUMDIMS; ++d )
253 double range =
static_cast<double>( globalMax[d] ) - globalMin[d];
254 scale[d] = ( range > 0 ) ? ( 65535.0 / range ) : 0.0;
264 std::vector<SORTED_ENTRY> sorted( aEntries.size() );
266 for(
size_t i = 0; i < aEntries.size(); ++i )
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] );
276 std::sort( sorted.begin(), sorted.end(),
277 [](
const SORTED_ENTRY& a,
const SORTED_ENTRY& b )
279 return a.hilbert < b.hilbert;
283 std::vector<BULK_ENTRY> reordered;
284 reordered.reserve( aEntries.size() );
286 for(
const auto& s : sorted )
287 reordered.push_back( std::move( aEntries[s.origIdx] ) );
289 aEntries = std::move( reordered );
292 std::vector<NODE*> currentLevel;
295 while( idx < aEntries.size() )
300 int fill = std::min(
static_cast<int>( TMAXNODES ),
301 static_cast<int>( aEntries.size() - idx ) );
303 for(
int i = 0; i < fill; ++i, ++idx )
307 leaf->
data[i] = aEntries[idx].data;
311 currentLevel.push_back( leaf );
317 while( currentLevel.size() > 1 )
319 std::vector<NODE*> nextLevel;
322 while( ci < currentLevel.size() )
325 parent->
level = level;
327 int fill = std::min(
static_cast<int>( TMAXNODES ),
328 static_cast<int>( currentLevel.size() - ci ) );
330 for(
int i = 0; i < fill; ++i, ++ci )
332 NODE* child = currentLevel[ci];
333 ELEMTYPE cmin[NUMDIMS], cmax[NUMDIMS];
339 parent->
count = fill;
340 nextLevel.push_back( parent );
343 currentLevel = std::move( nextLevel );
364 if( aRoot && aRoot->
count > 0 )
366 m_stack.push_back( { aRoot, 0 } );
390 return !( *
this == aOther );
406 if(
top.node->IsLeaf() )
408 if(
top.childIdx <
top.node->count )
420 if(
top.childIdx <
top.node->count )
422 NODE* child =
top.node->children[
top.childIdx];
424 m_stack.push_back( { child, 0 } );
442 Iterator
end()
const {
return Iterator(); }
454 if( aNode->
refcount.load( std::memory_order_relaxed ) > 1 )
465 for(
int i = 0; i < aNode->
count; ++i )
470 for(
int i = 0; i < aNode->
count; ++i )
475 if(
copy->children[i] )
477 copy->children[i]->refcount.fetch_add( 1,
478 std::memory_order_relaxed );
483 copy->refcount.store( 1, std::memory_order_relaxed );
500 if( aNode->
refcount.fetch_sub( 1, std::memory_order_acq_rel ) == 1 )
504 for(
int i = 0; i < aNode->
count; ++i )
527 if(
chain->allocator->Owns( aNode ) )
529 chain->allocator->Free( aNode );
534 assert(
false &&
"R-tree node not owned by any allocator in chain" );
550 const ELEMTYPE aMax[NUMDIMS],
const DATATYPE& aData )
556 int slot = aNode->
count;
559 aNode->
data[slot] = aData;
572 int64_t bestAreaInc = std::numeric_limits<int64_t>::max();
574 for(
int i = 0; i < aNode->
count; ++i )
578 if( areaInc < bestAreaInc )
581 bestAreaInc = areaInc;
589 int oldCount = child->
count;
593 ELEMTYPE childMin[NUMDIMS], childMax[NUMDIMS];
610 const ELEMTYPE aMax[NUMDIMS],
const DATATYPE& aData )
614 ELEMTYPE min[NUMDIMS];
615 ELEMTYPE max[NUMDIMS];
616 ELEMTYPE insertMin[NUMDIMS];
617 ELEMTYPE insertMax[NUMDIMS];
622 int total = aNode->
count + 1;
623 std::vector<ENTRY> entries( total );
626 ELEMTYPE nodeMin[NUMDIMS], nodeMax[NUMDIMS];
630 ELEMTYPE bestExtent = 0;
632 for(
int d = 0; d < NUMDIMS; ++d )
634 ELEMTYPE lo = std::min( nodeMin[d], aMin[d] );
635 ELEMTYPE hi = std::max( nodeMax[d], aMax[d] );
636 ELEMTYPE extent = hi - lo;
638 if( extent > bestExtent )
646 for(
int i = 0; i < aNode->
count; ++i )
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];
655 for(
int d = 0; d < NUMDIMS; ++d )
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];
663 entries[aNode->
count].data = aData;
664 entries[aNode->
count].sortKey =
static_cast<int64_t
>( aMin[bestAxis] )
667 std::sort( entries.begin(), entries.end(),
668 [](
const ENTRY& a,
const ENTRY& b )
670 return a.sortKey < b.sortKey;
673 int splitIdx = total / 2;
678 for(
int i = 0; i < splitIdx; ++i )
680 int slot = aNode->
count;
682 aNode->
SetInsertBounds( slot, entries[i].insertMin, entries[i].insertMax );
683 aNode->
data[slot] = entries[i].data;
691 for(
int i = splitIdx; i < total; ++i )
693 int slot = sibling->
count;
695 sibling->
SetInsertBounds( slot, entries[i].insertMin, entries[i].insertMax );
696 sibling->
data[slot] = entries[i].data;
703 ELEMTYPE sibMin[NUMDIMS], sibMax[NUMDIMS];
711 ELEMTYPE nMin[NUMDIMS], nMax[NUMDIMS];
729 ELEMTYPE rMin[NUMDIMS], rMax[NUMDIMS];
730 m_root->ComputeEnclosingBounds( rMin, rMax );
733 for(
int d = 0; d < NUMDIMS; ++d )
735 if( sibMin[d] < rMin[d] )
738 if( sibMax[d] > rMax[d] )
752 const ELEMTYPE aMax[NUMDIMS],
const DATATYPE& aData )
756 for(
int i = 0; i < aNode->
count; ++i )
758 if( aNode->
data[i] == aData
769 for(
int i = 0; i < aNode->
count; ++i )
780 if( child->
count > 0 )
782 ELEMTYPE childMin[NUMDIMS], childMax[NUMDIMS];
799 template <
class VISITOR>
801 const ELEMTYPE aMax[NUMDIMS], VISITOR& aVisitor,
int& aFound )
const
805 for(
int i = 0; i < aNode->
count; ++i )
811 if( !aVisitor( aNode->
data[i] ) )
818 for(
int i = 0; i < aNode->
count; ++i )
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).
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.
void freeToOwningAllocator(NODE *aNode)
Free a node through the allocator that actually owns its memory.
Pool allocator for R-tree nodes.
uint64_t HilbertXY2D(int aOrder, uint32_t aX, uint32_t aY)
Compute a 64-bit Hilbert curve index from 2D unsigned coordinates.
std::shared_ptr< ALLOC_CHAIN > next
std::shared_ptr< ALLOC > allocator
Entry type for bulk loading.
R-tree node with Structure-of-Arrays bounding box layout.
ELEMTYPE insertBounds[NUMDIMS *2][MAXNODES]
ELEMTYPE bounds[NUMDIMS *2][MAXNODES]
std::atomic< int > refcount
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...
void GetChildBounds(int i, ELEMTYPE aMin[NUMDIMS], ELEMTYPE aMax[NUMDIMS]) const
Get the bounding box for child slot i.
RTREE_NODE * children[MAXNODES]
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.
void SetChildBounds(int i, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS])
Set the bounding box for child slot i.
void SetInsertBounds(int i, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS])
Store the insertion bounding box for leaf entry i.
void GetInsertBounds(int i, ELEMTYPE aMin[NUMDIMS], ELEMTYPE aMax[NUMDIMS]) const
Get the stored insertion bounding box for leaf entry i.
void ComputeEnclosingBounds(ELEMTYPE aMin[NUMDIMS], ELEMTYPE aMax[NUMDIMS]) const
Compute the bounding box that encloses all children in this node.
void RemoveChild(int i)
Remove child at slot i by swapping with last entry.
KIBIS top(path, &reporter)
const SHAPE_LINE_CHAIN chain