QGIS API Documentation 3.37.0-Master (df6056bf1be)
Loading...
Searching...
No Matches
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.userType() == QMetaType::Type::QString )
366 {
367 s += qgsQStringApproximateMemoryUsage( v.toString() );
368 }
369 else if ( v.userType() == QMetaType::Type::QStringList )
370 {
371 for ( const QString &str : v.toStringList() )
372 s += qgsQStringApproximateMemoryUsage( str );
373 }
374 else if ( v.userType() == QMetaType::Type::QVariantList )
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
@ Warning
Warning message.
Definition qgis.h:101
A vector of attributes.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
Q_INVOKABLE bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
void resizeAttributes(int fieldCount)
Resizes the attributes attached to this feature to the given number of fields.
QgsAttributes attributes
Definition qgsfeature.h:67
bool operator!=(const QgsFeature &other) const
Compares two features.
virtual ~QgsFeature()
QgsFields fields
Definition qgsfeature.h:68
int fieldNameIndex(const QString &fieldName) const
Utility method to get attribute index from name.
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
void deleteAttribute(int field)
Clear's an attribute's value by its index.
QgsFeatureId id
Definition qgsfeature.h:66
QgsFeature & operator=(const QgsFeature &rhs)
Assignment operator.
int approximateMemoryUsage() const
Returns the approximate RAM usage of the feature, in bytes.
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
bool operator==(const QgsFeature &other) const
Compares two features.
void setFields(const QgsFields &fields, bool initAttributes=false)
Assigns a field map with the feature to allow attribute access by attribute name.
QgsFeature(QgsFeatureId id=FID_NULL)
Constructor for QgsFeature.
int attributeCount() const
Returns the number of attributes attached to the feature.
void padAttributes(int count)
Resizes the attributes attached to this feature by appending the specified count of NULL values to th...
const QgsSymbol * embeddedSymbol() const
Returns the feature's embedded symbology, or nullptr if the feature has no embedded symbol.
void setId(QgsFeatureId id)
Sets the feature id for this feature.
QgsGeometry geometry
Definition qgsfeature.h:69
void setEmbeddedSymbol(QgsSymbol *symbol)
Sets the feature's embedded symbol.
void clearGeometry()
Removes any geometry associated with the feature.
void setValid(bool validity)
Sets the validity of the feature.
bool hasGeometry() const
Returns true if the feature has an associated geometry.
bool isUnsetValue(int fieldIdx) const
Returns true if the attribute at the specified index is an unset value.
bool isValid() const
Returns the validity of this feature.
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
QVariantMap attributeMap() const
Returns the feature's attributes as a map of field name to value.
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:53
Container of fields for a vector layer.
Definition qgsfields.h:46
A geometry is the spatial representation of a feature.
Q_INVOKABLE 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)
QDataStream & operator<<(QDataStream &out, const QgsFeature &feature)
Writes the feature to stream out. QGIS version compatibility is not guaranteed.
QDataStream & operator>>(QDataStream &in, QgsFeature &feature)
Reads a feature from stream in into feature. QGIS version compatibility is not guaranteed.
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
#define QgsDebugError(str)
Definition qgslogger.h:38