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