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