~ubuntu-branches/ubuntu/trusty/qgis/trusty

« back to all changes in this revision

Viewing changes to src/providers/memory/qgsmemoryprovider.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Johan Van de Wauw
  • Date: 2010-07-11 20:23:24 UTC
  • mfrom: (3.1.4 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100711202324-5ktghxa7hracohmr
Tags: 1.4.0+12730-3ubuntu1
* Merge from Debian unstable (LP: #540941).
* Fix compilation issues with QT 4.7
* Add build-depends on libqt4-webkit-dev 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
    memoryprovider.cpp - provider with storage in memory
 
3
    ------------------
 
4
    begin                : June 2008
 
5
    copyright            : (C) 2008 by Martin Dobias
 
6
    email                : wonder.sk at gmail.com
 
7
 ***************************************************************************
 
8
 *                                                                         *
 
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.                                   *
 
13
 *                                                                         *
 
14
 ***************************************************************************/
 
15
 
 
16
#include "qgsmemoryprovider.h"
 
17
 
 
18
#include "qgsfeature.h"
 
19
#include "qgsfield.h"
 
20
#include "qgsgeometry.h"
 
21
#include "qgslogger.h"
 
22
#include "qgsspatialindex.h"
 
23
#include "qgscoordinatereferencesystem.h"
 
24
 
 
25
 
 
26
static const QString TEXT_PROVIDER_KEY = "memory";
 
27
static const QString TEXT_PROVIDER_DESCRIPTION = "Memory provider";
 
28
 
 
29
QgsMemoryProvider::QgsMemoryProvider( QString uri )
 
30
    : QgsVectorDataProvider( uri ),
 
31
    mSelectRectGeom( NULL ),
 
32
    mSpatialIndex( NULL )
 
33
{
 
34
  if ( uri == "Point" )
 
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;
 
46
  else
 
47
    mWkbType = QGis::WKBUnknown;
 
48
 
 
49
  mNextFeatureId = 1;
 
50
}
 
51
 
 
52
QgsMemoryProvider::~QgsMemoryProvider()
 
53
{
 
54
  delete mSpatialIndex;
 
55
  delete mSelectRectGeom;
 
56
}
 
57
 
 
58
QString QgsMemoryProvider::storageType() const
 
59
{
 
60
  return "Memory storage";
 
61
}
 
62
 
 
63
bool QgsMemoryProvider::nextFeature( QgsFeature& feature )
 
64
{
 
65
  feature.setValid( false );
 
66
  bool hasFeature = FALSE;
 
67
 
 
68
  // option 1: using spatial index
 
69
  if ( mSelectUsingSpatialIndex )
 
70
  {
 
71
    while ( mSelectSI_Iterator != mSelectSI_Features.end() )
 
72
    {
 
73
      // do exact check in case we're doing intersection
 
74
      if ( mSelectUseIntersect )
 
75
      {
 
76
        if ( mFeatures[*mSelectSI_Iterator].geometry()->intersects( mSelectRectGeom ) )
 
77
          hasFeature = TRUE;
 
78
      }
 
79
      else
 
80
        hasFeature = TRUE;
 
81
 
 
82
      if ( hasFeature )
 
83
        break;
 
84
 
 
85
      mSelectSI_Iterator++;
 
86
    }
 
87
 
 
88
    // copy feature
 
89
    if ( hasFeature )
 
90
    {
 
91
      feature = mFeatures[*mSelectSI_Iterator];
 
92
      mSelectSI_Iterator++;
 
93
    }
 
94
    return hasFeature;
 
95
  }
 
96
 
 
97
  // option 2: not using spatial index
 
98
  while ( mSelectIterator != mFeatures.end() )
 
99
  {
 
100
    if ( mSelectRect.isEmpty() )
 
101
    {
 
102
      // selection rect empty => using all features
 
103
      hasFeature = TRUE;
 
104
    }
 
105
    else
 
106
    {
 
107
      if ( mSelectUseIntersect )
 
108
      {
 
109
        // using exact test when checking for intersection
 
110
        if ( mSelectIterator->geometry()->intersects( mSelectRectGeom ) )
 
111
          hasFeature = TRUE;
 
112
      }
 
113
      else
 
114
      {
 
115
        // check just bounding box against rect when not using intersection
 
116
        if ( mSelectIterator->geometry()->boundingBox().intersects( mSelectRect ) )
 
117
          hasFeature = TRUE;
 
118
      }
 
119
    }
 
120
 
 
121
    if ( hasFeature )
 
122
      break;
 
123
 
 
124
    mSelectIterator++;
 
125
  }
 
126
 
 
127
  // copy feature
 
128
  if ( hasFeature )
 
129
  {
 
130
    feature = mSelectIterator.value();
 
131
    mSelectIterator++;
 
132
    feature.setValid( true );
 
133
  }
 
134
 
 
135
  return hasFeature;
 
136
}
 
137
 
 
138
 
 
139
bool QgsMemoryProvider::featureAtId( int featureId,
 
140
                                     QgsFeature& feature,
 
141
                                     bool fetchGeometry,
 
142
                                     QgsAttributeList fetchAttributes )
 
143
{
 
144
  QgsFeatureMap::iterator it = mFeatures.find( featureId );
 
145
 
 
146
  if ( it == mFeatures.end() )
 
147
    return FALSE;
 
148
 
 
149
  feature = *it;
 
150
  return TRUE;
 
151
}
 
152
 
 
153
 
 
154
void QgsMemoryProvider::select( QgsAttributeList fetchAttributes,
 
155
                                QgsRectangle rect,
 
156
                                bool fetchGeometry,
 
157
                                bool useIntersect )
 
158
{
 
159
  mSelectAttrs = fetchAttributes;
 
160
  mSelectRect = rect;
 
161
  delete mSelectRectGeom;
 
162
  mSelectRectGeom = QgsGeometry::fromRect( rect );
 
163
  mSelectGeometry = fetchGeometry;
 
164
  mSelectUseIntersect = useIntersect;
 
165
 
 
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() )
 
169
  {
 
170
    mSelectUsingSpatialIndex = TRUE;
 
171
    mSelectSI_Features = mSpatialIndex->intersects( rect );
 
172
    QgsDebugMsg( "Features returned by spatial index: " + QString::number( mSelectSI_Features.count() ) );
 
173
  }
 
174
  else
 
175
  {
 
176
    mSelectUsingSpatialIndex = FALSE;
 
177
    mSelectSI_Features.clear();
 
178
  }
 
179
 
 
180
  rewind();
 
181
}
 
182
 
 
183
void QgsMemoryProvider::rewind()
 
184
{
 
185
  if ( mSelectUsingSpatialIndex )
 
186
    mSelectSI_Iterator = mSelectSI_Features.begin();
 
187
  else
 
188
    mSelectIterator = mFeatures.begin();
 
189
}
 
190
 
 
191
 
 
192
QgsRectangle QgsMemoryProvider::extent()
 
193
{
 
194
  return mExtent;
 
195
}
 
196
 
 
197
QGis::WkbType QgsMemoryProvider::geometryType() const
 
198
{
 
199
  return mWkbType;
 
200
}
 
201
 
 
202
long QgsMemoryProvider::featureCount() const
 
203
{
 
204
  return mFeatures.count();
 
205
}
 
206
 
 
207
uint QgsMemoryProvider::fieldCount() const
 
208
{
 
209
  return mFields.count();
 
210
}
 
211
 
 
212
 
 
213
const QgsFieldMap & QgsMemoryProvider::fields() const
 
214
{
 
215
  return mFields;
 
216
}
 
217
 
 
218
bool QgsMemoryProvider::isValid()
 
219
{
 
220
  return ( mWkbType != QGis::WKBUnknown );
 
221
}
 
222
 
 
223
QgsCoordinateReferenceSystem QgsMemoryProvider::crs()
 
224
{
 
225
  // TODO: make provider projection-aware
 
226
  return QgsCoordinateReferenceSystem(); // return default CRS
 
227
}
 
228
 
 
229
 
 
230
bool QgsMemoryProvider::addFeatures( QgsFeatureList & flist )
 
231
{
 
232
  // TODO: sanity checks of fields and geometries
 
233
  for ( QgsFeatureList::iterator it = flist.begin(); it != flist.end(); ++it )
 
234
  {
 
235
    mFeatures[mNextFeatureId] = *it;
 
236
    QgsFeature& newfeat = mFeatures[mNextFeatureId];
 
237
    newfeat.setFeatureId( mNextFeatureId );
 
238
 
 
239
    // update spatial index
 
240
    if ( mSpatialIndex )
 
241
      mSpatialIndex->insertFeature( newfeat );
 
242
 
 
243
    mNextFeatureId++;
 
244
  }
 
245
 
 
246
 
 
247
  updateExtent();
 
248
 
 
249
  return TRUE;
 
250
}
 
251
 
 
252
bool QgsMemoryProvider::deleteFeatures( const QgsFeatureIds & id )
 
253
{
 
254
  for ( QgsFeatureIds::const_iterator it = id.begin(); it != id.end(); ++it )
 
255
  {
 
256
    QgsFeatureMap::iterator fit = mFeatures.find( *it );
 
257
 
 
258
    // check whether such feature exists
 
259
    if ( fit == mFeatures.end() )
 
260
      continue;
 
261
 
 
262
    // update spatial index
 
263
    if ( mSpatialIndex )
 
264
      mSpatialIndex->deleteFeature( *fit );
 
265
 
 
266
    mFeatures.erase( fit );
 
267
  }
 
268
 
 
269
  updateExtent();
 
270
 
 
271
  return TRUE;
 
272
}
 
273
 
 
274
bool QgsMemoryProvider::addAttributes( const QList<QgsField> &attributes )
 
275
{
 
276
  for ( QList<QgsField>::const_iterator it = attributes.begin(); it != attributes.end(); ++it )
 
277
  {
 
278
    switch ( it->type() )
 
279
    {
 
280
      case QVariant::Int:
 
281
      case QVariant::Double:
 
282
      case QVariant::String:
 
283
        break;
 
284
      default:
 
285
        QgsDebugMsg( "Field type not supported: " + it->typeName() );
 
286
        continue;
 
287
    }
 
288
 
 
289
    // add new field as a last one
 
290
    int nextId = -1;
 
291
    for ( QgsFieldMap::iterator it2 = mFields.begin(); it2 != mFields.end(); ++it2 )
 
292
      if ( it2.key() > nextId ) nextId = it2.key();
 
293
    mFields[nextId+1] = *it;
 
294
  }
 
295
  return TRUE;
 
296
}
 
297
 
 
298
bool QgsMemoryProvider::deleteAttributes( const QgsAttributeIds& attributes )
 
299
{
 
300
  for ( QgsAttributeIds::const_iterator it = attributes.begin(); it != attributes.end(); ++it )
 
301
    mFields.remove( *it );
 
302
  return TRUE;
 
303
}
 
304
 
 
305
bool QgsMemoryProvider::changeAttributeValues( const QgsChangedAttributesMap & attr_map )
 
306
{
 
307
  for ( QgsChangedAttributesMap::const_iterator it = attr_map.begin(); it != attr_map.end(); ++it )
 
308
  {
 
309
    QgsFeatureMap::iterator fit = mFeatures.find( it.key() );
 
310
    if ( fit == mFeatures.end() )
 
311
      continue;
 
312
 
 
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() );
 
316
  }
 
317
  return TRUE;
 
318
}
 
319
 
 
320
bool QgsMemoryProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
 
321
{
 
322
  for ( QgsGeometryMap::const_iterator it = geometry_map.begin(); it != geometry_map.end(); ++it )
 
323
  {
 
324
    QgsFeatureMap::iterator fit = mFeatures.find( it.key() );
 
325
    if ( fit == mFeatures.end() )
 
326
      continue;
 
327
 
 
328
    // update spatial index
 
329
    if ( mSpatialIndex )
 
330
      mSpatialIndex->deleteFeature( *fit );
 
331
 
 
332
    fit->setGeometry( it.value() );
 
333
 
 
334
    // update spatial index
 
335
    if ( mSpatialIndex )
 
336
      mSpatialIndex->insertFeature( *fit );
 
337
  }
 
338
 
 
339
  updateExtent();
 
340
 
 
341
  return TRUE;
 
342
}
 
343
 
 
344
bool QgsMemoryProvider::createSpatialIndex()
 
345
{
 
346
  if ( !mSpatialIndex )
 
347
  {
 
348
    mSpatialIndex = new QgsSpatialIndex();
 
349
 
 
350
    // add existing features to index
 
351
    for ( QgsFeatureMap::iterator it = mFeatures.begin(); it != mFeatures.end(); ++it )
 
352
    {
 
353
      mSpatialIndex->insertFeature( *it );
 
354
    }
 
355
  }
 
356
  return TRUE;
 
357
}
 
358
 
 
359
int QgsMemoryProvider::capabilities() const
 
360
{
 
361
  return AddFeatures | DeleteFeatures | ChangeGeometries |
 
362
         ChangeAttributeValues | AddAttributes | DeleteAttributes | CreateSpatialIndex |
 
363
         SelectAtId | SelectGeometryAtId;
 
364
}
 
365
 
 
366
 
 
367
void QgsMemoryProvider::updateExtent()
 
368
{
 
369
  if ( mFeatures.count() == 0 )
 
370
  {
 
371
    mExtent = QgsRectangle();
 
372
  }
 
373
  else
 
374
  {
 
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() );
 
378
  }
 
379
}
 
380
 
 
381
 
 
382
 
 
383
// --------------------------------
 
384
 
 
385
QString  QgsMemoryProvider::name() const
 
386
{
 
387
  return TEXT_PROVIDER_KEY;
 
388
}
 
389
 
 
390
QString  QgsMemoryProvider::description() const
 
391
{
 
392
  return TEXT_PROVIDER_DESCRIPTION;
 
393
}
 
394
 
 
395
// --------------------------------
 
396
 
 
397
 
 
398
/**
 
399
 * Class factory to return a pointer to a newly created
 
400
 * QgsMemoryProvider object
 
401
 */
 
402
QGISEXTERN QgsMemoryProvider *classFactory( const QString *uri )
 
403
{
 
404
  return new QgsMemoryProvider( *uri );
 
405
}
 
406
 
 
407
/** Required key function (used to map the plugin to a data store type)
 
408
 */
 
409
QGISEXTERN QString providerKey()
 
410
{
 
411
  return TEXT_PROVIDER_KEY;
 
412
}
 
413
 
 
414
/**
 
415
 * Required description function
 
416
 */
 
417
QGISEXTERN QString description()
 
418
{
 
419
  return TEXT_PROVIDER_DESCRIPTION;
 
420
}
 
421
 
 
422
/**
 
423
 * Required isProvider function. Used to determine if this shared library
 
424
 * is a data provider plugin
 
425
 */
 
426
QGISEXTERN bool isProvider()
 
427
{
 
428
  return true;
 
429
}