QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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  const auto constMFeatures = mFeatures;
300  for ( const QgsFeature &feat : constMFeatures )
301  {
302  if ( feat.hasGeometry() )
303  mExtent.combineExtentWith( feat.geometry().boundingBox() );
304  }
305  }
306  else
307  {
308  QgsFeature f;
309  QgsFeatureIterator fi = getFeatures( QgsFeatureRequest().setNoAttributes() );
310  while ( fi.nextFeature( f ) )
311  {
312  if ( f.hasGeometry() )
313  mExtent.combineExtentWith( f.geometry().boundingBox() );
314  }
315  }
316  }
317  else if ( mFeatures.isEmpty() )
318  {
319  mExtent.setMinimal();
320  }
321 
322  return mExtent;
323 }
324 
325 QgsWkbTypes::Type QgsMemoryProvider::wkbType() const
326 {
327  return mWkbType;
328 }
329 
330 long QgsMemoryProvider::featureCount() const
331 {
332  if ( mSubsetString.isEmpty() )
333  return mFeatures.count();
334 
335  // subset string set, no alternative but testing each feature
336  QgsFeatureIterator fit = QgsFeatureIterator( new QgsMemoryFeatureIterator( new QgsMemoryFeatureSource( this ), true, QgsFeatureRequest().setNoAttributes() ) );
337  int count = 0;
338  QgsFeature feature;
339  while ( fit.nextFeature( feature ) )
340  {
341  count++;
342  }
343  return count;
344 }
345 
346 QgsFields QgsMemoryProvider::fields() const
347 {
348  return mFields;
349 }
350 
351 bool QgsMemoryProvider::isValid() const
352 {
353  return ( mWkbType != QgsWkbTypes::Unknown );
354 }
355 
357 {
358  // TODO: make provider projection-aware
359  return mCrs; // return default CRS
360 }
361 
362 
363 bool QgsMemoryProvider::addFeatures( QgsFeatureList &flist, Flags )
364 {
365  bool result = true;
366  // whether or not to update the layer extent on the fly as we add features
367  bool updateExtent = mFeatures.isEmpty() || !mExtent.isEmpty();
368 
369  int fieldCount = mFields.count();
370 
371  // TODO: sanity checks of fields
372  for ( QgsFeatureList::iterator it = flist.begin(); it != flist.end(); ++it )
373  {
374  it->setId( mNextFeatureId );
375  it->setValid( true );
376  if ( it->attributes().count() < fieldCount )
377  {
378  // ensure features have the correct number of attributes by padding
379  // them with null attributes for missing values
380  QgsAttributes attributes = it->attributes();
381  for ( int i = it->attributes().count(); i < mFields.count(); ++i )
382  {
383  attributes.append( QVariant( mFields.at( i ).type() ) );
384  }
385  it->setAttributes( attributes );
386  }
387  else if ( it->attributes().count() > fieldCount )
388  {
389  // too many attributes
390  pushError( tr( "Feature has too many attributes (expecting %1, received %2)" ).arg( fieldCount ).arg( it->attributes().count() ) );
391  QgsAttributes attributes = it->attributes();
392  attributes.resize( mFields.count() );
393  it->setAttributes( attributes );
394  }
395 
396  if ( it->hasGeometry() && mWkbType == QgsWkbTypes::NoGeometry )
397  {
398  it->clearGeometry();
399  }
400  else if ( it->hasGeometry() && QgsWkbTypes::geometryType( it->geometry().wkbType() ) !=
401  QgsWkbTypes::geometryType( mWkbType ) )
402  {
403  pushError( tr( "Could not add feature with geometry type %1 to layer of type %2" ).arg( QgsWkbTypes::displayString( it->geometry().wkbType() ),
404  QgsWkbTypes::displayString( mWkbType ) ) );
405  result = false;
406  continue;
407  }
408 
409  mFeatures.insert( mNextFeatureId, *it );
410 
411  if ( it->hasGeometry() )
412  {
413  if ( updateExtent )
414  mExtent.combineExtentWith( it->geometry().boundingBox() );
415 
416  // update spatial index
417  if ( mSpatialIndex )
418  mSpatialIndex->addFeature( *it );
419  }
420 
421  mNextFeatureId++;
422  }
423 
424  clearMinMaxCache();
425  return result;
426 }
427 
428 bool QgsMemoryProvider::deleteFeatures( const QgsFeatureIds &id )
429 {
430  for ( QgsFeatureIds::const_iterator it = id.begin(); it != id.end(); ++it )
431  {
432  QgsFeatureMap::iterator fit = mFeatures.find( *it );
433 
434  // check whether such feature exists
435  if ( fit == mFeatures.end() )
436  continue;
437 
438  // update spatial index
439  if ( mSpatialIndex )
440  mSpatialIndex->deleteFeature( *fit );
441 
442  mFeatures.erase( fit );
443  }
444 
445  updateExtents();
446  clearMinMaxCache();
447 
448  return true;
449 }
450 
451 bool QgsMemoryProvider::addAttributes( const QList<QgsField> &attributes )
452 {
453  for ( QList<QgsField>::const_iterator it = attributes.begin(); it != attributes.end(); ++it )
454  {
455  switch ( it->type() )
456  {
457  case QVariant::Int:
458  case QVariant::Double:
459  case QVariant::String:
460  case QVariant::Date:
461  case QVariant::Time:
462  case QVariant::DateTime:
463  case QVariant::LongLong:
464  case QVariant::StringList:
465  case QVariant::List:
466  case QVariant::Bool:
467  case QVariant::ByteArray:
468  break;
469  default:
470  QgsDebugMsg( "Field type not supported: " + it->typeName() );
471  continue;
472  }
473  // add new field as a last one
474  mFields.append( *it );
475 
476  for ( QgsFeatureMap::iterator fit = mFeatures.begin(); fit != mFeatures.end(); ++fit )
477  {
478  QgsFeature &f = fit.value();
479  QgsAttributes attr = f.attributes();
480  attr.append( QVariant() );
481  f.setAttributes( attr );
482  }
483  }
484  return true;
485 }
486 
487 bool QgsMemoryProvider::renameAttributes( const QgsFieldNameMap &renamedAttributes )
488 {
489  QgsFieldNameMap::const_iterator renameIt = renamedAttributes.constBegin();
490  bool result = true;
491  for ( ; renameIt != renamedAttributes.constEnd(); ++renameIt )
492  {
493  int fieldIndex = renameIt.key();
494  if ( fieldIndex < 0 || fieldIndex >= mFields.count() )
495  {
496  result = false;
497  continue;
498  }
499  if ( mFields.indexFromName( renameIt.value() ) >= 0 )
500  {
501  //field name already in use
502  result = false;
503  continue;
504  }
505 
506  mFields[ fieldIndex ].setName( renameIt.value() );
507  }
508  return result;
509 }
510 
511 bool QgsMemoryProvider::deleteAttributes( const QgsAttributeIds &attributes )
512 {
513  QList<int> attrIdx = attributes.toList();
514  std::sort( attrIdx.begin(), attrIdx.end(), std::greater<int>() );
515 
516  // delete attributes one-by-one with decreasing index
517  for ( QList<int>::const_iterator it = attrIdx.constBegin(); it != attrIdx.constEnd(); ++it )
518  {
519  int idx = *it;
520  mFields.remove( idx );
521 
522  for ( QgsFeatureMap::iterator fit = mFeatures.begin(); fit != mFeatures.end(); ++fit )
523  {
524  QgsFeature &f = fit.value();
525  QgsAttributes attr = f.attributes();
526  attr.remove( idx );
527  f.setAttributes( attr );
528  }
529  }
530  clearMinMaxCache();
531  return true;
532 }
533 
534 bool QgsMemoryProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_map )
535 {
536  for ( QgsChangedAttributesMap::const_iterator it = attr_map.begin(); it != attr_map.end(); ++it )
537  {
538  QgsFeatureMap::iterator fit = mFeatures.find( it.key() );
539  if ( fit == mFeatures.end() )
540  continue;
541 
542  const QgsAttributeMap &attrs = it.value();
543  for ( QgsAttributeMap::const_iterator it2 = attrs.constBegin(); it2 != attrs.constEnd(); ++it2 )
544  fit->setAttribute( it2.key(), it2.value() );
545  }
546  clearMinMaxCache();
547  return true;
548 }
549 
550 bool QgsMemoryProvider::changeGeometryValues( const QgsGeometryMap &geometry_map )
551 {
552  for ( QgsGeometryMap::const_iterator it = geometry_map.begin(); it != geometry_map.end(); ++it )
553  {
554  QgsFeatureMap::iterator fit = mFeatures.find( it.key() );
555  if ( fit == mFeatures.end() )
556  continue;
557 
558  // update spatial index
559  if ( mSpatialIndex )
560  mSpatialIndex->deleteFeature( *fit );
561 
562  fit->setGeometry( it.value() );
563 
564  // update spatial index
565  if ( mSpatialIndex )
566  mSpatialIndex->addFeature( *fit );
567  }
568 
569  updateExtents();
570 
571  return true;
572 }
573 
574 QString QgsMemoryProvider::subsetString() const
575 {
576  return mSubsetString;
577 }
578 
579 bool QgsMemoryProvider::setSubsetString( const QString &theSQL, bool updateFeatureCount )
580 {
581  Q_UNUSED( updateFeatureCount )
582 
583  if ( !theSQL.isEmpty() )
584  {
585  QgsExpression tempExpression( theSQL );
586  if ( tempExpression.hasParserError() )
587  return false;
588  }
589 
590  if ( theSQL == mSubsetString )
591  return true;
592 
593  mSubsetString = theSQL;
594  clearMinMaxCache();
595  mExtent.setMinimal();
596 
597  emit dataChanged();
598  return true;
599 }
600 
601 bool QgsMemoryProvider::createSpatialIndex()
602 {
603  if ( !mSpatialIndex )
604  {
605  mSpatialIndex = new QgsSpatialIndex();
606 
607  // add existing features to index
608  for ( QgsFeatureMap::iterator it = mFeatures.begin(); it != mFeatures.end(); ++it )
609  {
610  mSpatialIndex->addFeature( *it );
611  }
612  }
613  return true;
614 }
615 
616 QgsVectorDataProvider::Capabilities QgsMemoryProvider::capabilities() const
617 {
618  return AddFeatures | DeleteFeatures | ChangeGeometries |
619  ChangeAttributeValues | AddAttributes | DeleteAttributes | RenameAttributes | CreateSpatialIndex |
620  SelectAtId | CircularGeometries | FastTruncate;
621 }
622 
623 bool QgsMemoryProvider::truncate()
624 {
625  mFeatures.clear();
626  clearMinMaxCache();
627  mExtent.setMinimal();
628  return true;
629 }
630 
631 void QgsMemoryProvider::updateExtents()
632 {
633  mExtent.setMinimal();
634 }
635 
636 QString QgsMemoryProvider::name() const
637 {
638  return TEXT_PROVIDER_KEY;
639 }
640 
641 QString QgsMemoryProvider::description() const
642 {
643  return TEXT_PROVIDER_DESCRIPTION;
644 }
645 
646 
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:666
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