QGIS API Documentation  3.6.0-Noosa (5873452)
qgsmemoryprovider.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  memoryprovider.cpp - provider with storage in memory
3  ------------------
4  begin : June 2008
5  copyright : (C) 2008 by Martin Dobias
6  email : wonder dot sk at gmail dot 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"
18 
19 #include "qgsfeature.h"
20 #include "qgsfields.h"
21 #include "qgsgeometry.h"
22 #include "qgslogger.h"
23 #include "qgsspatialindex.h"
25 
26 #include <QUrl>
27 #include <QRegExp>
28 
30 
31 static const QString TEXT_PROVIDER_KEY = QStringLiteral( "memory" );
32 static const QString TEXT_PROVIDER_DESCRIPTION = QStringLiteral( "Memory provider" );
33 
34 QgsMemoryProvider::QgsMemoryProvider( const QString &uri, const ProviderOptions &options )
35  : QgsVectorDataProvider( uri, options )
36 {
37  // Initialize the geometry with the uri to support old style uri's
38  // (ie, just 'point', 'line', 'polygon')
39  QUrl url = QUrl::fromEncoded( uri.toUtf8() );
40  QString geometry;
41  if ( url.hasQueryItem( QStringLiteral( "geometry" ) ) )
42  {
43  geometry = url.queryItemValue( QStringLiteral( "geometry" ) );
44  }
45  else
46  {
47  geometry = url.path();
48  }
49 
50  if ( geometry.compare( QLatin1String( "none" ), Qt::CaseInsensitive ) == 0 )
51  {
52  mWkbType = QgsWkbTypes::NoGeometry;
53  }
54  else
55  {
56  mWkbType = QgsWkbTypes::parseType( geometry );
57  }
58 
59  if ( url.hasQueryItem( QStringLiteral( "crs" ) ) )
60  {
61  QString crsDef = url.queryItemValue( QStringLiteral( "crs" ) );
62  mCrs.createFromString( crsDef );
63  }
64 
65  mNextFeatureId = 1;
66 
67  setNativeTypes( QList< NativeType >()
68  << QgsVectorDataProvider::NativeType( tr( "Whole number (integer)" ), QStringLiteral( "integer" ), QVariant::Int, 0, 10 )
69  // Decimal number from OGR/Shapefile/dbf may come with length up to 32 and
70  // precision up to length-2 = 30 (default, if width is not specified in dbf is length = 24 precision = 15)
71  // We know that double (QVariant::Double) has only 15-16 significant numbers,
72  // but setting that correct limits would disable the use of memory provider with
73  // data from Shapefiles. In any case, the data are handled as doubles.
74  // So the limits set here are not correct but enable use of data from Shapefiles.
75  << QgsVectorDataProvider::NativeType( tr( "Decimal number (real)" ), QStringLiteral( "double" ), QVariant::Double, 0, 32, 0, 30 )
76  << QgsVectorDataProvider::NativeType( tr( "Text (string)" ), QStringLiteral( "string" ), QVariant::String, 0, 255 )
77 
78  // date type
79  << QgsVectorDataProvider::NativeType( tr( "Date" ), QStringLiteral( "date" ), QVariant::Date, -1, -1, -1, -1 )
80  << QgsVectorDataProvider::NativeType( tr( "Time" ), QStringLiteral( "time" ), QVariant::Time, -1, -1, -1, -1 )
81  << QgsVectorDataProvider::NativeType( tr( "Date & Time" ), QStringLiteral( "datetime" ), QVariant::DateTime, -1, -1, -1, -1 )
82 
83  // integer types
84  << QgsVectorDataProvider::NativeType( tr( "Whole number (smallint - 16bit)" ), QStringLiteral( "int2" ), QVariant::Int, -1, -1, 0, 0 )
85  << QgsVectorDataProvider::NativeType( tr( "Whole number (integer - 32bit)" ), QStringLiteral( "int4" ), QVariant::Int, -1, -1, 0, 0 )
86  << QgsVectorDataProvider::NativeType( tr( "Whole number (integer - 64bit)" ), QStringLiteral( "int8" ), QVariant::LongLong, -1, -1, 0, 0 )
87  << QgsVectorDataProvider::NativeType( tr( "Decimal number (numeric)" ), QStringLiteral( "numeric" ), QVariant::Double, 1, 20, 0, 20 )
88  << QgsVectorDataProvider::NativeType( tr( "Decimal number (decimal)" ), QStringLiteral( "decimal" ), QVariant::Double, 1, 20, 0, 20 )
89 
90  // floating point
91  << QgsVectorDataProvider::NativeType( tr( "Decimal number (real)" ), QStringLiteral( "real" ), QVariant::Double, -1, -1, -1, -1 )
92  << QgsVectorDataProvider::NativeType( tr( "Decimal number (double)" ), QStringLiteral( "double precision" ), QVariant::Double, -1, -1, -1, -1 )
93 
94  // string types
95  << QgsVectorDataProvider::NativeType( tr( "Text, unlimited length (text)" ), QStringLiteral( "text" ), QVariant::String, -1, -1, -1, -1 )
96 
97  // boolean
98  << QgsVectorDataProvider::NativeType( tr( "Boolean" ), QStringLiteral( "bool" ), QVariant::Bool )
99 
100  // blob
101  << QgsVectorDataProvider::NativeType( tr( "Binary object (BLOB)" ), QStringLiteral( "binary" ), QVariant::ByteArray )
102 
103  );
104 
105  if ( url.hasQueryItem( QStringLiteral( "field" ) ) )
106  {
107  QList<QgsField> attributes;
108  QRegExp reFieldDef( "\\:"
109  "(int|integer|long|int8|real|double|string|date|time|datetime|binary|bool|boolean)" // type
110  "(?:\\((\\-?\\d+)" // length
111  "(?:\\,(\\-?\\d+))?" // precision
112  "\\))?(\\[\\])?" // array
113  "$", Qt::CaseInsensitive );
114  QStringList fields = url.allQueryItemValues( QStringLiteral( "field" ) );
115  for ( int i = 0; i < fields.size(); i++ )
116  {
117  QString name = QUrl::fromPercentEncoding( fields.at( i ).toUtf8() );
118  QVariant::Type type = QVariant::String;
119  QVariant::Type subType = QVariant::Invalid;
120  QString typeName( QStringLiteral( "string" ) );
121  int length = 255;
122  int precision = 0;
123 
124  int pos = reFieldDef.indexIn( name );
125  if ( pos >= 0 )
126  {
127  name = name.mid( 0, pos );
128  typeName = reFieldDef.cap( 1 ).toLower();
129  if ( typeName == QLatin1String( "int" ) || typeName == QLatin1String( "integer" ) )
130  {
131  type = QVariant::Int;
132  typeName = QStringLiteral( "integer" );
133  length = -1;
134  }
135  else if ( typeName == QLatin1String( "int8" ) || typeName == QLatin1String( "long" ) )
136  {
137  type = QVariant::LongLong;
138  typeName = QStringLiteral( "int8" );
139  length = -1;
140  }
141  else if ( typeName == QLatin1String( "real" ) || typeName == QLatin1String( "double" ) )
142  {
143  type = QVariant::Double;
144  typeName = QStringLiteral( "double" );
145  length = 20;
146  precision = 5;
147  }
148  else if ( typeName == QLatin1String( "date" ) )
149  {
150  type = QVariant::Date;
151  typeName = QStringLiteral( "date" );
152  length = -1;
153  }
154  else if ( typeName == QLatin1String( "time" ) )
155  {
156  type = QVariant::Time;
157  typeName = QStringLiteral( "time" );
158  length = -1;
159  }
160  else if ( typeName == QLatin1String( "datetime" ) )
161  {
162  type = QVariant::DateTime;
163  typeName = QStringLiteral( "datetime" );
164  length = -1;
165  }
166  else if ( typeName == QLatin1String( "bool" ) || typeName == QLatin1String( "boolean" ) )
167  {
168  type = QVariant::Bool;
169  typeName = QStringLiteral( "boolean" );
170  length = -1;
171  }
172  else if ( typeName == QLatin1String( "binary" ) )
173  {
174  type = QVariant::ByteArray;
175  typeName = QStringLiteral( "binary" );
176  length = -1;
177  }
178 
179  if ( !reFieldDef.cap( 2 ).isEmpty() )
180  {
181  length = reFieldDef.cap( 2 ).toInt();
182  }
183  if ( !reFieldDef.cap( 3 ).isEmpty() )
184  {
185  precision = reFieldDef.cap( 3 ).toInt();
186  }
187  if ( !reFieldDef.cap( 4 ).isEmpty() )
188  {
189  //array
190  subType = type;
191  type = ( subType == QVariant::String ? QVariant::StringList : QVariant::List );
192  }
193  }
194  if ( !name.isEmpty() )
195  attributes.append( QgsField( name, type, typeName, length, precision, QString(), subType ) );
196  }
197  addAttributes( attributes );
198  }
199 
200  if ( url.hasQueryItem( QStringLiteral( "index" ) ) && url.queryItemValue( QStringLiteral( "index" ) ) == QLatin1String( "yes" ) )
201  {
202  createSpatialIndex();
203  }
204 
205 }
206 
207 QgsMemoryProvider::~QgsMemoryProvider()
208 {
209  delete mSpatialIndex;
210 }
211 
212 QString QgsMemoryProvider::providerKey()
213 {
214  return TEXT_PROVIDER_KEY;
215 }
216 
217 QString QgsMemoryProvider::providerDescription()
218 {
219  return TEXT_PROVIDER_DESCRIPTION;
220 }
221 
222 QgsMemoryProvider *QgsMemoryProvider::createProvider( const QString &uri, const ProviderOptions &options )
223 {
224  return new QgsMemoryProvider( uri, options );
225 }
226 
227 QgsAbstractFeatureSource *QgsMemoryProvider::featureSource() const
228 {
229  return new QgsMemoryFeatureSource( this );
230 }
231 
232 QString QgsMemoryProvider::dataSourceUri( bool expandAuthConfig ) const
233 {
234  Q_UNUSED( expandAuthConfig )
235 
236  QUrl uri( QStringLiteral( "memory" ) );
237  QString geometry = QgsWkbTypes::displayString( mWkbType );
238  uri.addQueryItem( QStringLiteral( "geometry" ), geometry );
239 
240  if ( mCrs.isValid() )
241  {
242  QString crsDef;
243  QString authid = mCrs.authid();
244  if ( authid.startsWith( QLatin1String( "EPSG:" ) ) )
245  {
246  crsDef = authid;
247  }
248  else
249  {
250  int srid = mCrs.postgisSrid();
251  if ( srid )
252  {
253  crsDef = QStringLiteral( "postgis:%1" ).arg( srid );
254  }
255  else
256  {
257  crsDef = QStringLiteral( "wkt:%1" ).arg( mCrs.toWkt() );
258  }
259  }
260  uri.addQueryItem( QStringLiteral( "crs" ), crsDef );
261  }
262  if ( mSpatialIndex )
263  {
264  uri.addQueryItem( QStringLiteral( "index" ), QStringLiteral( "yes" ) );
265  }
266 
267  QgsAttributeList attrs = const_cast<QgsMemoryProvider *>( this )->attributeIndexes();
268  for ( int i = 0; i < attrs.size(); i++ )
269  {
270  QgsField field = mFields.at( attrs[i] );
271  QString fieldDef = field.name();
272  fieldDef.append( QStringLiteral( ":%2(%3,%4)" ).arg( field.typeName() ).arg( field.length() ).arg( field.precision() ) );
273  uri.addQueryItem( QStringLiteral( "field" ), fieldDef );
274  }
275 
276  return QString( uri.toEncoded() );
277 
278 }
279 
280 QString QgsMemoryProvider::storageType() const
281 {
282  return QStringLiteral( "Memory storage" );
283 }
284 
285 QgsFeatureIterator QgsMemoryProvider::getFeatures( const QgsFeatureRequest &request ) const
286 {
287  return QgsFeatureIterator( new QgsMemoryFeatureIterator( new QgsMemoryFeatureSource( this ), true, request ) );
288 }
289 
290 
291 QgsRectangle QgsMemoryProvider::extent() const
292 {
293  if ( mExtent.isEmpty() && !mFeatures.isEmpty() )
294  {
295  mExtent.setMinimal();
296  if ( mSubsetString.isEmpty() )
297  {
298  // fast way - iterate through all features
299  Q_FOREACH ( const QgsFeature &feat, mFeatures )
300  {
301  if ( feat.hasGeometry() )
302  mExtent.combineExtentWith( feat.geometry().boundingBox() );
303  }
304  }
305  else
306  {
307  QgsFeature f;
308  QgsFeatureIterator fi = getFeatures( QgsFeatureRequest().setNoAttributes() );
309  while ( fi.nextFeature( f ) )
310  {
311  if ( f.hasGeometry() )
312  mExtent.combineExtentWith( f.geometry().boundingBox() );
313  }
314  }
315  }
316  else if ( mFeatures.isEmpty() )
317  {
318  mExtent.setMinimal();
319  }
320 
321  return mExtent;
322 }
323 
324 QgsWkbTypes::Type QgsMemoryProvider::wkbType() const
325 {
326  return mWkbType;
327 }
328 
329 long QgsMemoryProvider::featureCount() const
330 {
331  if ( mSubsetString.isEmpty() )
332  return mFeatures.count();
333 
334  // subset string set, no alternative but testing each feature
335  QgsFeatureIterator fit = QgsFeatureIterator( new QgsMemoryFeatureIterator( new QgsMemoryFeatureSource( this ), true, QgsFeatureRequest().setNoAttributes() ) );
336  int count = 0;
337  QgsFeature feature;
338  while ( fit.nextFeature( feature ) )
339  {
340  count++;
341  }
342  return count;
343 }
344 
345 QgsFields QgsMemoryProvider::fields() const
346 {
347  return mFields;
348 }
349 
350 bool QgsMemoryProvider::isValid() const
351 {
352  return ( mWkbType != QgsWkbTypes::Unknown );
353 }
354 
356 {
357  // TODO: make provider projection-aware
358  return mCrs; // return default CRS
359 }
360 
361 
362 bool QgsMemoryProvider::addFeatures( QgsFeatureList &flist, Flags )
363 {
364  bool result = true;
365  // whether or not to update the layer extent on the fly as we add features
366  bool updateExtent = mFeatures.isEmpty() || !mExtent.isEmpty();
367 
368  int fieldCount = mFields.count();
369 
370  // TODO: sanity checks of fields
371  for ( QgsFeatureList::iterator it = flist.begin(); it != flist.end(); ++it )
372  {
373  it->setId( mNextFeatureId );
374  it->setValid( true );
375  if ( it->attributes().count() < fieldCount )
376  {
377  // ensure features have the correct number of attributes by padding
378  // them with null attributes for missing values
379  QgsAttributes attributes = it->attributes();
380  for ( int i = it->attributes().count(); i < mFields.count(); ++i )
381  {
382  attributes.append( QVariant( mFields.at( i ).type() ) );
383  }
384  it->setAttributes( attributes );
385  }
386  else if ( it->attributes().count() > fieldCount )
387  {
388  // too many attributes
389  pushError( tr( "Feature has too many attributes (expecting %1, received %2)" ).arg( fieldCount ).arg( it->attributes().count() ) );
390  QgsAttributes attributes = it->attributes();
391  attributes.resize( mFields.count() );
392  it->setAttributes( attributes );
393  }
394 
395  if ( it->hasGeometry() && mWkbType == QgsWkbTypes::NoGeometry )
396  {
397  it->clearGeometry();
398  }
399  else if ( it->hasGeometry() && QgsWkbTypes::geometryType( it->geometry().wkbType() ) !=
400  QgsWkbTypes::geometryType( mWkbType ) )
401  {
402  pushError( tr( "Could not add feature with geometry type %1 to layer of type %2" ).arg( QgsWkbTypes::displayString( it->geometry().wkbType() ),
403  QgsWkbTypes::displayString( mWkbType ) ) );
404  result = false;
405  continue;
406  }
407 
408  mFeatures.insert( mNextFeatureId, *it );
409 
410  if ( it->hasGeometry() )
411  {
412  if ( updateExtent )
413  mExtent.combineExtentWith( it->geometry().boundingBox() );
414 
415  // update spatial index
416  if ( mSpatialIndex )
417  mSpatialIndex->addFeature( *it );
418  }
419 
420  mNextFeatureId++;
421  }
422 
423  clearMinMaxCache();
424  return result;
425 }
426 
427 bool QgsMemoryProvider::deleteFeatures( const QgsFeatureIds &id )
428 {
429  for ( QgsFeatureIds::const_iterator it = id.begin(); it != id.end(); ++it )
430  {
431  QgsFeatureMap::iterator fit = mFeatures.find( *it );
432 
433  // check whether such feature exists
434  if ( fit == mFeatures.end() )
435  continue;
436 
437  // update spatial index
438  if ( mSpatialIndex )
439  mSpatialIndex->deleteFeature( *fit );
440 
441  mFeatures.erase( fit );
442  }
443 
444  updateExtents();
445  clearMinMaxCache();
446 
447  return true;
448 }
449 
450 bool QgsMemoryProvider::addAttributes( const QList<QgsField> &attributes )
451 {
452  for ( QList<QgsField>::const_iterator it = attributes.begin(); it != attributes.end(); ++it )
453  {
454  switch ( it->type() )
455  {
456  case QVariant::Int:
457  case QVariant::Double:
458  case QVariant::String:
459  case QVariant::Date:
460  case QVariant::Time:
461  case QVariant::DateTime:
462  case QVariant::LongLong:
463  case QVariant::StringList:
464  case QVariant::List:
465  case QVariant::Bool:
466  case QVariant::ByteArray:
467  break;
468  default:
469  QgsDebugMsg( "Field type not supported: " + it->typeName() );
470  continue;
471  }
472  // add new field as a last one
473  mFields.append( *it );
474 
475  for ( QgsFeatureMap::iterator fit = mFeatures.begin(); fit != mFeatures.end(); ++fit )
476  {
477  QgsFeature &f = fit.value();
478  QgsAttributes attr = f.attributes();
479  attr.append( QVariant() );
480  f.setAttributes( attr );
481  }
482  }
483  return true;
484 }
485 
486 bool QgsMemoryProvider::renameAttributes( const QgsFieldNameMap &renamedAttributes )
487 {
488  QgsFieldNameMap::const_iterator renameIt = renamedAttributes.constBegin();
489  bool result = true;
490  for ( ; renameIt != renamedAttributes.constEnd(); ++renameIt )
491  {
492  int fieldIndex = renameIt.key();
493  if ( fieldIndex < 0 || fieldIndex >= mFields.count() )
494  {
495  result = false;
496  continue;
497  }
498  if ( mFields.indexFromName( renameIt.value() ) >= 0 )
499  {
500  //field name already in use
501  result = false;
502  continue;
503  }
504 
505  mFields[ fieldIndex ].setName( renameIt.value() );
506  }
507  return result;
508 }
509 
510 bool QgsMemoryProvider::deleteAttributes( const QgsAttributeIds &attributes )
511 {
512  QList<int> attrIdx = attributes.toList();
513  std::sort( attrIdx.begin(), attrIdx.end(), std::greater<int>() );
514 
515  // delete attributes one-by-one with decreasing index
516  for ( QList<int>::const_iterator it = attrIdx.constBegin(); it != attrIdx.constEnd(); ++it )
517  {
518  int idx = *it;
519  mFields.remove( idx );
520 
521  for ( QgsFeatureMap::iterator fit = mFeatures.begin(); fit != mFeatures.end(); ++fit )
522  {
523  QgsFeature &f = fit.value();
524  QgsAttributes attr = f.attributes();
525  attr.remove( idx );
526  f.setAttributes( attr );
527  }
528  }
529  clearMinMaxCache();
530  return true;
531 }
532 
533 bool QgsMemoryProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_map )
534 {
535  for ( QgsChangedAttributesMap::const_iterator it = attr_map.begin(); it != attr_map.end(); ++it )
536  {
537  QgsFeatureMap::iterator fit = mFeatures.find( it.key() );
538  if ( fit == mFeatures.end() )
539  continue;
540 
541  const QgsAttributeMap &attrs = it.value();
542  for ( QgsAttributeMap::const_iterator it2 = attrs.constBegin(); it2 != attrs.constEnd(); ++it2 )
543  fit->setAttribute( it2.key(), it2.value() );
544  }
545  clearMinMaxCache();
546  return true;
547 }
548 
549 bool QgsMemoryProvider::changeGeometryValues( const QgsGeometryMap &geometry_map )
550 {
551  for ( QgsGeometryMap::const_iterator it = geometry_map.begin(); it != geometry_map.end(); ++it )
552  {
553  QgsFeatureMap::iterator fit = mFeatures.find( it.key() );
554  if ( fit == mFeatures.end() )
555  continue;
556 
557  // update spatial index
558  if ( mSpatialIndex )
559  mSpatialIndex->deleteFeature( *fit );
560 
561  fit->setGeometry( it.value() );
562 
563  // update spatial index
564  if ( mSpatialIndex )
565  mSpatialIndex->addFeature( *fit );
566  }
567 
568  updateExtents();
569 
570  return true;
571 }
572 
573 QString QgsMemoryProvider::subsetString() const
574 {
575  return mSubsetString;
576 }
577 
578 bool QgsMemoryProvider::setSubsetString( const QString &theSQL, bool updateFeatureCount )
579 {
580  Q_UNUSED( updateFeatureCount );
581 
582  if ( !theSQL.isEmpty() )
583  {
584  QgsExpression tempExpression( theSQL );
585  if ( tempExpression.hasParserError() )
586  return false;
587  }
588 
589  if ( theSQL == mSubsetString )
590  return true;
591 
592  mSubsetString = theSQL;
593  clearMinMaxCache();
594  mExtent.setMinimal();
595 
596  emit dataChanged();
597  return true;
598 }
599 
600 bool QgsMemoryProvider::createSpatialIndex()
601 {
602  if ( !mSpatialIndex )
603  {
604  mSpatialIndex = new QgsSpatialIndex();
605 
606  // add existing features to index
607  for ( QgsFeatureMap::iterator it = mFeatures.begin(); it != mFeatures.end(); ++it )
608  {
609  mSpatialIndex->addFeature( *it );
610  }
611  }
612  return true;
613 }
614 
615 QgsVectorDataProvider::Capabilities QgsMemoryProvider::capabilities() const
616 {
617  return AddFeatures | DeleteFeatures | ChangeGeometries |
618  ChangeAttributeValues | AddAttributes | DeleteAttributes | RenameAttributes | CreateSpatialIndex |
619  SelectAtId | CircularGeometries | FastTruncate;
620 }
621 
622 bool QgsMemoryProvider::truncate()
623 {
624  mFeatures.clear();
625  clearMinMaxCache();
626  mExtent.setMinimal();
627  return true;
628 }
629 
630 void QgsMemoryProvider::updateExtents()
631 {
632  mExtent.setMinimal();
633 }
634 
635 QString QgsMemoryProvider::name() const
636 {
637  return TEXT_PROVIDER_KEY;
638 }
639 
640 QString QgsMemoryProvider::description() const
641 {
642  return TEXT_PROVIDER_DESCRIPTION;
643 }
644 
645 
Class for parsing and evaluation of expressions (formerly called "search strings").
Wrapper for iterator of features from vector data provider or vector layer.
QMap< QgsFeatureId, QgsGeometry > QgsGeometryMap
Definition: qgsfeature.h:566
int precision
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
void setMinimal()
Set a rectangle so that min corner is at max and max corner is at min.
Definition: qgsrectangle.h:151
QString name
Definition: qgsfield.h:58
int precision
Definition: qgsfield.h:55
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:571
Container of fields for a vector layer.
Definition: qgsfields.h:42
void setAttributes(const QgsAttributes &attrs)
Sets the feature&#39;s attributes.
Definition: qgsfeature.cpp:127
static Type parseType(const QString &wktStr)
Attempts to extract the WKB type from a WKT string.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
const QgsCoordinateReferenceSystem & crs
const QgsAttributeList & attributeIndexes
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:197
int length
Definition: qgsfield.h:54
QSet< int > QgsAttributeIds
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
QString typeName() const
Gets the field type.
Definition: qgsfield.cpp:105
const QString & typeName
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
static GeometryType geometryType(Type type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:665
This class wraps a request for features to a vector layer (or directly its vector data provider)...
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:48
Base class that can be used for any class that is capable of returning features.
QMap< int, QString > QgsFieldNameMap
Definition: qgsattributes.h:44
A spatial index for QgsFeature objects.
QMap< QgsFeatureId, QgsAttributeMap > QgsChangedAttributesMap
Definition: qgsfeature.h:557
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
This class represents a coordinate reference system (CRS).
static QString displayString(Type type)
Returns a display string type for a WKB type, e.g., the geometry name used in WKT geometry representa...
QgsGeometry geometry
Definition: qgsfeature.h:67
QList< int > QgsAttributeList
Definition: qgsfield.h:27
bool nextFeature(QgsFeature &f)
This is the base class for vector data providers.
A vector of attributes.
Definition: qgsattributes.h:57
QgsAttributes attributes
Definition: qgsfeature.h:65