QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgsfeature.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsfeature.cpp - Spatial Feature Implementation
3 --------------------------------------
4Date : 09-Sep-2003
5Copyright : (C) 2003 by Gary E.Sherman
6email : 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
51QgsFeature::QgsFeature( const QgsFeature &rhs ) //NOLINT
52 : d( rhs.d )
53{
54}
55
57{
58 d = rhs.d;
59 return *this;
60}
61
62bool 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
85bool 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
137QVariantMap 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
171{
172 d.detach();
173 d->geometry = geometry;
174 d->valid = true;
175}
176
177void 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{
186 if ( d->geometry.isNull() && d->valid )
187 return;
188
190}
191
192/***************************************************************************
193 * This class is considered CRITICAL and any change MUST be accompanied with
194 * full unit tests in testqgsfeature.cpp.
195 * See details in QEP #17
196 ****************************************************************************/
197
198void QgsFeature::setFields( const QgsFields &fields, bool init )
199{
200 d.detach();
201 d->fields = fields;
202 if ( init )
203 {
204 initAttributes( d->fields.count() );
205 }
206}
207
209{
210 return d->fields;
211}
212
213/***************************************************************************
214 * This class is considered CRITICAL and any change MUST be accompanied with
215 * full unit tests in testqgsfeature.cpp.
216 * See details in QEP #17
217 ****************************************************************************/
218
220{
221 return d->valid;
222}
223
224void QgsFeature::setValid( bool validity )
225{
226 if ( d->valid == validity )
227 return;
228
229 d.detach();
230 d->valid = validity;
231}
232
234{
235 return !d->geometry.isNull();
236}
237
238void QgsFeature::initAttributes( int fieldCount )
239{
240 d.detach();
241 d->attributes.resize( 0 ); // clears existing elements, while still preserving the currently allocated capacity of the list (unlike clear)
242 // ensures ALL attributes, including previously existing ones are default constructed.
243 // doing it this way also avoids clearing individual QVariants -- which can trigger a detachment. Cheaper just to make a new one.
244 d->attributes.resize( fieldCount );
245}
246
247void QgsFeature::resizeAttributes( int fieldCount )
248{
249 if ( fieldCount == d->attributes.size() )
250 return;
251
252 d.detach();
253 d->attributes.resize( fieldCount );
254}
255
257{
258 if ( count == 0 )
259 return;
260
261 d.detach();
262 d->attributes.resize( d->attributes.size() + count );
263}
264
265bool QgsFeature::setAttribute( int idx, const QVariant &value )
266{
267 if ( idx < 0 || idx >= d->attributes.size() )
268 {
269 QgsMessageLog::logMessage( QObject::tr( "Attribute index %1 out of bounds [0;%2]" ).arg( idx ).arg( d->attributes.size() ), QString(), Qgis::MessageLevel::Warning );
270 return false;
271 }
272
273 d.detach();
274 d->attributes[idx] = value;
275 d->valid = true;
276 return true;
277}
278
279/***************************************************************************
280 * This class is considered CRITICAL and any change MUST be accompanied with
281 * full unit tests in testqgsfeature.cpp.
282 * See details in QEP #17
283 ****************************************************************************/
284
285bool QgsFeature::setAttribute( const QString &name, const QVariant &value )
286{
287 int fieldIdx = fieldNameIndex( name );
288 if ( fieldIdx == -1 )
289 return false;
290
291 d.detach();
292 d->attributes[fieldIdx] = value;
293 d->valid = true;
294 return true;
295}
296
297bool QgsFeature::deleteAttribute( const QString &name )
298{
299 int fieldIdx = fieldNameIndex( name );
300 if ( fieldIdx == -1 )
301 return false;
302
303 d.detach();
304 d->attributes[fieldIdx].clear();
305 return true;
306}
307
308QVariant QgsFeature::attribute( int fieldIdx ) const
309{
310 if ( fieldIdx < 0 || fieldIdx >= d->attributes.count() )
311 return QVariant();
312
313 return d->attributes.at( fieldIdx );
314}
315
316bool QgsFeature::isUnsetValue( int fieldIdx ) const
317{
318 if ( fieldIdx < 0 || fieldIdx >= d->attributes.count() )
319 return false;
320
321 return d->attributes.at( fieldIdx ).userType() == QMetaType::type( "QgsUnsetAttributeValue" );
322}
323
325{
326 return d->symbol.get();
327}
328
330{
331 if ( symbol == d->symbol.get() )
332 return;
333
334 d.detach();
335 d->symbol.reset( symbol );
336}
337
338QVariant QgsFeature::attribute( const QString &name ) const
339{
340 int fieldIdx = fieldNameIndex( name );
341 if ( fieldIdx == -1 )
342 return QVariant();
343
344 return d->attributes.at( fieldIdx );
345}
346
347/***************************************************************************
348 * This class is considered CRITICAL and any change MUST be accompanied with
349 * full unit tests in testqgsfeature.cpp.
350 * See details in QEP #17
351 ****************************************************************************/
352
353int QgsFeature::fieldNameIndex( const QString &fieldName ) const
354{
355 return d->fields.lookupField( fieldName );
356}
357
358static size_t qgsQStringApproximateMemoryUsage( const QString &str )
359{
360 return sizeof( QString ) + str.size() * sizeof( QChar );
361}
362
363static size_t qgsQVariantApproximateMemoryUsage( const QVariant &v )
364{
365 // A QVariant has a private structure that is a union of things whose larger
366 // size if a long long, and a int
367 size_t s = sizeof( QVariant ) + sizeof( long long ) + sizeof( int );
368 if ( v.type() == QVariant::String )
369 {
370 s += qgsQStringApproximateMemoryUsage( v.toString() );
371 }
372 else if ( v.type() == QVariant::StringList )
373 {
374 for ( const QString &str : v.toStringList() )
375 s += qgsQStringApproximateMemoryUsage( str );
376 }
377 else if ( v.type() == QVariant::List )
378 {
379 for ( const QVariant &subV : v.toList() )
380 s += qgsQVariantApproximateMemoryUsage( subV );
381 }
382 return s;
383}
384
386{
387 size_t s = sizeof( *this ) + sizeof( *d );
388
389 // Attributes
390 for ( const QVariant &attr : std::as_const( d->attributes ) )
391 {
392 s += qgsQVariantApproximateMemoryUsage( attr );
393 }
394
395 // Geometry
396 s += sizeof( QAtomicInt ) + sizeof( void * ); // ~ sizeof(QgsGeometryPrivate)
397 // For simplicity we consider that the RAM usage is the one of the WKB
398 // representation
399 s += d->geometry.wkbSize();
400
401 // Fields
402 s += sizeof( QgsFieldsPrivate );
403 // TODO potentially: take into account the length of the name, comment, default value, etc...
404 s += d->fields.size() * ( sizeof( QgsField ) + sizeof( QgsFieldPrivate ) );
405
406 return static_cast<int>( s );
407}
408
409
410/***************************************************************************
411 * This class is considered CRITICAL and any change MUST be accompanied with
412 * full unit tests in testqgsfeature.cpp.
413 * See details in QEP #17
414 ****************************************************************************/
415
416QDataStream &operator<<( QDataStream &out, const QgsFeature &feature )
417{
418 out << feature.id();
419 out << feature.attributes();
420 if ( feature.hasGeometry() )
421 {
422 out << ( feature.geometry() );
423 }
424 else
425 {
426 QgsGeometry geometry;
427 out << geometry;
428 }
429 out << feature.isValid();
430 return out;
431}
432
433QDataStream &operator>>( QDataStream &in, QgsFeature &feature )
434{
435 QgsFeatureId id;
436 QgsGeometry geometry;
437 bool valid;
438 QgsAttributes attr;
439 in >> id >> attr >> geometry >> valid;
440 feature.setId( id );
441 feature.setGeometry( geometry );
442 feature.setAttributes( attr );
443 feature.setValid( valid );
444 return in;
445}
446
447uint qHash( const QgsFeature &key, uint seed )
448{
449 uint hash = seed;
450 const auto constAttributes = key.attributes();
451 for ( const QVariant &attr : constAttributes )
452 {
453 hash ^= qHash( attr.toString() );
454 }
455
456 hash ^= qHash( key.geometry().asWkt() );
457 hash ^= qHash( key.id() );
458
459 return hash;
460}
461
A vector of attributes.
Definition: qgsattributes.h:59
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:265
void resizeAttributes(int fieldCount)
Resizes the attributes attached to this feature to the given number of fields.
Definition: qgsfeature.cpp:247
QgsAttributes attributes
Definition: qgsfeature.h:65
bool operator!=(const QgsFeature &other) const
Compares two features.
Definition: qgsfeature.cpp:85
virtual ~QgsFeature()
Definition: qgsfeature.cpp:90
QgsFields fields
Definition: qgsfeature.h:66
int fieldNameIndex(const QString &fieldName) const
Utility method to get attribute index from name.
Definition: qgsfeature.cpp:353
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
Definition: qgsfeature.cpp:238
void deleteAttribute(int field)
Clear's an attribute's value by its index.
Definition: qgsfeature.cpp:105
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:385
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:160
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:198
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:155
void padAttributes(int count)
Resizes the attributes attached to this feature by appending the specified count of NULL values to th...
Definition: qgsfeature.cpp:256
const QgsSymbol * embeddedSymbol() const
Returns the feature's embedded symbology, or nullptr if the feature has no embedded symbol.
Definition: qgsfeature.cpp:324
void setId(QgsFeatureId id)
Sets the feature id for this feature.
Definition: qgsfeature.cpp:122
QgsGeometry geometry
Definition: qgsfeature.h:67
void setEmbeddedSymbol(QgsSymbol *symbol)
Sets the feature's embedded symbol.
Definition: qgsfeature.cpp:329
void clearGeometry()
Removes any geometry associated with the feature.
Definition: qgsfeature.cpp:184
void setValid(bool validity)
Sets the validity of the feature.
Definition: qgsfeature.cpp:224
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:233
bool isUnsetValue(int fieldIdx) const
Returns true if the attribute at the specified index is an unset value.
Definition: qgsfeature.cpp:316
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:219
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:338
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:170
QVariantMap attributeMap() const
Returns the feature's attributes as a map of field name to value.
Definition: qgsfeature.cpp:137
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:164
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:93
#define str(x)
Definition: qgis.cpp:37
uint qHash(const QgsFeature &key, uint seed)
Definition: qgsfeature.cpp:447
QDataStream & operator<<(QDataStream &out, const QgsFeature &feature)
Writes the feature to stream out. QGIS version compatibility is not guaranteed.
Definition: qgsfeature.cpp:416
QDataStream & operator>>(QDataStream &in, QgsFeature &feature)
Reads a feature from stream in into feature. QGIS version compatibility is not guaranteed.
Definition: qgsfeature.cpp:433
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