QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
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 "qgsabstractgeometry.h"
17#include "qgspoint.h"
19#include "qgsvertexid.h"
20#include "qgscurve.h"
21
22#include <nlohmann/json.hpp>
23#include <limits>
24#include <QTransform>
25
27{
28 mWkbType = geom.mWkbType;
29}
30
32{
33 if ( &geom != this )
34 {
35 clear();
36 mWkbType = geom.mWkbType;
37 }
38 return *this;
39}
40
42{
43 // compare to self
44 if ( this == other )
45 {
46 return 0;
47 }
48
49 if ( sortIndex() != other->sortIndex() )
50 {
51 //different geometry types
52 const int diff = sortIndex() - other->sortIndex();
53 return ( diff > 0 ) - ( diff < 0 );
54 }
55
56 // same types
57 if ( isEmpty() && other->isEmpty() )
58 {
59 return 0;
60 }
61
62 if ( isEmpty() )
63 {
64 return -1;
65 }
66 if ( other->isEmpty() )
67 {
68 return 1;
69 }
70
71 return compareToSameClass( other );
72}
73
75{
76 if ( !subgeom )
77 {
78 return;
79 }
80
81 //special handling for 25d types:
82 if ( baseGeomType == Qgis::WkbType::LineString &&
83 ( subgeom->wkbType() == Qgis::WkbType::Point25D || subgeom->wkbType() == Qgis::WkbType::LineString25D ) )
84 {
86 return;
87 }
88 else if ( baseGeomType == Qgis::WkbType::Polygon &&
89 ( subgeom->wkbType() == Qgis::WkbType::Point25D || subgeom->wkbType() == Qgis::WkbType::LineString25D ) )
90 {
92 return;
93 }
94
95 const bool hasZ = subgeom->is3D();
96 const bool hasM = subgeom->isMeasure();
97
98 if ( hasZ && hasM )
99 {
100 mWkbType = QgsWkbTypes::addM( QgsWkbTypes::addZ( baseGeomType ) );
101 }
102 else if ( hasZ )
103 {
104 mWkbType = QgsWkbTypes::addZ( baseGeomType );
105 }
106 else if ( hasM )
107 {
108 mWkbType = QgsWkbTypes::addM( baseGeomType );
109 }
110 else
111 {
112 mWkbType = baseGeomType;
113 }
114}
115
117{
118 double xmin = std::numeric_limits<double>::max();
119 double ymin = std::numeric_limits<double>::max();
120 double xmax = -std::numeric_limits<double>::max();
121 double ymax = -std::numeric_limits<double>::max();
122
123 QgsVertexId id;
124 QgsPoint vertex;
125 double x, y;
126 while ( nextVertex( id, vertex ) )
127 {
128 x = vertex.x();
129 y = vertex.y();
130 if ( x < xmin )
131 xmin = x;
132 if ( x > xmax )
133 xmax = x;
134 if ( y < ymin )
135 ymin = y;
136 if ( y > ymax )
137 ymax = y;
138 }
139
140 return QgsRectangle( xmin, ymin, xmax, ymax );
141}
142
144{
145}
146
148{
149 int nCoords = 0;
150
152 for ( const QgsRingSequence &r : seq )
153 {
154 for ( const QgsPointSequence &p : r )
155 {
156 nCoords += p.size();
157 }
158 }
159
160 return nCoords;
161}
162
164{
165 return 0.0;
166}
167
169{
170 return 0.0;
171}
172
174{
175 return 0.0;
176}
177
179{
180 QString wkt = geometryType();
181 if ( is3D() )
182 wkt += 'Z';
183 if ( isMeasure() )
184 wkt += 'M';
185 return wkt;
186}
187
189{
190 return QString::fromStdString( asJsonObject( precision ).dump() );
191}
192
194{
195 Q_UNUSED( precision ) return nullptr;
196}
197
199{
200 if ( isEmpty() )
201 return QgsPoint();
202
203 // http://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
204 // Pick the first ring of first part for the moment
205
206 const int n = vertexCount( 0, 0 );
207 if ( n == 1 )
208 {
209 return vertexAt( QgsVertexId( 0, 0, 0 ) );
210 }
211
212 double A = 0.;
213 double Cx = 0.;
214 double Cy = 0.;
215 const QgsPoint v0 = vertexAt( QgsVertexId( 0, 0, 0 ) );
216 int i = 0, j = 1;
217 if ( vertexAt( QgsVertexId( 0, 0, 0 ) ) != vertexAt( QgsVertexId( 0, 0, n - 1 ) ) )
218 {
219 i = n - 1;
220 j = 0;
221 }
222 for ( ; j < n; i = j++ )
223 {
224 QgsPoint vi = vertexAt( QgsVertexId( 0, 0, i ) );
225 QgsPoint vj = vertexAt( QgsVertexId( 0, 0, j ) );
226 vi.rx() -= v0.x();
227 vi.ry() -= v0.y();
228 vj.rx() -= v0.x();
229 vj.ry() -= v0.y();
230 const double d = vi.x() * vj.y() - vj.x() * vi.y();
231 A += d;
232 Cx += ( vi.x() + vj.x() ) * d;
233 Cy += ( vi.y() + vj.y() ) * d;
234 }
235
236 if ( A < 1E-12 )
237 {
238 Cx = Cy = 0.;
239 for ( int i = 0; i < n - 1; ++i )
240 {
241 const QgsPoint vi = vertexAt( QgsVertexId( 0, 0, i ) );
242 Cx += vi.x();
243 Cy += vi.y();
244 }
245 return QgsPoint( Cx / ( n - 1 ), Cy / ( n - 1 ) );
246 }
247 else
248 {
249 return QgsPoint( v0.x() + Cx / ( 3. * A ), v0.y() + Cy / ( 3. * A ) );
250 }
251}
252
254{
255 if ( type == mWkbType )
256 return true;
257
259 return false;
260
261 const bool needZ = QgsWkbTypes::hasZ( type );
262 const bool needM = QgsWkbTypes::hasM( type );
263 if ( !needZ )
264 {
265 dropZValue();
266 }
267 else if ( !is3D() )
268 {
269 addZValue( std::numeric_limits<double>::quiet_NaN() );
270 }
271
272 if ( !needM )
273 {
274 dropMValue();
275 }
276 else if ( !isMeasure() )
277 {
278 addMValue( std::numeric_limits<double>::quiet_NaN() );
279 }
280
281 return true;
282}
283
285{
286 return this;
287}
288
289void QgsAbstractGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> & )
290{
291 // Ideally this would be pure virtual, but SIP has issues with that
292}
293
294void QgsAbstractGeometry::transformVertices( const std::function<QgsPoint( const QgsPoint & )> & )
295{
296 // Ideally this would be pure virtual, but SIP has issues with that
297}
298
300{
301 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( this );
302 return part_iterator( this, collection ? collection->partCount() : 1 );
303}
304
306{
307 return QgsGeometryPartIterator( this );
308}
309
311{
312 return QgsGeometryConstPartIterator( this );
313}
314
316{
317 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( this );
318 return const_part_iterator( this, collection ? collection->partCount() : 1 );
319}
320
322{
323 return QgsVertexIterator( this );
324}
325
327{
328 switch ( QgsWkbTypes::flatType( mWkbType ) )
329 {
331 return 0;
333 return 1;
335 return 2;
337 return 3;
339 return 4;
341 return 5;
343 return 6;
346 return 7;
348 return 8;
350 return 9;
352 return 10;
354 return 11;
356 return 12;
358 default:
359 break;
360 }
361 return 13;
362}
363
365{
366 return QgsWkbTypes::isMultiType( wkbType() ) || dimension() == 2;
367}
368
370{
371 Q_UNUSED( index )
372 return QgsPoint();
373}
374
376{
377 QgsVertexId vId;
378 QgsPoint vertex;
379 return !nextVertex( vId, vertex );
380}
381
383{
384 return false;
385}
386
388{
389 return boundingBox().intersects( rectangle );
390}
391
393{
394 Q_UNUSED( tolerance )
395 Q_UNUSED( toleranceType )
396 return clone();
397}
398
399
401 : depth( 0 )
402{
403 levels.fill( Level() );
404 levels[0].g = g;
405 levels[0].index = index;
406
407 digDown(); // go to the leaf level of the first vertex
408}
409
411{
412 if ( depth == 0 && levels[0].index >= levels[0].g->childCount() )
413 return *this; // end of geometry - nowhere else to go
414
415 Q_ASSERT( !levels[depth].g->hasChildGeometries() ); // we should be at a leaf level
416
417 ++levels[depth].index;
418
419 // traverse up if we are at the end in the current level
420 while ( depth > 0 && levels[depth].index >= levels[depth].g->childCount() )
421 {
422 --depth;
423 ++levels[depth].index;
424 }
425
426 digDown(); // go to the leaf level again
427
428 return *this;
429}
430
432{
433 vertex_iterator it( *this );
434 ++*this;
435 return it;
436}
437
439{
440 Q_ASSERT( !levels[depth].g->hasChildGeometries() );
441 return levels[depth].g->childPoint( levels[depth].index );
442}
443
445{
446 int part = 0, ring = 0, vertex = levels[depth].index;
447 if ( depth == 0 )
448 {
449 // nothing else to do
450 }
451 else if ( depth == 1 )
452 {
453 if ( QgsWkbTypes::isMultiType( levels[0].g->wkbType() ) )
454 part = levels[0].index;
455 else
456 ring = levels[0].index;
457 }
458 else if ( depth == 2 )
459 {
460 part = levels[0].index;
461 ring = levels[1].index;
462 }
463 else
464 {
465 Q_ASSERT( false );
466 return QgsVertexId();
467 }
468
469 // get the vertex type: find out from the leaf geometry
470 Qgis::VertexType vertexType = Qgis::VertexType::Segment;
471 if ( const QgsCurve *curve = dynamic_cast<const QgsCurve *>( levels[depth].g ) )
472 {
473 QgsPoint p;
474 curve->pointAt( vertex, p, vertexType );
475 }
476
477 return QgsVertexId( part, ring, vertex, vertexType );
478}
479
481{
482 if ( depth != other.depth )
483 return false;
484 return std::equal( std::begin( levels ), std::begin( levels ) + depth + 1, std::begin( other.levels ) );
485}
486
487void QgsAbstractGeometry::vertex_iterator::digDown()
488{
489 if ( levels[depth].g->hasChildGeometries() && levels[depth].index >= levels[depth].g->childCount() )
490 return; // first check we are not already at the end
491
492 // while not "final" depth for the geom: go one level down.
493 while ( levels[depth].g->hasChildGeometries() )
494 {
495 ++depth;
496 Q_ASSERT( depth < 3 ); // that's capacity of the levels array
497 levels[depth].index = 0;
498 levels[depth].g = levels[depth - 1].g->childGeometry( levels[depth - 1].index );
499 }
500}
501
503{
504 n = i++;
505 return *n;
506}
507
509 : mIndex( index )
510 , mGeometry( g )
511{
512}
513
515{
516 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
517 if ( !collection )
518 {
519 mIndex = 1;
520 return *this; // end of geometry -- nowhere else to go
521 }
522
523 if ( mIndex >= collection->partCount() )
524 return *this; // end of geometry - nowhere else to go
525
526 mIndex++;
527 return *this;
528}
529
531{
532 part_iterator it( *this );
533 ++*this;
534 return it;
535}
536
538{
539 QgsGeometryCollection *collection = qgsgeometry_cast< QgsGeometryCollection * >( mGeometry );
540 if ( !collection )
541 {
542 return mGeometry;
543 }
544
545 return collection->geometryN( mIndex );
546}
547
549{
550 return mIndex;
551}
552
554{
555 return mGeometry == other.mGeometry && mIndex == other.mIndex;
556}
557
559{
560 n = i++;
561 return *n;
562}
563
564
565
567 : mIndex( index )
568 , mGeometry( g )
569{
570}
571
573{
574 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
575 if ( !collection )
576 {
577 mIndex = 1;
578 return *this; // end of geometry -- nowhere else to go
579 }
580
581 if ( mIndex >= collection->partCount() )
582 return *this; // end of geometry - nowhere else to go
583
584 mIndex++;
585 return *this;
586}
587
589{
590 const_part_iterator it( *this );
591 ++*this;
592 return it;
593}
594
596{
597 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
598 if ( !collection )
599 {
600 return mGeometry;
601 }
602
603 return collection->geometryN( mIndex );
604}
605
607{
608 return mIndex;
609}
610
612{
613 return mGeometry == other.mGeometry && mIndex == other.mIndex;
614}
615
617{
618 n = i++;
619 return *n;
620}
621
622bool QgsAbstractGeometry::vertex_iterator::Level::operator==( const QgsAbstractGeometry::vertex_iterator::Level &other ) const
623{
624 return g == other.g && index == other.index;
625}
VertexType
Types of vertex.
Definition: qgis.h:1895
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition: qgis.h:155
@ LineString25D
LineString25D.
@ CompoundCurve
CompoundCurve.
@ LineString
LineString.
@ MultiPoint
MultiPoint.
@ Polygon
Polygon.
@ MultiPolygon
MultiPolygon.
@ Triangle
Triangle.
@ NoGeometry
No geometry.
@ MultiLineString
MultiLineString.
@ Unknown
Unknown.
@ CircularString
CircularString.
@ GeometryCollection
GeometryCollection.
@ MultiCurve
MultiCurve.
@ CurvePolygon
CurvePolygon.
@ Point25D
Point25D.
@ MultiSurface
MultiSurface.
@ Polygon25D
Polygon25D.
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 convertTo(Qgis::WkbType type)
Converts the geometry to a specified type.
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.
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, Qgis::WkbType baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
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 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)
Qgis::WkbType wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
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...
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...
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.
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 Qgis::WkbType addZ(Qgis::WkbType type) SIP_HOLDGIL
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1073
static Qgis::WkbType addM(Qgis::WkbType type) SIP_HOLDGIL
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1098
static bool isMultiType(Qgis::WkbType type) SIP_HOLDGIL
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:759
static bool hasZ(Qgis::WkbType type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:977
static bool hasM(Qgis::WkbType type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1027
static Qgis::WkbType flatType(Qgis::WkbType type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:629
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