QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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 QgsDebugError( 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 d.detach();
163 d->attributes = attrs;
164 d->valid = true;
165}
166
168{
169 d.detach();
170 d->geometry = geometry;
171 d->valid = true;
172}
173
174void QgsFeature::setGeometry( std::unique_ptr<QgsAbstractGeometry> geometry )
175{
176 d.detach();
177 d->geometry = QgsGeometry( std::move( geometry ) );
178 d->valid = true;
179}
180
182{
183 if ( d->geometry.isNull() && d->valid )
184 return;
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
195void 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
221void 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
235void 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
244void QgsFeature::resizeAttributes( int fieldCount )
245{
246 if ( fieldCount == d->attributes.size() )
247 return;
248
249 d.detach();
250 d->attributes.resize( fieldCount );
251}
252
254{
255 if ( count == 0 )
256 return;
257
258 d.detach();
259 d->attributes.resize( d->attributes.size() + count );
260}
261
262bool 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
282bool 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
294bool 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
305QVariant 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
313bool QgsFeature::isUnsetValue( int fieldIdx ) const
314{
315 if ( fieldIdx < 0 || fieldIdx >= d->attributes.count() )
316 return false;
317
318 return d->attributes.at( fieldIdx ).userType() == QMetaType::type( "QgsUnsetAttributeValue" );
319}
320
322{
323 return d->symbol.get();
324}
325
327{
328 if ( symbol == d->symbol.get() )
329 return;
330
331 d.detach();
332 d->symbol.reset( symbol );
333}
334
335QVariant QgsFeature::attribute( const QString &name ) const
336{
337 int fieldIdx = fieldNameIndex( name );
338 if ( fieldIdx == -1 )
339 return QVariant();
340
341 return d->attributes.at( fieldIdx );
342}
343
344/***************************************************************************
345 * This class is considered CRITICAL and any change MUST be accompanied with
346 * full unit tests in testqgsfeature.cpp.
347 * See details in QEP #17
348 ****************************************************************************/
349
350int QgsFeature::fieldNameIndex( const QString &fieldName ) const
351{
352 return d->fields.lookupField( fieldName );
353}
354
355static size_t qgsQStringApproximateMemoryUsage( const QString &str )
356{
357 return sizeof( QString ) + str.size() * sizeof( QChar );
358}
359
360static size_t qgsQVariantApproximateMemoryUsage( const QVariant &v )
361{
362 // A QVariant has a private structure that is a union of things whose larger
363 // size if a long long, and a int
364 size_t s = sizeof( QVariant ) + sizeof( long long ) + sizeof( int );
365 if ( v.type() == QVariant::String )
366 {
367 s += qgsQStringApproximateMemoryUsage( v.toString() );
368 }
369 else if ( v.type() == QVariant::StringList )
370 {
371 for ( const QString &str : v.toStringList() )
372 s += qgsQStringApproximateMemoryUsage( str );
373 }
374 else if ( v.type() == QVariant::List )
375 {
376 for ( const QVariant &subV : v.toList() )
377 s += qgsQVariantApproximateMemoryUsage( subV );
378 }
379 return s;
380}
381
383{
384 size_t s = sizeof( *this ) + sizeof( *d );
385
386 // Attributes
387 for ( const QVariant &attr : std::as_const( d->attributes ) )
388 {
389 s += qgsQVariantApproximateMemoryUsage( attr );
390 }
391
392 // Geometry
393 s += sizeof( QAtomicInt ) + sizeof( void * ); // ~ sizeof(QgsGeometryPrivate)
394 // For simplicity we consider that the RAM usage is the one of the WKB
395 // representation
396 s += d->geometry.wkbSize();
397
398 // Fields
399 s += sizeof( QgsFieldsPrivate );
400 // TODO potentially: take into account the length of the name, comment, default value, etc...
401 s += d->fields.size() * ( sizeof( QgsField ) + sizeof( QgsFieldPrivate ) );
402
403 return static_cast<int>( s );
404}
405
406
407/***************************************************************************
408 * This class is considered CRITICAL and any change MUST be accompanied with
409 * full unit tests in testqgsfeature.cpp.
410 * See details in QEP #17
411 ****************************************************************************/
412
413QDataStream &operator<<( QDataStream &out, const QgsFeature &feature )
414{
415 out << feature.id();
416 out << feature.attributes();
417 if ( feature.hasGeometry() )
418 {
419 out << ( feature.geometry() );
420 }
421 else
422 {
423 QgsGeometry geometry;
424 out << geometry;
425 }
426 out << feature.isValid();
427 return out;
428}
429
430QDataStream &operator>>( QDataStream &in, QgsFeature &feature )
431{
432 QgsFeatureId id;
433 QgsGeometry geometry;
434 bool valid;
435 QgsAttributes attr;
436 in >> id >> attr >> geometry >> valid;
437 feature.setId( id );
438 feature.setGeometry( geometry );
439 feature.setAttributes( attr );
440 feature.setValid( valid );
441 return in;
442}
443
444uint qHash( const QgsFeature &key, uint seed )
445{
446 uint hash = seed;
447 const auto constAttributes = key.attributes();
448 for ( const QVariant &attr : constAttributes )
449 {
450 hash ^= qHash( attr.toString() );
451 }
452
453 hash ^= qHash( key.geometry().asWkt() );
454 hash ^= qHash( key.id() );
455
456 return hash;
457}
458
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:262
void resizeAttributes(int fieldCount)
Resizes the attributes attached to this feature to the given number of fields.
Definition: qgsfeature.cpp:244
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:350
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
Definition: qgsfeature.cpp:235
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:382
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:195
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:253
const QgsSymbol * embeddedSymbol() const
Returns the feature's embedded symbology, or nullptr if the feature has no embedded symbol.
Definition: qgsfeature.cpp:321
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:326
void clearGeometry()
Removes any geometry associated with the feature.
Definition: qgsfeature.cpp:181
void setValid(bool validity)
Sets the validity of the feature.
Definition: qgsfeature.cpp:221
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:230
bool isUnsetValue(int fieldIdx) const
Returns true if the attribute at the specified index is an unset value.
Definition: qgsfeature.cpp:313
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:216
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:335
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:167
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:53
Container of fields for a vector layer.
Definition: qgsfields.h:45
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:162
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:94
#define str(x)
Definition: qgis.cpp:38
uint qHash(const QgsFeature &key, uint seed)
Definition: qgsfeature.cpp:444
QDataStream & operator<<(QDataStream &out, const QgsFeature &feature)
Writes the feature to stream out. QGIS version compatibility is not guaranteed.
Definition: qgsfeature.cpp:413
QDataStream & operator>>(QDataStream &in, QgsFeature &feature)
Reads a feature from stream in into feature. QGIS version compatibility is not guaranteed.
Definition: qgsfeature.cpp:430
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
#define QgsDebugError(str)
Definition: qgslogger.h:38