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