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
26
#include "../spatialindex/SpatialIndexImpl.h"
32
#include "BulkLoader.h"
33
#include "qgslogger.h"
36
// tell MSVC not to complain about exception declarations
37
#pragma warning(disable:4290)
38
#define UNUSED(symbol) symbol
40
#define UNUSED(symbol)
43
using namespace SpatialIndex::RTree;
45
BulkLoadSource::BulkLoadSource(
46
Tools::SmartPointer<IObjectStream> spStream, unsigned long howMany
47
) : m_spDataSource( spStream ), m_cHowMany( howMany )
51
BulkLoadSource::BulkLoadSource( IObjectStream* pStream, unsigned long howMany )
52
: m_spDataSource( pStream ), m_cHowMany( howMany )
56
BulkLoadSource::BulkLoadSource( IObjectStream* pStream )
57
: m_spDataSource( pStream ),
58
m_cHowMany( std::numeric_limits<unsigned long>::max() )
62
BulkLoadSource::~BulkLoadSource()
66
Tools::IObject* BulkLoadSource::getNext()
68
if ( m_cHowMany == 0 || ! m_spDataSource->hasNext() ) return 0;
70
return m_spDataSource->getNext();
73
bool BulkLoadSource::hasNext() throw()
75
return ( m_cHowMany != 0 && m_spDataSource->hasNext() );
78
unsigned long BulkLoadSource::size() throw( Tools::NotSupportedException )
80
throw Tools::NotSupportedException( "SpatialIndex::RTree::BulkLoadSource::size: this should never be called." );
83
void BulkLoadSource::rewind() throw( Tools::NotSupportedException )
85
throw Tools::NotSupportedException( "SpatialIndex::RTree::BulkLoadSource::rewind: this should never be called." );
88
BulkLoadComparator::BulkLoadComparator( unsigned long d ) : m_compareDimension( d )
92
BulkLoadComparator::~BulkLoadComparator()
96
int BulkLoadComparator::compare( Tools::IObject* o1, Tools::IObject* o2 )
98
IData* d1 = dynamic_cast<IData*>( o1 );
99
IData* d2 = dynamic_cast<IData*>( o2 );
101
IShape* s1; d1->getShape( &s1 );
102
IShape* s2; d2->getShape( &s2 );
103
Region r1; s1->getMBR( r1 );
104
Region r2; s2->getMBR( r2 );
108
r1.m_pHigh[m_compareDimension] + r1.m_pLow[m_compareDimension] <
109
r2.m_pHigh[m_compareDimension] + r2.m_pLow[m_compareDimension] ) ret = -1;
111
r1.m_pHigh[m_compareDimension] + r1.m_pLow[m_compareDimension] >
112
r2.m_pHigh[m_compareDimension] + r2.m_pLow[m_compareDimension] ) ret = 1;
120
BulkLoader::TmpFile::TmpFile() : m_pNext( 0 )
124
BulkLoader::TmpFile::~TmpFile()
126
if ( m_pNext != 0 ) delete m_pNext;
129
void BulkLoader::TmpFile::storeRecord( Region& r, long id )
131
unsigned long len = sizeof( long ) + sizeof( unsigned long ) + 2 * r.m_dimension * sizeof( double );
132
byte* data = new byte[len];
135
memcpy( ptr, &id, sizeof( long ) );
136
ptr += sizeof( long );
137
memcpy( ptr, &( r.m_dimension ), sizeof( unsigned long ) );
138
ptr += sizeof( unsigned long );
139
memcpy( ptr, r.m_pLow, r.m_dimension * sizeof( double ) );
140
ptr += r.m_dimension * sizeof( double );
141
memcpy( ptr, r.m_pHigh, r.m_dimension * sizeof( double ) );
143
m_tmpFile.storeNextObject( len, data );
147
void BulkLoader::TmpFile::loadRecord( Region& r, long& id )
151
m_tmpFile.loadNextObject( &data, len );
154
memcpy( &id, ptr, sizeof( long ) );
155
ptr += sizeof( long );
158
memcpy( &dim, ptr, sizeof( unsigned long ) );
159
ptr += sizeof( unsigned long );
161
if ( dim != r.m_dimension )
166
r.m_pLow = new double[dim];
167
r.m_pHigh = new double[dim];
170
memcpy( r.m_pLow, ptr, dim * sizeof( double ) );
171
ptr += dim * sizeof( double );
172
memcpy( r.m_pHigh, ptr, dim * sizeof( double ) );
177
IData* BulkLoader::TmpFile::getNext()
179
if ( m_pNext == 0 ) return 0;
181
IData* ret = m_pNext;
188
m_pNext = new Data( 0, 0, r, id );
190
catch ( Tools::EndOfStreamException& e )
204
bool BulkLoader::TmpFile::hasNext() throw()
206
return ( m_pNext != 0 );
209
unsigned long BulkLoader::TmpFile::size() throw( Tools::NotSupportedException )
211
throw Tools::NotSupportedException( "Not supported yet." );
214
void BulkLoader::TmpFile::rewind()
225
m_tmpFile.rewindForReading();
230
m_pNext = new Data( 0, 0, r, id );
232
catch ( Tools::EndOfStreamException& e )
238
void BulkLoader::bulkLoadUsingSTR(
240
// MSVC seems to find RTree* pTree ambiguous
241
SpatialIndex::RTree::RTree* pTree,
246
unsigned long bindex,
248
unsigned long bufferSize )
250
NodePtr n = pTree->readNode( pTree->m_rootID );
251
pTree->deleteNode( n.get() );
253
// create the leaf level first.
254
TmpFile* tmpFile = new TmpFile();
255
unsigned long cNodes = 0;
256
unsigned long cTotalData = 0;
259
QgsDebugMsg( "Building level 0" );
262
createLevel( pTree, stream, pTree->m_dimension, pTree->m_dimension, bleaf, 0, bufferSize, *tmpFile, cNodes, cTotalData );
264
pTree->m_stats.m_data = cTotalData;
266
// create index levels afterwards.
267
unsigned long level = 1;
269
BulkLoadSource* bs = new BulkLoadSource( tmpFile );
274
TmpFile* pTF = new TmpFile();
277
QgsDebugMsg( QString( "Building level %1" ).arg( level ) );
279
pTree->m_stats.m_nodesInLevel.push_back( 0 );
281
createLevel( pTree, *bs, pTree->m_dimension, pTree->m_dimension, bindex, level, bufferSize, *pTF, cNodes, cTotalData );
286
bs = new BulkLoadSource( pTF );
289
pTree->m_stats.m_treeHeight = level;
293
pTree->storeHeader();
296
void BulkLoader::createLevel(
298
// MSVC seems to find RTree* pTree ambiguous
299
SpatialIndex::RTree::RTree* pTree,
303
Tools::IObjectStream& stream,
304
unsigned long dimension,
308
unsigned long bufferSize,
309
BulkLoader::TmpFile& tmpFile,
310
unsigned long& numberOfNodes,
311
unsigned long& totalData )
313
BulkLoadComparator bc( dimension - k );
314
Tools::SmartPointer<Tools::IObjectStream> es( Tools::externalSort( stream, bc, bufferSize ) );
315
unsigned long r = es->size();
318
if ( k == dimension - 1 )
320
// store new pages in storage manager and page information in temporary file.
322
std::vector<Tools::SmartPointer<IData> > entries;
324
while ( es->hasNext() )
326
entries.push_back( Tools::SmartPointer<IData>( static_cast<IData*>( es->getNext() ) ) );
328
if ( entries.size() == b )
330
Node* n = createNode( pTree, entries, level );
331
pTree->writeNode( n );
332
if ( r <= b ) pTree->m_rootID = n->m_identifier;
334
tmpFile.storeRecord( n->m_nodeMBR, n->m_identifier );
340
if ( ! entries.empty() )
342
Node* n = createNode( pTree, entries, level );
343
pTree->writeNode( n );
344
if ( r <= b ) pTree->m_rootID = n->m_identifier;
346
tmpFile.storeRecord( n->m_nodeMBR, n->m_identifier );
353
unsigned long P = static_cast<unsigned long>( std::ceil( static_cast<double>( r ) / static_cast<double>( b ) ) );
354
unsigned long D = static_cast<unsigned long>( std::ceil( std::pow( static_cast<double>( P ), static_cast<double>( k - 1 ) / static_cast<double>( k ) ) ) );
356
while ( es->hasNext() ) // this will happen S = ceil[P^(1 / k)] times
358
BulkLoadSource bs( es, D * b );
359
unsigned long cTotalData;
360
createLevel( pTree, bs, dimension, k - 1, b, level, bufferSize, tmpFile, numberOfNodes, cTotalData );
366
// MSVC seems to find RTree* pTree ambiguous
367
Node* BulkLoader::createNode( SpatialIndex::RTree::RTree* pTree, std::vector<Tools::SmartPointer<IData> >& e, unsigned long level )
369
Node* BulkLoader::createNode( RTree* pTree, std::vector<Tools::SmartPointer<IData> >& e, unsigned long level )
374
if ( level == 0 ) n = new Leaf( pTree, -1 );
375
else n = new Index( pTree, -1, level );
377
for ( unsigned long cChild = 0; cChild < e.size(); cChild++ )
381
e[cChild]->getData( len, &data );
382
IShape* s; e[cChild]->getShape( &s );
383
RegionPtr mbr = pTree->m_regionPool.acquire();
386
unsigned long id = e[cChild]->getIdentifier();
387
n->insertEntry( len, data, *mbr, id );