QGIS API Documentation  3.2.0-Bonn (bc43194)
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 
23 #include <limits>
24 #include <QTransform>
25 
27 {
28  mWkbType = geom.mWkbType;
29 }
30 
32 {
33  if ( &geom != this )
34  {
35  clear();
36  mWkbType = geom.mWkbType;
37  }
38  return *this;
39 }
40 
42 {
43  if ( !subgeom )
44  {
45  return;
46  }
47 
48  //special handling for 25d types:
49  if ( baseGeomType == QgsWkbTypes::LineString &&
50  ( subgeom->wkbType() == QgsWkbTypes::Point25D || subgeom->wkbType() == QgsWkbTypes::LineString25D ) )
51  {
53  return;
54  }
55  else if ( baseGeomType == QgsWkbTypes::Polygon &&
56  ( subgeom->wkbType() == QgsWkbTypes::Point25D || subgeom->wkbType() == QgsWkbTypes::LineString25D ) )
57  {
59  return;
60  }
61 
62  bool hasZ = subgeom->is3D();
63  bool hasM = subgeom->isMeasure();
64 
65  if ( hasZ && hasM )
66  {
67  mWkbType = QgsWkbTypes::addM( QgsWkbTypes::addZ( baseGeomType ) );
68  }
69  else if ( hasZ )
70  {
71  mWkbType = QgsWkbTypes::addZ( baseGeomType );
72  }
73  else if ( hasM )
74  {
75  mWkbType = QgsWkbTypes::addM( baseGeomType );
76  }
77  else
78  {
79  mWkbType = baseGeomType;
80  }
81 }
82 
84 {
85  double xmin = std::numeric_limits<double>::max();
86  double ymin = std::numeric_limits<double>::max();
87  double xmax = -std::numeric_limits<double>::max();
88  double ymax = -std::numeric_limits<double>::max();
89 
90  QgsVertexId id;
91  QgsPoint vertex;
92  double x, y;
93  while ( nextVertex( id, vertex ) )
94  {
95  x = vertex.x();
96  y = vertex.y();
97  if ( x < xmin )
98  xmin = x;
99  if ( x > xmax )
100  xmax = x;
101  if ( y < ymin )
102  ymin = y;
103  if ( y > ymax )
104  ymax = y;
105  }
106 
107  return QgsRectangle( xmin, ymin, xmax, ymax );
108 }
109 
111 {
112 }
113 
115 {
116  int nCoords = 0;
117 
119  for ( const QgsRingSequence &r : seq )
120  {
121  for ( const QgsPointSequence &p : r )
122  {
123  nCoords += p.size();
124  }
125  }
126 
127  return nCoords;
128 }
129 
131 {
132  return 0.0;
133 }
134 
136 {
137  return 0.0;
138 }
139 
141 {
142  return 0.0;
143 }
144 
146 {
147  QString wkt = geometryType();
148  if ( is3D() )
149  wkt += 'Z';
150  if ( isMeasure() )
151  wkt += 'M';
152  return wkt;
153 }
154 
156 {
157  // http://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
158  // Pick the first ring of first part for the moment
159 
160  int n = vertexCount( 0, 0 );
161  if ( n == 1 )
162  {
163  return vertexAt( QgsVertexId( 0, 0, 0 ) );
164  }
165 
166  double A = 0.;
167  double Cx = 0.;
168  double Cy = 0.;
169  QgsPoint v0 = vertexAt( QgsVertexId( 0, 0, 0 ) );
170  int i = 0, j = 1;
171  if ( vertexAt( QgsVertexId( 0, 0, 0 ) ) != vertexAt( QgsVertexId( 0, 0, n - 1 ) ) )
172  {
173  i = n - 1;
174  j = 0;
175  }
176  for ( ; j < n; i = j++ )
177  {
178  QgsPoint vi = vertexAt( QgsVertexId( 0, 0, i ) );
179  QgsPoint vj = vertexAt( QgsVertexId( 0, 0, j ) );
180  vi.rx() -= v0.x();
181  vi.ry() -= v0.y();
182  vj.rx() -= v0.x();
183  vj.ry() -= v0.y();
184  double d = vi.x() * vj.y() - vj.x() * vi.y();
185  A += d;
186  Cx += ( vi.x() + vj.x() ) * d;
187  Cy += ( vi.y() + vj.y() ) * d;
188  }
189 
190  if ( A < 1E-12 )
191  {
192  Cx = Cy = 0.;
193  for ( int i = 0; i < n - 1; ++i )
194  {
195  QgsPoint vi = vertexAt( QgsVertexId( 0, 0, i ) );
196  Cx += vi.x();
197  Cy += vi.y();
198  }
199  return QgsPoint( Cx / ( n - 1 ), Cy / ( n - 1 ) );
200  }
201  else
202  {
203  return QgsPoint( v0.x() + Cx / ( 3. * A ), v0.y() + Cy / ( 3. * A ) );
204  }
205 }
206 
208 {
209  if ( type == mWkbType )
210  return true;
211 
213  return false;
214 
215  bool needZ = QgsWkbTypes::hasZ( type );
216  bool needM = QgsWkbTypes::hasM( type );
217  if ( !needZ )
218  {
219  dropZValue();
220  }
221  else if ( !is3D() )
222  {
223  addZValue( std::numeric_limits<double>::quiet_NaN() );
224  }
225 
226  if ( !needM )
227  {
228  dropMValue();
229  }
230  else if ( !isMeasure() )
231  {
232  addMValue( std::numeric_limits<double>::quiet_NaN() );
233  }
234 
235  return true;
236 }
237 
238 void QgsAbstractGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> & )
239 {
240  // Ideally this would be pure virtual, but SIP has issues with that
241 }
242 
244 {
245  return QgsVertexIterator( this );
246 }
247 
249 {
250  return QgsWkbTypes::isMultiType( wkbType() ) || dimension() == 2;
251 }
252 
254 {
255  Q_UNUSED( index );
256  return QgsPoint();
257 }
258 
260 {
261  QgsVertexId vId;
262  QgsPoint vertex;
263  return !nextVertex( vId, vertex );
264 }
265 
267 {
268  return false;
269 }
270 
272 {
273  Q_UNUSED( tolerance );
274  Q_UNUSED( toleranceType );
275  return clone();
276 }
277 
278 
280  : depth( 0 )
281 {
282  ::memset( levels, 0, sizeof( Level ) * 3 ); // make sure we clean up also the padding areas (for memcmp test in operator==)
283  levels[0].g = g;
284  levels[0].index = index;
285 
286  digDown(); // go to the leaf level of the first vertex
287 }
288 
290 {
291  if ( depth == 0 && levels[0].index >= levels[0].g->childCount() )
292  return *this; // end of geometry - nowhere else to go
293 
294  Q_ASSERT( !levels[depth].g->hasChildGeometries() ); // we should be at a leaf level
295 
296  ++levels[depth].index;
297 
298  // traverse up if we are at the end in the current level
299  while ( depth > 0 && levels[depth].index >= levels[depth].g->childCount() )
300  {
301  --depth;
302  ++levels[depth].index;
303  }
304 
305  digDown(); // go to the leaf level again
306 
307  return *this;
308 }
309 
311 {
312  vertex_iterator it( *this );
313  ++*this;
314  return it;
315 }
316 
318 {
319  Q_ASSERT( !levels[depth].g->hasChildGeometries() );
320  return levels[depth].g->childPoint( levels[depth].index );
321 }
322 
324 {
325  int part = 0, ring = 0, vertex = levels[depth].index;
326  if ( depth == 0 )
327  {
328  // nothing else to do
329  }
330  else if ( depth == 1 )
331  {
332  if ( QgsWkbTypes::isMultiType( levels[0].g->wkbType() ) )
333  part = levels[0].index;
334  else
335  ring = levels[0].index;
336  }
337  else if ( depth == 2 )
338  {
339  part = levels[0].index;
340  ring = levels[1].index;
341  }
342  else
343  {
344  Q_ASSERT( false );
345  return QgsVertexId();
346  }
347 
348  // get the vertex type: find out from the leaf geometry
350  if ( const QgsCurve *curve = dynamic_cast<const QgsCurve *>( levels[depth].g ) )
351  {
352  QgsPoint p;
353  curve->pointAt( vertex, p, vertexType );
354  }
355 
356  return QgsVertexId( part, ring, vertex, vertexType );
357 }
358 
360 {
361  if ( depth != other.depth )
362  return false;
363  int res = ::memcmp( levels, other.levels, sizeof( Level ) * ( depth + 1 ) );
364  return res == 0;
365 }
366 
367 void QgsAbstractGeometry::vertex_iterator::digDown()
368 {
369  if ( levels[depth].g->hasChildGeometries() && levels[depth].index >= levels[depth].g->childCount() )
370  return; // first check we are not already at the end
371 
372  // while not "final" depth for the geom: go one level down.
373  while ( levels[depth].g->hasChildGeometries() )
374  {
375  ++depth;
376  Q_ASSERT( depth < 3 ); // that's capacity of the levels array
377  levels[depth].index = 0;
378  levels[depth].g = levels[depth - 1].g->childGeometry( levels[depth - 1].index );
379  }
380 }
381 
383 {
384  n = i++;
385  return *n;
386 }
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:40
double y
Definition: qgspoint.h:42
virtual bool isEmpty() const
Returns true if the geometry is empty.
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:557
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
QgsVertexId vertexId() const
Returns vertex ID of the current item.
virtual bool addMValue(double mValue=0)=0
Adds a measure to the geometry, initialized to a preset value.
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:768
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.
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:67
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:889
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...
Utility class for identifying a unique vertex within a geometry.
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:864
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.
QVector< QgsPointSequence > QgsRingSequence
QgsPoint operator*() const
Returns the current item.
virtual void clear()=0
Clears the geometry, ie reset it to a null geometry.
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.
virtual QgsRectangle calculateBoundingBox() const
Default calculator for the minimal bounding box for the geometry.
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:818
virtual bool dropMValue()=0
Drops any measure values which exist in the geometry.
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:427
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 Java-style iterator for traversal of vertices 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