24#ifndef DYNAMIC_RTREE_COW_H
25#define DYNAMIC_RTREE_COW_H
54template <
class DATATYPE,
class ELEMTYPE =
int,
int NUMDIMS = 2,
int TMAXNODES = 16>
66 std::shared_ptr<ALLOC_CHAIN>
next;
88 aOther.m_root =
nullptr;
101 aOther.m_root =
nullptr;
125 m_root->refcount.fetch_add( 1, std::memory_order_relaxed );
140 void Insert(
const ELEMTYPE aMin[NUMDIMS],
const ELEMTYPE aMax[NUMDIMS],
141 const DATATYPE& aData )
161 bool Remove(
const ELEMTYPE aMin[NUMDIMS],
const ELEMTYPE aMax[NUMDIMS],
162 const DATATYPE& aData )
180 m_root->refcount.fetch_add( 1, std::memory_order_relaxed );
201 template <
class VISITOR>
202 int Search(
const ELEMTYPE aMin[NUMDIMS],
const ELEMTYPE aMax[NUMDIMS],
203 VISITOR& aVisitor )
const
230 if( aEntries.empty() )
236 ELEMTYPE globalMin[NUMDIMS], globalMax[NUMDIMS];
238 for(
int d = 0; d < NUMDIMS; ++d )
240 globalMin[d] = aEntries[0].min[d];
241 globalMax[d] = aEntries[0].max[d];
244 for(
const auto& e : aEntries )
246 for(
int d = 0; d < NUMDIMS; ++d )
248 if( e.min[d] < globalMin[d] ) globalMin[d] = e.min[d];
249 if( e.max[d] > globalMax[d] ) globalMax[d] = e.max[d];
253 double scale[NUMDIMS];
255 for(
int d = 0; d < NUMDIMS; ++d )
257 double range =
static_cast<double>( globalMax[d] ) - globalMin[d];
258 scale[d] = ( range > 0 ) ? ( 65535.0 / range ) : 0.0;
268 std::vector<SORTED_ENTRY> sorted( aEntries.size() );
270 for(
size_t i = 0; i < aEntries.size(); ++i )
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] );
280 std::sort( sorted.begin(), sorted.end(),
281 [](
const SORTED_ENTRY& a,
const SORTED_ENTRY& b )
283 return a.hilbert < b.hilbert;
287 std::vector<BULK_ENTRY> reordered;
288 reordered.reserve( aEntries.size() );
290 for(
const auto& s : sorted )
291 reordered.push_back( std::move( aEntries[s.origIdx] ) );
293 aEntries = std::move( reordered );
296 std::vector<NODE*> currentLevel;
299 while( idx < aEntries.size() )
304 int fill = std::min(
static_cast<int>( TMAXNODES ),
305 static_cast<int>( aEntries.size() - idx ) );
307 for(
int i = 0; i < fill; ++i, ++idx )
311 leaf->
data[i] = aEntries[idx].data;
315 currentLevel.push_back( leaf );
321 while( currentLevel.size() > 1 )
323 std::vector<NODE*> nextLevel;
326 while( ci < currentLevel.size() )
329 parent->
level = level;
331 int fill = std::min(
static_cast<int>( TMAXNODES ),
332 static_cast<int>( currentLevel.size() - ci ) );
334 for(
int i = 0; i < fill; ++i, ++ci )
336 NODE* child = currentLevel[ci];
337 ELEMTYPE cmin[NUMDIMS], cmax[NUMDIMS];
343 parent->
count = fill;
344 nextLevel.push_back( parent );
347 currentLevel = std::move( nextLevel );
368 if( aRoot && aRoot->
count > 0 )
370 m_stack.push_back( { aRoot, 0 } );
394 return !( *
this == aOther );
410 if(
top.node->IsLeaf() )
412 if(
top.childIdx <
top.node->count )
424 if(
top.childIdx <
top.node->count )
426 NODE* child =
top.node->children[
top.childIdx];
428 m_stack.push_back( { child, 0 } );
446 Iterator
end()
const {
return Iterator(); }
458 if( aNode->
refcount.load( std::memory_order_relaxed ) > 1 )
469 for(
int i = 0; i < aNode->
count; ++i )
474 for(
int i = 0; i < aNode->
count; ++i )
479 if(
copy->children[i] )
481 copy->children[i]->refcount.fetch_add( 1,
482 std::memory_order_relaxed );
487 copy->refcount.store( 1, std::memory_order_relaxed );
504 if( aNode->
refcount.fetch_sub( 1, std::memory_order_acq_rel ) == 1 )
508 for(
int i = 0; i < aNode->
count; ++i )
531 if(
chain->allocator->Owns( aNode ) )
533 chain->allocator->Free( aNode );
538 assert(
false &&
"R-tree node not owned by any allocator in chain" );
554 const ELEMTYPE aMax[NUMDIMS],
const DATATYPE& aData )
560 int slot = aNode->
count;
563 aNode->
data[slot] = aData;
576 int64_t bestAreaInc = std::numeric_limits<int64_t>::max();
578 for(
int i = 0; i < aNode->
count; ++i )
582 if( areaInc < bestAreaInc )
585 bestAreaInc = areaInc;
593 int oldCount = child->
count;
597 ELEMTYPE childMin[NUMDIMS], childMax[NUMDIMS];
614 const ELEMTYPE aMax[NUMDIMS],
const DATATYPE& aData )
618 ELEMTYPE min[NUMDIMS];
619 ELEMTYPE max[NUMDIMS];
620 ELEMTYPE insertMin[NUMDIMS];
621 ELEMTYPE insertMax[NUMDIMS];
626 int total = aNode->
count + 1;
627 std::vector<ENTRY> entries( total );
630 ELEMTYPE nodeMin[NUMDIMS], nodeMax[NUMDIMS];
634 ELEMTYPE bestExtent = 0;
636 for(
int d = 0; d < NUMDIMS; ++d )
638 ELEMTYPE lo = std::min( nodeMin[d], aMin[d] );
639 ELEMTYPE hi = std::max( nodeMax[d], aMax[d] );
640 ELEMTYPE extent = hi - lo;
642 if( extent > bestExtent )
650 for(
int i = 0; i < aNode->
count; ++i )
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];
659 for(
int d = 0; d < NUMDIMS; ++d )
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];
667 entries[aNode->
count].data = aData;
668 entries[aNode->
count].sortKey =
static_cast<int64_t
>( aMin[bestAxis] )
671 std::sort( entries.begin(), entries.end(),
672 [](
const ENTRY& a,
const ENTRY& b )
674 return a.sortKey < b.sortKey;
677 int splitIdx = total / 2;
682 for(
int i = 0; i < splitIdx; ++i )
684 int slot = aNode->
count;
686 aNode->
SetInsertBounds( slot, entries[i].insertMin, entries[i].insertMax );
687 aNode->
data[slot] = entries[i].data;
695 for(
int i = splitIdx; i < total; ++i )
697 int slot = sibling->
count;
699 sibling->
SetInsertBounds( slot, entries[i].insertMin, entries[i].insertMax );
700 sibling->
data[slot] = entries[i].data;
707 ELEMTYPE sibMin[NUMDIMS], sibMax[NUMDIMS];
715 ELEMTYPE nMin[NUMDIMS], nMax[NUMDIMS];
733 ELEMTYPE rMin[NUMDIMS], rMax[NUMDIMS];
734 m_root->ComputeEnclosingBounds( rMin, rMax );
737 for(
int d = 0; d < NUMDIMS; ++d )
739 if( sibMin[d] < rMin[d] )
742 if( sibMax[d] > rMax[d] )
756 const ELEMTYPE aMax[NUMDIMS],
const DATATYPE& aData )
760 for(
int i = 0; i < aNode->
count; ++i )
762 if( aNode->
data[i] == aData
773 for(
int i = 0; i < aNode->
count; ++i )
784 if( child->
count > 0 )
786 ELEMTYPE childMin[NUMDIMS], childMax[NUMDIMS];
803 template <
class VISITOR>
805 const ELEMTYPE aMax[NUMDIMS], VISITOR& aVisitor,
int& aFound )
const
809 for(
int i = 0; i < aNode->
count; ++i )
815 if( !aVisitor( aNode->
data[i] ) )
822 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