QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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  if ( attrs == d->attributes )
132  return;
133 
134  d.detach();
135  d->attributes = attrs;
136  d->valid = true;
137 }
138 
139 void QgsFeature::setGeometry( const QgsGeometry &geometry )
140 {
141  d.detach();
142  d->geometry = geometry;
143  d->valid = true;
144 }
145 
146 void QgsFeature::setGeometry( std::unique_ptr<QgsAbstractGeometry> geometry )
147 {
148  d.detach();
149  d->geometry = QgsGeometry( std::move( geometry ) );
150  d->valid = true;
151 }
152 
154 {
156 }
157 
158 /***************************************************************************
159  * This class is considered CRITICAL and any change MUST be accompanied with
160  * full unit tests in testqgsfeature.cpp.
161  * See details in QEP #17
162  ****************************************************************************/
163 
164 void QgsFeature::setFields( const QgsFields &fields, bool init )
165 {
166  d.detach();
167  d->fields = fields;
168  if ( init )
169  {
170  initAttributes( d->fields.count() );
171  }
172 }
173 
175 {
176  return d->fields;
177 }
178 
179 /***************************************************************************
180  * This class is considered CRITICAL and any change MUST be accompanied with
181  * full unit tests in testqgsfeature.cpp.
182  * See details in QEP #17
183  ****************************************************************************/
184 
186 {
187  return d->valid;
188 }
189 
190 void QgsFeature::setValid( bool validity )
191 {
192  if ( d->valid == validity )
193  return;
194 
195  d.detach();
196  d->valid = validity;
197 }
198 
200 {
201  return !d->geometry.isNull();
202 }
203 
204 void QgsFeature::initAttributes( int fieldCount )
205 {
206  d.detach();
207  d->attributes.resize( 0 ); // clears existing elements, while still preserving the currently allocated capacity of the list (unlike clear)
208  // ensures ALL attributes, including previously existing ones are default constructed.
209  // doing it this way also avoids clearing individual QVariants -- which can trigger a detachment. Cheaper just to make a new one.
210  d->attributes.resize( fieldCount );
211 }
212 
213 bool QgsFeature::setAttribute( int idx, const QVariant &value )
214 {
215  if ( idx < 0 || idx >= d->attributes.size() )
216  {
217  QgsMessageLog::logMessage( QObject::tr( "Attribute index %1 out of bounds [0;%2]" ).arg( idx ).arg( d->attributes.size() ), QString(), Qgis::Warning );
218  return false;
219  }
220 
221  d.detach();
222  d->attributes[idx] = value;
223  d->valid = true;
224  return true;
225 }
226 
227 /***************************************************************************
228  * This class is considered CRITICAL and any change MUST be accompanied with
229  * full unit tests in testqgsfeature.cpp.
230  * See details in QEP #17
231  ****************************************************************************/
232 
233 bool QgsFeature::setAttribute( const QString &name, const QVariant &value )
234 {
235  int fieldIdx = fieldNameIndex( name );
236  if ( fieldIdx == -1 )
237  return false;
238 
239  d.detach();
240  d->attributes[fieldIdx] = value;
241  d->valid = true;
242  return true;
243 }
244 
245 bool QgsFeature::deleteAttribute( const QString &name )
246 {
247  int fieldIdx = fieldNameIndex( name );
248  if ( fieldIdx == -1 )
249  return false;
250 
251  d.detach();
252  d->attributes[fieldIdx].clear();
253  return true;
254 }
255 
256 QVariant QgsFeature::attribute( int fieldIdx ) const
257 {
258  if ( fieldIdx < 0 || fieldIdx >= d->attributes.count() )
259  return QVariant();
260 
261  return d->attributes.at( fieldIdx );
262 }
263 
264 QVariant QgsFeature::attribute( const QString &name ) const
265 {
266  int fieldIdx = fieldNameIndex( name );
267  if ( fieldIdx == -1 )
268  return QVariant();
269 
270  return d->attributes.at( fieldIdx );
271 }
272 
273 /***************************************************************************
274  * This class is considered CRITICAL and any change MUST be accompanied with
275  * full unit tests in testqgsfeature.cpp.
276  * See details in QEP #17
277  ****************************************************************************/
278 
279 int QgsFeature::fieldNameIndex( const QString &fieldName ) const
280 {
281  return d->fields.lookupField( fieldName );
282 }
283 
284 static size_t qgsQStringApproximateMemoryUsage( const QString &str )
285 {
286  return sizeof( QString ) + str.size() * sizeof( QChar );
287 }
288 
289 static size_t qgsQVariantApproximateMemoryUsage( const QVariant &v )
290 {
291  // A QVariant has a private structure that is a union of things whose larger
292  // size if a long long, and a int
293  size_t s = sizeof( QVariant ) + sizeof( long long ) + sizeof( int );
294  if ( v.type() == QVariant::String )
295  {
296  s += qgsQStringApproximateMemoryUsage( v.toString() );
297  }
298  else if ( v.type() == QVariant::StringList )
299  {
300  for ( const QString &str : v.toStringList() )
301  s += qgsQStringApproximateMemoryUsage( str );
302  }
303  else if ( v.type() == QVariant::List )
304  {
305  for ( const QVariant &subV : v.toList() )
306  s += qgsQVariantApproximateMemoryUsage( subV );
307  }
308  return s;
309 }
310 
312 {
313  size_t s = sizeof( *this ) + sizeof( *d );
314 
315  // Attributes
316  for ( const QVariant &attr : qgis::as_const( d->attributes ) )
317  {
318  s += qgsQVariantApproximateMemoryUsage( attr );
319  }
320 
321  // Geometry
322  s += sizeof( QAtomicInt ) + sizeof( void * ); // ~ sizeof(QgsGeometryPrivate)
323  // For simplicity we consider that the RAM usage is the one of the WKB
324  // representation
325  s += d->geometry.wkbSize();
326 
327  // Fields
328  s += sizeof( QgsFieldsPrivate );
329  // TODO potentially: take into account the length of the name, comment, default value, etc...
330  s += d->fields.size() * ( sizeof( QgsField ) + sizeof( QgsFieldPrivate ) );
331 
332  return static_cast<int>( s );
333 }
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 QDataStream &operator<<( QDataStream &out, const QgsFeature &feature )
343 {
344  out << feature.id();
345  out << feature.attributes();
346  if ( feature.hasGeometry() )
347  {
348  out << ( feature.geometry() );
349  }
350  else
351  {
352  QgsGeometry geometry;
353  out << geometry;
354  }
355  out << feature.isValid();
356  return out;
357 }
358 
359 QDataStream &operator>>( QDataStream &in, QgsFeature &feature )
360 {
361  QgsFeatureId id;
362  QgsGeometry geometry;
363  bool valid;
364  QgsAttributes attr;
365  in >> id >> attr >> geometry >> valid;
366  feature.setId( id );
367  feature.setGeometry( geometry );
368  feature.setAttributes( attr );
369  feature.setValid( valid );
370  return in;
371 }
372 
373 uint qHash( const QgsFeature &key, uint seed )
374 {
375  uint hash = seed;
376  const auto constAttributes = key.attributes();
377  for ( const QVariant &attr : constAttributes )
378  {
379  hash ^= qHash( attr.toString() );
380  }
381 
382  hash ^= qHash( key.geometry().asWkt() );
383  hash ^= qHash( key.id() );
384 
385  return hash;
386 }
387 
qgsfields.h
qgsfield_p.h
QgsFeature::id
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
qgsrectangle.h
QgsFeature::setId
void setId(QgsFeatureId id)
Sets the feature ID for this feature.
Definition: qgsfeature.cpp:114
QgsFeature::initAttributes
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
Definition: qgsfeature.cpp:204
qHash
uint qHash(const QgsFeature &key, uint seed)
Definition: qgsfeature.cpp:373
Qgis::Warning
@ Warning
Definition: qgis.h:91
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:45
qgsfeature.h
QgsFeature::geometry
QgsGeometry geometry
Definition: qgsfeature.h:67
QgsFeature::setValid
void setValid(bool validity)
Sets the validity of the feature.
Definition: qgsfeature.cpp:190
QgsFeature::operator==
bool operator==(const QgsFeature &other) const
Compares two features.
Definition: qgsfeature.cpp:62
field
const QgsField & field
Definition: qgsfield.h:456
QgsFeature::fieldNameIndex
int fieldNameIndex(const QString &fieldName) const
Utility method to get attribute index from name.
Definition: qgsfeature.cpp:279
QgsFeature::approximateMemoryUsage
int approximateMemoryUsage() const
Returns the approximate RAM usage of the feature, in bytes.
Definition: qgsfeature.cpp:311
QgsFeature::clearGeometry
void clearGeometry()
Removes any geometry associated with the feature.
Definition: qgsfeature.cpp:153
qgsfields_p.h
QgsFeature::setGeometry
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:139
QgsFeature::isValid
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:185
QgsFeature::setFields
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:164
operator>>
QDataStream & operator>>(QDataStream &in, QgsFeature &feature)
Reads a feature from stream in into feature. QGIS version compatibility is not guaranteed.
Definition: qgsfeature.cpp:359
QgsFeature::operator=
QgsFeature & operator=(const QgsFeature &rhs)
Assignment operator.
Definition: qgsfeature.cpp:56
QgsFeature::attribute
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:264
QgsFeature::attributes
QgsAttributes attributes
Definition: qgsfeature.h:65
operator<<
QDataStream & operator<<(QDataStream &out, const QgsFeature &feature)
Writes the feature to stream out. QGIS version compatibility is not guaranteed.
Definition: qgsfeature.cpp:342
QgsFeature::setAttribute
bool setAttribute(int field, const QVariant &attr)
Set an attribute's value by field index.
Definition: qgsfeature.cpp:213
QgsGeometry::asWkt
QString asWkt(int precision=17) const
Exports the geometry to WKT.
Definition: qgsgeometry.cpp:1288
qgsgeometry.h
QgsGeometry
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsFeature::hasGeometry
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:199
QgsFeature::~QgsFeature
virtual ~QgsFeature()
Definition: qgsfeature.cpp:82
QgsMessageLog::logMessage
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).
Definition: qgsmessagelog.cpp:27
qgsfeature_p.h
QgsFeature::operator!=
bool operator!=(const QgsFeature &other) const
Compares two features.
Definition: qgsfeature.cpp:77
QgsAttributes
A vector of attributes.
Definition: qgsattributes.h:58
QgsFeature::fields
QgsFields fields
Definition: qgsfeature.h:66
QgsFeature
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
QgsFeature::deleteAttribute
void deleteAttribute(int field)
Deletes an attribute and its value.
Definition: qgsfeature.cpp:97
QgsFeature::setAttributes
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:129
QgsFeature::QgsFeature
QgsFeature(QgsFeatureId id=FID_NULL)
Constructor for QgsFeature.
Definition: qgsfeature.cpp:39
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