1
/***************************************************************************
2
memoryprovider.cpp - provider with storage in memory
5
copyright : (C) 2008 by Martin Dobias
6
email : wonder.sk at gmail.com
7
***************************************************************************
9
* This program is free software; you can redistribute it and/or modify *
10
* it under the terms of the GNU General Public License as published by *
11
* the Free Software Foundation; either version 2 of the License, or *
12
* (at your option) any later version. *
14
***************************************************************************/
16
#include "qgsmemoryprovider.h"
18
#include "qgsfeature.h"
20
#include "qgsgeometry.h"
21
#include "qgslogger.h"
22
#include "qgsspatialindex.h"
23
#include "qgscoordinatereferencesystem.h"
26
static const QString TEXT_PROVIDER_KEY = "memory";
27
static const QString TEXT_PROVIDER_DESCRIPTION = "Memory provider";
29
QgsMemoryProvider::QgsMemoryProvider( QString uri )
30
: QgsVectorDataProvider( uri ),
31
mSelectRectGeom( NULL ),
35
mWkbType = QGis::WKBPoint;
36
else if ( uri == "LineString" )
37
mWkbType = QGis::WKBLineString;
38
else if ( uri == "Polygon" )
39
mWkbType = QGis::WKBPolygon;
40
else if ( uri == "MultiPoint" )
41
mWkbType = QGis::WKBMultiPoint;
42
else if ( uri == "MultiLineString" )
43
mWkbType = QGis::WKBMultiLineString;
44
else if ( uri == "MultiPolygon" )
45
mWkbType = QGis::WKBMultiPolygon;
47
mWkbType = QGis::WKBUnknown;
52
QgsMemoryProvider::~QgsMemoryProvider()
55
delete mSelectRectGeom;
58
QString QgsMemoryProvider::storageType() const
60
return "Memory storage";
63
bool QgsMemoryProvider::nextFeature( QgsFeature& feature )
65
feature.setValid( false );
66
bool hasFeature = FALSE;
68
// option 1: using spatial index
69
if ( mSelectUsingSpatialIndex )
71
while ( mSelectSI_Iterator != mSelectSI_Features.end() )
73
// do exact check in case we're doing intersection
74
if ( mSelectUseIntersect )
76
if ( mFeatures[*mSelectSI_Iterator].geometry()->intersects( mSelectRectGeom ) )
91
feature = mFeatures[*mSelectSI_Iterator];
97
// option 2: not using spatial index
98
while ( mSelectIterator != mFeatures.end() )
100
if ( mSelectRect.isEmpty() )
102
// selection rect empty => using all features
107
if ( mSelectUseIntersect )
109
// using exact test when checking for intersection
110
if ( mSelectIterator->geometry()->intersects( mSelectRectGeom ) )
115
// check just bounding box against rect when not using intersection
116
if ( mSelectIterator->geometry()->boundingBox().intersects( mSelectRect ) )
130
feature = mSelectIterator.value();
132
feature.setValid( true );
139
bool QgsMemoryProvider::featureAtId( int featureId,
142
QgsAttributeList fetchAttributes )
144
QgsFeatureMap::iterator it = mFeatures.find( featureId );
146
if ( it == mFeatures.end() )
154
void QgsMemoryProvider::select( QgsAttributeList fetchAttributes,
159
mSelectAttrs = fetchAttributes;
161
delete mSelectRectGeom;
162
mSelectRectGeom = QgsGeometry::fromRect( rect );
163
mSelectGeometry = fetchGeometry;
164
mSelectUseIntersect = useIntersect;
166
// if there's spatial index, use it!
167
// (but don't use it when selection rect is not specified)
168
if ( mSpatialIndex && !mSelectRect.isEmpty() )
170
mSelectUsingSpatialIndex = TRUE;
171
mSelectSI_Features = mSpatialIndex->intersects( rect );
172
QgsDebugMsg( "Features returned by spatial index: " + QString::number( mSelectSI_Features.count() ) );
176
mSelectUsingSpatialIndex = FALSE;
177
mSelectSI_Features.clear();
183
void QgsMemoryProvider::rewind()
185
if ( mSelectUsingSpatialIndex )
186
mSelectSI_Iterator = mSelectSI_Features.begin();
188
mSelectIterator = mFeatures.begin();
192
QgsRectangle QgsMemoryProvider::extent()
197
QGis::WkbType QgsMemoryProvider::geometryType() const
202
long QgsMemoryProvider::featureCount() const
204
return mFeatures.count();
207
uint QgsMemoryProvider::fieldCount() const
209
return mFields.count();
213
const QgsFieldMap & QgsMemoryProvider::fields() const
218
bool QgsMemoryProvider::isValid()
220
return ( mWkbType != QGis::WKBUnknown );
223
QgsCoordinateReferenceSystem QgsMemoryProvider::crs()
225
// TODO: make provider projection-aware
226
return QgsCoordinateReferenceSystem(); // return default CRS
230
bool QgsMemoryProvider::addFeatures( QgsFeatureList & flist )
232
// TODO: sanity checks of fields and geometries
233
for ( QgsFeatureList::iterator it = flist.begin(); it != flist.end(); ++it )
235
mFeatures[mNextFeatureId] = *it;
236
QgsFeature& newfeat = mFeatures[mNextFeatureId];
237
newfeat.setFeatureId( mNextFeatureId );
239
// update spatial index
241
mSpatialIndex->insertFeature( newfeat );
252
bool QgsMemoryProvider::deleteFeatures( const QgsFeatureIds & id )
254
for ( QgsFeatureIds::const_iterator it = id.begin(); it != id.end(); ++it )
256
QgsFeatureMap::iterator fit = mFeatures.find( *it );
258
// check whether such feature exists
259
if ( fit == mFeatures.end() )
262
// update spatial index
264
mSpatialIndex->deleteFeature( *fit );
266
mFeatures.erase( fit );
274
bool QgsMemoryProvider::addAttributes( const QList<QgsField> &attributes )
276
for ( QList<QgsField>::const_iterator it = attributes.begin(); it != attributes.end(); ++it )
278
switch ( it->type() )
281
case QVariant::Double:
282
case QVariant::String:
285
QgsDebugMsg( "Field type not supported: " + it->typeName() );
289
// add new field as a last one
291
for ( QgsFieldMap::iterator it2 = mFields.begin(); it2 != mFields.end(); ++it2 )
292
if ( it2.key() > nextId ) nextId = it2.key();
293
mFields[nextId+1] = *it;
298
bool QgsMemoryProvider::deleteAttributes( const QgsAttributeIds& attributes )
300
for ( QgsAttributeIds::const_iterator it = attributes.begin(); it != attributes.end(); ++it )
301
mFields.remove( *it );
305
bool QgsMemoryProvider::changeAttributeValues( const QgsChangedAttributesMap & attr_map )
307
for ( QgsChangedAttributesMap::const_iterator it = attr_map.begin(); it != attr_map.end(); ++it )
309
QgsFeatureMap::iterator fit = mFeatures.find( it.key() );
310
if ( fit == mFeatures.end() )
313
const QgsAttributeMap& attrs = it.value();
314
for ( QgsAttributeMap::const_iterator it2 = attrs.begin(); it2 != attrs.end(); ++it2 )
315
fit->changeAttribute( it2.key(), it2.value() );
320
bool QgsMemoryProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
322
for ( QgsGeometryMap::const_iterator it = geometry_map.begin(); it != geometry_map.end(); ++it )
324
QgsFeatureMap::iterator fit = mFeatures.find( it.key() );
325
if ( fit == mFeatures.end() )
328
// update spatial index
330
mSpatialIndex->deleteFeature( *fit );
332
fit->setGeometry( it.value() );
334
// update spatial index
336
mSpatialIndex->insertFeature( *fit );
344
bool QgsMemoryProvider::createSpatialIndex()
346
if ( !mSpatialIndex )
348
mSpatialIndex = new QgsSpatialIndex();
350
// add existing features to index
351
for ( QgsFeatureMap::iterator it = mFeatures.begin(); it != mFeatures.end(); ++it )
353
mSpatialIndex->insertFeature( *it );
359
int QgsMemoryProvider::capabilities() const
361
return AddFeatures | DeleteFeatures | ChangeGeometries |
362
ChangeAttributeValues | AddAttributes | DeleteAttributes | CreateSpatialIndex |
363
SelectAtId | SelectGeometryAtId;
367
void QgsMemoryProvider::updateExtent()
369
if ( mFeatures.count() == 0 )
371
mExtent = QgsRectangle();
375
mExtent = mFeatures.begin().value().geometry()->boundingBox();
376
for ( QgsFeatureMap::iterator it = mFeatures.begin(); it != mFeatures.end(); ++it )
377
mExtent.unionRect( it.value().geometry()->boundingBox() );
383
// --------------------------------
385
QString QgsMemoryProvider::name() const
387
return TEXT_PROVIDER_KEY;
390
QString QgsMemoryProvider::description() const
392
return TEXT_PROVIDER_DESCRIPTION;
395
// --------------------------------
399
* Class factory to return a pointer to a newly created
400
* QgsMemoryProvider object
402
QGISEXTERN QgsMemoryProvider *classFactory( const QString *uri )
404
return new QgsMemoryProvider( *uri );
407
/** Required key function (used to map the plugin to a data store type)
409
QGISEXTERN QString providerKey()
411
return TEXT_PROVIDER_KEY;
415
* Required description function
417
QGISEXTERN QString description()
419
return TEXT_PROVIDER_DESCRIPTION;
423
* Required isProvider function. Used to determine if this shared library
424
* is a data provider plugin
426
QGISEXTERN bool isProvider()