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