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