QGIS API Documentation  3.0.2-Girona (307d082)
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  return QgsWkbTypes::hasZ( mWkbType );
44 }
45 
47 {
48  return QgsWkbTypes::hasM( mWkbType );
49 }
50 
51 
53 {
54  if ( !subgeom )
55  {
56  return;
57  }
58 
59  //special handling for 25d types:
60  if ( baseGeomType == QgsWkbTypes::LineString &&
61  ( subgeom->wkbType() == QgsWkbTypes::Point25D || subgeom->wkbType() == QgsWkbTypes::LineString25D ) )
62  {
64  return;
65  }
66  else if ( baseGeomType == QgsWkbTypes::Polygon &&
67  ( subgeom->wkbType() == QgsWkbTypes::Point25D || subgeom->wkbType() == QgsWkbTypes::LineString25D ) )
68  {
70  return;
71  }
72 
73  bool hasZ = subgeom->is3D();
74  bool hasM = subgeom->isMeasure();
75 
76  if ( hasZ && hasM )
77  {
78  mWkbType = QgsWkbTypes::addM( QgsWkbTypes::addZ( baseGeomType ) );
79  }
80  else if ( hasZ )
81  {
82  mWkbType = QgsWkbTypes::addZ( baseGeomType );
83  }
84  else if ( hasM )
85  {
86  mWkbType = QgsWkbTypes::addM( baseGeomType );
87  }
88  else
89  {
90  mWkbType = baseGeomType;
91  }
92 }
93 
95 {
96  double xmin = std::numeric_limits<double>::max();
97  double ymin = std::numeric_limits<double>::max();
98  double xmax = -std::numeric_limits<double>::max();
99  double ymax = -std::numeric_limits<double>::max();
100 
101  QgsVertexId id;
102  QgsPoint vertex;
103  double x, y;
104  while ( nextVertex( id, vertex ) )
105  {
106  x = vertex.x();
107  y = vertex.y();
108  if ( x < xmin )
109  xmin = x;
110  if ( x > xmax )
111  xmax = x;
112  if ( y < ymin )
113  ymin = y;
114  if ( y > ymax )
115  ymax = y;
116  }
117 
118  return QgsRectangle( xmin, ymin, xmax, ymax );
119 }
120 
122 {
123 }
124 
126 {
127  int nCoords = 0;
128 
130  for ( const QgsRingSequence &r : seq )
131  {
132  for ( const QgsPointSequence &p : r )
133  {
134  nCoords += p.size();
135  }
136  }
137 
138  return nCoords;
139 }
140 
142 {
143  return 0.0;
144 }
145 
147 {
148  return 0.0;
149 }
150 
152 {
153  return 0.0;
154 }
155 
157 {
158  QString wkt = geometryType();
159  if ( is3D() )
160  wkt += 'Z';
161  if ( isMeasure() )
162  wkt += 'M';
163  return wkt;
164 }
165 
167 {
168  // http://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
169  // Pick the first ring of first part for the moment
170 
171  int n = vertexCount( 0, 0 );
172  if ( n == 1 )
173  {
174  return vertexAt( QgsVertexId( 0, 0, 0 ) );
175  }
176 
177  double A = 0.;
178  double Cx = 0.;
179  double Cy = 0.;
180  QgsPoint v0 = vertexAt( QgsVertexId( 0, 0, 0 ) );
181  int i = 0, j = 1;
182  if ( vertexAt( QgsVertexId( 0, 0, 0 ) ) != vertexAt( QgsVertexId( 0, 0, n - 1 ) ) )
183  {
184  i = n - 1;
185  j = 0;
186  }
187  for ( ; j < n; i = j++ )
188  {
189  QgsPoint vi = vertexAt( QgsVertexId( 0, 0, i ) );
190  QgsPoint vj = vertexAt( QgsVertexId( 0, 0, j ) );
191  vi.rx() -= v0.x();
192  vi.ry() -= v0.y();
193  vj.rx() -= v0.x();
194  vj.ry() -= v0.y();
195  double d = vi.x() * vj.y() - vj.x() * vi.y();
196  A += d;
197  Cx += ( vi.x() + vj.x() ) * d;
198  Cy += ( vi.y() + vj.y() ) * d;
199  }
200 
201  if ( A < 1E-12 )
202  {
203  Cx = Cy = 0.;
204  for ( int i = 0; i < n - 1; ++i )
205  {
206  QgsPoint vi = vertexAt( QgsVertexId( 0, 0, i ) );
207  Cx += vi.x();
208  Cy += vi.y();
209  }
210  return QgsPoint( Cx / ( n - 1 ), Cy / ( n - 1 ) );
211  }
212  else
213  {
214  return QgsPoint( v0.x() + Cx / ( 3. * A ), v0.y() + Cy / ( 3. * A ) );
215  }
216 }
217 
219 {
220  if ( type == mWkbType )
221  return true;
222 
224  return false;
225 
226  bool needZ = QgsWkbTypes::hasZ( type );
227  bool needM = QgsWkbTypes::hasM( type );
228  if ( !needZ )
229  {
230  dropZValue();
231  }
232  else if ( !is3D() )
233  {
234  addZValue( std::numeric_limits<double>::quiet_NaN() );
235  }
236 
237  if ( !needM )
238  {
239  dropMValue();
240  }
241  else if ( !isMeasure() )
242  {
243  addMValue( std::numeric_limits<double>::quiet_NaN() );
244  }
245 
246  return true;
247 }
248 
250 {
251  return QgsVertexIterator( this );
252 }
253 
255 {
256  return QgsWkbTypes::isMultiType( wkbType() ) || dimension() == 2;
257 }
258 
260 {
261  Q_UNUSED( index );
262  return QgsPoint();
263 }
264 
266 {
267  QgsVertexId vId;
268  QgsPoint vertex;
269  return !nextVertex( vId, vertex );
270 }
271 
273 {
274  return false;
275 }
276 
278 {
279  Q_UNUSED( tolerance );
280  Q_UNUSED( toleranceType );
281  return clone();
282 }
283 
284 
286  : depth( 0 )
287 {
288  ::memset( levels, 0, sizeof( Level ) * 3 ); // make sure we clean up also the padding areas (for memcmp test in operator==)
289  levels[0].g = g;
290  levels[0].index = index;
291 
292  digDown(); // go to the leaf level of the first vertex
293 }
294 
296 {
297  if ( depth == 0 && levels[0].index >= levels[0].g->childCount() )
298  return *this; // end of geometry - nowhere else to go
299 
300  Q_ASSERT( !levels[depth].g->hasChildGeometries() ); // we should be at a leaf level
301 
302  ++levels[depth].index;
303 
304  // traverse up if we are at the end in the current level
305  while ( depth > 0 && levels[depth].index >= levels[depth].g->childCount() )
306  {
307  --depth;
308  ++levels[depth].index;
309  }
310 
311  digDown(); // go to the leaf level again
312 
313  return *this;
314 }
315 
317 {
318  vertex_iterator it( *this );
319  ++*this;
320  return it;
321 }
322 
324 {
325  Q_ASSERT( !levels[depth].g->hasChildGeometries() );
326  return levels[depth].g->childPoint( levels[depth].index );
327 }
328 
330 {
331  int part = 0, ring = 0, vertex = levels[depth].index;
332  if ( depth == 0 )
333  {
334  // nothing else to do
335  }
336  else if ( depth == 1 )
337  {
338  if ( QgsWkbTypes::isMultiType( levels[0].g->wkbType() ) )
339  part = levels[0].index;
340  else
341  ring = levels[0].index;
342  }
343  else if ( depth == 2 )
344  {
345  part = levels[0].index;
346  ring = levels[1].index;
347  }
348  else
349  {
350  Q_ASSERT( false );
351  return QgsVertexId();
352  }
353 
354  // get the vertex type: find out from the leaf geometry
356  if ( const QgsCurve *curve = dynamic_cast<const QgsCurve *>( levels[depth].g ) )
357  {
358  QgsPoint p;
359  curve->pointAt( vertex, p, vertexType );
360  }
361 
362  return QgsVertexId( part, ring, vertex, vertexType );
363 }
364 
366 {
367  if ( depth != other.depth )
368  return false;
369  int res = ::memcmp( levels, other.levels, sizeof( Level ) * ( depth + 1 ) );
370  return res == 0;
371 }
372 
373 void QgsAbstractGeometry::vertex_iterator::digDown()
374 {
375  if ( levels[depth].g->hasChildGeometries() && levels[depth].index >= levels[depth].g->childCount() )
376  return; // first check we are not already at the end
377 
378  // while not "final" depth for the geom: go one level down.
379  while ( levels[depth].g->hasChildGeometries() )
380  {
381  ++depth;
382  Q_ASSERT( depth < 3 ); // that's capacity of the levels array
383  levels[depth].index = 0;
384  levels[depth].g = levels[depth - 1].g->childGeometry( levels[depth - 1].index );
385  }
386 }
387 
389 {
390  n = i++;
391  return *n;
392 }
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:39
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
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:158
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()
Return next vertex of the geometry (undefined behavior if hasNext() returns false before calling next...
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:167
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