Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsabstractgeometry.h
3 : : -------------------------------------------------------------------
4 : : Date : 04 Sept 2014
5 : : Copyright : (C) 2014 by Marco Hugentobler
6 : : email : marco.hugentobler at sourcepole dot 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 QGSABSTRACTGEOMETRYV2
17 : : #define QGSABSTRACTGEOMETRYV2
18 : :
19 : : #include <array>
20 : : #include <functional>
21 : : #include <type_traits>
22 : : #include <QString>
23 : :
24 : : #include "qgis_core.h"
25 : : #include "qgscoordinatetransform.h"
26 : : #include "qgswkbtypes.h"
27 : : #include "qgswkbptr.h"
28 : :
29 : : #ifndef SIP_RUN
30 : : #include "json_fwd.hpp"
31 : : using namespace nlohmann;
32 : : #endif
33 : :
34 : : class QgsMapToPixel;
35 : : class QgsCurve;
36 : : class QgsMultiCurve;
37 : : class QgsMultiPoint;
38 : :
39 : : struct QgsVertexId;
40 : : class QgsVertexIterator;
41 : : class QPainter;
42 : : class QDomDocument;
43 : : class QDomElement;
44 : : class QgsGeometryPartIterator;
45 : : class QgsGeometryConstPartIterator;
46 : : class QgsConstWkbPtr;
47 : : class QPainterPath;
48 : : class QgsAbstractGeometryTransformer;
49 : : class QgsFeedback;
50 : :
51 : : typedef QVector< QgsPoint > QgsPointSequence;
52 : : #ifndef SIP_RUN
53 : : typedef QVector< QgsPointSequence > QgsRingSequence;
54 : : typedef QVector< QgsRingSequence > QgsCoordinateSequence;
55 : : #else
56 : : typedef QVector< QVector< QgsPoint > > QgsRingSequence;
57 : : typedef QVector< QVector< QVector< QgsPoint > > > QgsCoordinateSequence;
58 : : #endif
59 : :
60 : :
61 : : /**
62 : : * \ingroup core
63 : : * \class QgsAbstractGeometry
64 : : * \brief Abstract base class for all geometries
65 : : *
66 : : * \note QgsAbstractGeometry objects are inherently Cartesian/planar geometries. They have no concept of geodesy, and none
67 : : * of the methods or properties exposed from the QgsAbstractGeometry API (or QgsGeometry API) utilize
68 : : * geodesic calculations. Accordingly, properties like length() and area() and spatial operations like centroid()
69 : : * are always calculated using strictly Cartesian mathematics. In contrast, the QgsDistanceArea class exposes
70 : : * methods for working with geodesic calculations and spatial operations on geometries,
71 : : * and should be used whenever calculations which account for the curvature of the Earth (or any other celestial body)
72 : : * are required.
73 : : *
74 : : * \since QGIS 2.10
75 : : */
76 : : class CORE_EXPORT QgsAbstractGeometry
77 : : {
78 : :
79 : : #ifdef SIP_RUN
80 : : SIP_CONVERT_TO_SUBCLASS_CODE
81 : : if ( qgsgeometry_cast<QgsPoint *>( sipCpp ) != nullptr )
82 : : sipType = sipType_QgsPoint;
83 : : else if ( qgsgeometry_cast<QgsLineString *>( sipCpp ) != nullptr )
84 : : sipType = sipType_QgsLineString;
85 : : else if ( qgsgeometry_cast<QgsCircularString *>( sipCpp ) != nullptr )
86 : : sipType = sipType_QgsCircularString;
87 : : else if ( qgsgeometry_cast<QgsCompoundCurve *>( sipCpp ) != nullptr )
88 : : sipType = sipType_QgsCompoundCurve;
89 : : else if ( qgsgeometry_cast<QgsTriangle *>( sipCpp ) != nullptr )
90 : : sipType = sipType_QgsTriangle;
91 : : else if ( qgsgeometry_cast<QgsPolygon *>( sipCpp ) != nullptr )
92 : : sipType = sipType_QgsPolygon;
93 : : else if ( qgsgeometry_cast<QgsCurvePolygon *>( sipCpp ) != nullptr )
94 : : sipType = sipType_QgsCurvePolygon;
95 : : else if ( qgsgeometry_cast<QgsMultiPoint *>( sipCpp ) != nullptr )
96 : : sipType = sipType_QgsMultiPoint;
97 : : else if ( qgsgeometry_cast<QgsMultiLineString *>( sipCpp ) != nullptr )
98 : : sipType = sipType_QgsMultiLineString;
99 : : else if ( qgsgeometry_cast<QgsMultiPolygon *>( sipCpp ) != nullptr )
100 : : sipType = sipType_QgsMultiPolygon;
101 : : else if ( qgsgeometry_cast<QgsMultiSurface *>( sipCpp ) != nullptr )
102 : : sipType = sipType_QgsMultiSurface;
103 : : else if ( qgsgeometry_cast<QgsMultiCurve *>( sipCpp ) != nullptr )
104 : : sipType = sipType_QgsMultiCurve;
105 : : else if ( qgsgeometry_cast<QgsGeometryCollection *>( sipCpp ) != nullptr )
106 : : sipType = sipType_QgsGeometryCollection;
107 : : else
108 : : sipType = 0;
109 : : SIP_END
110 : : #endif
111 : :
112 : : Q_GADGET
113 : :
114 : : public:
115 : :
116 : : //! Segmentation tolerance as maximum angle or maximum difference between approximation and circle
117 : : enum SegmentationToleranceType
118 : : {
119 : :
120 : : /**
121 : : * Maximum angle between generating radii (lines from arc center
122 : : * to output vertices)
123 : : */
124 : : MaximumAngle = 0,
125 : :
126 : : /**
127 : : * Maximum distance between an arbitrary point on the original
128 : : * curve and closest point on its approximation.
129 : : */
130 : : MaximumDifference
131 : : };
132 : : Q_ENUM( SegmentationToleranceType )
133 : :
134 : : //! Axis order for GML generation
135 : : enum AxisOrder
136 : : {
137 : :
138 : : /**
139 : : * X comes before Y (or lon before lat)
140 : : */
141 : : XY = 0,
142 : :
143 : : /**
144 : : * Y comes before X (or lat before lon)
145 : : */
146 : : YX
147 : : };
148 : : Q_ENUM( QgsAbstractGeometry::AxisOrder )
149 : :
150 : : /**
151 : : * Constructor for QgsAbstractGeometry.
152 : : */
153 : 333413 : QgsAbstractGeometry() = default;
154 : 422970 : virtual ~QgsAbstractGeometry() = default;
155 : : QgsAbstractGeometry( const QgsAbstractGeometry &geom );
156 : : QgsAbstractGeometry &operator=( const QgsAbstractGeometry &geom );
157 : :
158 : : virtual bool operator==( const QgsAbstractGeometry &other ) const = 0;
159 : : virtual bool operator!=( const QgsAbstractGeometry &other ) const = 0;
160 : :
161 : : /**
162 : : * Clones the geometry by performing a deep copy
163 : : */
164 : : virtual QgsAbstractGeometry *clone() const = 0 SIP_FACTORY;
165 : :
166 : : /**
167 : : * Clears the geometry, ie reset it to a null geometry
168 : : */
169 : : virtual void clear() = 0;
170 : :
171 : : /**
172 : : * Returns the minimal bounding box for the geometry
173 : : */
174 : : virtual QgsRectangle boundingBox() const = 0;
175 : :
176 : : //mm-sql interface
177 : :
178 : : /**
179 : : * Returns the inherent dimension of the geometry. For example, this is 0 for a point geometry,
180 : : * 1 for a linestring and 2 for a polygon.
181 : : */
182 : : virtual int dimension() const = 0;
183 : :
184 : : /**
185 : : * Returns a unique string representing the geometry type.
186 : : * \see wkbType
187 : : * \see wktTypeStr
188 : : */
189 : : virtual QString geometryType() const = 0;
190 : :
191 : : /**
192 : : * Returns the WKB type of the geometry.
193 : : * \see geometryType
194 : : * \see wktTypeStr
195 : : */
196 : 846244 : inline QgsWkbTypes::Type wkbType() const SIP_HOLDGIL { return mWkbType; }
197 : :
198 : : /**
199 : : * Returns the WKT type string of the geometry.
200 : : * \see geometryType
201 : : * \see wkbType
202 : : */
203 : : QString wktTypeStr() const;
204 : :
205 : : /**
206 : : * Returns TRUE if the geometry is 3D and contains a z-value.
207 : : * \see isMeasure
208 : : */
209 : 521817 : bool is3D() const SIP_HOLDGIL
210 : : {
211 : 521817 : return QgsWkbTypes::hasZ( mWkbType );
212 : : }
213 : :
214 : : /**
215 : : * Returns TRUE if the geometry contains m values.
216 : : * \see is3D
217 : : */
218 : 413155 : bool isMeasure() const SIP_HOLDGIL
219 : : {
220 : 413155 : return QgsWkbTypes::hasM( mWkbType );
221 : : }
222 : :
223 : : /**
224 : : * Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the geometry).
225 : : * For instance, a polygon geometry will have a boundary consisting of the linestrings for each ring in the polygon.
226 : : * \returns boundary for geometry. May be NULLPTR for some geometry types.
227 : : * \since QGIS 3.0
228 : : */
229 : : virtual QgsAbstractGeometry *boundary() const = 0 SIP_FACTORY;
230 : :
231 : : //import
232 : :
233 : : /**
234 : : * Sets the geometry from a WKB string.
235 : : * After successful read the wkb argument will be at the position where the reading has stopped.
236 : : * \see fromWkt
237 : : */
238 : : virtual bool fromWkb( QgsConstWkbPtr &wkb ) = 0;
239 : :
240 : : /**
241 : : * Sets the geometry from a WKT string.
242 : : * \see fromWkb
243 : : */
244 : : virtual bool fromWkt( const QString &wkt ) = 0;
245 : :
246 : : //export
247 : :
248 : : /**
249 : : * WKB export flags.
250 : : * \since QGIS 3.14
251 : : */
252 : : enum WkbFlag
253 : : {
254 : : FlagExportTrianglesAsPolygons = 1 << 0, //!< Triangles should be exported as polygon geometries
255 : : };
256 : : Q_DECLARE_FLAGS( WkbFlags, WkbFlag )
257 : :
258 : : /**
259 : : * Returns the length of the QByteArray returned by asWkb()
260 : : *
261 : : * The optional \a flags argument specifies flags controlling WKB export behavior
262 : : *
263 : : * \since QGIS 3.16
264 : : */
265 : : virtual int wkbSize( QgsAbstractGeometry::WkbFlags flags = QgsAbstractGeometry::WkbFlags() ) const = 0;
266 : :
267 : : /**
268 : : * Returns a WKB representation of the geometry.
269 : : *
270 : : * The optional \a flags argument specifies flags controlling WKB export behavior (since QGIS 3.14).
271 : : *
272 : : * \see asWkt
273 : : * \see asGml2
274 : : * \see asGml3
275 : : * \see asJson()
276 : : * \since QGIS 3.0
277 : : */
278 : : virtual QByteArray asWkb( WkbFlags flags = QgsAbstractGeometry::WkbFlags() ) const = 0;
279 : :
280 : : /**
281 : : * Returns a WKT representation of the geometry.
282 : : * \param precision number of decimal places for coordinates
283 : : * \see asWkb()
284 : : * \see asGml2()
285 : : * \see asGml3()
286 : : * \see asJson()
287 : : */
288 : : virtual QString asWkt( int precision = 17 ) const = 0;
289 : :
290 : : /**
291 : : * Returns a GML2 representation of the geometry.
292 : : * \param doc DOM document
293 : : * \param precision number of decimal places for coordinates
294 : : * \param ns XML namespace
295 : : * \param axisOrder Axis order for generated GML
296 : : * \see asWkb()
297 : : * \see asWkt()
298 : : * \see asGml3()
299 : : * \see asJson()
300 : : */
301 : : virtual QDomElement asGml2( QDomDocument &doc, int precision = 17, const QString &ns = "gml", AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const = 0;
302 : :
303 : : /**
304 : : * Returns a GML3 representation of the geometry.
305 : : * \param doc DOM document
306 : : * \param precision number of decimal places for coordinates
307 : : * \param ns XML namespace
308 : : * \param axisOrder Axis order for generated GML
309 : : * \see asWkb()
310 : : * \see asWkt()
311 : : * \see asGml2()
312 : : * \see asJson()
313 : : */
314 : : virtual QDomElement asGml3( QDomDocument &doc, int precision = 17, const QString &ns = "gml", AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const = 0;
315 : :
316 : : /**
317 : : * Returns a GeoJSON representation of the geometry as a QString.
318 : : * \param precision number of decimal places for coordinates
319 : : * \see asWkb()
320 : : * \see asWkt()
321 : : * \see asGml2()
322 : : * \see asGml3()
323 : : * \see asJsonObject()
324 : : */
325 : : QString asJson( int precision = 17 );
326 : :
327 : : /**
328 : : * Returns a json object representation of the geometry.
329 : : * \see asWkb()
330 : : * \see asWkt()
331 : : * \see asGml2()
332 : : * \see asGml3()
333 : : * \see asJson()
334 : : * \note not available in Python bindings
335 : : * \since QGIS 3.10
336 : : */
337 : : virtual json asJsonObject( int precision = 17 ) SIP_SKIP const;
338 : :
339 : : /**
340 : : * Returns a KML representation of the geometry.
341 : : * \since QGIS 3.12
342 : : */
343 : : virtual QString asKml( int precision = 17 ) const = 0;
344 : :
345 : :
346 : : //render pipeline
347 : :
348 : : /**
349 : : * Transforms the geometry using a coordinate transform
350 : : * \param ct coordinate transform
351 : : * \param d transformation direction
352 : : * \param transformZ set to TRUE to also transform z coordinates. This requires that
353 : : * the z coordinates in the geometry represent height relative to the vertical datum
354 : : * of the source CRS (generally ellipsoidal heights) and are expressed in its vertical
355 : : * units (generally meters). If FALSE, then z coordinates will not be changed by the
356 : : * transform.
357 : : */
358 : : virtual void transform( const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform, bool transformZ = false ) SIP_THROW( QgsCsException ) = 0;
359 : :
360 : : /**
361 : : * Transforms the x and y components of the geometry using a QTransform object \a t.
362 : : *
363 : : * Optionally, the geometry's z values can be scaled via \a zScale and translated via \a zTranslate.
364 : : * Similarly, m-values can be scaled via \a mScale and translated via \a mTranslate.
365 : : */
366 : : virtual void transform( const QTransform &t, double zTranslate = 0.0, double zScale = 1.0,
367 : : double mTranslate = 0.0, double mScale = 1.0 ) = 0;
368 : :
369 : : /**
370 : : * Draws the geometry using the specified QPainter.
371 : : * \param p destination QPainter
372 : : */
373 : : virtual void draw( QPainter &p ) const = 0;
374 : :
375 : : /**
376 : : * Returns the geometry represented as a QPainterPath.
377 : : *
378 : : * \warning not all geometry subclasses can be represented by a QPainterPath, e.g.
379 : : * points and multipoint geometries will return an empty path.
380 : : *
381 : : * \since QGIS 3.16
382 : : */
383 : : virtual QPainterPath asQPainterPath() const = 0;
384 : :
385 : : /**
386 : : * Returns the vertex number corresponding to a vertex \a id.
387 : : *
388 : : * The vertex numbers start at 0, so a return value of 0 corresponds
389 : : * to the first vertex.
390 : : *
391 : : * Returns -1 if a corresponding vertex could not be found.
392 : : *
393 : : * \since QGIS 3.0
394 : : */
395 : : virtual int vertexNumberFromVertexId( QgsVertexId id ) const = 0;
396 : :
397 : : /**
398 : : * Returns next vertex id and coordinates
399 : : * \param id initial value should be the starting vertex id. The next vertex id will be stored
400 : : * in this variable if found.
401 : : * \param vertex container for found node
402 : : * \returns FALSE if at end
403 : : */
404 : : virtual bool nextVertex( QgsVertexId &id, QgsPoint &vertex SIP_OUT ) const = 0;
405 : :
406 : : /**
407 : : * Returns the vertices adjacent to a specified \a vertex within a geometry.
408 : : * \since QGIS 3.0
409 : : */
410 : : virtual void adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex SIP_OUT, QgsVertexId &nextVertex SIP_OUT ) const = 0;
411 : :
412 : : /**
413 : : * Retrieves the sequence of geometries, rings and nodes.
414 : : * \returns coordinate sequence
415 : : */
416 : : virtual QgsCoordinateSequence coordinateSequence() const = 0;
417 : :
418 : : /**
419 : : * Returns the number of nodes contained in the geometry
420 : : */
421 : : virtual int nCoordinates() const;
422 : :
423 : : /**
424 : : * Returns the point corresponding to a specified vertex id
425 : : */
426 : : virtual QgsPoint vertexAt( QgsVertexId id ) const = 0;
427 : :
428 : : /**
429 : : * Searches for the closest segment of the geometry to a given point.
430 : : * \param pt specifies the point to find closest segment to
431 : : * \param segmentPt storage for the closest point within the geometry
432 : : * \param vertexAfter storage for the ID of the vertex at the end of the closest segment
433 : : * \param leftOf indicates whether the point lies on the left side of the geometry (-1 if point is to the left
434 : : * of the geometry, +1 if the point is to the right of the geometry, or 0 for cases where left/right could not
435 : : * be determined, e.g. point exactly on a line)
436 : : * FALSE if point is to right of segment)
437 : : * \param epsilon epsilon for segment snapping
438 : : * \returns squared distance to closest segment or negative value on error
439 : : */
440 : : virtual double closestSegment( const QgsPoint &pt, QgsPoint &segmentPt SIP_OUT,
441 : : QgsVertexId &vertexAfter SIP_OUT,
442 : : int *leftOf SIP_OUT = nullptr, double epsilon = 4 * std::numeric_limits<double>::epsilon() ) const = 0;
443 : :
444 : : //low-level editing
445 : :
446 : : /**
447 : : * Inserts a vertex into the geometry
448 : : * \param position vertex id for position of inserted vertex
449 : : * \param vertex vertex to insert
450 : : * \returns TRUE if insert was successful
451 : : * \see moveVertex
452 : : * \see deleteVertex
453 : : */
454 : : virtual bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) = 0;
455 : :
456 : : /**
457 : : * Moves a vertex within the geometry
458 : : * \param position vertex id for vertex to move
459 : : * \param newPos new position of vertex
460 : : * \returns TRUE if move was successful
461 : : * \see insertVertex
462 : : * \see deleteVertex
463 : : */
464 : : virtual bool moveVertex( QgsVertexId position, const QgsPoint &newPos ) = 0;
465 : :
466 : : /**
467 : : * Deletes a vertex within the geometry
468 : : * \param position vertex id for vertex to delete
469 : : * \returns TRUE if delete was successful
470 : : * \see insertVertex
471 : : * \see moveVertex
472 : : */
473 : : virtual bool deleteVertex( QgsVertexId position ) = 0;
474 : :
475 : : /**
476 : : * Returns the planar, 2-dimensional length of the geometry.
477 : : *
478 : : * \warning QgsAbstractGeometry objects are inherently Cartesian/planar geometries, and the length
479 : : * returned by this method is calculated using strictly Cartesian mathematics. In contrast,
480 : : * the QgsDistanceArea class exposes methods for calculating the lengths of geometries using
481 : : * geodesic calculations which account for the curvature of the Earth (or any other
482 : : * celestial body).
483 : : *
484 : : * \see area()
485 : : * \see perimeter()
486 : : */
487 : : virtual double length() const;
488 : :
489 : : /**
490 : : * Returns the planar, 2-dimensional perimeter of the geometry.
491 : : *
492 : : * \warning QgsAbstractGeometry objects are inherently Cartesian/planar geometries, and the perimeter
493 : : * returned by this method is calculated using strictly Cartesian mathematics. In contrast,
494 : : * the QgsDistanceArea class exposes methods for calculating the perimeters of geometries using
495 : : * geodesic calculations which account for the curvature of the Earth (or any other
496 : : * celestial body).
497 : : *
498 : : * \see area()
499 : : * \see length()
500 : : */
501 : : virtual double perimeter() const;
502 : :
503 : : /**
504 : : * Returns the planar, 2-dimensional area of the geometry.
505 : : *
506 : : * \warning QgsAbstractGeometry objects are inherently Cartesian/planar geometries, and the area
507 : : * returned by this method is calculated using strictly Cartesian mathematics. In contrast,
508 : : * the QgsDistanceArea class exposes methods for calculating the areas of geometries using
509 : : * geodesic calculations which account for the curvature of the Earth (or any other
510 : : * celestial body).
511 : : *
512 : : * \see length()
513 : : * \see perimeter()
514 : : */
515 : : virtual double area() const;
516 : :
517 : : /**
518 : : * Returns the length of the segment of the geometry which begins at \a startVertex.
519 : : *
520 : : * \warning QgsAbstractGeometry objects are inherently Cartesian/planar geometries, and the lengths
521 : : * returned by this method are calculated using strictly Cartesian mathematics.
522 : : *
523 : : * \since QGIS 3.0
524 : : */
525 : : virtual double segmentLength( QgsVertexId startVertex ) const = 0;
526 : :
527 : : //! Returns the centroid of the geometry
528 : : virtual QgsPoint centroid() const;
529 : :
530 : : /**
531 : : * Returns TRUE if the geometry is empty
532 : : */
533 : : virtual bool isEmpty() const;
534 : :
535 : : /**
536 : : * Returns TRUE if the geometry contains curved segments
537 : : */
538 : : virtual bool hasCurvedSegments() const;
539 : :
540 : : /**
541 : : * Returns TRUE if the bounding box of this geometry intersects with a \a rectangle.
542 : : *
543 : : * Since this test only considers the bounding box of the geometry, is is very fast to
544 : : * calculate and handles invalid geometries.
545 : : *
546 : : * \since QGIS 3.20
547 : : */
548 : : virtual bool boundingBoxIntersects( const QgsRectangle &rectangle ) const SIP_HOLDGIL;
549 : :
550 : : /**
551 : : * Returns a version of the geometry without curves. Caller takes ownership of
552 : : * the returned geometry.
553 : : * \param tolerance segmentation tolerance
554 : : * \param toleranceType maximum segmentation angle or maximum difference between approximation and curve
555 : : */
556 : : virtual QgsAbstractGeometry *segmentize( double tolerance = M_PI / 180., SegmentationToleranceType toleranceType = MaximumAngle ) const SIP_FACTORY;
557 : :
558 : : /**
559 : : * Returns the geometry converted to the more generic curve type.
560 : : * E.g. QgsLineString -> QgsCompoundCurve, QgsPolygon -> QgsCurvePolygon,
561 : : * QgsMultiLineString -> QgsMultiCurve, QgsMultiPolygon -> QgsMultiSurface
562 : : * \returns the converted geometry. Caller takes ownership
563 : : */
564 : : virtual QgsAbstractGeometry *toCurveType() const = 0 SIP_FACTORY;
565 : :
566 : : /**
567 : : * Makes a new geometry with all the points or vertices snapped to the closest point of the grid.
568 : : * Ownership is transferred to the caller.
569 : : *
570 : : * If the gridified geometry could not be calculated NULLPTR will be returned.
571 : : * It may generate an invalid geometry (in some corner cases).
572 : : * It can also be thought as rounding the edges and it may be useful for removing errors.
573 : : *
574 : : * Example:
575 : : *
576 : : * \code{.py}
577 : : * geometry.snappedToGrid(1, 1)
578 : : * \endcode
579 : : *
580 : : * In this case we use a 2D grid of 1x1 to gridify.
581 : : * In this case, it can be thought like rounding the x and y of all the points/vertices to full units (remove all decimals).
582 : : * \param hSpacing Horizontal spacing of the grid (x axis). 0 to disable.
583 : : * \param vSpacing Vertical spacing of the grid (y axis). 0 to disable.
584 : : * \param dSpacing Depth spacing of the grid (z axis). 0 (default) to disable.
585 : : * \param mSpacing Custom dimension spacing of the grid (m axis). 0 (default) to disable.
586 : : * \since 3.0
587 : : */
588 : : virtual QgsAbstractGeometry *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const = 0 SIP_FACTORY;
589 : :
590 : : /**
591 : : * Removes duplicate nodes from the geometry, wherever removing the nodes does not result in a
592 : : * degenerate geometry.
593 : : *
594 : : * The \a epsilon parameter specifies the tolerance for coordinates when determining that
595 : : * vertices are identical.
596 : : *
597 : : * By default, z values are not considered when detecting duplicate nodes. E.g. two nodes
598 : : * with the same x and y coordinate but different z values will still be considered
599 : : * duplicate and one will be removed. If \a useZValues is TRUE, then the z values are
600 : : * also tested and nodes with the same x and y but different z will be maintained.
601 : : *
602 : : * Note that duplicate nodes are not tested between different parts of a multipart geometry. E.g.
603 : : * a multipoint geometry with overlapping points will not be changed by this method.
604 : : *
605 : : * The function will return TRUE if nodes were removed, or FALSE if no duplicate nodes
606 : : * were found.
607 : : *
608 : : * \since QGIS 3.0
609 : : */
610 : : virtual bool removeDuplicateNodes( double epsilon = 4 * std::numeric_limits<double>::epsilon(), bool useZValues = false ) = 0;
611 : :
612 : : /**
613 : : * Returns approximate angle at a vertex. This is usually the average angle between adjacent
614 : : * segments, and can be pictured as the orientation of a line following the curvature of the
615 : : * geometry at the specified vertex.
616 : : * \param vertex the vertex id
617 : : * \returns rotation in radians, clockwise from north
618 : : */
619 : : virtual double vertexAngle( QgsVertexId vertex ) const = 0;
620 : :
621 : : /**
622 : : * Returns the number of vertices of which this geometry is built.
623 : : */
624 : : virtual int vertexCount( int part = 0, int ring = 0 ) const = 0;
625 : :
626 : : /**
627 : : * Returns the number of rings of which this geometry is built.
628 : : */
629 : : virtual int ringCount( int part = 0 ) const = 0;
630 : :
631 : : /**
632 : : * Returns count of parts contained in the geometry.
633 : : * \see vertexCount
634 : : * \see ringCount
635 : : */
636 : : virtual int partCount() const = 0;
637 : :
638 : : /**
639 : : * Adds a z-dimension to the geometry, initialized to a preset value.
640 : : * \param zValue initial z-value for all nodes
641 : : * \returns TRUE on success
642 : : * \see dropZValue()
643 : : * \see addMValue()
644 : : * \since QGIS 2.12
645 : : */
646 : : virtual bool addZValue( double zValue = 0 ) = 0;
647 : :
648 : : /**
649 : : * Adds a measure to the geometry, initialized to a preset value.
650 : : * \param mValue initial m-value for all nodes
651 : : * \returns TRUE on success
652 : : * \see dropMValue()
653 : : * \see addZValue()
654 : : * \since QGIS 2.12
655 : : */
656 : : virtual bool addMValue( double mValue = 0 ) = 0;
657 : :
658 : : /**
659 : : * Drops any z-dimensions which exist in the geometry.
660 : : * \returns TRUE if Z values were present and have been removed
661 : : * \see addZValue()
662 : : * \see dropMValue()
663 : : * \since QGIS 2.14
664 : : */
665 : : virtual bool dropZValue() = 0;
666 : :
667 : : /**
668 : : * Drops any measure values which exist in the geometry.
669 : : * \returns TRUE if m-values were present and have been removed
670 : : * \see addMValue()
671 : : * \see dropZValue()
672 : : * \since QGIS 2.14
673 : : */
674 : : virtual bool dropMValue() = 0;
675 : :
676 : : /**
677 : : * Swaps the x and y coordinates from the geometry. This can be used
678 : : * to repair geometries which have accidentally had their latitude and longitude
679 : : * coordinates reversed.
680 : : * \since QGIS 3.2
681 : : */
682 : : virtual void swapXy() = 0;
683 : :
684 : : /**
685 : : * Converts the geometry to a specified type.
686 : : * \returns TRUE if conversion was successful
687 : : * \since QGIS 2.14
688 : : */
689 : : virtual bool convertTo( QgsWkbTypes::Type type );
690 : :
691 : : /**
692 : : * Checks validity of the geometry, and returns TRUE if the geometry is valid.
693 : : *
694 : : * \param error will be set to the validity error message
695 : : * \param flags indicates optional flags which control the type of validity checking performed
696 : : * (corresponding to QgsGeometry::ValidityFlags).
697 : : *
698 : : * \returns TRUE if geometry is valid
699 : : *
700 : : * \since QGIS 3.8
701 : : */
702 : : virtual bool isValid( QString &error SIP_OUT, int flags = 0 ) const = 0;
703 : :
704 : : /**
705 : : * Transforms the vertices from the geometry in place, using the specified geometry \a transformer
706 : : * object.
707 : : *
708 : : * Depending on the \a transformer used, this may result in an invalid geometry.
709 : : *
710 : : * The optional \a feedback argument can be used to cancel the transformation before it completes.
711 : : * If this is done, the geometry will be left in a semi-transformed state.
712 : : *
713 : : * \returns TRUE if the geometry was successfully transformed.
714 : : *
715 : : * \since QGIS 3.18
716 : : */
717 : : virtual bool transform( QgsAbstractGeometryTransformer *transformer, QgsFeedback *feedback = nullptr ) = 0;
718 : :
719 : : #ifndef SIP_RUN
720 : :
721 : : /**
722 : : * Filters the vertices from the geometry in place, removing any which do not return TRUE for the \a filter function
723 : : * check. Has no meaning when called on a single point geometry.
724 : : *
725 : : * Depending on the \a filter used, this may result in an invalid geometry.
726 : : *
727 : : * \note Not available in Python bindings
728 : : * \since QGIS 3.2
729 : : */
730 : : virtual void filterVertices( const std::function< bool( const QgsPoint & ) > &filter );
731 : :
732 : : /**
733 : : * Transforms the vertices from the geometry in place, applying the \a transform function
734 : : * to every vertex.
735 : : *
736 : : * Depending on the \a transform used, this may result in an invalid geometry.
737 : : *
738 : : * Transform functions are not permitted to alter the dimensionality of vertices. If
739 : : * a transform which adds (or removes) z/m values is desired, first call the corresponding
740 : : * addZValue() or addMValue() function to change the geometry's dimensionality and then
741 : : * transform.
742 : : *
743 : : * \note Not available in Python bindings
744 : : * \since QGIS 3.4
745 : : */
746 : : virtual void transformVertices( const std::function< QgsPoint( const QgsPoint & ) > &transform );
747 : :
748 : : /**
749 : : * \ingroup core
750 : : * \brief The part_iterator class provides STL-style iterator for geometry parts.
751 : : * \since QGIS 3.6
752 : : */
753 : : class CORE_EXPORT part_iterator
754 : : {
755 : : private:
756 : :
757 : 2 : int mIndex = 0; //!< Current part in the geometry
758 : 2 : QgsAbstractGeometry *mGeometry = nullptr;
759 : :
760 : : public:
761 : : //! Create invalid iterator
762 : 2 : part_iterator() = default;
763 : :
764 : : //! Create part iterator for a geometry
765 : : part_iterator( QgsAbstractGeometry *g, int index );
766 : :
767 : : /**
768 : : * The prefix ++ operator (++it) advances the iterator to the next part and returns an iterator to the new current part.
769 : : * Calling this function on iterator that is already past the last item leads to undefined results.
770 : : */
771 : : part_iterator &operator++();
772 : :
773 : : //! The postfix ++ operator (it++) advances the iterator to the next part and returns an iterator to the previously current part.
774 : : part_iterator operator++( int );
775 : :
776 : : //! Returns the current item.
777 : : QgsAbstractGeometry *operator*() const;
778 : :
779 : : //! Returns the part number of the current item.
780 : : int partNumber() const;
781 : :
782 : : bool operator==( part_iterator other ) const;
783 : 37 : bool operator!=( part_iterator other ) const { return !( *this == other ); }
784 : : };
785 : :
786 : : /**
787 : : * Returns STL-style iterator pointing to the first part of the geometry.
788 : : *
789 : : * \see parts_end()
790 : : * \see parts()
791 : : *
792 : : * \since QGIS 3.6
793 : : */
794 : 6 : part_iterator parts_begin()
795 : : {
796 : 6 : return part_iterator( this, 0 );
797 : : }
798 : :
799 : : /**
800 : : * Returns STL-style iterator pointing to the imaginary part after the last part of the geometry.
801 : : *
802 : : * \see parts_begin()
803 : : * \see parts()
804 : : *
805 : : * \since QGIS 3.6
806 : : */
807 : : part_iterator parts_end();
808 : :
809 : : /**
810 : : * Returns Java-style iterator for traversal of parts of the geometry. This iterator
811 : : * returns read-only references to parts and cannot be used to modify the parts.
812 : : *
813 : : * \note Not available in Python bindings
814 : : * \since QGIS 3.6
815 : : */
816 : : QgsGeometryConstPartIterator parts() const;
817 : :
818 : : /**
819 : : * \ingroup core
820 : : * \brief The part_iterator class provides STL-style iterator for const references to geometry parts.
821 : : * \since QGIS 3.6
822 : : */
823 : : class CORE_EXPORT const_part_iterator
824 : : {
825 : : private:
826 : :
827 : 0 : int mIndex = 0; //!< Current part in the geometry
828 : 0 : const QgsAbstractGeometry *mGeometry = nullptr;
829 : :
830 : : public:
831 : : //! Create invalid iterator
832 : 0 : const_part_iterator() = default;
833 : :
834 : : //! Create part iterator for a geometry
835 : : const_part_iterator( const QgsAbstractGeometry *g, int index );
836 : :
837 : : /**
838 : : * The prefix ++ operator (++it) advances the iterator to the next part and returns an iterator to the new current part.
839 : : * Calling this function on iterator that is already past the last item leads to undefined results.
840 : : */
841 : : const_part_iterator &operator++();
842 : :
843 : : //! The postfix ++ operator (it++) advances the iterator to the next part and returns an iterator to the previously current part.
844 : : const_part_iterator operator++( int );
845 : :
846 : : //! Returns the current item.
847 : : const QgsAbstractGeometry *operator*() const;
848 : :
849 : : //! Returns the part number of the current item.
850 : : int partNumber() const;
851 : :
852 : : bool operator==( const_part_iterator other ) const;
853 : 2 : bool operator!=( const_part_iterator other ) const { return !( *this == other ); }
854 : : };
855 : :
856 : : /**
857 : : * Returns STL-style iterator pointing to the const first part of the geometry.
858 : : *
859 : : * \see const_parts_end()
860 : : *
861 : : * \since QGIS 3.6
862 : : */
863 : 1 : const_part_iterator const_parts_begin() const
864 : : {
865 : 1 : return const_part_iterator( this, 0 );
866 : : }
867 : :
868 : : /**
869 : : * Returns STL-style iterator pointing to the imaginary const part after the last part of the geometry.
870 : : *
871 : : * \see const_parts_begin()
872 : : *
873 : : * \since QGIS 3.6
874 : : */
875 : : const_part_iterator const_parts_end() const;
876 : :
877 : :
878 : : /**
879 : : * \ingroup core
880 : : * \brief The vertex_iterator class provides STL-style iterator for vertices.
881 : : * \since QGIS 3.0
882 : : */
883 : : class CORE_EXPORT vertex_iterator
884 : : {
885 : : private:
886 : :
887 : : /**
888 : : * A helper structure to keep track of vertex traversal within one level within a geometry.
889 : : * For example, linestring geometry will have just one level, while multi-polygon has three levels
890 : : * (part index, ring index, vertex index).
891 : : */
892 : 1310 : struct Level
893 : : {
894 : 1310 : const QgsAbstractGeometry *g = nullptr; //!< Current geometry
895 : 1310 : int index = 0; //!< Ptr in the current geometry
896 : :
897 : : bool operator==( const Level &other ) const;
898 : : };
899 : :
900 : : std::array<Level, 3> levels; //!< Stack of levels - three levels should be sufficient (e.g. part index, ring index, vertex index)
901 : 6 : int depth = -1; //!< At what depth level are we right now
902 : :
903 : : void digDown(); //!< Prepare the stack of levels so that it points to a leaf child geometry
904 : :
905 : : public:
906 : : //! Create invalid iterator
907 : 6 : vertex_iterator() = default;
908 : :
909 : : //! Create vertex iterator for a geometry
910 : : vertex_iterator( const QgsAbstractGeometry *g, int index );
911 : :
912 : : /**
913 : : * The prefix ++ operator (++it) advances the iterator to the next vertex and returns an iterator to the new current vertex.
914 : : * Calling this function on iterator that is already past the last item leads to undefined results.
915 : : */
916 : : vertex_iterator &operator++();
917 : :
918 : : //! The postfix ++ operator (it++) advances the iterator to the next vertex and returns an iterator to the previously current vertex.
919 : : vertex_iterator operator++( int );
920 : :
921 : : //! Returns the current item.
922 : : QgsPoint operator*() const;
923 : :
924 : : //! Returns vertex ID of the current item.
925 : : QgsVertexId vertexId() const;
926 : :
927 : : bool operator==( const vertex_iterator &other ) const;
928 : 241 : bool operator!=( const vertex_iterator &other ) const { return !( *this == other ); }
929 : : };
930 : :
931 : : /**
932 : : * Returns STL-style iterator pointing to the first vertex of the geometry.
933 : : *
934 : : * \see vertices_end()
935 : : * \see vertices()
936 : : *
937 : : * \since QGIS 3.0
938 : : */
939 : 41 : vertex_iterator vertices_begin() const
940 : : {
941 : 41 : return vertex_iterator( this, 0 );
942 : : }
943 : :
944 : : /**
945 : : * Returns STL-style iterator pointing to the imaginary vertex after the last vertex of the geometry.
946 : : *
947 : : * \see vertices_begin()
948 : : * \see vertices()
949 : : *
950 : : * \since QGIS 3.0
951 : : */
952 : 282 : vertex_iterator vertices_end() const
953 : : {
954 : 282 : return vertex_iterator( this, childCount() );
955 : : }
956 : : #endif
957 : :
958 : : /**
959 : : * Returns Java-style iterator for traversal of parts of the geometry. This iterator
960 : : * can safely be used to modify parts of the geometry.
961 : : *
962 : : * Example
963 : : *
964 : : * \code{.py}
965 : : * # print the WKT representation of each part in a multi-point geometry
966 : : * geometry = QgsMultiPoint.fromWkt( 'MultiPoint( 0 0, 1 1, 2 2)' )
967 : : * for part in geometry.parts():
968 : : * print(part.asWkt())
969 : : *
970 : : * # single part geometries only have one part - this loop will iterate once only
971 : : * geometry = QgsLineString.fromWkt( 'LineString( 0 0, 10 10 )' )
972 : : * for part in geometry.parts():
973 : : * print(part.asWkt())
974 : : *
975 : : * # parts can be modified during the iteration
976 : : * geometry = QgsMultiPoint.fromWkt( 'MultiPoint( 0 0, 1 1, 2 2)' )
977 : : * for part in geometry.parts():
978 : : * part.transform(ct)
979 : : *
980 : : * # part iteration can also be combined with vertex iteration
981 : : * geometry = QgsMultiPolygon.fromWkt( 'MultiPolygon((( 0 0, 0 10, 10 10, 10 0, 0 0 ),( 5 5, 5 6, 6 6, 6 5, 5 5)),((20 2, 22 2, 22 4, 20 4, 20 2)))' )
982 : : * for part in geometry.parts():
983 : : * for v in part.vertices():
984 : : * print(v.x(), v.y())
985 : : *
986 : : * \endcode
987 : : *
988 : : * \see vertices()
989 : : * \since QGIS 3.6
990 : : */
991 : : QgsGeometryPartIterator parts();
992 : :
993 : :
994 : : /**
995 : : * Returns a read-only, Java-style iterator for traversal of vertices of all the geometry, including all geometry parts and rings.
996 : : *
997 : : * \warning The iterator returns a copy of individual vertices, and accordingly geometries cannot be
998 : : * modified using the iterator. See transformVertices() for a safe method to modify vertices "in-place".
999 : : *
1000 : : * Example
1001 : : *
1002 : : * \code{.py}
1003 : : * # print the x and y coordinate for each vertex in a LineString
1004 : : * geometry = QgsLineString.fromWkt( 'LineString( 0 0, 1 1, 2 2)' )
1005 : : * for v in geometry.vertices():
1006 : : * print(v.x(), v.y())
1007 : : *
1008 : : * # vertex iteration includes all parts and rings
1009 : : * geometry = QgsMultiPolygon.fromWkt( 'MultiPolygon((( 0 0, 0 10, 10 10, 10 0, 0 0 ),( 5 5, 5 6, 6 6, 6 5, 5 5)),((20 2, 22 2, 22 4, 20 4, 20 2)))' )
1010 : : * for v in geometry.vertices():
1011 : : * print(v.x(), v.y())
1012 : : * \endcode
1013 : : *
1014 : : * \see parts()
1015 : : * \since QGIS 3.0
1016 : : */
1017 : : QgsVertexIterator vertices() const;
1018 : :
1019 : : /**
1020 : : * Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
1021 : : * To create it, the geometry is default constructed and then the WKB is changed.
1022 : : * \see clone()
1023 : : * \since 3.0
1024 : : */
1025 : : virtual QgsAbstractGeometry *createEmptyWithSameType() const = 0 SIP_FACTORY;
1026 : :
1027 : : protected:
1028 : :
1029 : : /**
1030 : : * Returns whether the geometry has any child geometries (FALSE for point / curve, TRUE otherwise)
1031 : : * \note used for vertex_iterator implementation
1032 : : * \since QGIS 3.0
1033 : : */
1034 : : virtual bool hasChildGeometries() const;
1035 : :
1036 : : /**
1037 : : * Returns number of child geometries (for geometries with child geometries) or child points (for geometries without child geometries - i.e. curve / point)
1038 : : * \note used for vertex_iterator implementation
1039 : : * \since QGIS 3.0
1040 : : */
1041 : 0 : virtual int childCount() const { return 0; }
1042 : :
1043 : : /**
1044 : : * Returns pointer to child geometry (for geometries with child geometries - i.e. geom. collection / polygon)
1045 : : * \note used for vertex_iterator implementation
1046 : : * \since QGIS 3.0
1047 : : */
1048 : 0 : virtual QgsAbstractGeometry *childGeometry( int index ) const { Q_UNUSED( index ) return nullptr; }
1049 : :
1050 : : /**
1051 : : * Returns point at index (for geometries without child geometries - i.e. curve / point)
1052 : : * \note used for vertex_iterator implementation
1053 : : * \since QGIS 3.0
1054 : : */
1055 : : virtual QgsPoint childPoint( int index ) const;
1056 : :
1057 : : protected:
1058 : 333413 : QgsWkbTypes::Type mWkbType = QgsWkbTypes::Unknown;
1059 : :
1060 : : /**
1061 : : * Updates the geometry type based on whether sub geometries contain z or m values.
1062 : : */
1063 : : void setZMTypeFromSubGeometry( const QgsAbstractGeometry *subggeom, QgsWkbTypes::Type baseGeomType );
1064 : :
1065 : : /**
1066 : : * Default calculator for the minimal bounding box for the geometry. Derived classes should override this method
1067 : : * if a more efficient bounding box calculation is available.
1068 : : */
1069 : : virtual QgsRectangle calculateBoundingBox() const;
1070 : :
1071 : : /**
1072 : : * Clears any cached parameters associated with the geometry, e.g., bounding boxes
1073 : : */
1074 : : virtual void clearCache() const;
1075 : :
1076 : : friend class TestQgsGeometry;
1077 : : };
1078 : :
1079 : :
1080 : : /**
1081 : : * \ingroup core
1082 : : * \class QgsVertexId
1083 : : * \brief Utility class for identifying a unique vertex within a geometry.
1084 : : * \since QGIS 2.10
1085 : : */
1086 : : struct CORE_EXPORT QgsVertexId
1087 : : {
1088 : :
1089 : : /**
1090 : : * Type of vertex
1091 : : */
1092 : : enum VertexType
1093 : : {
1094 : : SegmentVertex = 1, //!< The actual start or end point of a segment
1095 : : CurveVertex, //!< An intermediate point on a segment defining the curvature of the segment
1096 : : };
1097 : :
1098 : : /**
1099 : : * Constructor for QgsVertexId.
1100 : : */
1101 : 12111 : explicit QgsVertexId( int _part = -1, int _ring = -1, int _vertex = -1, VertexType _type = SegmentVertex ) SIP_HOLDGIL
1102 : 12111 : : part( _part )
1103 : 12111 : , ring( _ring )
1104 : 12111 : , vertex( _vertex )
1105 : 12111 : , type( _type )
1106 : 12111 : {}
1107 : :
1108 : : /**
1109 : : * Returns TRUE if the vertex id is valid
1110 : : */
1111 : 113 : bool isValid() const SIP_HOLDGIL { return part >= 0 && ring >= 0 && vertex >= 0; }
1112 : :
1113 : 378 : bool operator==( QgsVertexId other ) const SIP_HOLDGIL
1114 : : {
1115 : 378 : return part == other.part && ring == other.ring && vertex == other.vertex;
1116 : : }
1117 : 25 : bool operator!=( QgsVertexId other ) const SIP_HOLDGIL
1118 : : {
1119 : 25 : return part != other.part || ring != other.ring || vertex != other.vertex;
1120 : : }
1121 : :
1122 : : /**
1123 : : * Returns TRUE if this vertex ID belongs to the same part as another vertex ID.
1124 : : */
1125 : 11 : bool partEqual( QgsVertexId o ) const SIP_HOLDGIL
1126 : : {
1127 : 11 : return part >= 0 && o.part == part;
1128 : : }
1129 : :
1130 : : /**
1131 : : * Returns TRUE if this vertex ID belongs to the same ring as another vertex ID (i.e. the part
1132 : : * and ring number are equal).
1133 : : */
1134 : 7 : bool ringEqual( QgsVertexId o ) const SIP_HOLDGIL
1135 : : {
1136 : 14 : return partEqual( o ) && ( ring >= 0 && o.ring == ring );
1137 : : }
1138 : :
1139 : : /**
1140 : : * Returns TRUE if this vertex ID corresponds to the same vertex as another vertex ID (i.e. the part,
1141 : : * ring number and vertex number are equal).
1142 : : */
1143 : : bool vertexEqual( QgsVertexId o ) const SIP_HOLDGIL
1144 : : {
1145 : : return ringEqual( o ) && ( vertex >= 0 && o.ring == ring );
1146 : : }
1147 : :
1148 : : /**
1149 : : * Returns TRUE if this vertex ID is valid for the specified \a geom.
1150 : : */
1151 : 13 : bool isValid( const QgsAbstractGeometry *geom ) const SIP_HOLDGIL
1152 : : {
1153 : 26 : return ( part >= 0 && part < geom->partCount() ) &&
1154 : 13 : ( ring < geom->ringCount( part ) ) &&
1155 : 13 : ( vertex < 0 || vertex < geom->vertexCount( part, ring ) );
1156 : : }
1157 : :
1158 : : //! Part number
1159 : : int part = -1;
1160 : :
1161 : : //! Ring number
1162 : : int ring = -1;
1163 : :
1164 : : //! Vertex number
1165 : : int vertex = -1;
1166 : :
1167 : : //! Vertex type
1168 : : VertexType type = SegmentVertex;
1169 : :
1170 : : #ifdef SIP_RUN
1171 : : SIP_PYOBJECT __repr__();
1172 : : % MethodCode
1173 : : QString str = QStringLiteral( "<QgsVertexId: %1,%2,%3%4>" ).arg( sipCpp->part ).arg( sipCpp->ring ).arg( sipCpp->vertex ).arg( sipCpp->type == QgsVertexId::CurveVertex ? QStringLiteral( " CurveVertex" ) : QString() );
1174 : : sipRes = PyUnicode_FromString( str.toUtf8().data() );
1175 : : % End
1176 : : #endif
1177 : :
1178 : : };
1179 : :
1180 : : #ifndef SIP_RUN
1181 : :
1182 : : template <class T>
1183 : 313116 : inline T qgsgeometry_cast( const QgsAbstractGeometry *geom )
1184 : : {
1185 : 313116 : return const_cast<T>( std::remove_pointer<T>::type::cast( geom ) );
1186 : : }
1187 : :
1188 : : #endif
1189 : :
1190 : : // clazy:excludeall=qstring-allocations
1191 : :
1192 : : /**
1193 : : * \ingroup core
1194 : : * \brief Java-style iterator for traversal of vertices of a geometry
1195 : : * \since QGIS 3.0
1196 : : */
1197 : : class CORE_EXPORT QgsVertexIterator
1198 : : {
1199 : : public:
1200 : : //! Constructor for QgsVertexIterator
1201 : 3 : QgsVertexIterator() = default;
1202 : :
1203 : : //! Constructs iterator for the given geometry
1204 : 35 : QgsVertexIterator( const QgsAbstractGeometry *geometry )
1205 : 35 : : g( geometry )
1206 : 35 : , i( g->vertices_begin() )
1207 : 35 : , n( g->vertices_end() )
1208 : : {
1209 : 35 : }
1210 : :
1211 : : //! Find out whether there are more vertices
1212 : 244 : bool hasNext() const
1213 : : {
1214 : 244 : return g && g->vertices_end() != i;
1215 : : }
1216 : :
1217 : : //! Returns next vertex of the geometry (undefined behavior if hasNext() returns FALSE before calling next())
1218 : : QgsPoint next();
1219 : :
1220 : : #ifdef SIP_RUN
1221 : : QgsVertexIterator *__iter__();
1222 : : % MethodCode
1223 : : sipRes = sipCpp;
1224 : : % End
1225 : :
1226 : : SIP_PYOBJECT __next__() SIP_TYPEHINT( QgsPoint );
1227 : : % MethodCode
1228 : : if ( sipCpp->hasNext() )
1229 : : sipRes = sipConvertFromType( new QgsPoint( sipCpp->next() ), sipType_QgsPoint, Py_None );
1230 : : else
1231 : : PyErr_SetString( PyExc_StopIteration, "" );
1232 : : % End
1233 : : #endif
1234 : :
1235 : : private:
1236 : 3 : const QgsAbstractGeometry *g = nullptr;
1237 : : QgsAbstractGeometry::vertex_iterator i, n;
1238 : :
1239 : : };
1240 : :
1241 : : /**
1242 : : * \ingroup core
1243 : : * \brief Java-style iterator for traversal of parts of a geometry
1244 : : * \since QGIS 3.6
1245 : : */
1246 : : class CORE_EXPORT QgsGeometryPartIterator
1247 : : {
1248 : : public:
1249 : : //! Constructor for QgsGeometryPartIterator
1250 : 1 : QgsGeometryPartIterator() = default;
1251 : :
1252 : : //! Constructs iterator for the given geometry
1253 : 6 : QgsGeometryPartIterator( QgsAbstractGeometry *geometry )
1254 : 6 : : g( geometry )
1255 : 6 : , i( g->parts_begin() )
1256 : 6 : , n( g->parts_end() )
1257 : : {
1258 : 6 : }
1259 : :
1260 : : //! Find out whether there are more parts
1261 : 38 : bool hasNext() const SIP_HOLDGIL
1262 : : {
1263 : 38 : return g && g->parts_end() != i;
1264 : : }
1265 : :
1266 : : //! Returns next part of the geometry (undefined behavior if hasNext() returns FALSE before calling next())
1267 : : QgsAbstractGeometry *next();
1268 : :
1269 : : #ifdef SIP_RUN
1270 : : QgsGeometryPartIterator *__iter__();
1271 : : % MethodCode
1272 : : sipRes = sipCpp;
1273 : : % End
1274 : :
1275 : : SIP_PYOBJECT __next__() SIP_TYPEHINT( QgsAbstractGeometry );
1276 : : % MethodCode
1277 : : if ( sipCpp->hasNext() )
1278 : : sipRes = sipConvertFromType( sipCpp->next(), sipType_QgsAbstractGeometry, NULL );
1279 : : else
1280 : : PyErr_SetString( PyExc_StopIteration, "" );
1281 : : % End
1282 : : #endif
1283 : :
1284 : : private:
1285 : 1 : QgsAbstractGeometry *g = nullptr;
1286 : : QgsAbstractGeometry::part_iterator i, n;
1287 : :
1288 : : };
1289 : :
1290 : :
1291 : : /**
1292 : : * \ingroup core
1293 : : * \brief Java-style iterator for const traversal of parts of a geometry
1294 : : * \since QGIS 3.6
1295 : : */
1296 : : class CORE_EXPORT QgsGeometryConstPartIterator
1297 : : {
1298 : : public:
1299 : : //! Constructor for QgsGeometryConstPartIterator
1300 : 0 : QgsGeometryConstPartIterator() = default;
1301 : :
1302 : : //! Constructs iterator for the given geometry
1303 : 1 : QgsGeometryConstPartIterator( const QgsAbstractGeometry *geometry )
1304 : 1 : : g( geometry )
1305 : 1 : , i( g->const_parts_begin() )
1306 : 1 : , n( g->const_parts_end() )
1307 : : {
1308 : 1 : }
1309 : :
1310 : : //! Find out whether there are more parts
1311 : 2 : bool hasNext() const SIP_HOLDGIL
1312 : : {
1313 : 2 : return g && g->const_parts_end() != i;
1314 : : }
1315 : :
1316 : : //! Returns next part of the geometry (undefined behavior if hasNext() returns FALSE before calling next())
1317 : : const QgsAbstractGeometry *next();
1318 : :
1319 : : #ifdef SIP_RUN
1320 : : QgsGeometryConstPartIterator *__iter__();
1321 : : % MethodCode
1322 : : sipRes = sipCpp;
1323 : : % End
1324 : :
1325 : : SIP_PYOBJECT __next__() SIP_TYPEHINT( QgsAbstractGeometry );
1326 : : % MethodCode
1327 : : if ( sipCpp->hasNext() )
1328 : : sipRes = sipConvertFromType( const_cast< QgsAbstractGeometry * >( sipCpp->next() ), sipType_QgsAbstractGeometry, NULL );
1329 : : else
1330 : : PyErr_SetString( PyExc_StopIteration, "" );
1331 : : % End
1332 : : #endif
1333 : :
1334 : : private:
1335 : 0 : const QgsAbstractGeometry *g = nullptr;
1336 : : QgsAbstractGeometry::const_part_iterator i, n;
1337 : :
1338 : : };
1339 : :
1340 : : Q_DECLARE_OPERATORS_FOR_FLAGS( QgsAbstractGeometry::WkbFlags )
1341 : :
1342 : : #endif //QGSABSTRACTGEOMETRYV2
|