QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
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  if ( !subgeom )
46  {
47  return;
48  }
49 
50  //special handling for 25d types:
51  if ( baseGeomType == QgsWkbTypes::LineString &&
52  ( subgeom->wkbType() == QgsWkbTypes::Point25D || subgeom->wkbType() == QgsWkbTypes::LineString25D ) )
53  {
55  return;
56  }
57  else if ( baseGeomType == QgsWkbTypes::Polygon &&
58  ( subgeom->wkbType() == QgsWkbTypes::Point25D || subgeom->wkbType() == QgsWkbTypes::LineString25D ) )
59  {
61  return;
62  }
63 
64  bool hasZ = subgeom->is3D();
65  bool hasM = subgeom->isMeasure();
66 
67  if ( hasZ && hasM )
68  {
69  mWkbType = QgsWkbTypes::addM( QgsWkbTypes::addZ( baseGeomType ) );
70  }
71  else if ( hasZ )
72  {
73  mWkbType = QgsWkbTypes::addZ( baseGeomType );
74  }
75  else if ( hasM )
76  {
77  mWkbType = QgsWkbTypes::addM( baseGeomType );
78  }
79  else
80  {
81  mWkbType = baseGeomType;
82  }
83 }
84 
86 {
87  double xmin = std::numeric_limits<double>::max();
88  double ymin = std::numeric_limits<double>::max();
89  double xmax = -std::numeric_limits<double>::max();
90  double ymax = -std::numeric_limits<double>::max();
91 
92  QgsVertexId id;
93  QgsPoint vertex;
94  double x, y;
95  while ( nextVertex( id, vertex ) )
96  {
97  x = vertex.x();
98  y = vertex.y();
99  if ( x < xmin )
100  xmin = x;
101  if ( x > xmax )
102  xmax = x;
103  if ( y < ymin )
104  ymin = y;
105  if ( y > ymax )
106  ymax = y;
107  }
108 
109  return QgsRectangle( xmin, ymin, xmax, ymax );
110 }
111 
113 {
114 }
115 
117 {
118  int nCoords = 0;
119 
121  for ( const QgsRingSequence &r : seq )
122  {
123  for ( const QgsPointSequence &p : r )
124  {
125  nCoords += p.size();
126  }
127  }
128 
129  return nCoords;
130 }
131 
133 {
134  return 0.0;
135 }
136 
138 {
139  return 0.0;
140 }
141 
143 {
144  return 0.0;
145 }
146 
148 {
149  QString wkt = geometryType();
150  if ( is3D() )
151  wkt += 'Z';
152  if ( isMeasure() )
153  wkt += 'M';
154  return wkt;
155 }
156 
158 {
159  return QString::fromStdString( asJsonObject( precision ).dump() );
160 }
161 
163 {
164  Q_UNUSED( precision ) return nullptr;
165 }
166 
168 {
169  // http://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
170  // Pick the first ring of first part for the moment
171 
172  int n = vertexCount( 0, 0 );
173  if ( n == 1 )
174  {
175  return vertexAt( QgsVertexId( 0, 0, 0 ) );
176  }
177 
178  double A = 0.;
179  double Cx = 0.;
180  double Cy = 0.;
181  QgsPoint v0 = vertexAt( QgsVertexId( 0, 0, 0 ) );
182  int i = 0, j = 1;
183  if ( vertexAt( QgsVertexId( 0, 0, 0 ) ) != vertexAt( QgsVertexId( 0, 0, n - 1 ) ) )
184  {
185  i = n - 1;
186  j = 0;
187  }
188  for ( ; j < n; i = j++ )
189  {
190  QgsPoint vi = vertexAt( QgsVertexId( 0, 0, i ) );
191  QgsPoint vj = vertexAt( QgsVertexId( 0, 0, j ) );
192  vi.rx() -= v0.x();
193  vi.ry() -= v0.y();
194  vj.rx() -= v0.x();
195  vj.ry() -= v0.y();
196  double d = vi.x() * vj.y() - vj.x() * vi.y();
197  A += d;
198  Cx += ( vi.x() + vj.x() ) * d;
199  Cy += ( vi.y() + vj.y() ) * d;
200  }
201 
202  if ( A < 1E-12 )
203  {
204  Cx = Cy = 0.;
205  for ( int i = 0; i < n - 1; ++i )
206  {
207  QgsPoint vi = vertexAt( QgsVertexId( 0, 0, i ) );
208  Cx += vi.x();
209  Cy += vi.y();
210  }
211  return QgsPoint( Cx / ( n - 1 ), Cy / ( n - 1 ) );
212  }
213  else
214  {
215  return QgsPoint( v0.x() + Cx / ( 3. * A ), v0.y() + Cy / ( 3. * A ) );
216  }
217 }
218 
220 {
221  if ( type == mWkbType )
222  return true;
223 
225  return false;
226 
227  bool needZ = QgsWkbTypes::hasZ( type );
228  bool needM = QgsWkbTypes::hasM( type );
229  if ( !needZ )
230  {
231  dropZValue();
232  }
233  else if ( !is3D() )
234  {
235  addZValue( std::numeric_limits<double>::quiet_NaN() );
236  }
237 
238  if ( !needM )
239  {
240  dropMValue();
241  }
242  else if ( !isMeasure() )
243  {
244  addMValue( std::numeric_limits<double>::quiet_NaN() );
245  }
246 
247  return true;
248 }
249 
250 void QgsAbstractGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> & )
251 {
252  // Ideally this would be pure virtual, but SIP has issues with that
253 }
254 
255 void QgsAbstractGeometry::transformVertices( const std::function<QgsPoint( const QgsPoint & )> & )
256 {
257  // Ideally this would be pure virtual, but SIP has issues with that
258 }
259 
261 {
262  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( this );
263  return part_iterator( this, collection ? collection->partCount() : 1 );
264 }
265 
267 {
268  return QgsGeometryPartIterator( this );
269 }
270 
272 {
273  return QgsGeometryConstPartIterator( this );
274 }
275 
277 {
278  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( this );
279  return const_part_iterator( this, collection ? collection->partCount() : 1 );
280 }
281 
283 {
284  return QgsVertexIterator( this );
285 }
286 
288 {
289  return QgsWkbTypes::isMultiType( wkbType() ) || dimension() == 2;
290 }
291 
293 {
294  Q_UNUSED( index )
295  return QgsPoint();
296 }
297 
299 {
300  QgsVertexId vId;
301  QgsPoint vertex;
302  return !nextVertex( vId, vertex );
303 }
304 
306 {
307  return false;
308 }
309 
311 {
312  Q_UNUSED( tolerance )
313  Q_UNUSED( toleranceType )
314  return clone();
315 }
316 
317 
319  : depth( 0 )
320 {
321  levels.fill( Level() );
322  levels[0].g = g;
323  levels[0].index = index;
324 
325  digDown(); // go to the leaf level of the first vertex
326 }
327 
329 {
330  if ( depth == 0 && levels[0].index >= levels[0].g->childCount() )
331  return *this; // end of geometry - nowhere else to go
332 
333  Q_ASSERT( !levels[depth].g->hasChildGeometries() ); // we should be at a leaf level
334 
335  ++levels[depth].index;
336 
337  // traverse up if we are at the end in the current level
338  while ( depth > 0 && levels[depth].index >= levels[depth].g->childCount() )
339  {
340  --depth;
341  ++levels[depth].index;
342  }
343 
344  digDown(); // go to the leaf level again
345 
346  return *this;
347 }
348 
350 {
351  vertex_iterator it( *this );
352  ++*this;
353  return it;
354 }
355 
357 {
358  Q_ASSERT( !levels[depth].g->hasChildGeometries() );
359  return levels[depth].g->childPoint( levels[depth].index );
360 }
361 
363 {
364  int part = 0, ring = 0, vertex = levels[depth].index;
365  if ( depth == 0 )
366  {
367  // nothing else to do
368  }
369  else if ( depth == 1 )
370  {
371  if ( QgsWkbTypes::isMultiType( levels[0].g->wkbType() ) )
372  part = levels[0].index;
373  else
374  ring = levels[0].index;
375  }
376  else if ( depth == 2 )
377  {
378  part = levels[0].index;
379  ring = levels[1].index;
380  }
381  else
382  {
383  Q_ASSERT( false );
384  return QgsVertexId();
385  }
386 
387  // get the vertex type: find out from the leaf geometry
389  if ( const QgsCurve *curve = dynamic_cast<const QgsCurve *>( levels[depth].g ) )
390  {
391  QgsPoint p;
392  curve->pointAt( vertex, p, vertexType );
393  }
394 
395  return QgsVertexId( part, ring, vertex, vertexType );
396 }
397 
399 {
400  if ( depth != other.depth )
401  return false;
402  return std::equal( std::begin( levels ), std::begin( levels ) + depth + 1, std::begin( other.levels ) );
403 }
404 
405 void QgsAbstractGeometry::vertex_iterator::digDown()
406 {
407  if ( levels[depth].g->hasChildGeometries() && levels[depth].index >= levels[depth].g->childCount() )
408  return; // first check we are not already at the end
409 
410  // while not "final" depth for the geom: go one level down.
411  while ( levels[depth].g->hasChildGeometries() )
412  {
413  ++depth;
414  Q_ASSERT( depth < 3 ); // that's capacity of the levels array
415  levels[depth].index = 0;
416  levels[depth].g = levels[depth - 1].g->childGeometry( levels[depth - 1].index );
417  }
418 }
419 
421 {
422  n = i++;
423  return *n;
424 }
425 
427  : mIndex( index )
428  , mGeometry( g )
429 {
430 }
431 
433 {
434  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
435  if ( !collection )
436  {
437  mIndex = 1;
438  return *this; // end of geometry -- nowhere else to go
439  }
440 
441  if ( mIndex >= collection->partCount() )
442  return *this; // end of geometry - nowhere else to go
443 
444  mIndex++;
445  return *this;
446 }
447 
449 {
450  part_iterator it( *this );
451  ++*this;
452  return it;
453 }
454 
456 {
457  QgsGeometryCollection *collection = qgsgeometry_cast< QgsGeometryCollection * >( mGeometry );
458  if ( !collection )
459  {
460  return mGeometry;
461  }
462 
463  return collection->geometryN( mIndex );
464 }
465 
467 {
468  return mIndex;
469 }
470 
472 {
473  return mGeometry == other.mGeometry && mIndex == other.mIndex;
474 }
475 
477 {
478  n = i++;
479  return *n;
480 }
481 
482 
483 
485  : mIndex( index )
486  , mGeometry( g )
487 {
488 }
489 
491 {
492  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
493  if ( !collection )
494  {
495  mIndex = 1;
496  return *this; // end of geometry -- nowhere else to go
497  }
498 
499  if ( mIndex >= collection->partCount() )
500  return *this; // end of geometry - nowhere else to go
501 
502  mIndex++;
503  return *this;
504 }
505 
507 {
508  const_part_iterator it( *this );
509  ++*this;
510  return it;
511 }
512 
514 {
515  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
516  if ( !collection )
517  {
518  return mGeometry;
519  }
520 
521  return collection->geometryN( mIndex );
522 }
523 
525 {
526  return mIndex;
527 }
528 
530 {
531  return mGeometry == other.mGeometry && mIndex == other.mIndex;
532 }
533 
535 {
536  n = i++;
537  return *n;
538 }
539 
540 bool QgsAbstractGeometry::vertex_iterator::Level::operator==( const QgsAbstractGeometry::vertex_iterator::Level &other ) const
541 {
542  return g == other.g && index == other.index;
543 }
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 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 QString geometryType() const =0
Returns a unique string representing the geometry type.
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.
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.
QgsAbstractGeometry()=default
Constructor for QgsAbstractGeometry.
virtual double area() const
Returns the planar, 2-dimensional area of the geometry.
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:38
double & ry()
Returns a reference to the y-coordinate of this point.
Definition: qgspoint.h:244
Q_GADGET double x
Definition: qgspoint.h:41
double & rx()
Returns a reference to the x-coordinate of this point.
Definition: qgspoint.h:235
double y
Definition: qgspoint.h:42
A rectangle specified with double values.
Definition: qgsrectangle.h:42
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
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.