QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
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 #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 
292 void QgsAbstractGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> & )
293 {
294  // Ideally this would be pure virtual, but SIP has issues with that
295 }
296 
297 void 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  {
333  case QgsWkbTypes::Point:
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 
490 void 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 
625 bool 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:990
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: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