QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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  ::memset( levels, 0, sizeof( Level ) * 3 ); // make sure we clean up also the padding areas (for memcmp test in operator==)
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  int res = ::memcmp( levels, other.levels, sizeof( Level ) * ( depth + 1 ) );
403  return res == 0;
404 }
405 
406 void QgsAbstractGeometry::vertex_iterator::digDown()
407 {
408  if ( levels[depth].g->hasChildGeometries() && levels[depth].index >= levels[depth].g->childCount() )
409  return; // first check we are not already at the end
410 
411  // while not "final" depth for the geom: go one level down.
412  while ( levels[depth].g->hasChildGeometries() )
413  {
414  ++depth;
415  Q_ASSERT( depth < 3 ); // that's capacity of the levels array
416  levels[depth].index = 0;
417  levels[depth].g = levels[depth - 1].g->childGeometry( levels[depth - 1].index );
418  }
419 }
420 
422 {
423  n = i++;
424  return *n;
425 }
426 
428  : mIndex( index )
429  , mGeometry( g )
430 {
431 }
432 
434 {
435  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
436  if ( !collection )
437  {
438  mIndex = 1;
439  return *this; // end of geometry -- nowhere else to go
440  }
441 
442  if ( mIndex >= collection->partCount() )
443  return *this; // end of geometry - nowhere else to go
444 
445  mIndex++;
446  return *this;
447 }
448 
450 {
451  part_iterator it( *this );
452  ++*this;
453  return it;
454 }
455 
457 {
458  QgsGeometryCollection *collection = qgsgeometry_cast< QgsGeometryCollection * >( mGeometry );
459  if ( !collection )
460  {
461  return mGeometry;
462  }
463 
464  return collection->geometryN( mIndex );
465 }
466 
468 {
469  return mIndex;
470 }
471 
473 {
474  return mGeometry == other.mGeometry && mIndex == other.mIndex;
475 }
476 
478 {
479  n = i++;
480  return *n;
481 }
482 
483 
484 
486  : mIndex( index )
487  , mGeometry( g )
488 {
489 }
490 
492 {
493  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
494  if ( !collection )
495  {
496  mIndex = 1;
497  return *this; // end of geometry -- nowhere else to go
498  }
499 
500  if ( mIndex >= collection->partCount() )
501  return *this; // end of geometry - nowhere else to go
502 
503  mIndex++;
504  return *this;
505 }
506 
508 {
509  const_part_iterator it( *this );
510  ++*this;
511  return it;
512 }
513 
515 {
516  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
517  if ( !collection )
518  {
519  return mGeometry;
520  }
521 
522  return collection->geometryN( mIndex );
523 }
524 
526 {
527  return mIndex;
528 }
529 
531 {
532  return mGeometry == other.mGeometry && mIndex == other.mIndex;
533 }
534 
536 {
537  n = i++;
538  return *n;
539 }
bool isMeasure() const
Returns true if the geometry contains m values.
virtual bool hasChildGeometries() const
Returns whether the geometry has any child geometries (false for point / curve, true otherwise) ...
int precision
A rectangle specified with double values.
Definition: qgsrectangle.h:41
Java-style iterator for traversal of parts of a geometry.
double y
Definition: qgspoint.h:42
virtual bool isEmpty() const
Returns true if the geometry is empty.
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...
int partNumber() const
Returns the part number of the current item.
QgsAbstractGeometry & operator=(const QgsAbstractGeometry &geom)
Java-style iterator for traversal of vertices of a geometry.
static bool isMultiType(Type type)
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:560
QgsAbstractGeometry()=default
Constructor for QgsAbstractGeometry.
virtual QgsPoint childPoint(int index) const
Returns point at index (for geometries without child geometries - i.e.
QVector< QgsRingSequence > QgsCoordinateSequence
Java-style iterator for const traversal of parts of a geometry.
int partNumber() const
Returns the part number of the current item.
QgsVertexId vertexId() const
Returns vertex ID of the current item.
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 addMValue(double mValue=0)=0
Adds a measure to the geometry, initialized to a preset value.
The part_iterator class provides STL-style iterator for const references to geometry parts...
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle...
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.
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:771
vertex_iterator & operator++()
The prefix ++ operator (++it) advances the iterator to the next vertex and returns an iterator to the...
QgsWkbTypes::Type mWkbType
vertex_iterator()=default
Create invalid iterator.
virtual QgsPoint centroid() const
Returns the centroid of the geometry.
bool operator==(const vertex_iterator &other) const
QString wktTypeStr() const
Returns the WKT type string of the geometry.
part_iterator()=default
Create invalid iterator.
virtual double length() const
Returns the length of the geometry.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
part_iterator & operator++()
The prefix ++ operator (++it) advances the iterator to the next part and returns an iterator to the n...
virtual void clearCache() const
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
static Type addM(Type type)
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:892
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...
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts of the geometry.
Utility class for identifying a unique vertex within a geometry.
const_part_iterator()=default
Create invalid iterator.
Geometry collection.
The part_iterator class provides STL-style iterator for geometry parts.
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, QgsWkbTypes::Type baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
static Type addZ(Type type)
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:867
T qgsgeometry_cast(const QgsAbstractGeometry *geom)
QString asJson(int precision=17)
Returns a GeoJSON representation of the geometry as a QString.
bool operator==(part_iterator other) const
part_iterator parts_end()
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry...
virtual double area() const
Returns the area of the geometry.
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
double & rx()
Returns a reference to the x-coordinate of this point.
Definition: qgspoint.h:179
Abstract base class for all geometries.
virtual int dimension() const =0
Returns the inherent dimension of the geometry.
The vertex_iterator class provides STL-style iterator for vertices.
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
nlohmann::json json
Definition: qgsjsonutils.h:27
QVector< QgsPoint > QgsPointSequence
virtual QgsCoordinateSequence coordinateSequence() const =0
Retrieves the sequence of geometries, rings and nodes.
int partCount() const override
Returns count of parts contained in the geometry.
QVector< QgsPointSequence > QgsRingSequence
const QgsAbstractGeometry * next()
Returns next part of the geometry (undefined behavior if hasNext() returns false before calling next(...
QgsPoint operator*() const
Returns the current item.
virtual void clear()=0
Clears the geometry, ie reset it to a null geometry.
QgsAbstractGeometry * next()
Returns next part of the geometry (undefined behavior if hasNext() returns false before calling next(...
QgsAbstractGeometry * operator*() const
Returns the current item.
QgsPoint next()
Returns next vertex of the geometry (undefined behavior if hasNext() returns false before calling nex...
virtual bool addZValue(double zValue=0)=0
Adds a z-dimension to the geometry, initialized to a preset value.
virtual double perimeter() const
Returns the perimeter of the geometry.
virtual int vertexCount(int part=0, int ring=0) const =0
Returns the number of vertices of which this geometry is built.
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
virtual QgsRectangle calculateBoundingBox() const
Default calculator for the minimal bounding box for the geometry.
bool operator==(const_part_iterator other) const
virtual bool convertTo(QgsWkbTypes::Type type)
Converts the geometry to a specified type.
static bool hasM(Type type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:821
const QgsAbstractGeometry * operator*() const
Returns the current item.
virtual bool dropMValue()=0
Drops any measure values which exist in the geometry.
const_part_iterator & operator++()
The prefix ++ operator (++it) advances the iterator to the next part and returns an iterator to the n...
virtual QgsPoint vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
virtual int nCoordinates() const
Returns the number of nodes contained in the geometry.
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:430
virtual bool hasCurvedSegments() const
Returns true if the geometry contains curved segments.
virtual QgsAbstractGeometry * segmentize(double tolerance=M_PI/180., SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a version of the geometry without curves.
QgsVertexIterator vertices() const
Returns a read-only, Java-style iterator for traversal of vertices of all the geometry, including all geometry parts and rings.
virtual json asJsonObject(int precision=17) const
Returns a json object representation of the geometry.
double & ry()
Returns a reference to the y-coordinate of this point.
Definition: qgspoint.h:188
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
virtual bool dropZValue()=0
Drops any z-dimensions which exist in the geometry.
virtual QString geometryType() const =0
Returns a unique string representing the geometry type.
double x
Definition: qgspoint.h:41