QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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 }
QgsCurve::isValid
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
QgsCurve
Abstract base class for curved geometry type.
Definition: qgscurve.h:36
QgsCurve::nextVertex
bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const override
Returns next vertex id and coordinates.
Definition: qgscurve.cpp:78
QgsVertexId::part
int part
Part number.
Definition: qgsabstractgeometry.h:1131
QgsCurve::pointAt
virtual bool pointAt(int node, QgsPoint &point, QgsVertexId::VertexType &type) const =0
Returns the point and vertex id of a point within the curve.
QgsCoordinateSequence
QVector< QgsRingSequence > QgsCoordinateSequence
Definition: qgsabstractgeometry.h:51
QgsVertexId::vertex
int vertex
Vertex number.
Definition: qgsabstractgeometry.h:1137
QgsCurve::isRing
virtual bool isRing() const SIP_HOLDGIL
Returns true if the curve is a ring.
Definition: qgscurve.cpp:56
QgsAbstractGeometry::clearCache
virtual void clearCache() const
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
Definition: qgsabstractgeometry.cpp:112
QgsWkbTypes::Point
@ Point
Definition: qgswkbtypes.h:72
qgslinestring.h
QgsCurve::startPoint
virtual QgsPoint startPoint() const =0
Returns the starting point of the curve.
QgsPoint::distance
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
QgsCurve::asQPainterPath
QPainterPath asQPainterPath() const override
Returns the geometry represented as a QPainterPath.
Definition: qgscurve.cpp:61
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:38
QgsCurve::operator==
bool operator==(const QgsAbstractGeometry &other) const override
Definition: qgscurve.cpp:26
QgsMultiPoint::addGeometry
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
Definition: qgsmultipoint.cpp:148
geos
Contains geos related utilities and functions.
Definition: qgsgeos.h:42
qgsmultipoint.h
QgsCurve::childCount
int childCount() const override
Returns number of child geometries (for geometries with child geometries) or child points (for geomet...
Definition: qgscurve.cpp:265
QgsPoint::z
double z
Definition: qgspoint.h:43
QgsAbstractGeometry::length
virtual double length() const
Returns the planar, 2-dimensional length of the geometry.
Definition: qgsabstractgeometry.cpp:132
QgsWkbTypes::Type
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
QgsAbstractGeometry::SegmentationToleranceType
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
Definition: qgsabstractgeometry.h:115
qgspoint.h
QgsCurve::sumUpArea
virtual void sumUpArea(double &sum) const =0
Sums up the area of the curve by iterating over the vertices (shoelace formula).
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QgsCurve::partCount
int partCount() const override
Returns count of parts contained in the geometry.
Definition: qgscurve.cpp:184
QgsCurve::clearCache
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
Definition: qgscurve.cpp:257
QgsAbstractGeometry::isMeasure
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
Definition: qgsabstractgeometry.h:215
QgsCurve::asKml
QString asKml(int precision=17) const override
Returns a KML representation of the geometry.
Definition: qgscurve.cpp:155
QgsCurve::adjacentVertices
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
QgsPoint::y
double y
Definition: qgspoint.h:42
precision
int precision
Definition: qgswfsgetfeature.cpp:49
QgsCurve::childPoint
QgsPoint childPoint(int index) const override
Returns point at index (for geometries without child geometries - i.e.
Definition: qgscurve.cpp:270
QgsCurve::addToPainterPath
virtual void addToPainterPath(QPainterPath &path) const =0
Adds a curve to a painter path.
QgsCurve::endPoint
virtual QgsPoint endPoint() const =0
Returns the end point of the curve.
QgsCurve::vertexNumberFromVertexId
int vertexNumberFromVertexId(QgsVertexId id) const override
Returns the vertex number corresponding to a vertex id.
Definition: qgscurve.cpp:131
QgsCurve::asQPolygonF
virtual QPolygonF asQPolygonF() const
Returns a QPolygonF representing the points.
Definition: qgscurve.cpp:230
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:315
QgsGeometry::FlagAllowSelfTouchingHoles
@ FlagAllowSelfTouchingHoles
Indicates that self-touching holes are permitted. OGC validity states that self-touching holes are NO...
Definition: qgsgeometry.h:369
QgsCurve::Clockwise
@ Clockwise
Clockwise orientation.
Definition: qgscurve.h:240
QgsCurve::equals
virtual bool equals(const QgsCurve &other) const =0
Checks whether this curve exactly equals another curve.
QgsGeos
Does vector analysis using the geos library and handles import, export, exception handling*.
Definition: qgsgeos.h:104
QgsCurve::CounterClockwise
@ CounterClockwise
Counter-clockwise orientation.
Definition: qgscurve.h:241
QgsPoint::x
Q_GADGET double x
Definition: qgspoint.h:41
QgsWkbTypes::zmType
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
QgsCurve::vertexAt
QgsPoint vertexAt(QgsVertexId id) const override
Returns the point corresponding to a specified vertex id.
Definition: qgscurve.cpp:189
QgsRingSequence
QVector< QgsPointSequence > QgsRingSequence
Definition: qgsabstractgeometry.h:50
QgsCurve::snapToGridPrivate
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
QgsAbstractGeometry::isEmpty
virtual bool isEmpty() const
Returns true if the geometry is empty.
Definition: qgsabstractgeometry.cpp:298
QgsCurve::coordinateSequence
QgsCoordinateSequence coordinateSequence() const override
Retrieves the sequence of geometries, rings and nodes.
Definition: qgscurve.cpp:68
QgsMultiPoint
Multi point geometry collection.
Definition: qgsmultipoint.h:30
QgsAbstractGeometry
Abstract base class for all geometries.
Definition: qgsabstractgeometry.h:74
QgsAbstractGeometry::is3D
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
Definition: qgsabstractgeometry.h:206
QgsCurve::clone
QgsCurve * clone() const override=0
Clones the geometry by performing a deep copy.
QgsCurve::vertexCount
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
QgsPointSequence
QVector< QgsPoint > QgsPointSequence
Definition: qgsabstractgeometry.h:46
qgscurve.h
QgsCurve::ringCount
int ringCount(int part=0) const override
Returns the number of rings of which this geometry is built.
Definition: qgscurve.cpp:178
QgsCurve::toCurveType
QgsCurve * toCurveType() const override
Returns the geometry converted to the more generic curve type.
Definition: qgscurve.cpp:197
QgsCurve::boundingBox
QgsRectangle boundingBox() const override
Returns the minimal bounding box for the geometry.
Definition: qgscurve.cpp:202
QgsVertexId
Utility class for identifying a unique vertex within a geometry.
Definition: qgsabstractgeometry.h:1059
QgsCurve::boundary
QgsAbstractGeometry * boundary() const override
Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the...
Definition: qgscurve.cpp:140
QgsVertexId::ring
int ring
Ring number.
Definition: qgsabstractgeometry.h:1134
QgsVertexId::VertexType
VertexType
Type of vertex.
Definition: qgsabstractgeometry.h:1065
QgsCurve::straightDistance2d
double straightDistance2d() const
Returns the straight distance of the curve, i.e.
Definition: qgscurve.cpp:236
QgsCurve::points
virtual void points(QgsPointSequence &pt) const =0
Returns a list of points within the curve.
QgsCurve::numPoints
virtual int numPoints() const =0
Returns the number of points in the curve.
QgsCurve::segmentize
QgsCurve * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
Definition: qgscurve.cpp:166
QgsCurve::isClosed
virtual bool isClosed() const SIP_HOLDGIL
Returns true if the curve is closed.
Definition: qgscurve.cpp:40
QgsCurve::orientation
Orientation orientation() const
Returns the curve's orientation, e.g.
Definition: qgscurve.cpp:250
QgsGeometryCollection::reserve
void reserve(int size) SIP_HOLDGIL
Attempts to allocate memory for at least size geometries.
Definition: qgsgeometrycollection.cpp:202
QgsCurve::Orientation
Orientation
Curve orientation.
Definition: qgscurve.h:239
QgsCurve::sinuosity
double sinuosity() const
Returns the curve sinuosity, which is the ratio of the curve length() to curve straightDistance2d().
Definition: qgscurve.cpp:241
QgsCurve::curveToLine
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.
QgsCurve::operator!=
bool operator!=(const QgsAbstractGeometry &other) const override
Definition: qgscurve.cpp:35
QgsRectangle::isNull
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:447
qgsgeos.h
QgsAbstractGeometry::calculateBoundingBox
virtual QgsRectangle calculateBoundingBox() const
Default calculator for the minimal bounding box for the geometry.
Definition: qgsabstractgeometry.cpp:85