QGIS API Documentation 3.41.0-Master (af5edcb665c)
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 "moc_qgsfeature.cpp"
18#include "qgsfeature_p.h"
19#include "qgsfields.h"
20#include "qgsgeometry.h"
21#include "qgsrectangle.h"
22#include "qgsfield_p.h" // for approximateMemoryUsage()
23#include "qgsfields_p.h" // for approximateMemoryUsage()
24
25#include "qgsmessagelog.h"
26#include "qgslogger.h"
27#include <QDataStream>
28
29/***************************************************************************
30 * This class is considered CRITICAL and any change MUST be accompanied with
31 * full unit tests in testqgsfeature.cpp.
32 * See details in QEP #17
33 ****************************************************************************/
34
35
36//
37// QgsFeature
38//
39
41{
42 d = new QgsFeaturePrivate( id );
43}
44
46{
47 d = new QgsFeaturePrivate( id );
48 d->fields = fields;
49 initAttributes( d->fields.count() );
50}
51
52QgsFeature::QgsFeature( const QgsFeature &rhs ) //NOLINT
53 : d( rhs.d )
54{
55}
56
58{
59 d = rhs.d;
60 return *this;
61}
62
63bool QgsFeature::operator ==( const QgsFeature &other ) const
64{
65 if ( d == other.d )
66 return true;
67
68 if ( !( d->fid == other.d->fid
69 && d->valid == other.d->valid
70 && d->fields == other.d->fields
71 && d->attributes == other.d->attributes
72 && d->symbol == other.d->symbol ) )
73 return false;
74
75 // compare geometry
76 if ( d->geometry.isNull() && other.d->geometry.isNull() )
77 return true;
78 else if ( d->geometry.isNull() || other.d->geometry.isNull() )
79 return false;
80 else if ( !d->geometry.equals( other.d->geometry ) )
81 return false;
82
83 return true;
84}
85
86bool QgsFeature::operator!=( const QgsFeature &other ) const
87{
88 return !( *this == other );
89}
90
92{
93}
94
95/***************************************************************************
96 * This class is considered CRITICAL and any change MUST be accompanied with
97 * full unit tests in testqgsfeature.cpp.
98 * See details in QEP #17
99 ****************************************************************************/
100
102{
103 return d->fid;
104}
105
107{
108 d.detach();
109 d->attributes.remove( field );
110}
111
113{
114 return d->geometry;
115}
116
117/***************************************************************************
118 * This class is considered CRITICAL and any change MUST be accompanied with
119 * full unit tests in testqgsfeature.cpp.
120 * See details in QEP #17
121 ****************************************************************************/
122
124{
125 if ( id == d->fid )
126 return;
127
128 d.detach();
129 d->fid = id;
130 d->valid = true;
131}
132
134{
135 return d->attributes;
136}
137
138QVariantMap QgsFeature::attributeMap() const
139{
140 QVariantMap res;
141 const int fieldSize = d->fields.size();
142 const int attributeSize = d->attributes.size();
143 if ( fieldSize != attributeSize )
144 {
145 QgsDebugError( QStringLiteral( "Attribute size (%1) does not match number of fields (%2)" ).arg( attributeSize ).arg( fieldSize ) );
146 return QVariantMap();
147 }
148
149 for ( int i = 0; i < attributeSize; ++i )
150 {
151 res[d->fields.at( i ).name()] = d->attributes.at( i );
152 }
153 return res;
154}
155
157{
158 return d->attributes.size();
159}
160
162{
163 d.detach();
164 d->attributes = attrs;
165 d->valid = true;
166}
167
169{
170 d.detach();
171 d->geometry = geometry;
172 d->valid = true;
173}
174
175void QgsFeature::setGeometry( std::unique_ptr<QgsAbstractGeometry> geometry )
176{
177 d.detach();
178 d->geometry = QgsGeometry( std::move( geometry ) );
179 d->valid = true;
180}
181
183{
184 if ( d->geometry.isNull() && d->valid )
185 return;
186
188}
189
190/***************************************************************************
191 * This class is considered CRITICAL and any change MUST be accompanied with
192 * full unit tests in testqgsfeature.cpp.
193 * See details in QEP #17
194 ****************************************************************************/
195
196void QgsFeature::setFields( const QgsFields &fields, bool init )
197{
198 d.detach();
199 d->fields = fields;
200 if ( init )
201 {
202 initAttributes( d->fields.count() );
203 }
204}
205
207{
208 return d->fields;
209}
210
211/***************************************************************************
212 * This class is considered CRITICAL and any change MUST be accompanied with
213 * full unit tests in testqgsfeature.cpp.
214 * See details in QEP #17
215 ****************************************************************************/
216
218{
219 return d->valid;
220}
221
222void QgsFeature::setValid( bool validity )
223{
224 if ( d->valid == validity )
225 return;
226
227 d.detach();
228 d->valid = validity;
229}
230
232{
233 return !d->geometry.isNull();
234}
235
236void QgsFeature::initAttributes( int fieldCount )
237{
238 d.detach();
239 d->attributes.resize( 0 ); // clears existing elements, while still preserving the currently allocated capacity of the list (unlike clear)
240 // ensures ALL attributes, including previously existing ones are default constructed.
241 // doing it this way also avoids clearing individual QVariants -- which can trigger a detachment. Cheaper just to make a new one.
242 d->attributes.resize( fieldCount );
243}
244
245void QgsFeature::resizeAttributes( int fieldCount )
246{
247 if ( fieldCount == d->attributes.size() )
248 return;
249
250 d.detach();
251 d->attributes.resize( fieldCount );
252}
253
255{
256 if ( count == 0 )
257 return;
258
259 d.detach();
260 d->attributes.resize( d->attributes.size() + count );
261}
262
263bool QgsFeature::setAttribute( int idx, const QVariant &value )
264{
265 if ( idx < 0 || idx >= d->attributes.size() )
266 {
267 QgsMessageLog::logMessage( QObject::tr( "Attribute index %1 out of bounds [0;%2]" ).arg( idx ).arg( d->attributes.size() ), QString(), Qgis::MessageLevel::Warning );
268 return false;
269 }
270
271 d.detach();
272 d->attributes[idx] = value;
273 d->valid = true;
274 return true;
275}
276
277/***************************************************************************
278 * This class is considered CRITICAL and any change MUST be accompanied with
279 * full unit tests in testqgsfeature.cpp.
280 * See details in QEP #17
281 ****************************************************************************/
282
283bool QgsFeature::setAttribute( const QString &name, const QVariant &value )
284{
285 int fieldIdx = fieldNameIndex( name );
286 if ( fieldIdx == -1 )
287 return false;
288
289 d.detach();
290 d->attributes[fieldIdx] = value;
291 d->valid = true;
292 return true;
293}
294
295bool QgsFeature::deleteAttribute( const QString &name )
296{
297 int fieldIdx = fieldNameIndex( name );
298 if ( fieldIdx == -1 )
299 return false;
300
301 d.detach();
302 d->attributes[fieldIdx].clear();
303 return true;
304}
305
306QVariant QgsFeature::attribute( int fieldIdx ) const
307{
308 if ( fieldIdx < 0 || fieldIdx >= d->attributes.count() )
309 return QVariant();
310
311 return d->attributes.at( fieldIdx );
312}
313
314bool QgsFeature::isUnsetValue( int fieldIdx ) const
315{
316 if ( fieldIdx < 0 || fieldIdx >= d->attributes.count() )
317 return false;
318
319 return d->attributes.at( fieldIdx ).userType() == qMetaTypeId<QgsUnsetAttributeValue>();
320}
321
323{
324 return d->symbol.get();
325}
326
328{
329 if ( symbol == d->symbol.get() )
330 return;
331
332 d.detach();
333 d->symbol.reset( symbol );
334}
335
336QVariant QgsFeature::attribute( const QString &name ) const
337{
338 int fieldIdx = fieldNameIndex( name );
339 if ( fieldIdx == -1 )
340 return QVariant();
341
342 return d->attributes.at( fieldIdx );
343}
344
345/***************************************************************************
346 * This class is considered CRITICAL and any change MUST be accompanied with
347 * full unit tests in testqgsfeature.cpp.
348 * See details in QEP #17
349 ****************************************************************************/
350
351int QgsFeature::fieldNameIndex( const QString &fieldName ) const
352{
353 return d->fields.lookupField( fieldName );
354}
355
356static size_t qgsQStringApproximateMemoryUsage( const QString &str )
357{
358 return sizeof( QString ) + str.size() * sizeof( QChar );
359}
360
361static size_t qgsQVariantApproximateMemoryUsage( const QVariant &v )
362{
363 // A QVariant has a private structure that is a union of things whose larger
364 // size if a long long, and a int
365 size_t s = sizeof( QVariant ) + sizeof( long long ) + sizeof( int );
366 if ( v.userType() == QMetaType::Type::QString )
367 {
368 s += qgsQStringApproximateMemoryUsage( v.toString() );
369 }
370 else if ( v.userType() == QMetaType::Type::QStringList )
371 {
372 for ( const QString &str : v.toStringList() )
373 s += qgsQStringApproximateMemoryUsage( str );
374 }
375 else if ( v.userType() == QMetaType::Type::QVariantList )
376 {
377 for ( const QVariant &subV : v.toList() )
378 s += qgsQVariantApproximateMemoryUsage( subV );
379 }
380 return s;
381}
382
384{
385 size_t s = sizeof( *this ) + sizeof( *d );
386
387 // Attributes
388 for ( const QVariant &attr : std::as_const( d->attributes ) )
389 {
390 s += qgsQVariantApproximateMemoryUsage( attr );
391 }
392
393 // Geometry
394 s += sizeof( QAtomicInt ) + sizeof( void * ); // ~ sizeof(QgsGeometryPrivate)
395 // For simplicity we consider that the RAM usage is the one of the WKB
396 // representation
397 s += d->geometry.wkbSize();
398
399 // Fields
400 s += sizeof( QgsFieldsPrivate );
401 // TODO potentially: take into account the length of the name, comment, default value, etc...
402 s += d->fields.size() * ( sizeof( QgsField ) + sizeof( QgsFieldPrivate ) );
403
404 return static_cast<int>( s );
405}
406
407
408/***************************************************************************
409 * This class is considered CRITICAL and any change MUST be accompanied with
410 * full unit tests in testqgsfeature.cpp.
411 * See details in QEP #17
412 ****************************************************************************/
413
414QDataStream &operator<<( QDataStream &out, const QgsFeature &feature )
415{
416 out << feature.id();
417 out << feature.attributes();
418 if ( feature.hasGeometry() )
419 {
420 out << ( feature.geometry() );
421 }
422 else
423 {
424 QgsGeometry geometry;
425 out << geometry;
426 }
427 out << feature.isValid();
428 return out;
429}
430
431QDataStream &operator>>( QDataStream &in, QgsFeature &feature )
432{
433 QgsFeatureId id;
434 QgsGeometry geometry;
435 bool valid;
436 QgsAttributes attr;
437 in >> id >> attr >> geometry >> valid;
438 feature.setId( id );
439 feature.setGeometry( geometry );
440 feature.setAttributes( attr );
441 feature.setValid( valid );
442 return in;
443}
444
445uint qHash( const QgsFeature &key, uint seed )
446{
447 uint hash = seed;
448 const auto constAttributes = key.attributes();
449 for ( const QVariant &attr : constAttributes )
450 {
451 hash ^= qHash( attr.toString() );
452 }
453
454 hash ^= qHash( key.geometry().asWkt() );
455 hash ^= qHash( key.id() );
456
457 return hash;
458}
459
@ Warning
Warning message.
Definition qgis.h:156
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
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)
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
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:231
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