QGIS API Documentation  3.21.0-Master (909859188c)
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 
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 
131 {
132  return d->attributes.size();
133 }
134 
136 {
137  if ( attrs == d->attributes )
138  return;
139 
140  d.detach();
141  d->attributes = attrs;
142  d->valid = true;
143 }
144 
145 void QgsFeature::setGeometry( const QgsGeometry &geometry )
146 {
147  d.detach();
148  d->geometry = geometry;
149  d->valid = true;
150 }
151 
152 void QgsFeature::setGeometry( std::unique_ptr<QgsAbstractGeometry> geometry )
153 {
154  d.detach();
155  d->geometry = QgsGeometry( std::move( geometry ) );
156  d->valid = true;
157 }
158 
160 {
162 }
163 
164 /***************************************************************************
165  * This class is considered CRITICAL and any change MUST be accompanied with
166  * full unit tests in testqgsfeature.cpp.
167  * See details in QEP #17
168  ****************************************************************************/
169 
170 void QgsFeature::setFields( const QgsFields &fields, bool init )
171 {
172  d.detach();
173  d->fields = fields;
174  if ( init )
175  {
176  initAttributes( d->fields.count() );
177  }
178 }
179 
181 {
182  return d->fields;
183 }
184 
185 /***************************************************************************
186  * This class is considered CRITICAL and any change MUST be accompanied with
187  * full unit tests in testqgsfeature.cpp.
188  * See details in QEP #17
189  ****************************************************************************/
190 
192 {
193  return d->valid;
194 }
195 
196 void QgsFeature::setValid( bool validity )
197 {
198  if ( d->valid == validity )
199  return;
200 
201  d.detach();
202  d->valid = validity;
203 }
204 
206 {
207  return !d->geometry.isNull();
208 }
209 
210 void QgsFeature::initAttributes( int fieldCount )
211 {
212  d.detach();
213  d->attributes.resize( 0 ); // clears existing elements, while still preserving the currently allocated capacity of the list (unlike clear)
214  // ensures ALL attributes, including previously existing ones are default constructed.
215  // doing it this way also avoids clearing individual QVariants -- which can trigger a detachment. Cheaper just to make a new one.
216  d->attributes.resize( fieldCount );
217 }
218 
219 void QgsFeature::resizeAttributes( int fieldCount )
220 {
221  if ( fieldCount == d->attributes.size() )
222  return;
223 
224  d.detach();
225  d->attributes.resize( fieldCount );
226 }
227 
228 void QgsFeature::padAttributes( int count )
229 {
230  if ( count == 0 )
231  return;
232 
233  d.detach();
234  d->attributes.resize( d->attributes.size() + count );
235 }
236 
237 bool QgsFeature::setAttribute( int idx, const QVariant &value )
238 {
239  if ( idx < 0 || idx >= d->attributes.size() )
240  {
241  QgsMessageLog::logMessage( QObject::tr( "Attribute index %1 out of bounds [0;%2]" ).arg( idx ).arg( d->attributes.size() ), QString(), Qgis::MessageLevel::Warning );
242  return false;
243  }
244 
245  d.detach();
246  d->attributes[idx] = value;
247  d->valid = true;
248  return true;
249 }
250 
251 /***************************************************************************
252  * This class is considered CRITICAL and any change MUST be accompanied with
253  * full unit tests in testqgsfeature.cpp.
254  * See details in QEP #17
255  ****************************************************************************/
256 
257 bool QgsFeature::setAttribute( const QString &name, const QVariant &value )
258 {
259  int fieldIdx = fieldNameIndex( name );
260  if ( fieldIdx == -1 )
261  return false;
262 
263  d.detach();
264  d->attributes[fieldIdx] = value;
265  d->valid = true;
266  return true;
267 }
268 
269 bool QgsFeature::deleteAttribute( const QString &name )
270 {
271  int fieldIdx = fieldNameIndex( name );
272  if ( fieldIdx == -1 )
273  return false;
274 
275  d.detach();
276  d->attributes[fieldIdx].clear();
277  return true;
278 }
279 
280 QVariant QgsFeature::attribute( int fieldIdx ) const
281 {
282  if ( fieldIdx < 0 || fieldIdx >= d->attributes.count() )
283  return QVariant();
284 
285  return d->attributes.at( fieldIdx );
286 }
287 
289 {
290  return d->symbol.get();
291 }
292 
294 {
295  if ( symbol == d->symbol.get() )
296  return;
297 
298  d.detach();
299  d->symbol.reset( symbol );
300 }
301 
302 QVariant QgsFeature::attribute( const QString &name ) const
303 {
304  int fieldIdx = fieldNameIndex( name );
305  if ( fieldIdx == -1 )
306  return QVariant();
307 
308  return d->attributes.at( fieldIdx );
309 }
310 
311 /***************************************************************************
312  * This class is considered CRITICAL and any change MUST be accompanied with
313  * full unit tests in testqgsfeature.cpp.
314  * See details in QEP #17
315  ****************************************************************************/
316 
317 int QgsFeature::fieldNameIndex( const QString &fieldName ) const
318 {
319  return d->fields.lookupField( fieldName );
320 }
321 
322 static size_t qgsQStringApproximateMemoryUsage( const QString &str )
323 {
324  return sizeof( QString ) + str.size() * sizeof( QChar );
325 }
326 
327 static size_t qgsQVariantApproximateMemoryUsage( const QVariant &v )
328 {
329  // A QVariant has a private structure that is a union of things whose larger
330  // size if a long long, and a int
331  size_t s = sizeof( QVariant ) + sizeof( long long ) + sizeof( int );
332  if ( v.type() == QVariant::String )
333  {
334  s += qgsQStringApproximateMemoryUsage( v.toString() );
335  }
336  else if ( v.type() == QVariant::StringList )
337  {
338  for ( const QString &str : v.toStringList() )
339  s += qgsQStringApproximateMemoryUsage( str );
340  }
341  else if ( v.type() == QVariant::List )
342  {
343  for ( const QVariant &subV : v.toList() )
344  s += qgsQVariantApproximateMemoryUsage( subV );
345  }
346  return s;
347 }
348 
350 {
351  size_t s = sizeof( *this ) + sizeof( *d );
352 
353  // Attributes
354  for ( const QVariant &attr : std::as_const( d->attributes ) )
355  {
356  s += qgsQVariantApproximateMemoryUsage( attr );
357  }
358 
359  // Geometry
360  s += sizeof( QAtomicInt ) + sizeof( void * ); // ~ sizeof(QgsGeometryPrivate)
361  // For simplicity we consider that the RAM usage is the one of the WKB
362  // representation
363  s += d->geometry.wkbSize();
364 
365  // Fields
366  s += sizeof( QgsFieldsPrivate );
367  // TODO potentially: take into account the length of the name, comment, default value, etc...
368  s += d->fields.size() * ( sizeof( QgsField ) + sizeof( QgsFieldPrivate ) );
369 
370  return static_cast<int>( s );
371 }
372 
373 
374 /***************************************************************************
375  * This class is considered CRITICAL and any change MUST be accompanied with
376  * full unit tests in testqgsfeature.cpp.
377  * See details in QEP #17
378  ****************************************************************************/
379 
380 QDataStream &operator<<( QDataStream &out, const QgsFeature &feature )
381 {
382  out << feature.id();
383  out << feature.attributes();
384  if ( feature.hasGeometry() )
385  {
386  out << ( feature.geometry() );
387  }
388  else
389  {
390  QgsGeometry geometry;
391  out << geometry;
392  }
393  out << feature.isValid();
394  return out;
395 }
396 
397 QDataStream &operator>>( QDataStream &in, QgsFeature &feature )
398 {
399  QgsFeatureId id;
400  QgsGeometry geometry;
401  bool valid;
402  QgsAttributes attr;
403  in >> id >> attr >> geometry >> valid;
404  feature.setId( id );
405  feature.setGeometry( geometry );
406  feature.setAttributes( attr );
407  feature.setValid( valid );
408  return in;
409 }
410 
411 uint qHash( const QgsFeature &key, uint seed )
412 {
413  uint hash = seed;
414  const auto constAttributes = key.attributes();
415  for ( const QVariant &attr : constAttributes )
416  {
417  hash ^= qHash( attr.toString() );
418  }
419 
420  hash ^= qHash( key.geometry().asWkt() );
421  hash ^= qHash( key.id() );
422 
423  return hash;
424 }
425 
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:237
void resizeAttributes(int fieldCount)
Resizes the attributes attached to this feature to the given number of fields.
Definition: qgsfeature.cpp:219
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:317
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
Definition: qgsfeature.cpp:210
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:349
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:135
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:170
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:130
void padAttributes(int count)
Resizes the attributes attached to this feature by appending the specified count of NULL values to th...
Definition: qgsfeature.cpp:228
const QgsSymbol * embeddedSymbol() const
Returns the feature's embedded symbology, or nullptr if the feature has no embedded symbol.
Definition: qgsfeature.cpp:288
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:293
void clearGeometry()
Removes any geometry associated with the feature.
Definition: qgsfeature.cpp:159
void setValid(bool validity)
Sets the validity of the feature.
Definition: qgsfeature.cpp:196
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:205
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:191
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:302
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:145
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:124
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:411
QDataStream & operator<<(QDataStream &out, const QgsFeature &feature)
Writes the feature to stream out. QGIS version compatibility is not guaranteed.
Definition: qgsfeature.cpp:380
QDataStream & operator>>(QDataStream &in, QgsFeature &feature)
Reads a feature from stream in into feature. QGIS version compatibility is not guaranteed.
Definition: qgsfeature.cpp:397
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