1
// Spatial Index Library
3
// Copyright (C) 2002 Navel Ltd.
5
// This library is free software; you can redistribute it and/or
6
// modify it under the terms of the GNU Lesser General Public
7
// License as published by the Free Software Foundation; either
8
// version 2.1 of the License, or (at your option) any later version.
10
// This library is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
// Lesser General Public License for more details.
15
// You should have received a copy of the GNU Lesser General Public
16
// License along with this library; if not, write to the Free Software
17
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
#include "../spatialindex/SpatialIndexImpl.h"
32
using namespace SpatialIndex::RTree;
39
// MSVC seems to find RTree* pTree ambiguous
40
Index::Index( SpatialIndex::RTree::RTree* pTree, long id, unsigned long level ) : Node( pTree, id, level, pTree->m_indexCapacity )
42
Index::Index( RTree* pTree, long id, unsigned long level ) : Node( pTree, id, level, pTree->m_indexCapacity )
47
NodePtr Index::chooseSubtree( const Region& mbr, unsigned long insertionLevel, std::stack<long>& pathBuffer )
49
if ( m_level == insertionLevel ) return NodePtr( this, &( m_pTree->m_indexPool ) );
51
pathBuffer.push( m_identifier );
53
unsigned long child = 0;
55
switch ( m_pTree->m_treeVariant )
59
child = findLeastEnlargement( mbr );
64
// if this node points to leaves...
65
child = findLeastOverlap( mbr );
69
child = findLeastEnlargement( mbr );
73
throw Tools::NotSupportedException( "Index::chooseSubtree: Tree variant not supported." );
77
NodePtr n = m_pTree->readNode( m_pIdentifier[child] );
78
NodePtr ret = n->chooseSubtree( mbr, insertionLevel, pathBuffer );
80
if ( ret.get() == n.get() ) n.relinquish();
85
NodePtr Index::findLeaf( const Region& mbr, long id, std::stack<long>& pathBuffer )
87
pathBuffer.push( m_identifier );
89
for ( unsigned long cChild = 0; cChild < m_children; cChild++ )
91
if ( m_ptrMBR[cChild]->containsRegion( mbr ) )
93
NodePtr n = m_pTree->readNode( m_pIdentifier[cChild] );
94
NodePtr l = n->findLeaf( mbr, id, pathBuffer );
95
if ( n.get() == l.get() ) n.relinquish();
96
if ( l.get() != 0 ) return l;
105
void Index::split( unsigned long dataLength, byte* pData, Region& mbr, long id, NodePtr& ptrLeft, NodePtr& ptrRight )
107
m_pTree->m_stats.m_splits++;
111
switch ( m_pTree->m_treeVariant )
115
rtreeSplit( dataLength, pData, mbr, id, g1, g2 );
118
rstarSplit( dataLength, pData, mbr, id, g1, g2 );
121
throw Tools::NotSupportedException( "Index::split: Tree variant not supported." );
124
ptrLeft = m_pTree->m_indexPool.acquire();
125
ptrRight = m_pTree->m_indexPool.acquire();
127
if ( ptrLeft.get() == 0 ) ptrLeft = NodePtr( new Index( m_pTree, m_identifier, m_level ), &( m_pTree->m_indexPool ) );
128
if ( ptrRight.get() == 0 ) ptrRight = NodePtr( new Index( m_pTree, -1, m_level ), &( m_pTree->m_indexPool ) );
130
ptrLeft->m_nodeMBR = m_pTree->m_infiniteRegion;
131
ptrRight->m_nodeMBR = m_pTree->m_infiniteRegion;
133
unsigned long cIndex;
135
for ( cIndex = 0; cIndex < g1.size(); cIndex++ )
137
ptrLeft->insertEntry( 0, 0, *( m_ptrMBR[g1[cIndex]] ), m_pIdentifier[g1[cIndex]] );
140
for ( cIndex = 0; cIndex < g2.size(); cIndex++ )
142
ptrRight->insertEntry( 0, 0, *( m_ptrMBR[g2[cIndex]] ), m_pIdentifier[g2[cIndex]] );
146
long Index::findLeastEnlargement( const Region& r ) const
148
double area = std::numeric_limits<double>::max();
151
RegionPtr t = m_pTree->m_regionPool.acquire();
153
for ( unsigned long cChild = 0; cChild < m_children; cChild++ )
155
m_ptrMBR[cChild]->getCombinedRegion( *t, r );
157
double a = m_ptrMBR[cChild]->getArea();
158
double enl = t->getArea() - a;
165
else if ( enl == area )
167
// this will rarely happen, so compute best area on the fly only
169
if ( a < m_ptrMBR[best]->getArea() ) best = cChild;
176
long Index::findLeastOverlap( const Region& r ) const
178
OverlapEntry** entries = new OverlapEntry*[m_children];
180
double leastOverlap = std::numeric_limits<double>::max();
181
double me = std::numeric_limits<double>::max();
182
OverlapEntry* best = 0;
184
// find combined region and enlargement of every entry and store it.
185
for ( unsigned long cChild = 0; cChild < m_children; cChild++ )
189
entries[cChild] = new OverlapEntry();
193
for ( unsigned long i = 0; i < cChild; i++ ) delete entries[i];
198
entries[cChild]->m_id = cChild;
199
entries[cChild]->m_original = m_ptrMBR[cChild];
200
entries[cChild]->m_combined = m_pTree->m_regionPool.acquire();
201
m_ptrMBR[cChild]->getCombinedRegion( *( entries[cChild]->m_combined ), r );
202
entries[cChild]->m_oa = entries[cChild]->m_original->getArea();
203
entries[cChild]->m_ca = entries[cChild]->m_combined->getArea();
204
entries[cChild]->m_enlargement = entries[cChild]->m_ca - entries[cChild]->m_oa;
206
if ( entries[cChild]->m_enlargement < me )
208
me = entries[cChild]->m_enlargement;
209
best = entries[cChild];
211
else if ( entries[cChild]->m_enlargement == me && entries[cChild]->m_oa < best->m_oa )
213
best = entries[cChild];
217
if ( me < -std::numeric_limits<double>::epsilon() || me > std::numeric_limits<double>::epsilon() )
219
unsigned long cIterations;
221
if ( m_children > m_pTree->m_nearMinimumOverlapFactor )
223
// sort entries in increasing order of enlargement.
224
::qsort( entries, m_children,
225
sizeof( OverlapEntry* ),
226
OverlapEntry::compareEntries );
227
assert( entries[0]->m_enlargement <= entries[m_children - 1]->m_enlargement );
229
cIterations = m_pTree->m_nearMinimumOverlapFactor;
233
cIterations = m_children;
236
// calculate overlap of most important original entries (near minimum overlap cost).
237
for ( unsigned long cIndex = 0; cIndex < cIterations; cIndex++ )
240
OverlapEntry* e = entries[cIndex];
242
for ( unsigned long cChild = 0; cChild < m_children; cChild++ )
244
if ( e->m_id != cChild )
246
double f = e->m_combined->getIntersectingArea( *( m_ptrMBR[cChild] ) );
247
if ( f != 0.0 ) dif += f - e->m_original->getIntersectingArea( *( m_ptrMBR[cChild] ) );
251
if ( dif < leastOverlap )
254
best = entries[cIndex];
256
else if ( dif == leastOverlap )
258
if ( e->m_enlargement == best->m_enlargement )
260
// keep the one with least area.
261
if ( e->m_original->getArea() < best->m_original->getArea() ) best = entries[cIndex];
265
// keep the one with least enlargement.
266
if ( e->m_enlargement < best->m_enlargement ) best = entries[cIndex];
272
long ret = best->m_id;
274
for ( unsigned long cChild = 0; cChild < m_children; cChild++ )
276
delete entries[cChild];
283
void Index::adjustTree( Node* n, std::stack<long>& pathBuffer )
285
m_pTree->m_stats.m_adjustments++;
287
// find entry pointing to old node;
289
for ( child = 0; child < m_children; child++ )
291
if ( m_pIdentifier[child] == n->m_identifier ) break;
294
// MBR needs recalculation if either:
295
// 1. the NEW child MBR is not contained.
296
// 2. the OLD child MBR is touching.
297
bool bContained = m_nodeMBR.containsRegion( n->m_nodeMBR );
298
bool bTouches = m_nodeMBR.touchesRegion( *( m_ptrMBR[child] ) );
299
bool bRecompute = ( ! bContained || ( bTouches && m_pTree->m_bTightMBRs ) );
301
*( m_ptrMBR[child] ) = n->m_nodeMBR;
305
for ( unsigned long cDim = 0; cDim < m_nodeMBR.m_dimension; cDim++ )
307
m_nodeMBR.m_pLow[cDim] = std::numeric_limits<double>::max();
308
m_nodeMBR.m_pHigh[cDim] = -std::numeric_limits<double>::max();
310
for ( unsigned long cChild = 0; cChild < m_children; cChild++ )
312
m_nodeMBR.m_pLow[cDim] = std::min( m_nodeMBR.m_pLow[cDim], m_ptrMBR[cChild]->m_pLow[cDim] );
313
m_nodeMBR.m_pHigh[cDim] = std::max( m_nodeMBR.m_pHigh[cDim], m_ptrMBR[cChild]->m_pHigh[cDim] );
318
m_pTree->writeNode( this );
320
if ( bRecompute && ( ! pathBuffer.empty() ) )
322
long cParent = pathBuffer.top(); pathBuffer.pop();
323
NodePtr ptrN = m_pTree->readNode( cParent );
324
Index* p = static_cast<Index*>( ptrN.get() );
325
p->adjustTree( this, pathBuffer );
329
void Index::adjustTree( Node* n1, Node* n2, std::stack<long>& pathBuffer, byte* overflowTable )
331
m_pTree->m_stats.m_adjustments++;
333
// find entry pointing to old node;
335
for ( child = 0; child < m_children; child++ )
337
if ( m_pIdentifier[child] == n1->m_identifier ) break;
340
// MBR needs recalculation if either:
341
// 1. the NEW child MBR is not contained.
342
// 2. the OLD child MBR is touching.
343
bool bContained = m_nodeMBR.containsRegion( n1->m_nodeMBR );
344
bool bTouches = m_nodeMBR.touchesRegion( *( m_ptrMBR[child] ) );
345
bool bRecompute = ( ! bContained || ( bTouches && m_pTree->m_bTightMBRs ) );
347
*( m_ptrMBR[child] ) = n1->m_nodeMBR;
351
for ( unsigned long cDim = 0; cDim < m_nodeMBR.m_dimension; cDim++ )
353
m_nodeMBR.m_pLow[cDim] = std::numeric_limits<double>::max();
354
m_nodeMBR.m_pHigh[cDim] = -std::numeric_limits<double>::max();
356
for ( unsigned long cChild = 0; cChild < m_children; cChild++ )
358
m_nodeMBR.m_pLow[cDim] = std::min( m_nodeMBR.m_pLow[cDim], m_ptrMBR[cChild]->m_pLow[cDim] );
359
m_nodeMBR.m_pHigh[cDim] = std::max( m_nodeMBR.m_pHigh[cDim], m_ptrMBR[cChild]->m_pHigh[cDim] );
364
// No write necessary here. insertData will write the node if needed.
365
//m_pTree->writeNode(this);
367
bool bAdjusted = insertData( 0, 0, n2->m_nodeMBR, n2->m_identifier, pathBuffer, overflowTable );
369
// if n2 is contained in the node and there was no split or reinsert,
370
// we need to adjust only if recalculation took place.
371
// In all other cases insertData above took care of adjustment.
372
if (( ! bAdjusted ) && bRecompute && ( ! pathBuffer.empty() ) )
374
long cParent = pathBuffer.top(); pathBuffer.pop();
375
NodePtr ptrN = m_pTree->readNode( cParent );
376
Index* p = static_cast<Index*>( ptrN.get() );
377
p->adjustTree( this, pathBuffer );