QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
qgsfeature.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsfeature.cpp - Spatial Feature Implementation
3  --------------------------------------
4 Date : 09-Sep-2003
5 Copyright : (C) 2003 by Gary E.Sherman
6 email : sherman at mrcc.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 "qgsfeature.h"
17 #include "qgsfeature_p.h"
18 #include "qgsfields.h"
19 #include "qgsgeometry.h"
20 #include "qgsrectangle.h"
21 #include "qgsfield_p.h" // for approximateMemoryUsage()
22 #include "qgsfields_p.h" // for approximateMemoryUsage()
23 
24 #include "qgsmessagelog.h"
25 #include "qgslogger.h"
26 #include <QDataStream>
27 
28 /***************************************************************************
29  * This class is considered CRITICAL and any change MUST be accompanied with
30  * full unit tests in testqgsfeature.cpp.
31  * See details in QEP #17
32  ****************************************************************************/
33 
34 
35 //
36 // QgsFeature
37 //
38 
40 {
41  d = new QgsFeaturePrivate( id );
42 }
43 
45 {
46  d = new QgsFeaturePrivate( id );
47  d->fields = fields;
48  initAttributes( d->fields.count() );
49 }
50 
51 QgsFeature::QgsFeature( const QgsFeature &rhs ) //NOLINT
52  : d( rhs.d )
53 {
54 }
55 
57 {
58  d = rhs.d;
59  return *this;
60 }
61 
62 bool QgsFeature::operator ==( const QgsFeature &other ) const
63 {
64  if ( d == other.d )
65  return true;
66 
67  if ( d->fid == other.d->fid
68  && d->valid == other.d->valid
69  && d->fields == other.d->fields
70  && d->attributes == other.d->attributes
71  && d->geometry.equals( other.d->geometry )
72  && d->symbol == other.d->symbol )
73  return true;
74 
75  return false;
76 }
77 
78 bool QgsFeature::operator!=( const QgsFeature &other ) const
79 {
80  return !( *this == other );
81 }
82 
84 {
85 }
86 
87 /***************************************************************************
88  * This class is considered CRITICAL and any change MUST be accompanied with
89  * full unit tests in testqgsfeature.cpp.
90  * See details in QEP #17
91  ****************************************************************************/
92 
94 {
95  return d->fid;
96 }
97 
99 {
100  d.detach();
101  d->attributes.remove( field );
102 }
103 
105 {
106  return d->geometry;
107 }
108 
109 /***************************************************************************
110  * This class is considered CRITICAL and any change MUST be accompanied with
111  * full unit tests in testqgsfeature.cpp.
112  * See details in QEP #17
113  ****************************************************************************/
114 
116 {
117  if ( id == d->fid )
118  return;
119 
120  d.detach();
121  d->fid = id;
122  d->valid = true;
123 }
124 
126 {
127  return d->attributes;
128 }
129 
130 QVariantMap QgsFeature::attributeMap() const
131 {
132  QVariantMap res;
133  const int fieldSize = d->fields.size();
134  const int attributeSize = d->attributes.size();
135  if ( fieldSize != attributeSize )
136  {
137  QgsDebugMsg( QStringLiteral( "Attribute size (%1) does not match number of fields (%2)" ).arg( attributeSize ).arg( fieldSize ) );
138  return QVariantMap();
139  }
140 
141  for ( int i = 0; i < attributeSize; ++i )
142  {
143  res[d->fields.at( i ).name()] = d->attributes.at( i );
144  }
145  return res;
146 }
147 
149 {
150  return d->attributes.size();
151 }
152 
154 {
155  if ( attrs == d->attributes )
156  return;
157 
158  d.detach();
159  d->attributes = attrs;
160  d->valid = true;
161 }
162 
163 void QgsFeature::setGeometry( const QgsGeometry &geometry )
164 {
165  d.detach();
166  d->geometry = geometry;
167  d->valid = true;
168 }
169 
170 void QgsFeature::setGeometry( std::unique_ptr<QgsAbstractGeometry> geometry )
171 {
172  d.detach();
173  d->geometry = QgsGeometry( std::move( geometry ) );
174  d->valid = true;
175 }
176 
178 {
180 }
181 
182 /***************************************************************************
183  * This class is considered CRITICAL and any change MUST be accompanied with
184  * full unit tests in testqgsfeature.cpp.
185  * See details in QEP #17
186  ****************************************************************************/
187 
188 void QgsFeature::setFields( const QgsFields &fields, bool init )
189 {
190  d.detach();
191  d->fields = fields;
192  if ( init )
193  {
194  initAttributes( d->fields.count() );
195  }
196 }
197 
199 {
200  return d->fields;
201 }
202 
203 /***************************************************************************
204  * This class is considered CRITICAL and any change MUST be accompanied with
205  * full unit tests in testqgsfeature.cpp.
206  * See details in QEP #17
207  ****************************************************************************/
208 
210 {
211  return d->valid;
212 }
213 
214 void QgsFeature::setValid( bool validity )
215 {
216  if ( d->valid == validity )
217  return;
218 
219  d.detach();
220  d->valid = validity;
221 }
222 
224 {
225  return !d->geometry.isNull();
226 }
227 
228 void QgsFeature::initAttributes( int fieldCount )
229 {
230  d.detach();
231  d->attributes.resize( 0 ); // clears existing elements, while still preserving the currently allocated capacity of the list (unlike clear)
232  // ensures ALL attributes, including previously existing ones are default constructed.
233  // doing it this way also avoids clearing individual QVariants -- which can trigger a detachment. Cheaper just to make a new one.
234  d->attributes.resize( fieldCount );
235 }
236 
237 void QgsFeature::resizeAttributes( int fieldCount )
238 {
239  if ( fieldCount == d->attributes.size() )
240  return;
241 
242  d.detach();
243  d->attributes.resize( fieldCount );
244 }
245 
246 void QgsFeature::padAttributes( int count )
247 {
248  if ( count == 0 )
249  return;
250 
251  d.detach();
252  d->attributes.resize( d->attributes.size() + count );
253 }
254 
255 bool QgsFeature::setAttribute( int idx, const QVariant &value )
256 {
257  if ( idx < 0 || idx >= d->attributes.size() )
258  {
259  QgsMessageLog::logMessage( QObject::tr( "Attribute index %1 out of bounds [0;%2]" ).arg( idx ).arg( d->attributes.size() ), QString(), Qgis::MessageLevel::Warning );
260  return false;
261  }
262 
263  d.detach();
264  d->attributes[idx] = value;
265  d->valid = true;
266  return true;
267 }
268 
269 /***************************************************************************
270  * This class is considered CRITICAL and any change MUST be accompanied with
271  * full unit tests in testqgsfeature.cpp.
272  * See details in QEP #17
273  ****************************************************************************/
274 
275 bool QgsFeature::setAttribute( const QString &name, const QVariant &value )
276 {
277  int fieldIdx = fieldNameIndex( name );
278  if ( fieldIdx == -1 )
279  return false;
280 
281  d.detach();
282  d->attributes[fieldIdx] = value;
283  d->valid = true;
284  return true;
285 }
286 
287 bool QgsFeature::deleteAttribute( const QString &name )
288 {
289  int fieldIdx = fieldNameIndex( name );
290  if ( fieldIdx == -1 )
291  return false;
292 
293  d.detach();
294  d->attributes[fieldIdx].clear();
295  return true;
296 }
297 
298 QVariant QgsFeature::attribute( int fieldIdx ) const
299 {
300  if ( fieldIdx < 0 || fieldIdx >= d->attributes.count() )
301  return QVariant();
302 
303  return d->attributes.at( fieldIdx );
304 }
305 
307 {
308  return d->symbol.get();
309 }
310 
312 {
313  if ( symbol == d->symbol.get() )
314  return;
315 
316  d.detach();
317  d->symbol.reset( symbol );
318 }
319 
320 QVariant QgsFeature::attribute( const QString &name ) const
321 {
322  int fieldIdx = fieldNameIndex( name );
323  if ( fieldIdx == -1 )
324  return QVariant();
325 
326  return d->attributes.at( fieldIdx );
327 }
328 
329 /***************************************************************************
330  * This class is considered CRITICAL and any change MUST be accompanied with
331  * full unit tests in testqgsfeature.cpp.
332  * See details in QEP #17
333  ****************************************************************************/
334 
335 int QgsFeature::fieldNameIndex( const QString &fieldName ) const
336 {
337  return d->fields.lookupField( fieldName );
338 }
339 
340 static size_t qgsQStringApproximateMemoryUsage( const QString &str )
341 {
342  return sizeof( QString ) + str.size() * sizeof( QChar );
343 }
344 
345 static size_t qgsQVariantApproximateMemoryUsage( const QVariant &v )
346 {
347  // A QVariant has a private structure that is a union of things whose larger
348  // size if a long long, and a int
349  size_t s = sizeof( QVariant ) + sizeof( long long ) + sizeof( int );
350  if ( v.type() == QVariant::String )
351  {
352  s += qgsQStringApproximateMemoryUsage( v.toString() );
353  }
354  else if ( v.type() == QVariant::StringList )
355  {
356  for ( const QString &str : v.toStringList() )
357  s += qgsQStringApproximateMemoryUsage( str );
358  }
359  else if ( v.type() == QVariant::List )
360  {
361  for ( const QVariant &subV : v.toList() )
362  s += qgsQVariantApproximateMemoryUsage( subV );
363  }
364  return s;
365 }
366 
368 {
369  size_t s = sizeof( *this ) + sizeof( *d );
370 
371  // Attributes
372  for ( const QVariant &attr : std::as_const( d->attributes ) )
373  {
374  s += qgsQVariantApproximateMemoryUsage( attr );
375  }
376 
377  // Geometry
378  s += sizeof( QAtomicInt ) + sizeof( void * ); // ~ sizeof(QgsGeometryPrivate)
379  // For simplicity we consider that the RAM usage is the one of the WKB
380  // representation
381  s += d->geometry.wkbSize();
382 
383  // Fields
384  s += sizeof( QgsFieldsPrivate );
385  // TODO potentially: take into account the length of the name, comment, default value, etc...
386  s += d->fields.size() * ( sizeof( QgsField ) + sizeof( QgsFieldPrivate ) );
387 
388  return static_cast<int>( s );
389 }
390 
391 
392 /***************************************************************************
393  * This class is considered CRITICAL and any change MUST be accompanied with
394  * full unit tests in testqgsfeature.cpp.
395  * See details in QEP #17
396  ****************************************************************************/
397 
398 QDataStream &operator<<( QDataStream &out, const QgsFeature &feature )
399 {
400  out << feature.id();
401  out << feature.attributes();
402  if ( feature.hasGeometry() )
403  {
404  out << ( feature.geometry() );
405  }
406  else
407  {
408  QgsGeometry geometry;
409  out << geometry;
410  }
411  out << feature.isValid();
412  return out;
413 }
414 
415 QDataStream &operator>>( QDataStream &in, QgsFeature &feature )
416 {
417  QgsFeatureId id;
418  QgsGeometry geometry;
419  bool valid;
420  QgsAttributes attr;
421  in >> id >> attr >> geometry >> valid;
422  feature.setId( id );
423  feature.setGeometry( geometry );
424  feature.setAttributes( attr );
425  feature.setValid( valid );
426  return in;
427 }
428 
429 uint qHash( const QgsFeature &key, uint seed )
430 {
431  uint hash = seed;
432  const auto constAttributes = key.attributes();
433  for ( const QVariant &attr : constAttributes )
434  {
435  hash ^= qHash( attr.toString() );
436  }
437 
438  hash ^= qHash( key.geometry().asWkt() );
439  hash ^= qHash( key.id() );
440 
441  return hash;
442 }
443 
A vector of attributes.
Definition: qgsattributes.h:58
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
Definition: qgsfeature.cpp:255
void resizeAttributes(int fieldCount)
Resizes the attributes attached to this feature to the given number of fields.
Definition: qgsfeature.cpp:237
QgsAttributes attributes
Definition: qgsfeature.h:65
bool operator!=(const QgsFeature &other) const
Compares two features.
Definition: qgsfeature.cpp:78
virtual ~QgsFeature()
Definition: qgsfeature.cpp:83
QgsFields fields
Definition: qgsfeature.h:66
int fieldNameIndex(const QString &fieldName) const
Utility method to get attribute index from name.
Definition: qgsfeature.cpp:335
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
Definition: qgsfeature.cpp:228
void deleteAttribute(int field)
Clear's an attribute's value by its index.
Definition: qgsfeature.cpp:98
QgsFeature & operator=(const QgsFeature &rhs)
Assignment operator.
Definition: qgsfeature.cpp:56
int approximateMemoryUsage() const
Returns the approximate RAM usage of the feature, in bytes.
Definition: qgsfeature.cpp:367
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:153
bool operator==(const QgsFeature &other) const
Compares two features.
Definition: qgsfeature.cpp:62
void setFields(const QgsFields &fields, bool initAttributes=false)
Assigns a field map with the feature to allow attribute access by attribute name.
Definition: qgsfeature.cpp:188
QgsFeature(QgsFeatureId id=FID_NULL)
Constructor for QgsFeature.
Definition: qgsfeature.cpp:39
int attributeCount() const
Returns the number of attributes attached to the feature.
Definition: qgsfeature.cpp:148
void padAttributes(int count)
Resizes the attributes attached to this feature by appending the specified count of NULL values to th...
Definition: qgsfeature.cpp:246
const QgsSymbol * embeddedSymbol() const
Returns the feature's embedded symbology, or nullptr if the feature has no embedded symbol.
Definition: qgsfeature.cpp:306
void setId(QgsFeatureId id)
Sets the feature id for this feature.
Definition: qgsfeature.cpp:115
QgsGeometry geometry
Definition: qgsfeature.h:67
void setEmbeddedSymbol(QgsSymbol *symbol)
Sets the feature's embedded symbol.
Definition: qgsfeature.cpp:311
void clearGeometry()
Removes any geometry associated with the feature.
Definition: qgsfeature.cpp:177
void setValid(bool validity)
Sets the validity of the feature.
Definition: qgsfeature.cpp:214
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:223
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:209
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:320
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:163
QVariantMap attributeMap() const
Returns the feature's attributes as a map of field name to value.
Definition: qgsfeature.cpp:130
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
Container of fields for a vector layer.
Definition: qgsfields.h:45
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:125
QString asWkt(int precision=17) const
Exports the geometry to WKT.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:38
#define str(x)
Definition: qgis.cpp:37
uint qHash(const QgsFeature &key, uint seed)
Definition: qgsfeature.cpp:429
QDataStream & operator<<(QDataStream &out, const QgsFeature &feature)
Writes the feature to stream out. QGIS version compatibility is not guaranteed.
Definition: qgsfeature.cpp:398
QDataStream & operator>>(QDataStream &in, QgsFeature &feature)
Reads a feature from stream in into feature. QGIS version compatibility is not guaranteed.
Definition: qgsfeature.cpp:415
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
const QgsField & field
Definition: qgsfield.h:463
#define QgsDebugMsg(str)
Definition: qgslogger.h:38