Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsfeature.h - Spatial Feature Class
3 : : --------------------------------------
4 : : Date : 09-Sep-2003
5 : : Copyright : (C) 2003 by Gary E.Sherman
6 : : email : 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 : : #ifndef QGSFEATURE_H
17 : : #define QGSFEATURE_H
18 : :
19 : : #include "qgis_core.h"
20 : : #include "qgis_sip.h"
21 : :
22 : : #include <QExplicitlySharedDataPointer>
23 : : #include <QList>
24 : : #include <QMap>
25 : : #include <QSet>
26 : : #include <QString>
27 : : #include <QVariant>
28 : : #include <QVector>
29 : :
30 : : #include "qgsattributes.h"
31 : : #include "qgsfields.h"
32 : : #include "qgsfeatureid.h"
33 : : #include <memory>
34 : : class QgsFeature;
35 : : class QgsFeaturePrivate;
36 : : class QgsField;
37 : : class QgsGeometry;
38 : : class QgsRectangle;
39 : : class QgsAbstractGeometry;
40 : : class QgsSymbol;
41 : :
42 : : /***************************************************************************
43 : : * This class is considered CRITICAL and any change MUST be accompanied with
44 : : * full unit tests in testqgsfeature.cpp.
45 : : * See details in QEP #17
46 : : ****************************************************************************/
47 : :
48 : :
49 : : /**
50 : : * \ingroup core
51 : : * \brief The feature class encapsulates a single feature including its id,
52 : : * geometry and a list of field/values attributes.
53 : : * \note QgsFeature objects are implicitly shared.
54 : : */
55 : : class CORE_EXPORT QgsFeature
56 : : {
57 : : #ifdef SIP_RUN
58 : : #if (SIP_VERSION >= 0x040900 && SIP_VERSION < 0x040c01)
59 : : #define sipType_QVariant ((sipWrapperType *) sipTypeAsPyTypeObject (sipType_QVariant))
60 : : #endif
61 : : #endif
62 : : Q_GADGET
63 : :
64 : : Q_PROPERTY( QgsFeatureId id READ id WRITE setId )
65 : : Q_PROPERTY( QgsAttributes attributes READ attributes WRITE setAttributes )
66 : : Q_PROPERTY( QgsFields fields READ fields WRITE setFields )
67 : : Q_PROPERTY( QgsGeometry geometry READ geometry WRITE setGeometry )
68 : :
69 : : public:
70 : :
71 : : #ifdef SIP_RUN
72 : : SIP_PYOBJECT __iter__();
73 : : % MethodCode
74 : : QgsAttributes attributes = sipCpp->attributes();
75 : : PyObject *attrs = sipConvertFromType( &attributes, sipType_QgsAttributes, Py_None );
76 : : sipRes = PyObject_GetIter( attrs );
77 : : % End
78 : :
79 : : SIP_PYOBJECT __getitem__( int key );
80 : : % MethodCode
81 : : QgsAttributes attrs = sipCpp->attributes();
82 : : if ( a0 < 0 || a0 >= attrs.count() )
83 : : {
84 : : PyErr_SetString( PyExc_KeyError, QByteArray::number( a0 ) );
85 : : sipIsErr = 1;
86 : : }
87 : : else
88 : : {
89 : : QVariant *v = new QVariant( attrs.at( a0 ) );
90 : : sipRes = sipConvertFromNewType( v, sipType_QVariant, Py_None );
91 : : }
92 : : % End
93 : :
94 : : SIP_PYOBJECT __getitem__( const QString &name );
95 : : % MethodCode
96 : : int fieldIdx = sipCpp->fieldNameIndex( *a0 );
97 : : if ( fieldIdx == -1 )
98 : : {
99 : : PyErr_SetString( PyExc_KeyError, a0->toLatin1() );
100 : : sipIsErr = 1;
101 : : }
102 : : else
103 : : {
104 : : QVariant *v = new QVariant( sipCpp->attribute( fieldIdx ) );
105 : : sipRes = sipConvertFromNewType( v, sipType_QVariant, Py_None );
106 : : }
107 : : % End
108 : :
109 : : void __setitem__( int key, QVariant value / GetWrapper / );
110 : : % MethodCode
111 : : bool rv;
112 : :
113 : : if ( a1Wrapper == Py_None )
114 : : {
115 : : rv = sipCpp->setAttribute( a0, QVariant( QVariant::Int ) );
116 : : }
117 : : else
118 : : {
119 : : rv = sipCpp->setAttribute( a0, *a1 );
120 : : }
121 : :
122 : : if ( !rv )
123 : : {
124 : : PyErr_SetString( PyExc_KeyError, QByteArray::number( a0 ) );
125 : : sipIsErr = 1;
126 : : }
127 : : % End
128 : :
129 : : void __setitem__( const QString &key, QVariant value / GetWrapper / );
130 : : % MethodCode
131 : : int fieldIdx = sipCpp->fieldNameIndex( *a0 );
132 : : if ( fieldIdx == -1 )
133 : : {
134 : : PyErr_SetString( PyExc_KeyError, a0->toLatin1() );
135 : : sipIsErr = 1;
136 : : }
137 : : else
138 : : {
139 : : if ( a1Wrapper == Py_None )
140 : : {
141 : : sipCpp->setAttribute( *a0, QVariant( QVariant::Int ) );
142 : : }
143 : : else
144 : : {
145 : : sipCpp->setAttribute( fieldIdx, *a1 );
146 : : }
147 : : }
148 : : % End
149 : :
150 : : void __delitem__( int key );
151 : : % MethodCode
152 : : if ( a0 >= 0 && a0 < sipCpp->attributes().count() )
153 : : sipCpp->deleteAttribute( a0 );
154 : : else
155 : : {
156 : : PyErr_SetString( PyExc_KeyError, QByteArray::number( a0 ) );
157 : : sipIsErr = 1;
158 : : }
159 : : % End
160 : :
161 : : void __delitem__( const QString &name );
162 : : % MethodCode
163 : : int fieldIdx = sipCpp->fieldNameIndex( *a0 );
164 : : if ( fieldIdx == -1 )
165 : : {
166 : : PyErr_SetString( PyExc_KeyError, a0->toLatin1() );
167 : : sipIsErr = 1;
168 : : }
169 : : else
170 : : sipCpp->deleteAttribute( fieldIdx );
171 : : % End
172 : : #endif
173 : :
174 : : /**
175 : : * Constructor for QgsFeature
176 : : * \param id feature id
177 : : */
178 : : #ifndef SIP_RUN
179 : : QgsFeature( QgsFeatureId id = FID_NULL );
180 : : #else
181 : : QgsFeature( qint64 id = FID_NULL );
182 : : #endif
183 : :
184 : : /**
185 : : * Constructor for QgsFeature
186 : : * \param fields feature's fields
187 : : * \param id feature id
188 : : */
189 : : #ifndef SIP_RUN
190 : : QgsFeature( const QgsFields &fields, QgsFeatureId id = FID_NULL );
191 : : #else
192 : : QgsFeature( const QgsFields &fields, qint64 id = FID_NULL );
193 : : #endif
194 : :
195 : : /**
196 : : * Copy constructor
197 : : */
198 : : QgsFeature( const QgsFeature &rhs );
199 : :
200 : : /**
201 : : * Assignment operator
202 : : */
203 : : QgsFeature &operator=( const QgsFeature &rhs ) SIP_SKIP;
204 : :
205 : : /**
206 : : * Compares two features
207 : : */
208 : : bool operator==( const QgsFeature &other ) const SIP_SKIP;
209 : :
210 : : /**
211 : : * Compares two features
212 : : */
213 : : bool operator!=( const QgsFeature &other ) const SIP_SKIP;
214 : :
215 : : virtual ~QgsFeature();
216 : :
217 : : /**
218 : : * Gets the feature ID for this feature.
219 : : * \returns feature ID
220 : : * \see setId()
221 : : */
222 : : QgsFeatureId id() const;
223 : :
224 : : /**
225 : : * Sets the feature ID for this feature.
226 : : * \param id feature id
227 : : * \see id
228 : : */
229 : : void setId( QgsFeatureId id );
230 : :
231 : : /**
232 : : * Returns the feature's attributes.
233 : : * \returns list of feature's attributes
234 : : * \see setAttributes
235 : : * \note Alternatively in Python: iterate feature, eg. @code [attr for attr in feature] @endcode
236 : : * \since QGIS 2.9
237 : : */
238 : : QgsAttributes attributes() const;
239 : :
240 : : /**
241 : : * Returns the number of attributes attached to the feature.
242 : : * \since QGIS 3.18
243 : : */
244 : : int attributeCount() const;
245 : :
246 : : /**
247 : : * Sets the feature's attributes.
248 : : * The feature will be valid after. The number of provided attributes need to match exactly the
249 : : * number of the feature's fields.
250 : : * \param attrs List of attribute values
251 : : * \see setAttribute
252 : : * \see attributes
253 : : * \warning Method will return false if the number of provided attributes does not exactly match
254 : : * the number of the feature's fields and it will not be possible to add this feature to the data
255 : : * provider.
256 : : */
257 : : void setAttributes( const QgsAttributes &attrs );
258 : :
259 : : /**
260 : : * Set an attribute's value by field index.
261 : : * The feature will be valid if it was successful.
262 : : * \param field the index of the field to set
263 : : * \param attr the value of the attribute
264 : : * \returns FALSE, if the field index does not exist
265 : : * \note For Python: raises a KeyError exception instead of returning FALSE
266 : : * \note Alternatively in Python: @code feature[field] = attr @endcode
267 : : * \see setAttributes
268 : : */
269 : : #ifndef SIP_RUN
270 : : bool setAttribute( int field, const QVariant &attr );
271 : : #else
272 : : bool setAttribute( int field, const QVariant &attr / GetWrapper / );
273 : : % MethodCode
274 : : bool rv;
275 : :
276 : : if ( a1Wrapper == Py_None )
277 : : {
278 : : rv = sipCpp->setAttribute( a0, QVariant( QVariant::Int ) );
279 : : }
280 : : else
281 : : {
282 : : rv = sipCpp->setAttribute( a0, *a1 );
283 : : }
284 : :
285 : : if ( !rv )
286 : : {
287 : : PyErr_SetString( PyExc_KeyError, QByteArray::number( a0 ) );
288 : : sipIsErr = 1;
289 : : }
290 : :
291 : : sipRes = rv;
292 : : % End
293 : : #endif
294 : :
295 : : /**
296 : : * Initialize this feature with the given number of fields. Discard any previously set attribute data.
297 : : * \param fieldCount Number of fields to initialize
298 : : *
299 : : * \see resizeAttributes()
300 : : */
301 : : void initAttributes( int fieldCount );
302 : :
303 : : /**
304 : : * Resizes the attributes attached to this feature to the given number of fields.
305 : : *
306 : : * If the new \a fieldCount is greater than the original number of fields then the additional attributes will
307 : : * be filled with NULL values. All existing attributes will remain unchanged.
308 : : *
309 : : * If the new \a fieldCount is less than the original number of fields then the unwanted values will be discarded from the
310 : : * end of the existing attributes.
311 : : *
312 : : * \see initAttributes()
313 : : * \see padAttributes()
314 : : * \since QGIS 3.18
315 : : */
316 : : void resizeAttributes( int fieldCount );
317 : :
318 : : /**
319 : : * Resizes the attributes attached to this feature by appending the specified \a count of NULL values to the end of the existing attributes.
320 : : *
321 : : * \see resizeAttributes()
322 : : * \since QGIS 3.18
323 : : */
324 : : void padAttributes( int count );
325 : :
326 : : /**
327 : : * Deletes an attribute and its value.
328 : : * \param field the index of the field
329 : : * \see setAttribute
330 : : * \note For Python: raises a KeyError exception if the field is not found
331 : : * \note Alternatively in Python: @code del feature[field] @endcode
332 : : */
333 : : void deleteAttribute( int field );
334 : : #ifdef SIP_RUN
335 : : % MethodCode
336 : : if ( a0 >= 0 && a0 < sipCpp->attributes().count() )
337 : : sipCpp->deleteAttribute( a0 );
338 : : else
339 : : {
340 : : PyErr_SetString( PyExc_KeyError, QByteArray::number( a0 ) );
341 : : sipIsErr = 1;
342 : : }
343 : : % End
344 : : #endif
345 : :
346 : : /**
347 : : * Returns the validity of this feature. This is normally set by
348 : : * the provider to indicate some problem that makes the feature
349 : : * invalid or to indicate a null feature.
350 : : * \see setValid
351 : : */
352 : : bool isValid() const;
353 : :
354 : : /**
355 : : * Sets the validity of the feature.
356 : : * \param validity set to TRUE if feature is valid
357 : : * \see isValid
358 : : */
359 : : void setValid( bool validity );
360 : :
361 : : /**
362 : : * Returns TRUE if the feature has an associated geometry.
363 : : * \see geometry()
364 : : * \since QGIS 3.0.
365 : : */
366 : : bool hasGeometry() const;
367 : :
368 : : /**
369 : : * Returns the geometry associated with this feature. If the feature has no geometry,
370 : : * an empty QgsGeometry object will be returned.
371 : : * \see hasGeometry()
372 : : * \see setGeometry()
373 : : */
374 : : QgsGeometry geometry() const;
375 : :
376 : : /**
377 : : * Set the feature's geometry. The feature will be valid after.
378 : : * \param geometry new feature geometry
379 : : * \see geometry()
380 : : * \see clearGeometry()
381 : : */
382 : : void setGeometry( const QgsGeometry &geometry );
383 : :
384 : : /**
385 : : * Set the feature's \a geometry. Ownership of the geometry is transferred to the feature.
386 : : * The feature will be made valid after calling this method.
387 : : *
388 : : * This method is a shortcut for calling:
389 : : * \code{.py}
390 : : * feature.setGeometry( QgsGeometry( geometry ) )
391 : : * \endcode
392 : : *
393 : : * ### Example
394 : : *
395 : : * \code{.py}
396 : : * # Sets a feature's geometry to a point geometry
397 : : * feature.setGeometry( QgsPoint( 210, 41 ) )
398 : : * print(feature.geometry())
399 : : * # output: <QgsGeometry: Point (210 41)>
400 : : *
401 : : * # Sets a feature's geometry to a line string
402 : : * feature.setGeometry( QgsLineString( [ QgsPoint( 210, 41 ), QgsPoint( 301, 55 ) ] ) )
403 : : * print(feature.geometry())
404 : : * # output: <QgsGeometry: LineString (210 41, 301 55)>
405 : : * \endcode
406 : : *
407 : : * \see geometry()
408 : : * \see clearGeometry()
409 : : * \since QGIS 3.6
410 : : */
411 : : #ifndef SIP_RUN
412 : : void setGeometry( std::unique_ptr< QgsAbstractGeometry > geometry );
413 : : #else
414 : : void setGeometry( QgsAbstractGeometry *geometry SIP_TRANSFER );
415 : : % MethodCode
416 : : sipCpp->setGeometry( std::unique_ptr< QgsAbstractGeometry>( a0 ) );
417 : : % End
418 : : #endif
419 : :
420 : : /**
421 : : * Removes any geometry associated with the feature.
422 : : * \see setGeometry()
423 : : * \see hasGeometry()
424 : : * \since QGIS 3.0
425 : : */
426 : : void clearGeometry();
427 : :
428 : : /**
429 : : * Assign a field map with the feature to allow attribute access by attribute name.
430 : : * \param fields The attribute fields which this feature holds
431 : : * \param initAttributes If TRUE, attributes are initialized. Clears any data previously assigned.
432 : : * C++: Defaults to FALSE
433 : : * Python: Defaults to TRUE
434 : : * \see fields
435 : : * \since QGIS 2.9
436 : : */
437 : : void setFields( const QgsFields &fields, bool initAttributes = false SIP_PYARGDEFAULT( true ) );
438 : :
439 : : /**
440 : : * Returns the field map associated with the feature.
441 : : * \see setFields
442 : : */
443 : : QgsFields fields() const;
444 : :
445 : : /**
446 : : * Insert a value into attribute. Returns FALSE if attribute name could not be converted to index.
447 : : * Field map must be associated using setFields() before this method can be used.
448 : : * The feature will be valid if it was successful
449 : : * \param name The name of the field to set
450 : : * \param value The value to set
451 : : * \returns FALSE if attribute name could not be converted to index (C++ only)
452 : : * \note For Python: raises a KeyError exception instead of returning FALSE
453 : : * \note Alternatively in Python: @code feature[name] = attr @endcode
454 : : * \see setFields
455 : : */
456 : : #ifndef SIP_RUN
457 : : bool setAttribute( const QString &name, const QVariant &value );
458 : : #else
459 : : void setAttribute( const QString &name, const QVariant &value / GetWrapper / );
460 : : % MethodCode
461 : : int fieldIdx = sipCpp->fieldNameIndex( *a0 );
462 : : if ( fieldIdx == -1 )
463 : : {
464 : : PyErr_SetString( PyExc_KeyError, a0->toLatin1() );
465 : : sipIsErr = 1;
466 : : }
467 : : else
468 : : {
469 : : if ( a1Wrapper == Py_None )
470 : : {
471 : : sipCpp->setAttribute( *a0, QVariant( QVariant::Int ) );
472 : : }
473 : : else
474 : : {
475 : : sipCpp->setAttribute( fieldIdx, *a1 );
476 : : }
477 : : }
478 : : % End
479 : : #endif
480 : :
481 : : /**
482 : : * Removes an attribute value by field name. Field map must be associated using setFields()
483 : : * before this method can be used.
484 : : * \param name The name of the field to delete
485 : : * \returns FALSE if attribute name could not be converted to index (C++ only)
486 : : * \note For Python: raises a KeyError exception instead of returning FALSE
487 : : * \note Alternatively in Python: @code del feature[name] @endcode
488 : : * \see setFields
489 : : */
490 : : bool deleteAttribute( const QString &name );
491 : : #ifdef SIP_RUN
492 : : % MethodCode
493 : : int fieldIdx = sipCpp->fieldNameIndex( *a0 );
494 : : if ( fieldIdx == -1 )
495 : : {
496 : : PyErr_SetString( PyExc_KeyError, a0->toLatin1() );
497 : : sipIsErr = 1;
498 : : sipRes = false;
499 : : }
500 : : else
501 : : {
502 : : sipCpp->deleteAttribute( fieldIdx );
503 : : sipRes = true;
504 : : }
505 : : % End
506 : : #endif
507 : :
508 : : /**
509 : : * Lookup attribute value from attribute name. Field map must be associated using setFields()
510 : : * before this method can be used.
511 : : * \param name The name of the attribute to get
512 : : * \returns The value of the attribute (C++: Invalid variant if no such name exists )
513 : : * \note For Python: raises a KeyError exception if the field is not found
514 : : * \note Alternatively in Python: @code feature[name] @endcode
515 : : * \see setFields
516 : : */
517 : : #ifndef SIP_RUN
518 : : QVariant attribute( const QString &name ) const;
519 : : #else
520 : : SIP_PYOBJECT attribute( const QString &name ) const;
521 : : % MethodCode
522 : : int fieldIdx = sipCpp->fieldNameIndex( *a0 );
523 : : if ( fieldIdx == -1 )
524 : : {
525 : : PyErr_SetString( PyExc_KeyError, a0->toLatin1() );
526 : : sipIsErr = 1;
527 : : }
528 : : else
529 : : {
530 : : QVariant *v = new QVariant( sipCpp->attribute( fieldIdx ) );
531 : : sipRes = sipConvertFromNewType( v, sipType_QVariant, Py_None );
532 : : }
533 : : % End
534 : : #endif
535 : :
536 : : /**
537 : : * Lookup attribute value from its index. Field map must be associated using setFields()
538 : : * before this method can be used.
539 : : * \param fieldIdx The index of the attribute to get
540 : : * \returns The value of the attribute (C++: Invalid variant if no such index exists )
541 : : * \note For Python: raises a KeyError exception if the field is not found
542 : : * \note Alternatively in Python: @code feature[fieldIdx] @endcode
543 : : * \see setFields
544 : : */
545 : : #ifndef SIP_RUN
546 : : QVariant attribute( int fieldIdx ) const;
547 : : #else
548 : : SIP_PYOBJECT attribute( int fieldIdx ) const;
549 : : % MethodCode
550 : : {
551 : : if ( a0 < 0 || a0 >= sipCpp->attributes().count() )
552 : : {
553 : : PyErr_SetString( PyExc_KeyError, QByteArray::number( a0 ) );
554 : : sipIsErr = 1;
555 : : }
556 : : else
557 : : {
558 : : QVariant *v = new QVariant( sipCpp->attribute( a0 ) );
559 : : sipRes = sipConvertFromNewType( v, sipType_QVariant, Py_None );
560 : : }
561 : : }
562 : : % End
563 : : #endif
564 : :
565 : : /**
566 : : * Returns the feature's embedded symbology, or NULLPTR if the feature has no embedded symbol.
567 : : *
568 : : * \since QGIS 3.20
569 : : */
570 : : const QgsSymbol *embeddedSymbol() const;
571 : :
572 : : /**
573 : : * Sets the feature's embedded \a symbol.
574 : : *
575 : : * Ownership of \a symbol is transferred to the feature.
576 : : *
577 : : * \since QGIS 3.20
578 : : */
579 : : void setEmbeddedSymbol( QgsSymbol *symbol SIP_TRANSFER );
580 : :
581 : : /**
582 : : * Utility method to get attribute index from name. Field map must be associated using setFields()
583 : : * before this method can be used.
584 : : * \param fieldName name of field to get attribute index of
585 : : * \returns -1 if field does not exist or field map is not associated.
586 : : * \see setFields
587 : : */
588 : : int fieldNameIndex( const QString &fieldName ) const;
589 : :
590 : : /**
591 : : * Returns the approximate RAM usage of the feature, in bytes.
592 : : *
593 : : * This method takes into account the size of variable elements (strings,
594 : : * geometry, ...), but the value returned should be considered as a lower
595 : : * bound estimation.
596 : : *
597 : : * \since QGIS 3.16
598 : : */
599 : : int approximateMemoryUsage() const;
600 : :
601 : : //! Allows direct construction of QVariants from features.
602 : 0 : operator QVariant() const
603 : : {
604 : 0 : return QVariant::fromValue( *this );
605 : : }
606 : :
607 : : private:
608 : :
609 : : QExplicitlySharedDataPointer<QgsFeaturePrivate> d;
610 : :
611 : : }; // class QgsFeature
612 : :
613 : : //! Writes the feature to stream out. QGIS version compatibility is not guaranteed.
614 : : CORE_EXPORT QDataStream &operator<<( QDataStream &out, const QgsFeature &feature ) SIP_SKIP;
615 : : //! Reads a feature from stream in into feature. QGIS version compatibility is not guaranteed.
616 : : CORE_EXPORT QDataStream &operator>>( QDataStream &in, QgsFeature &feature ) SIP_SKIP;
617 : :
618 : : // key = feature id, value = changed attributes
619 : : #ifndef SIP_RUN
620 : : typedef QMap<QgsFeatureId, QgsAttributeMap> QgsChangedAttributesMap;
621 : : #else
622 : : typedef QMap<qint64, QMap<int, QVariant> > QgsChangedAttributesMap;
623 : : #endif
624 : :
625 : : #include "qgsgeometry.h"
626 : :
627 : : // key = feature id, value = changed geometry
628 : : #ifndef SIP_RUN
629 : : typedef QMap<QgsFeatureId, QgsGeometry> QgsGeometryMap;
630 : : #else
631 : : typedef QMap<qint64, QgsGeometry> QgsGeometryMap;
632 : : #endif
633 : :
634 : : typedef QList<QgsFeature> QgsFeatureList;
635 : :
636 : : uint qHash( const QgsFeature &key, uint seed = 0 ) SIP_SKIP;
637 : :
638 : 0 : Q_DECLARE_METATYPE( QgsFeature )
639 : 0 : Q_DECLARE_METATYPE( QgsFeatureList )
640 : :
641 : : #endif
|