QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
qgscurve.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscurve.cpp
3  --------------
4  begin : November 2014
5  copyright : (C) 2014 by Marco Hugentobler
6  email : marco at sourcepole dot ch
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include <memory>
19 
20 #include "qgscurve.h"
21 #include "qgslinestring.h"
22 #include "qgspoint.h"
23 #include "qgsmultipoint.h"
24 #include "qgsgeos.h"
25 
26 bool QgsCurve::operator==( const QgsAbstractGeometry &other ) const
27 {
28  const QgsCurve *otherCurve = qgsgeometry_cast< const QgsCurve * >( &other );
29  if ( !otherCurve )
30  return false;
31 
32  return equals( *otherCurve );
33 }
34 
35 bool QgsCurve::operator!=( const QgsAbstractGeometry &other ) const
36 {
37  return !operator==( other );
38 }
39 
40 bool QgsCurve::isClosed() const
41 {
42  if ( numPoints() == 0 )
43  return false;
44 
45  //don't consider M-coordinates when testing closedness
46  QgsPoint start = startPoint();
47  QgsPoint end = endPoint();
48 
49  bool closed = qgsDoubleNear( start.x(), end.x() ) &&
50  qgsDoubleNear( start.y(), end.y() );
51  if ( is3D() && closed )
52  closed &= qgsDoubleNear( start.z(), end.z() ) || ( std::isnan( start.z() ) && std::isnan( end.z() ) );
53  return closed;
54 }
55 
56 bool QgsCurve::isRing() const
57 {
58  return ( isClosed() && numPoints() >= 4 );
59 }
60 
61 QPainterPath QgsCurve::asQPainterPath() const
62 {
63  QPainterPath p;
64  addToPainterPath( p );
65  return p;
66 }
67 
69 {
70  QgsCoordinateSequence sequence;
71  sequence.append( QgsRingSequence() );
72  sequence.back().append( QgsPointSequence() );
73  points( sequence.back().back() );
74 
75  return sequence;
76 }
77 
78 bool QgsCurve::nextVertex( QgsVertexId &id, QgsPoint &vertex ) const
79 {
80  if ( id.vertex < 0 )
81  {
82  id.vertex = 0;
83  if ( id.part < 0 )
84  {
85  id.part = 0;
86  }
87  if ( id.ring < 0 )
88  {
89  id.ring = 0;
90  }
91  }
92  else
93  {
94  if ( id.vertex + 1 >= numPoints() )
95  {
96  return false;
97  }
98  ++id.vertex;
99  }
100  return pointAt( id.vertex, vertex, id.type );
101 }
102 
103 void QgsCurve::adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex ) const
104 {
105  int n = numPoints();
106  if ( vertex.vertex < 0 || vertex.vertex >= n )
107  {
108  previousVertex = QgsVertexId();
110  return;
111  }
112 
113  if ( vertex.vertex == 0 )
114  {
115  previousVertex = QgsVertexId();
116  }
117  else
118  {
119  previousVertex = QgsVertexId( vertex.part, vertex.ring, vertex.vertex - 1 );
120  }
121  if ( vertex.vertex == n - 1 )
122  {
124  }
125  else
126  {
127  nextVertex = QgsVertexId( vertex.part, vertex.ring, vertex.vertex + 1 );
128  }
129 }
130 
132 {
133  if ( id.part != 0 || id.ring != 0 )
134  return -1;
135  if ( id.vertex < 0 || id.vertex >= numPoints() )
136  return -1;
137  return id.vertex;
138 }
139 
141 {
142  if ( isEmpty() )
143  return nullptr;
144 
145  if ( isClosed() )
146  return nullptr;
147 
148  QgsMultiPoint *multiPoint = new QgsMultiPoint();
149  multiPoint->reserve( 2 );
150  multiPoint->addGeometry( new QgsPoint( startPoint() ) );
151  multiPoint->addGeometry( new QgsPoint( endPoint() ) );
152  return multiPoint;
153 }
154 
155 QString QgsCurve::asKml( int precision ) const
156 {
157  std::unique_ptr<QgsLineString> lineString( curveToLine() );
158  if ( !lineString )
159  {
160  return QString();
161  }
162  QString kml = lineString->asKml( precision );
163  return kml;
164 }
165 
166 QgsCurve *QgsCurve::segmentize( double tolerance, SegmentationToleranceType toleranceType ) const
167 {
168  return curveToLine( tolerance, toleranceType );
169 }
170 
171 int QgsCurve::vertexCount( int part, int ring ) const
172 {
173  Q_UNUSED( part )
174  Q_UNUSED( ring )
175  return numPoints();
176 }
177 
178 int QgsCurve::ringCount( int part ) const
179 {
180  Q_UNUSED( part )
181  return numPoints() > 0 ? 1 : 0;
182 }
183 
185 {
186  return numPoints() > 0 ? 1 : 0;
187 }
188 
190 {
191  QgsPoint v;
193  pointAt( id.vertex, v, type );
194  return v;
195 }
196 
198 {
199  return clone();
200 }
201 
203 {
204  if ( mBoundingBox.isNull() )
205  {
206  mBoundingBox = calculateBoundingBox();
207  }
208  return mBoundingBox;
209 }
210 
211 bool QgsCurve::isValid( QString &error, int flags ) const
212 {
213  if ( flags == 0 && mHasCachedValidity )
214  {
215  // use cached validity results
216  error = mValidityFailureReason;
217  return error.isEmpty();
218  }
219 
220  QgsGeos geos( this );
221  bool res = geos.isValid( &error, flags & QgsGeometry::FlagAllowSelfTouchingHoles, nullptr );
222  if ( flags == 0 )
223  {
224  mValidityFailureReason = !res ? error : QString();
225  mHasCachedValidity = true;
226  }
227  return res;
228 }
229 
230 QPolygonF QgsCurve::asQPolygonF() const
231 {
232  std::unique_ptr< QgsLineString > segmentized( curveToLine() );
233  return segmentized->asQPolygonF();
234 }
235 
237 {
238  return startPoint().distance( endPoint() );
239 }
240 
241 double QgsCurve::sinuosity() const
242 {
243  double d = straightDistance2d();
244  if ( qgsDoubleNear( d, 0.0 ) )
245  return std::numeric_limits<double>::quiet_NaN();
246 
247  return length() / d;
248 }
249 
251 {
252  double a = 0;
253  sumUpArea( a );
254  return a < 0 ? Clockwise : CounterClockwise;
255 }
256 
258 {
259  mBoundingBox = QgsRectangle();
260  mHasCachedValidity = false;
261  mValidityFailureReason.clear();
263 }
264 
266 {
267  return numPoints();
268 }
269 
270 QgsPoint QgsCurve::childPoint( int index ) const
271 {
272  QgsPoint point;
274  bool res = pointAt( index, point, type );
275  Q_ASSERT( res );
276  Q_UNUSED( res )
277  return point;
278 }
279 
280 bool QgsCurve::snapToGridPrivate( double hSpacing, double vSpacing, double dSpacing, double mSpacing,
281  const QVector<double> &srcX, const QVector<double> &srcY, const QVector<double> &srcZ, const QVector<double> &srcM,
282  QVector<double> &outX, QVector<double> &outY, QVector<double> &outZ, QVector<double> &outM ) const
283 {
284  int length = numPoints();
285 
286  if ( length <= 0 )
287  return false;
288 
289  bool hasZ = is3D();
290  bool hasM = isMeasure();
291 
292  // helper functions
293  auto roundVertex = [hSpacing, vSpacing, dSpacing, mSpacing, hasZ, hasM, &srcX, &srcY, &srcZ, &srcM]( QgsPoint & out, int i )
294  {
295  if ( hSpacing > 0 )
296  out.setX( std::round( srcX.at( i ) / hSpacing ) * hSpacing );
297  else
298  out.setX( srcX.at( i ) );
299 
300  if ( vSpacing > 0 )
301  out.setY( std::round( srcY.at( i ) / vSpacing ) * vSpacing );
302  else
303  out.setY( srcY.at( i ) );
304 
305  if ( hasZ )
306  {
307  if ( dSpacing > 0 )
308  out.setZ( std::round( srcZ.at( i ) / dSpacing ) * dSpacing );
309  else
310  out.setZ( srcZ.at( i ) );
311  }
312 
313  if ( hasM )
314  {
315  if ( mSpacing > 0 )
316  out.setM( std::round( srcM.at( i ) / mSpacing ) * mSpacing );
317  else
318  out.setM( srcM.at( i ) );
319  }
320  };
321 
322 
323  auto append = [hasZ, hasM, &outX, &outY, &outM, &outZ]( QgsPoint const & point )
324  {
325  outX.append( point.x() );
326 
327  outY.append( point.y() );
328 
329  if ( hasZ )
330  outZ.append( point.z() );
331 
332  if ( hasM )
333  outM.append( point.m() );
334  };
335 
336  auto isPointEqual = [dSpacing, mSpacing, hasZ, hasM]( const QgsPoint & a, const QgsPoint & b )
337  {
338  return ( a.x() == b.x() )
339  && ( a.y() == b.y() )
340  && ( !hasZ || dSpacing <= 0 || a.z() == b.z() )
341  && ( !hasM || mSpacing <= 0 || a.m() == b.m() );
342  };
343 
344  // temporary values
345  QgsWkbTypes::Type pointType = QgsWkbTypes::zmType( QgsWkbTypes::Point, hasZ, hasM );
346  QgsPoint last( pointType );
347  QgsPoint current( pointType );
348 
349  // Actual code (what does all the work)
350  roundVertex( last, 0 );
351  append( last );
352 
353  for ( int i = 1; i < length; ++i )
354  {
355  roundVertex( current, i );
356  if ( !isPointEqual( current, last ) )
357  {
358  append( current );
359  last = current;
360  }
361  }
362 
363  // if it's not closed, with 2 points you get a correct line
364  // if it is, you need at least 4 (3 + the vertex that closes)
365  if ( outX.length() < 2 || ( isClosed() && outX.length() < 4 ) )
366  return false;
367 
368  return true;
369 }
Abstract base class for all geometries.
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
virtual QgsRectangle calculateBoundingBox() const
Default calculator for the minimal bounding box for the geometry.
virtual void clearCache() const
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
virtual double length() const
Returns the planar, 2-dimensional length of the geometry.
virtual bool isEmpty() const
Returns true if the geometry is empty.
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
Abstract base class for curved geometry type.
Definition: qgscurve.h:36
virtual bool equals(const QgsCurve &other) const =0
Checks whether this curve exactly equals another curve.
QgsCoordinateSequence coordinateSequence() const override
Retrieves the sequence of geometries, rings and nodes.
Definition: qgscurve.cpp:68
QgsRectangle boundingBox() const override
Returns the minimal bounding box for the geometry.
Definition: qgscurve.cpp:202
virtual int numPoints() const =0
Returns the number of points in the curve.
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
Definition: qgscurve.cpp:257
double sinuosity() const
Returns the curve sinuosity, which is the ratio of the curve length() to curve straightDistance2d().
Definition: qgscurve.cpp:241
QPainterPath asQPainterPath() const override
Returns the geometry represented as a QPainterPath.
Definition: qgscurve.cpp:61
QgsPoint childPoint(int index) const override
Returns point at index (for geometries without child geometries - i.e.
Definition: qgscurve.cpp:270
int vertexNumberFromVertexId(QgsVertexId id) const override
Returns the vertex number corresponding to a vertex id.
Definition: qgscurve.cpp:131
int partCount() const override
Returns count of parts contained in the geometry.
Definition: qgscurve.cpp:184
QgsCurve * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
Definition: qgscurve.cpp:166
virtual bool isClosed() const SIP_HOLDGIL
Returns true if the curve is closed.
Definition: qgscurve.cpp:40
int childCount() const override
Returns number of child geometries (for geometries with child geometries) or child points (for geomet...
Definition: qgscurve.cpp:265
virtual bool isRing() const SIP_HOLDGIL
Returns true if the curve is a ring.
Definition: qgscurve.cpp:56
bool snapToGridPrivate(double hSpacing, double vSpacing, double dSpacing, double mSpacing, const QVector< double > &srcX, const QVector< double > &srcY, const QVector< double > &srcZ, const QVector< double > &srcM, QVector< double > &outX, QVector< double > &outY, QVector< double > &outZ, QVector< double > &outM) const
Helper function for QgsCurve subclasses to snap to grids.
Definition: qgscurve.cpp:280
virtual QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const =0
Returns a new line string geometry corresponding to a segmentized approximation of the curve.
Orientation orientation() const
Returns the curve's orientation, e.g.
Definition: qgscurve.cpp:250
bool isValid(QString &error, int flags=0) const override
Checks validity of the geometry, and returns true if the geometry is valid.
Definition: qgscurve.cpp:211
int vertexCount(int part=0, int ring=0) const override
Returns the number of vertices of which this geometry is built.
Definition: qgscurve.cpp:171
QgsPoint vertexAt(QgsVertexId id) const override
Returns the point corresponding to a specified vertex id.
Definition: qgscurve.cpp:189
QgsAbstractGeometry * boundary() const override
Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the...
Definition: qgscurve.cpp:140
virtual QPolygonF asQPolygonF() const
Returns a QPolygonF representing the points.
Definition: qgscurve.cpp:230
void adjacentVertices(QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex) const override
Returns the vertices adjacent to a specified vertex within a geometry.
Definition: qgscurve.cpp:103
virtual void addToPainterPath(QPainterPath &path) const =0
Adds a curve to a painter path.
QgsCurve * toCurveType() const override
Returns the geometry converted to the more generic curve type.
Definition: qgscurve.cpp:197
virtual void sumUpArea(double &sum) const =0
Sums up the area of the curve by iterating over the vertices (shoelace formula).
bool operator==(const QgsAbstractGeometry &other) const override
Definition: qgscurve.cpp:26
QString asKml(int precision=17) const override
Returns a KML representation of the geometry.
Definition: qgscurve.cpp:155
QgsCurve * clone() const override=0
Clones the geometry by performing a deep copy.
Orientation
Curve orientation.
Definition: qgscurve.h:239
@ Clockwise
Clockwise orientation.
Definition: qgscurve.h:240
@ CounterClockwise
Counter-clockwise orientation.
Definition: qgscurve.h:241
int ringCount(int part=0) const override
Returns the number of rings of which this geometry is built.
Definition: qgscurve.cpp:178
virtual QgsPoint startPoint() const =0
Returns the starting point of the curve.
bool operator!=(const QgsAbstractGeometry &other) const override
Definition: qgscurve.cpp:35
double straightDistance2d() const
Returns the straight distance of the curve, i.e.
Definition: qgscurve.cpp:236
bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const override
Returns next vertex id and coordinates.
Definition: qgscurve.cpp:78
virtual bool pointAt(int node, QgsPoint &point, QgsVertexId::VertexType &type) const =0
Returns the point and vertex id of a point within the curve.
virtual QgsPoint endPoint() const =0
Returns the end point of the curve.
virtual void points(QgsPointSequence &pt) const =0
Returns a list of points within the curve.
void reserve(int size) SIP_HOLDGIL
Attempts to allocate memory for at least size geometries.
@ FlagAllowSelfTouchingHoles
Indicates that self-touching holes are permitted. OGC validity states that self-touching holes are NO...
Definition: qgsgeometry.h:369
Does vector analysis using the geos library and handles import, export, exception handling*.
Definition: qgsgeos.h:104
Multi point geometry collection.
Definition: qgsmultipoint.h:30
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:38
double distance(double x, double y) const SIP_HOLDGIL
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
Definition: qgspoint.h:332
Q_GADGET double x
Definition: qgspoint.h:41
double z
Definition: qgspoint.h:43
double y
Definition: qgspoint.h:42
A rectangle specified with double values.
Definition: qgsrectangle.h:42
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:447
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
static Type zmType(Type type, bool hasZ, bool hasM) SIP_HOLDGIL
Returns the modified input geometry type according to hasZ / hasM.
Definition: qgswkbtypes.h:801
Contains geos related utilities and functions.
Definition: qgsgeos.h:42
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:316
QVector< QgsRingSequence > QgsCoordinateSequence
QVector< QgsPointSequence > QgsRingSequence
QVector< QgsPoint > QgsPointSequence
int precision
Utility class for identifying a unique vertex within a geometry.
int vertex
Vertex number.
int part
Part number.
int ring
Ring number.
VertexType
Type of vertex.