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