QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgsabstractgeometry.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsabstractgeometry.cpp
3 -------------------------------------------------------------------
4Date : 04 Sept 2014
5Copyright : (C) 2014 by Marco Hugentobler
6email : 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#include "qgsapplication.h"
17#include "qgsabstractgeometry.h"
18#include "qgswkbptr.h"
19#include "qgsgeos.h"
20#include "qgsmaptopixel.h"
21#include "qgspoint.h"
23#include "qgsvertexid.h"
24
25#include <nlohmann/json.hpp>
26#include <limits>
27#include <QTransform>
28
30{
31 mWkbType = geom.mWkbType;
32}
33
35{
36 if ( &geom != this )
37 {
38 clear();
39 mWkbType = geom.mWkbType;
40 }
41 return *this;
42}
43
45{
46 // compare to self
47 if ( this == other )
48 {
49 return 0;
50 }
51
52 if ( sortIndex() != other->sortIndex() )
53 {
54 //different geometry types
55 const int diff = sortIndex() - other->sortIndex();
56 return ( diff > 0 ) - ( diff < 0 );
57 }
58
59 // same types
60 if ( isEmpty() && other->isEmpty() )
61 {
62 return 0;
63 }
64
65 if ( isEmpty() )
66 {
67 return -1;
68 }
69 if ( other->isEmpty() )
70 {
71 return 1;
72 }
73
74 return compareToSameClass( other );
75}
76
78{
79 if ( !subgeom )
80 {
81 return;
82 }
83
84 //special handling for 25d types:
85 if ( baseGeomType == QgsWkbTypes::LineString &&
86 ( subgeom->wkbType() == QgsWkbTypes::Point25D || subgeom->wkbType() == QgsWkbTypes::LineString25D ) )
87 {
89 return;
90 }
91 else if ( baseGeomType == QgsWkbTypes::Polygon &&
92 ( subgeom->wkbType() == QgsWkbTypes::Point25D || subgeom->wkbType() == QgsWkbTypes::LineString25D ) )
93 {
95 return;
96 }
97
98 const bool hasZ = subgeom->is3D();
99 const bool hasM = subgeom->isMeasure();
100
101 if ( hasZ && hasM )
102 {
103 mWkbType = QgsWkbTypes::addM( QgsWkbTypes::addZ( baseGeomType ) );
104 }
105 else if ( hasZ )
106 {
107 mWkbType = QgsWkbTypes::addZ( baseGeomType );
108 }
109 else if ( hasM )
110 {
111 mWkbType = QgsWkbTypes::addM( baseGeomType );
112 }
113 else
114 {
115 mWkbType = baseGeomType;
116 }
117}
118
120{
121 double xmin = std::numeric_limits<double>::max();
122 double ymin = std::numeric_limits<double>::max();
123 double xmax = -std::numeric_limits<double>::max();
124 double ymax = -std::numeric_limits<double>::max();
125
126 QgsVertexId id;
127 QgsPoint vertex;
128 double x, y;
129 while ( nextVertex( id, vertex ) )
130 {
131 x = vertex.x();
132 y = vertex.y();
133 if ( x < xmin )
134 xmin = x;
135 if ( x > xmax )
136 xmax = x;
137 if ( y < ymin )
138 ymin = y;
139 if ( y > ymax )
140 ymax = y;
141 }
142
143 return QgsRectangle( xmin, ymin, xmax, ymax );
144}
145
147{
148}
149
151{
152 int nCoords = 0;
153
155 for ( const QgsRingSequence &r : seq )
156 {
157 for ( const QgsPointSequence &p : r )
158 {
159 nCoords += p.size();
160 }
161 }
162
163 return nCoords;
164}
165
167{
168 return 0.0;
169}
170
172{
173 return 0.0;
174}
175
177{
178 return 0.0;
179}
180
182{
183 QString wkt = geometryType();
184 if ( is3D() )
185 wkt += 'Z';
186 if ( isMeasure() )
187 wkt += 'M';
188 return wkt;
189}
190
192{
193 return QString::fromStdString( asJsonObject( precision ).dump() );
194}
195
197{
198 Q_UNUSED( precision ) return nullptr;
199}
200
202{
203 if ( isEmpty() )
204 return QgsPoint();
205
206 // http://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
207 // Pick the first ring of first part for the moment
208
209 const int n = vertexCount( 0, 0 );
210 if ( n == 1 )
211 {
212 return vertexAt( QgsVertexId( 0, 0, 0 ) );
213 }
214
215 double A = 0.;
216 double Cx = 0.;
217 double Cy = 0.;
218 const QgsPoint v0 = vertexAt( QgsVertexId( 0, 0, 0 ) );
219 int i = 0, j = 1;
220 if ( vertexAt( QgsVertexId( 0, 0, 0 ) ) != vertexAt( QgsVertexId( 0, 0, n - 1 ) ) )
221 {
222 i = n - 1;
223 j = 0;
224 }
225 for ( ; j < n; i = j++ )
226 {
227 QgsPoint vi = vertexAt( QgsVertexId( 0, 0, i ) );
228 QgsPoint vj = vertexAt( QgsVertexId( 0, 0, j ) );
229 vi.rx() -= v0.x();
230 vi.ry() -= v0.y();
231 vj.rx() -= v0.x();
232 vj.ry() -= v0.y();
233 const double d = vi.x() * vj.y() - vj.x() * vi.y();
234 A += d;
235 Cx += ( vi.x() + vj.x() ) * d;
236 Cy += ( vi.y() + vj.y() ) * d;
237 }
238
239 if ( A < 1E-12 )
240 {
241 Cx = Cy = 0.;
242 for ( int i = 0; i < n - 1; ++i )
243 {
244 const QgsPoint vi = vertexAt( QgsVertexId( 0, 0, i ) );
245 Cx += vi.x();
246 Cy += vi.y();
247 }
248 return QgsPoint( Cx / ( n - 1 ), Cy / ( n - 1 ) );
249 }
250 else
251 {
252 return QgsPoint( v0.x() + Cx / ( 3. * A ), v0.y() + Cy / ( 3. * A ) );
253 }
254}
255
257{
258 if ( type == mWkbType )
259 return true;
260
262 return false;
263
264 const bool needZ = QgsWkbTypes::hasZ( type );
265 const bool needM = QgsWkbTypes::hasM( type );
266 if ( !needZ )
267 {
268 dropZValue();
269 }
270 else if ( !is3D() )
271 {
272 addZValue( std::numeric_limits<double>::quiet_NaN() );
273 }
274
275 if ( !needM )
276 {
277 dropMValue();
278 }
279 else if ( !isMeasure() )
280 {
281 addMValue( std::numeric_limits<double>::quiet_NaN() );
282 }
283
284 return true;
285}
286
288{
289 return this;
290}
291
292void QgsAbstractGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> & )
293{
294 // Ideally this would be pure virtual, but SIP has issues with that
295}
296
297void QgsAbstractGeometry::transformVertices( const std::function<QgsPoint( const QgsPoint & )> & )
298{
299 // Ideally this would be pure virtual, but SIP has issues with that
300}
301
303{
304 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( this );
305 return part_iterator( this, collection ? collection->partCount() : 1 );
306}
307
309{
310 return QgsGeometryPartIterator( this );
311}
312
314{
315 return QgsGeometryConstPartIterator( this );
316}
317
319{
320 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( this );
321 return const_part_iterator( this, collection ? collection->partCount() : 1 );
322}
323
325{
326 return QgsVertexIterator( this );
327}
328
330{
331 switch ( QgsWkbTypes::flatType( mWkbType ) )
332 {
334 return 0;
336 return 1;
338 return 2;
340 return 3;
342 return 4;
344 return 5;
346 return 6;
349 return 7;
351 return 8;
353 return 9;
355 return 10;
357 return 11;
359 return 12;
361 default:
362 break;
363 }
364 return 13;
365}
366
368{
369 return QgsWkbTypes::isMultiType( wkbType() ) || dimension() == 2;
370}
371
373{
374 Q_UNUSED( index )
375 return QgsPoint();
376}
377
379{
380 QgsVertexId vId;
381 QgsPoint vertex;
382 return !nextVertex( vId, vertex );
383}
384
386{
387 return false;
388}
389
391{
392 return boundingBox().intersects( rectangle );
393}
394
396{
397 Q_UNUSED( tolerance )
398 Q_UNUSED( toleranceType )
399 return clone();
400}
401
402
404 : depth( 0 )
405{
406 levels.fill( Level() );
407 levels[0].g = g;
408 levels[0].index = index;
409
410 digDown(); // go to the leaf level of the first vertex
411}
412
414{
415 if ( depth == 0 && levels[0].index >= levels[0].g->childCount() )
416 return *this; // end of geometry - nowhere else to go
417
418 Q_ASSERT( !levels[depth].g->hasChildGeometries() ); // we should be at a leaf level
419
420 ++levels[depth].index;
421
422 // traverse up if we are at the end in the current level
423 while ( depth > 0 && levels[depth].index >= levels[depth].g->childCount() )
424 {
425 --depth;
426 ++levels[depth].index;
427 }
428
429 digDown(); // go to the leaf level again
430
431 return *this;
432}
433
435{
436 vertex_iterator it( *this );
437 ++*this;
438 return it;
439}
440
442{
443 Q_ASSERT( !levels[depth].g->hasChildGeometries() );
444 return levels[depth].g->childPoint( levels[depth].index );
445}
446
448{
449 int part = 0, ring = 0, vertex = levels[depth].index;
450 if ( depth == 0 )
451 {
452 // nothing else to do
453 }
454 else if ( depth == 1 )
455 {
456 if ( QgsWkbTypes::isMultiType( levels[0].g->wkbType() ) )
457 part = levels[0].index;
458 else
459 ring = levels[0].index;
460 }
461 else if ( depth == 2 )
462 {
463 part = levels[0].index;
464 ring = levels[1].index;
465 }
466 else
467 {
468 Q_ASSERT( false );
469 return QgsVertexId();
470 }
471
472 // get the vertex type: find out from the leaf geometry
473 Qgis::VertexType vertexType = Qgis::VertexType::Segment;
474 if ( const QgsCurve *curve = dynamic_cast<const QgsCurve *>( levels[depth].g ) )
475 {
476 QgsPoint p;
477 curve->pointAt( vertex, p, vertexType );
478 }
479
480 return QgsVertexId( part, ring, vertex, vertexType );
481}
482
484{
485 if ( depth != other.depth )
486 return false;
487 return std::equal( std::begin( levels ), std::begin( levels ) + depth + 1, std::begin( other.levels ) );
488}
489
490void QgsAbstractGeometry::vertex_iterator::digDown()
491{
492 if ( levels[depth].g->hasChildGeometries() && levels[depth].index >= levels[depth].g->childCount() )
493 return; // first check we are not already at the end
494
495 // while not "final" depth for the geom: go one level down.
496 while ( levels[depth].g->hasChildGeometries() )
497 {
498 ++depth;
499 Q_ASSERT( depth < 3 ); // that's capacity of the levels array
500 levels[depth].index = 0;
501 levels[depth].g = levels[depth - 1].g->childGeometry( levels[depth - 1].index );
502 }
503}
504
506{
507 n = i++;
508 return *n;
509}
510
512 : mIndex( index )
513 , mGeometry( g )
514{
515}
516
518{
519 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
520 if ( !collection )
521 {
522 mIndex = 1;
523 return *this; // end of geometry -- nowhere else to go
524 }
525
526 if ( mIndex >= collection->partCount() )
527 return *this; // end of geometry - nowhere else to go
528
529 mIndex++;
530 return *this;
531}
532
534{
535 part_iterator it( *this );
536 ++*this;
537 return it;
538}
539
541{
542 QgsGeometryCollection *collection = qgsgeometry_cast< QgsGeometryCollection * >( mGeometry );
543 if ( !collection )
544 {
545 return mGeometry;
546 }
547
548 return collection->geometryN( mIndex );
549}
550
552{
553 return mIndex;
554}
555
557{
558 return mGeometry == other.mGeometry && mIndex == other.mIndex;
559}
560
562{
563 n = i++;
564 return *n;
565}
566
567
568
570 : mIndex( index )
571 , mGeometry( g )
572{
573}
574
576{
577 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
578 if ( !collection )
579 {
580 mIndex = 1;
581 return *this; // end of geometry -- nowhere else to go
582 }
583
584 if ( mIndex >= collection->partCount() )
585 return *this; // end of geometry - nowhere else to go
586
587 mIndex++;
588 return *this;
589}
590
592{
593 const_part_iterator it( *this );
594 ++*this;
595 return it;
596}
597
599{
600 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
601 if ( !collection )
602 {
603 return mGeometry;
604 }
605
606 return collection->geometryN( mIndex );
607}
608
610{
611 return mIndex;
612}
613
615{
616 return mGeometry == other.mGeometry && mIndex == other.mIndex;
617}
618
620{
621 n = i++;
622 return *n;
623}
624
625bool QgsAbstractGeometry::vertex_iterator::Level::operator==( const QgsAbstractGeometry::vertex_iterator::Level &other ) const
626{
627 return g == other.g && index == other.index;
628}
VertexType
Types of vertex.
Definition: qgis.h:1518
The part_iterator class provides STL-style iterator for const references to geometry parts.
const_part_iterator & operator++()
The prefix ++ operator (++it) advances the iterator to the next part and returns an iterator to the n...
const_part_iterator()=default
Create invalid iterator.
const QgsAbstractGeometry * operator*() const
Returns the current item.
int partNumber() const
Returns the part number of the current item.
bool operator==(const_part_iterator other) const
The part_iterator class provides STL-style iterator for geometry parts.
part_iterator & operator++()
The prefix ++ operator (++it) advances the iterator to the next part and returns an iterator to the n...
part_iterator()=default
Create invalid iterator.
QgsAbstractGeometry * operator*() const
Returns the current item.
bool operator==(part_iterator other) const
int partNumber() const
Returns the part number of the current item.
The vertex_iterator class provides STL-style iterator for vertices.
vertex_iterator()=default
Create invalid iterator.
bool operator==(const vertex_iterator &other) const
QgsPoint operator*() const
Returns the current item.
vertex_iterator & operator++()
The prefix ++ operator (++it) advances the iterator to the next vertex and returns an iterator to the...
QgsVertexId vertexId() const
Returns vertex ID of the current item.
Abstract base class for all geometries.
virtual QgsPoint childPoint(int index) const
Returns point at index (for geometries without child geometries - i.e.
virtual bool addZValue(double zValue=0)=0
Adds a z-dimension to the geometry, initialized to a preset value.
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
virtual bool dropMValue()=0
Drops any measure values which exist in the geometry.
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
QgsVertexIterator vertices() const
Returns a read-only, Java-style iterator for traversal of vertices of all the geometry,...
virtual QgsAbstractGeometry * segmentize(double tolerance=M_PI/180., SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a version of the geometry without curves.
virtual int vertexCount(int part=0, int ring=0) const =0
Returns the number of vertices of which this geometry is built.
virtual QgsRectangle boundingBox() const =0
Returns the minimal bounding box for the geometry.
virtual QgsRectangle calculateBoundingBox() const
Default calculator for the minimal bounding box for the geometry.
virtual void transformVertices(const std::function< QgsPoint(const QgsPoint &) > &transform)
Transforms the vertices from the geometry in place, applying the transform function to every vertex.
virtual bool boundingBoxIntersects(const QgsRectangle &rectangle) const SIP_HOLDGIL
Returns true if the bounding box of this geometry intersects with a rectangle.
virtual QString geometryType() const =0
Returns a unique string representing the geometry type.
int sortIndex() const
Returns the sort index for the geometry, used in the compareTo() method to compare geometries of diff...
QString wktTypeStr() const
Returns the WKT type string of the geometry.
virtual double perimeter() const
Returns the planar, 2-dimensional perimeter of the geometry.
virtual int nCoordinates() const
Returns the number of nodes contained in the geometry.
virtual QgsPoint vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
virtual void clearCache() const
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
QgsAbstractGeometry & operator=(const QgsAbstractGeometry &geom)
virtual bool addMValue(double mValue=0)=0
Adds a measure to the geometry, initialized to a preset value.
QString asJson(int precision=17)
Returns a GeoJSON representation of the geometry as a QString.
part_iterator parts_end()
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry.
virtual double length() const
Returns the planar, 2-dimensional length of the geometry.
virtual const QgsAbstractGeometry * simplifiedTypeRef() const SIP_HOLDGIL
Returns a reference to the simplest lossless representation of this geometry, e.g.
const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary const part after the last part of the geometry.
virtual bool isEmpty() const
Returns true if the geometry is empty.
virtual json asJsonObject(int precision=17) const
Returns a json object representation of the geometry.
virtual bool convertTo(QgsWkbTypes::Type type)
Converts the geometry to a specified type.
virtual QgsCoordinateSequence coordinateSequence() const =0
Retrieves the sequence of geometries, rings and nodes.
virtual bool hasChildGeometries() const
Returns whether the geometry has any child geometries (false for point / curve, true otherwise)
virtual bool hasCurvedSegments() const
Returns true if the geometry contains curved segments.
virtual void clear()=0
Clears the geometry, ie reset it to a null geometry.
virtual void filterVertices(const std::function< bool(const QgsPoint &) > &filter)
Filters the vertices from the geometry in place, removing any which do not return true for the filter...
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
virtual bool dropZValue()=0
Drops any z-dimensions which exist in the geometry.
virtual QgsPoint centroid() const
Returns the centroid of the geometry.
virtual int dimension() const =0
Returns the inherent dimension of the geometry.
virtual int compareTo(const QgsAbstractGeometry *other) const
Comparator for sorting of geometry.
QgsAbstractGeometry()=default
Constructor for QgsAbstractGeometry.
virtual double area() const
Returns the planar, 2-dimensional area of the geometry.
virtual int compareToSameClass(const QgsAbstractGeometry *other) const =0
Compares to an other geometry of the same class, and returns a integer for sorting of the two geometr...
QgsWkbTypes::Type mWkbType
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts of the geometry.
virtual bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const =0
Returns next vertex id and coordinates.
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, QgsWkbTypes::Type baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
Abstract base class for curved geometry type.
Definition: qgscurve.h:36
Geometry collection.
int partCount() const override
Returns count of parts contained in the geometry.
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
Java-style iterator for const traversal of parts of a geometry.
const QgsAbstractGeometry * next()
Returns next part of the geometry (undefined behavior if hasNext() returns false before calling next(...
Java-style iterator for traversal of parts of a geometry.
QgsAbstractGeometry * next()
Returns next part of the geometry (undefined behavior if hasNext() returns false before calling next(...
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
double & rx()
Returns a reference to the x-coordinate of this point.
Definition: qgspoint.h:246
Q_GADGET double x
Definition: qgspoint.h:52
double & ry()
Returns a reference to the y-coordinate of this point.
Definition: qgspoint.h:255
double y
Definition: qgspoint.h:53
A rectangle specified with double values.
Definition: qgsrectangle.h:42
bool intersects(const QgsRectangle &rect) const SIP_HOLDGIL
Returns true when rectangle intersects with other rectangle.
Definition: qgsrectangle.h:349
Java-style iterator for traversal of vertices of a geometry.
QgsPoint next()
Returns next vertex of the geometry (undefined behavior if hasNext() returns false before calling nex...
static bool isMultiType(Type type) SIP_HOLDGIL
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:862
static bool hasM(Type type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1130
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
@ GeometryCollection
Definition: qgswkbtypes.h:79
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:732
static Type addZ(Type type) SIP_HOLDGIL
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1176
static bool hasZ(Type type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:1080
static Type addM(Type type) SIP_HOLDGIL
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1201
QVector< QgsRingSequence > QgsCoordinateSequence
QVector< QgsPointSequence > QgsRingSequence
QVector< QgsPoint > QgsPointSequence
bool operator==(const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2)
int precision
Utility class for identifying a unique vertex within a geometry.
Definition: qgsvertexid.h:31