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