QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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#include "qgsbox3d.h"
22
23#include <nlohmann/json.hpp>
24#include <limits>
25#include <QTransform>
26
28{
29 mWkbType = geom.mWkbType;
30}
31
33{
34 if ( &geom != this )
35 {
36 clear();
37 mWkbType = geom.mWkbType;
38 }
39 return *this;
40}
41
43{
44 // compare to self
45 if ( this == other )
46 {
47 return 0;
48 }
49
50 if ( sortIndex() != other->sortIndex() )
51 {
52 //different geometry types
53 const int diff = sortIndex() - other->sortIndex();
54 return ( diff > 0 ) - ( diff < 0 );
55 }
56
57 // same types
58 if ( isEmpty() && other->isEmpty() )
59 {
60 return 0;
61 }
62
63 if ( isEmpty() )
64 {
65 return -1;
66 }
67 if ( other->isEmpty() )
68 {
69 return 1;
70 }
71
72 return compareToSameClass( other );
73}
74
76{
77 if ( !subgeom )
78 {
79 return;
80 }
81
82 //special handling for 25d types:
83 if ( baseGeomType == Qgis::WkbType::LineString &&
84 ( subgeom->wkbType() == Qgis::WkbType::Point25D || subgeom->wkbType() == Qgis::WkbType::LineString25D ) )
85 {
87 return;
88 }
89 else if ( baseGeomType == Qgis::WkbType::Polygon &&
90 ( subgeom->wkbType() == Qgis::WkbType::Point25D || subgeom->wkbType() == Qgis::WkbType::LineString25D ) )
91 {
93 return;
94 }
95
96 const bool hasZ = subgeom->is3D();
97 const bool hasM = subgeom->isMeasure();
98
99 if ( hasZ && hasM )
100 {
101 mWkbType = QgsWkbTypes::addM( QgsWkbTypes::addZ( baseGeomType ) );
102 }
103 else if ( hasZ )
104 {
105 mWkbType = QgsWkbTypes::addZ( baseGeomType );
106 }
107 else if ( hasM )
108 {
109 mWkbType = QgsWkbTypes::addM( baseGeomType );
110 }
111 else
112 {
113 mWkbType = baseGeomType;
114 }
115}
116
118{
119 return boundingBox3D().toRectangle();
120}
121
123{
125}
126
128{
129 double xmin = std::numeric_limits<double>::max();
130 double ymin = std::numeric_limits<double>::max();
131 double zmin = std::numeric_limits<double>::max();
132 double xmax = -std::numeric_limits<double>::max();
133 double ymax = -std::numeric_limits<double>::max();
134 double zmax = -std::numeric_limits<double>::max();
135
136 QgsVertexId id;
137 QgsPoint vertex;
138 double x, y, z;
139 if ( is3D() )
140 {
141 while ( nextVertex( id, vertex ) )
142 {
143 x = vertex.x();
144 y = vertex.y();
145 z = vertex.z();
146
147 xmin = std::min( xmin, x );
148 xmax = std::max( xmax, x );
149
150 ymin = std::min( ymin, y );
151 ymax = std::max( ymax, y );
152
153 zmin = std::min( zmin, z );
154 zmax = std::max( zmax, z );
155 }
156 }
157 else
158 {
159 while ( nextVertex( id, vertex ) )
160 {
161 x = vertex.x();
162 y = vertex.y();
163 xmin = std::min( xmin, x );
164 xmax = std::max( xmax, x );
165
166 ymin = std::min( ymin, y );
167 ymax = std::max( ymax, y );
168 }
169 zmin = std::numeric_limits<double>::quiet_NaN();
170 zmax = std::numeric_limits<double>::quiet_NaN();
171 }
172
173 return QgsBox3D( xmin, ymin, zmin, xmax, ymax, zmax );
174}
175
177{
178}
179
181{
182 int nCoords = 0;
183
185 for ( const QgsRingSequence &r : seq )
186 {
187 for ( const QgsPointSequence &p : r )
188 {
189 nCoords += p.size();
190 }
191 }
192
193 return nCoords;
194}
195
197{
198 return 0.0;
199}
200
202{
203 return 0.0;
204}
205
207{
208 return 0.0;
209}
210
212{
213 QString wkt = geometryType();
214 if ( is3D() )
215 wkt += 'Z';
216 if ( isMeasure() )
217 wkt += 'M';
218 return wkt;
219}
220
222{
223 return QString::fromStdString( asJsonObject( precision ).dump() );
224}
225
227{
228 Q_UNUSED( precision ) return nullptr;
229}
230
232{
233 if ( isEmpty() )
234 return QgsPoint();
235
236 // http://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
237 // Pick the first ring of first part for the moment
238
239 const int n = vertexCount( 0, 0 );
240 if ( n == 1 )
241 {
242 return vertexAt( QgsVertexId( 0, 0, 0 ) );
243 }
244
245 double A = 0.;
246 double Cx = 0.;
247 double Cy = 0.;
248 const QgsPoint v0 = vertexAt( QgsVertexId( 0, 0, 0 ) );
249 int i = 0, j = 1;
250 if ( vertexAt( QgsVertexId( 0, 0, 0 ) ) != vertexAt( QgsVertexId( 0, 0, n - 1 ) ) )
251 {
252 i = n - 1;
253 j = 0;
254 }
255 for ( ; j < n; i = j++ )
256 {
257 QgsPoint vi = vertexAt( QgsVertexId( 0, 0, i ) );
258 QgsPoint vj = vertexAt( QgsVertexId( 0, 0, j ) );
259 vi.rx() -= v0.x();
260 vi.ry() -= v0.y();
261 vj.rx() -= v0.x();
262 vj.ry() -= v0.y();
263 const double d = vi.x() * vj.y() - vj.x() * vi.y();
264 A += d;
265 Cx += ( vi.x() + vj.x() ) * d;
266 Cy += ( vi.y() + vj.y() ) * d;
267 }
268
269 if ( A < 1E-12 )
270 {
271 Cx = Cy = 0.;
272 for ( int i = 0; i < n - 1; ++i )
273 {
274 const QgsPoint vi = vertexAt( QgsVertexId( 0, 0, i ) );
275 Cx += vi.x();
276 Cy += vi.y();
277 }
278 return QgsPoint( Cx / ( n - 1 ), Cy / ( n - 1 ) );
279 }
280 else
281 {
282 return QgsPoint( v0.x() + Cx / ( 3. * A ), v0.y() + Cy / ( 3. * A ) );
283 }
284}
285
287{
288 if ( type == mWkbType )
289 return true;
290
292 return false;
293
294 const bool needZ = QgsWkbTypes::hasZ( type );
295 const bool needM = QgsWkbTypes::hasM( type );
296 if ( !needZ )
297 {
298 dropZValue();
299 }
300 else if ( !is3D() )
301 {
302 addZValue( std::numeric_limits<double>::quiet_NaN() );
303 }
304
305 if ( !needM )
306 {
307 dropMValue();
308 }
309 else if ( !isMeasure() )
310 {
311 addMValue( std::numeric_limits<double>::quiet_NaN() );
312 }
313
314 return true;
315}
316
318{
319 return this;
320}
321
322void QgsAbstractGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> & )
323{
324 // Ideally this would be pure virtual, but SIP has issues with that
325}
326
327void QgsAbstractGeometry::transformVertices( const std::function<QgsPoint( const QgsPoint & )> & )
328{
329 // Ideally this would be pure virtual, but SIP has issues with that
330}
331
333{
334 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( this );
335 return part_iterator( this, collection ? collection->partCount() : 1 );
336}
337
339{
340 return QgsGeometryPartIterator( this );
341}
342
344{
345 return QgsGeometryConstPartIterator( this );
346}
347
349{
350 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( this );
351 return const_part_iterator( this, collection ? collection->partCount() : 1 );
352}
353
355{
356 return QgsVertexIterator( this );
357}
358
360{
361 switch ( QgsWkbTypes::flatType( mWkbType ) )
362 {
364 return 0;
366 return 1;
368 return 2;
370 return 3;
372 return 4;
374 return 5;
376 return 6;
379 return 7;
381 return 8;
383 return 9;
385 return 10;
387 return 11;
389 return 12;
391 default:
392 break;
393 }
394 return 13;
395}
396
398{
399 return QgsWkbTypes::isMultiType( wkbType() ) || dimension() == 2;
400}
401
403{
404 Q_UNUSED( index )
405 return QgsPoint();
406}
407
409{
410 QgsVertexId vId;
411 QgsPoint vertex;
412 return !nextVertex( vId, vertex );
413}
414
416{
417 return false;
418}
419
421{
422 return boundingBox().intersects( rectangle );
423}
424
426{
427 return boundingBox3D().intersects( box3d );
428}
429
431{
432 Q_UNUSED( tolerance )
433 Q_UNUSED( toleranceType )
434 return clone();
435}
436
437
439 : depth( 0 )
440{
441 levels.fill( Level() );
442 levels[0].g = g;
443 levels[0].index = index;
444
445 digDown(); // go to the leaf level of the first vertex
446}
447
449{
450 if ( depth == 0 && levels[0].index >= levels[0].g->childCount() )
451 return *this; // end of geometry - nowhere else to go
452
453 Q_ASSERT( !levels[depth].g->hasChildGeometries() ); // we should be at a leaf level
454
455 ++levels[depth].index;
456
457 // traverse up if we are at the end in the current level
458 while ( depth > 0 && levels[depth].index >= levels[depth].g->childCount() )
459 {
460 --depth;
461 ++levels[depth].index;
462 }
463
464 digDown(); // go to the leaf level again
465
466 return *this;
467}
468
470{
471 vertex_iterator it( *this );
472 ++*this;
473 return it;
474}
475
477{
478 Q_ASSERT( !levels[depth].g->hasChildGeometries() );
479 return levels[depth].g->childPoint( levels[depth].index );
480}
481
483{
484 int part = 0, ring = 0, vertex = levels[depth].index;
485 if ( depth == 0 )
486 {
487 // nothing else to do
488 }
489 else if ( depth == 1 )
490 {
491 if ( QgsWkbTypes::isMultiType( levels[0].g->wkbType() ) )
492 part = levels[0].index;
493 else
494 ring = levels[0].index;
495 }
496 else if ( depth == 2 )
497 {
498 part = levels[0].index;
499 ring = levels[1].index;
500 }
501 else
502 {
503 Q_ASSERT( false );
504 return QgsVertexId();
505 }
506
507 // get the vertex type: find out from the leaf geometry
509 if ( const QgsCurve *curve = dynamic_cast<const QgsCurve *>( levels[depth].g ) )
510 {
511 QgsPoint p;
512 curve->pointAt( vertex, p, vertexType );
513 }
514
515 return QgsVertexId( part, ring, vertex, vertexType );
516}
517
519{
520 if ( depth != other.depth )
521 return false;
522 return std::equal( std::begin( levels ), std::begin( levels ) + depth + 1, std::begin( other.levels ) );
523}
524
525void QgsAbstractGeometry::vertex_iterator::digDown()
526{
527 if ( levels[depth].g->hasChildGeometries() && levels[depth].index >= levels[depth].g->childCount() )
528 return; // first check we are not already at the end
529
530 // while not "final" depth for the geom: go one level down.
531 while ( levels[depth].g->hasChildGeometries() )
532 {
533 ++depth;
534 Q_ASSERT( depth < 3 ); // that's capacity of the levels array
535 levels[depth].index = 0;
536 levels[depth].g = levels[depth - 1].g->childGeometry( levels[depth - 1].index );
537 }
538}
539
541{
542 n = i++;
543 return *n;
544}
545
547 : mIndex( index )
548 , mGeometry( g )
549{
550}
551
553{
554 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
555 if ( !collection )
556 {
557 mIndex = 1;
558 return *this; // end of geometry -- nowhere else to go
559 }
560
561 if ( mIndex >= collection->partCount() )
562 return *this; // end of geometry - nowhere else to go
563
564 mIndex++;
565 return *this;
566}
567
569{
570 part_iterator it( *this );
571 ++*this;
572 return it;
573}
574
576{
577 QgsGeometryCollection *collection = qgsgeometry_cast< QgsGeometryCollection * >( mGeometry );
578 if ( !collection )
579 {
580 return mGeometry;
581 }
582
583 return collection->geometryN( mIndex );
584}
585
587{
588 return mIndex;
589}
590
592{
593 return mGeometry == other.mGeometry && mIndex == other.mIndex;
594}
595
597{
598 n = i++;
599 return *n;
600}
601
602
603
605 : mIndex( index )
606 , mGeometry( g )
607{
608}
609
611{
612 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
613 if ( !collection )
614 {
615 mIndex = 1;
616 return *this; // end of geometry -- nowhere else to go
617 }
618
619 if ( mIndex >= collection->partCount() )
620 return *this; // end of geometry - nowhere else to go
621
622 mIndex++;
623 return *this;
624}
625
627{
628 const_part_iterator it( *this );
629 ++*this;
630 return it;
631}
632
634{
635 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
636 if ( !collection )
637 {
638 return mGeometry;
639 }
640
641 return collection->geometryN( mIndex );
642}
643
645{
646 return mIndex;
647}
648
650{
651 return mGeometry == other.mGeometry && mIndex == other.mIndex;
652}
653
655{
656 n = i++;
657 return *n;
658}
659
660bool QgsAbstractGeometry::vertex_iterator::Level::operator==( const QgsAbstractGeometry::vertex_iterator::Level &other ) const
661{
662 return g == other.g && index == other.index;
663}
VertexType
Types of vertex.
Definition: qgis.h:2477
@ Segment
The actual start or end point of a segment.
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition: qgis.h:182
@ 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.
virtual QgsBox3D calculateBoundingBox3D() const
Calculates the minimal 3D bounding box for the geometry.
virtual const QgsAbstractGeometry * simplifiedTypeRef() const
Returns a reference to the simplest lossless representation of this geometry, e.g.
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.
bool isMeasure() const
Returns true if the geometry contains m values.
virtual QgsRectangle calculateBoundingBox() const
Default calculator for the minimal bounding box for the geometry.
virtual QgsRectangle boundingBox() const
Returns 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.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
virtual QgsBox3D boundingBox3D() const =0
Returns the 3D bounding box for the geometry.
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.
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
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.
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)
virtual bool boundingBoxIntersects(const QgsRectangle &rectangle) const
Returns true if the bounding box of this geometry intersects with a rectangle.
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.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
A 3-dimensional box composed of x, y, z coordinates.
Definition: qgsbox3d.h:43
bool intersects(const QgsBox3D &other) const
Returns true if box intersects with another box.
Definition: qgsbox3d.cpp:132
QgsRectangle toRectangle() const
Converts the box to a 2D rectangle.
Definition: qgsbox3d.h:338
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
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:298
Q_GADGET double x
Definition: qgspoint.h:52
double z
Definition: qgspoint.h:54
double & ry()
Returns a reference to the y-coordinate of this point.
Definition: qgspoint.h:307
double y
Definition: qgspoint.h:53
A rectangle specified with double values.
Definition: qgsrectangle.h:42
bool intersects(const QgsRectangle &rect) const
Returns true when rectangle intersects with other rectangle.
Definition: qgsrectangle.h:371
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(Qgis::WkbType type)
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:758
static Qgis::WkbType addM(Qgis::WkbType type)
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1092
static Qgis::WkbType addZ(Qgis::WkbType type)
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1068
static bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:973
static bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1023
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:628
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:30