QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgsabstractgeometry.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsabstractgeometry.cpp
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 #include "qgsapplication.h"
17 #include "qgsabstractgeometry.h"
18 #include "qgswkbptr.h"
19 #include "qgsgeos.h"
20 #include "qgsmaptopixel.h"
21 #include "qgspoint.h"
22 #include "qgsgeometrycollection.h"
23 
24 #include <nlohmann/json.hpp>
25 #include <limits>
26 #include <QTransform>
27 
29 {
30  mWkbType = geom.mWkbType;
31 }
32 
34 {
35  if ( &geom != this )
36  {
37  clear();
38  mWkbType = geom.mWkbType;
39  }
40  return *this;
41 }
42 
44 {
45  // compare to self
46  if ( this == other )
47  {
48  return 0;
49  }
50 
51  if ( sortIndex() != other->sortIndex() )
52  {
53  //different geometry types
54  const int diff = sortIndex() - other->sortIndex();
55  return ( diff > 0 ) - ( diff < 0 );
56  }
57 
58  // same types
59  if ( isEmpty() && other->isEmpty() )
60  {
61  return 0;
62  }
63 
64  if ( isEmpty() )
65  {
66  return -1;
67  }
68  if ( other->isEmpty() )
69  {
70  return 1;
71  }
72 
73  return compareToSameClass( other );
74 }
75 
77 {
78  if ( !subgeom )
79  {
80  return;
81  }
82 
83  //special handling for 25d types:
84  if ( baseGeomType == QgsWkbTypes::LineString &&
85  ( subgeom->wkbType() == QgsWkbTypes::Point25D || subgeom->wkbType() == QgsWkbTypes::LineString25D ) )
86  {
88  return;
89  }
90  else if ( baseGeomType == QgsWkbTypes::Polygon &&
91  ( subgeom->wkbType() == QgsWkbTypes::Point25D || subgeom->wkbType() == QgsWkbTypes::LineString25D ) )
92  {
94  return;
95  }
96 
97  bool hasZ = subgeom->is3D();
98  bool hasM = subgeom->isMeasure();
99 
100  if ( hasZ && hasM )
101  {
102  mWkbType = QgsWkbTypes::addM( QgsWkbTypes::addZ( baseGeomType ) );
103  }
104  else if ( hasZ )
105  {
106  mWkbType = QgsWkbTypes::addZ( baseGeomType );
107  }
108  else if ( hasM )
109  {
110  mWkbType = QgsWkbTypes::addM( baseGeomType );
111  }
112  else
113  {
114  mWkbType = baseGeomType;
115  }
116 }
117 
119 {
120  double xmin = std::numeric_limits<double>::max();
121  double ymin = std::numeric_limits<double>::max();
122  double xmax = -std::numeric_limits<double>::max();
123  double ymax = -std::numeric_limits<double>::max();
124 
125  QgsVertexId id;
126  QgsPoint vertex;
127  double x, y;
128  while ( nextVertex( id, vertex ) )
129  {
130  x = vertex.x();
131  y = vertex.y();
132  if ( x < xmin )
133  xmin = x;
134  if ( x > xmax )
135  xmax = x;
136  if ( y < ymin )
137  ymin = y;
138  if ( y > ymax )
139  ymax = y;
140  }
141 
142  return QgsRectangle( xmin, ymin, xmax, ymax );
143 }
144 
146 {
147 }
148 
150 {
151  int nCoords = 0;
152 
154  for ( const QgsRingSequence &r : seq )
155  {
156  for ( const QgsPointSequence &p : r )
157  {
158  nCoords += p.size();
159  }
160  }
161 
162  return nCoords;
163 }
164 
166 {
167  return 0.0;
168 }
169 
171 {
172  return 0.0;
173 }
174 
176 {
177  return 0.0;
178 }
179 
181 {
182  QString wkt = geometryType();
183  if ( is3D() )
184  wkt += 'Z';
185  if ( isMeasure() )
186  wkt += 'M';
187  return wkt;
188 }
189 
191 {
192  return QString::fromStdString( asJsonObject( precision ).dump() );
193 }
194 
196 {
197  Q_UNUSED( precision ) return nullptr;
198 }
199 
201 {
202  if ( isEmpty() )
203  return QgsPoint();
204 
205  // http://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
206  // Pick the first ring of first part for the moment
207 
208  int n = vertexCount( 0, 0 );
209  if ( n == 1 )
210  {
211  return vertexAt( QgsVertexId( 0, 0, 0 ) );
212  }
213 
214  double A = 0.;
215  double Cx = 0.;
216  double Cy = 0.;
217  QgsPoint v0 = vertexAt( QgsVertexId( 0, 0, 0 ) );
218  int i = 0, j = 1;
219  if ( vertexAt( QgsVertexId( 0, 0, 0 ) ) != vertexAt( QgsVertexId( 0, 0, n - 1 ) ) )
220  {
221  i = n - 1;
222  j = 0;
223  }
224  for ( ; j < n; i = j++ )
225  {
226  QgsPoint vi = vertexAt( QgsVertexId( 0, 0, i ) );
227  QgsPoint vj = vertexAt( QgsVertexId( 0, 0, j ) );
228  vi.rx() -= v0.x();
229  vi.ry() -= v0.y();
230  vj.rx() -= v0.x();
231  vj.ry() -= v0.y();
232  double d = vi.x() * vj.y() - vj.x() * vi.y();
233  A += d;
234  Cx += ( vi.x() + vj.x() ) * d;
235  Cy += ( vi.y() + vj.y() ) * d;
236  }
237 
238  if ( A < 1E-12 )
239  {
240  Cx = Cy = 0.;
241  for ( int i = 0; i < n - 1; ++i )
242  {
243  QgsPoint vi = vertexAt( QgsVertexId( 0, 0, i ) );
244  Cx += vi.x();
245  Cy += vi.y();
246  }
247  return QgsPoint( Cx / ( n - 1 ), Cy / ( n - 1 ) );
248  }
249  else
250  {
251  return QgsPoint( v0.x() + Cx / ( 3. * A ), v0.y() + Cy / ( 3. * A ) );
252  }
253 }
254 
256 {
257  if ( type == mWkbType )
258  return true;
259 
261  return false;
262 
263  bool needZ = QgsWkbTypes::hasZ( type );
264  bool needM = QgsWkbTypes::hasM( type );
265  if ( !needZ )
266  {
267  dropZValue();
268  }
269  else if ( !is3D() )
270  {
271  addZValue( std::numeric_limits<double>::quiet_NaN() );
272  }
273 
274  if ( !needM )
275  {
276  dropMValue();
277  }
278  else if ( !isMeasure() )
279  {
280  addMValue( std::numeric_limits<double>::quiet_NaN() );
281  }
282 
283  return true;
284 }
285 
287 {
288  return this;
289 }
290 
291 void QgsAbstractGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> & )
292 {
293  // Ideally this would be pure virtual, but SIP has issues with that
294 }
295 
296 void QgsAbstractGeometry::transformVertices( const std::function<QgsPoint( const QgsPoint & )> & )
297 {
298  // Ideally this would be pure virtual, but SIP has issues with that
299 }
300 
302 {
303  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( this );
304  return part_iterator( this, collection ? collection->partCount() : 1 );
305 }
306 
308 {
309  return QgsGeometryPartIterator( this );
310 }
311 
313 {
314  return QgsGeometryConstPartIterator( this );
315 }
316 
318 {
319  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( this );
320  return const_part_iterator( this, collection ? collection->partCount() : 1 );
321 }
322 
324 {
325  return QgsVertexIterator( this );
326 }
327 
329 {
330  switch ( QgsWkbTypes::flatType( mWkbType ) )
331  {
332  case QgsWkbTypes::Point:
333  return 0;
335  return 1;
337  return 2;
339  return 3;
341  return 4;
343  return 5;
345  return 6;
348  return 7;
350  return 8;
352  return 9;
354  return 10;
356  return 11;
358  return 12;
360  default:
361  break;
362  }
363  return 13;
364 }
365 
367 {
368  return QgsWkbTypes::isMultiType( wkbType() ) || dimension() == 2;
369 }
370 
372 {
373  Q_UNUSED( index )
374  return QgsPoint();
375 }
376 
378 {
379  QgsVertexId vId;
380  QgsPoint vertex;
381  return !nextVertex( vId, vertex );
382 }
383 
385 {
386  return false;
387 }
388 
390 {
391  return boundingBox().intersects( rectangle );
392 }
393 
395 {
396  Q_UNUSED( tolerance )
397  Q_UNUSED( toleranceType )
398  return clone();
399 }
400 
401 
403  : depth( 0 )
404 {
405  levels.fill( Level() );
406  levels[0].g = g;
407  levels[0].index = index;
408 
409  digDown(); // go to the leaf level of the first vertex
410 }
411 
413 {
414  if ( depth == 0 && levels[0].index >= levels[0].g->childCount() )
415  return *this; // end of geometry - nowhere else to go
416 
417  Q_ASSERT( !levels[depth].g->hasChildGeometries() ); // we should be at a leaf level
418 
419  ++levels[depth].index;
420 
421  // traverse up if we are at the end in the current level
422  while ( depth > 0 && levels[depth].index >= levels[depth].g->childCount() )
423  {
424  --depth;
425  ++levels[depth].index;
426  }
427 
428  digDown(); // go to the leaf level again
429 
430  return *this;
431 }
432 
434 {
435  vertex_iterator it( *this );
436  ++*this;
437  return it;
438 }
439 
441 {
442  Q_ASSERT( !levels[depth].g->hasChildGeometries() );
443  return levels[depth].g->childPoint( levels[depth].index );
444 }
445 
447 {
448  int part = 0, ring = 0, vertex = levels[depth].index;
449  if ( depth == 0 )
450  {
451  // nothing else to do
452  }
453  else if ( depth == 1 )
454  {
455  if ( QgsWkbTypes::isMultiType( levels[0].g->wkbType() ) )
456  part = levels[0].index;
457  else
458  ring = levels[0].index;
459  }
460  else if ( depth == 2 )
461  {
462  part = levels[0].index;
463  ring = levels[1].index;
464  }
465  else
466  {
467  Q_ASSERT( false );
468  return QgsVertexId();
469  }
470 
471  // get the vertex type: find out from the leaf geometry
473  if ( const QgsCurve *curve = dynamic_cast<const QgsCurve *>( levels[depth].g ) )
474  {
475  QgsPoint p;
476  curve->pointAt( vertex, p, vertexType );
477  }
478 
479  return QgsVertexId( part, ring, vertex, vertexType );
480 }
481 
483 {
484  if ( depth != other.depth )
485  return false;
486  return std::equal( std::begin( levels ), std::begin( levels ) + depth + 1, std::begin( other.levels ) );
487 }
488 
489 void QgsAbstractGeometry::vertex_iterator::digDown()
490 {
491  if ( levels[depth].g->hasChildGeometries() && levels[depth].index >= levels[depth].g->childCount() )
492  return; // first check we are not already at the end
493 
494  // while not "final" depth for the geom: go one level down.
495  while ( levels[depth].g->hasChildGeometries() )
496  {
497  ++depth;
498  Q_ASSERT( depth < 3 ); // that's capacity of the levels array
499  levels[depth].index = 0;
500  levels[depth].g = levels[depth - 1].g->childGeometry( levels[depth - 1].index );
501  }
502 }
503 
505 {
506  n = i++;
507  return *n;
508 }
509 
511  : mIndex( index )
512  , mGeometry( g )
513 {
514 }
515 
517 {
518  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
519  if ( !collection )
520  {
521  mIndex = 1;
522  return *this; // end of geometry -- nowhere else to go
523  }
524 
525  if ( mIndex >= collection->partCount() )
526  return *this; // end of geometry - nowhere else to go
527 
528  mIndex++;
529  return *this;
530 }
531 
533 {
534  part_iterator it( *this );
535  ++*this;
536  return it;
537 }
538 
540 {
541  QgsGeometryCollection *collection = qgsgeometry_cast< QgsGeometryCollection * >( mGeometry );
542  if ( !collection )
543  {
544  return mGeometry;
545  }
546 
547  return collection->geometryN( mIndex );
548 }
549 
551 {
552  return mIndex;
553 }
554 
556 {
557  return mGeometry == other.mGeometry && mIndex == other.mIndex;
558 }
559 
561 {
562  n = i++;
563  return *n;
564 }
565 
566 
567 
569  : mIndex( index )
570  , mGeometry( g )
571 {
572 }
573 
575 {
576  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
577  if ( !collection )
578  {
579  mIndex = 1;
580  return *this; // end of geometry -- nowhere else to go
581  }
582 
583  if ( mIndex >= collection->partCount() )
584  return *this; // end of geometry - nowhere else to go
585 
586  mIndex++;
587  return *this;
588 }
589 
591 {
592  const_part_iterator it( *this );
593  ++*this;
594  return it;
595 }
596 
598 {
599  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
600  if ( !collection )
601  {
602  return mGeometry;
603  }
604 
605  return collection->geometryN( mIndex );
606 }
607 
609 {
610  return mIndex;
611 }
612 
614 {
615  return mGeometry == other.mGeometry && mIndex == other.mIndex;
616 }
617 
619 {
620  n = i++;
621  return *n;
622 }
623 
624 bool QgsAbstractGeometry::vertex_iterator::Level::operator==( const QgsAbstractGeometry::vertex_iterator::Level &other ) const
625 {
626  return g == other.g && index == other.index;
627 }
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 QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
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.
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.
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
int partCount() const override
Returns count of parts contained in the geometry.
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 & ry()
Returns a reference to the y-coordinate of this point.
Definition: qgspoint.h:255
Q_GADGET double x
Definition: qgspoint.h:52
double & rx()
Returns a reference to the x-coordinate of this point.
Definition: qgspoint.h:246
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:832
static bool hasM(Type type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1100
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:702
static Type addZ(Type type) SIP_HOLDGIL
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1146
static bool hasZ(Type type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:1050
static Type addM(Type type) SIP_HOLDGIL
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1171
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.
VertexType
Type of vertex.
@ SegmentVertex
The actual start or end point of a segment.