QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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 #include "qgsvertexid.h"
26 
27 bool QgsCurve::operator==( const QgsAbstractGeometry &other ) const
28 {
29  const QgsCurve *otherCurve = qgsgeometry_cast< const QgsCurve * >( &other );
30  if ( !otherCurve )
31  return false;
32 
33  return equals( *otherCurve );
34 }
35 
36 bool QgsCurve::operator!=( const QgsAbstractGeometry &other ) const
37 {
38  return !operator==( other );
39 }
40 
42 {
43  if ( numPoints() == 0 )
44  return false;
45 
46  //don't consider M-coordinates when testing closedness
47  const QgsPoint start = startPoint();
48  const QgsPoint end = endPoint();
49 
50  return qgsDoubleNear( start.x(), end.x() ) &&
51  qgsDoubleNear( start.y(), end.y() );
52 }
53 bool QgsCurve::isClosed() const
54 {
55  bool closed = isClosed2D();
56  if ( is3D() && closed )
57  {
58  const QgsPoint start = startPoint();
59  const QgsPoint end = endPoint();
60  closed &= qgsDoubleNear( start.z(), end.z() ) || ( std::isnan( start.z() ) && std::isnan( end.z() ) );
61  }
62  return closed;
63 }
64 
65 bool QgsCurve::isRing() const
66 {
67  return ( isClosed() && numPoints() >= 4 );
68 }
69 
70 QPainterPath QgsCurve::asQPainterPath() const
71 {
72  QPainterPath p;
73  addToPainterPath( p );
74  return p;
75 }
76 
78 {
79  QgsCoordinateSequence sequence;
80  sequence.append( QgsRingSequence() );
81  sequence.back().append( QgsPointSequence() );
82  points( sequence.back().back() );
83 
84  return sequence;
85 }
86 
87 bool QgsCurve::nextVertex( QgsVertexId &id, QgsPoint &vertex ) const
88 {
89  if ( id.vertex < 0 )
90  {
91  id.vertex = 0;
92  if ( id.part < 0 )
93  {
94  id.part = 0;
95  }
96  if ( id.ring < 0 )
97  {
98  id.ring = 0;
99  }
100  }
101  else
102  {
103  if ( id.vertex + 1 >= numPoints() )
104  {
105  return false;
106  }
107  ++id.vertex;
108  }
109  return pointAt( id.vertex, vertex, id.type );
110 }
111 
112 void QgsCurve::adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex ) const
113 {
114  const int n = numPoints();
115  if ( vertex.vertex < 0 || vertex.vertex >= n )
116  {
117  previousVertex = QgsVertexId();
119  return;
120  }
121 
122  if ( vertex.vertex == 0 )
123  {
124  previousVertex = QgsVertexId();
125  }
126  else
127  {
128  previousVertex = QgsVertexId( vertex.part, vertex.ring, vertex.vertex - 1 );
129  }
130  if ( vertex.vertex == n - 1 )
131  {
133  }
134  else
135  {
136  nextVertex = QgsVertexId( vertex.part, vertex.ring, vertex.vertex + 1 );
137  }
138 }
139 
141 {
142  if ( id.part != 0 || id.ring != 0 )
143  return -1;
144  if ( id.vertex < 0 || id.vertex >= numPoints() )
145  return -1;
146  return id.vertex;
147 }
148 
150 {
151  if ( isEmpty() )
152  return nullptr;
153 
154  if ( isClosed() )
155  return nullptr;
156 
157  QgsMultiPoint *multiPoint = new QgsMultiPoint();
158  multiPoint->reserve( 2 );
159  multiPoint->addGeometry( new QgsPoint( startPoint() ) );
160  multiPoint->addGeometry( new QgsPoint( endPoint() ) );
161  return multiPoint;
162 }
163 
164 QString QgsCurve::asKml( int precision ) const
165 {
166  std::unique_ptr<QgsLineString> lineString( curveToLine() );
167  if ( !lineString )
168  {
169  return QString();
170  }
171  QString kml = lineString->asKml( precision );
172  return kml;
173 }
174 
175 QgsCurve *QgsCurve::segmentize( double tolerance, SegmentationToleranceType toleranceType ) const
176 {
177  return curveToLine( tolerance, toleranceType );
178 }
179 
180 int QgsCurve::vertexCount( int part, int ring ) const
181 {
182  Q_UNUSED( part )
183  Q_UNUSED( ring )
184  return numPoints();
185 }
186 
187 int QgsCurve::ringCount( int part ) const
188 {
189  Q_UNUSED( part )
190  return numPoints() > 0 ? 1 : 0;
191 }
192 
194 {
195  return numPoints() > 0 ? 1 : 0;
196 }
197 
199 {
200  QgsPoint v;
201  Qgis::VertexType type;
202  pointAt( id.vertex, v, type );
203  return v;
204 }
205 
207 {
208  return clone();
209 }
210 
212 {
213  if ( isEmpty() )
214  return;
215 
216  if ( !isClosed() )
217  {
218  return;
219  }
220 
221  int minCoordinateIndex = 0;
222  QgsPoint minCoord;
223  int i = 0;
224  for ( auto it = vertices_begin(); it != vertices_end(); ++it )
225  {
226  const QgsPoint vertex = *it;
227  if ( minCoord.isEmpty() || minCoord.compareTo( &vertex ) > 0 )
228  {
229  minCoord = vertex;
230  minCoordinateIndex = i;
231  }
232  i++;
233  }
234 
235  scroll( minCoordinateIndex );
236 }
237 
239 {
240  if ( mBoundingBox.isNull() )
241  {
243  }
244  return mBoundingBox;
245 }
246 
247 bool QgsCurve::isValid( QString &error, Qgis::GeometryValidityFlags flags ) const
248 {
249  if ( flags == 0 && mHasCachedValidity )
250  {
251  // use cached validity results
252  error = mValidityFailureReason;
253  return error.isEmpty();
254  }
255 
256  const QgsGeos geos( this );
257  const bool res = geos.isValid( &error, flags & Qgis::GeometryValidityFlag::AllowSelfTouchingHoles, nullptr );
258  if ( flags == 0 )
259  {
260  mValidityFailureReason = !res ? error : QString();
261  mHasCachedValidity = true;
262  }
263  return res;
264 }
265 
266 QPolygonF QgsCurve::asQPolygonF() const
267 {
268  std::unique_ptr< QgsLineString > segmentized( curveToLine() );
269  return segmentized->asQPolygonF();
270 }
271 
273 {
274  return startPoint().distance( endPoint() );
275 }
276 
277 double QgsCurve::sinuosity() const
278 {
279  const double d = straightDistance2d();
280  if ( qgsDoubleNear( d, 0.0 ) )
281  return std::numeric_limits<double>::quiet_NaN();
282 
283  return length() / d;
284 }
285 
287 {
288  double a = 0;
289  sumUpArea( a );
291 }
292 
294 {
296  mHasCachedValidity = false;
297  mValidityFailureReason.clear();
299 }
300 
302 {
303  return numPoints();
304 }
305 
306 QgsPoint QgsCurve::childPoint( int index ) const
307 {
308  QgsPoint point;
309  Qgis::VertexType type;
310  const bool res = pointAt( index, point, type );
311  Q_ASSERT( res );
312  Q_UNUSED( res )
313  return point;
314 }
315 
316 bool QgsCurve::snapToGridPrivate( double hSpacing, double vSpacing, double dSpacing, double mSpacing,
317  const QVector<double> &srcX, const QVector<double> &srcY, const QVector<double> &srcZ, const QVector<double> &srcM,
318  QVector<double> &outX, QVector<double> &outY, QVector<double> &outZ, QVector<double> &outM ) const
319 {
320  const int length = numPoints();
321 
322  if ( length <= 0 )
323  return false;
324 
325  const bool hasZ = is3D();
326  const bool hasM = isMeasure();
327 
328  // helper functions
329  auto roundVertex = [hSpacing, vSpacing, dSpacing, mSpacing, hasZ, hasM, &srcX, &srcY, &srcZ, &srcM]( QgsPoint & out, int i )
330  {
331  if ( hSpacing > 0 )
332  out.setX( std::round( srcX.at( i ) / hSpacing ) * hSpacing );
333  else
334  out.setX( srcX.at( i ) );
335 
336  if ( vSpacing > 0 )
337  out.setY( std::round( srcY.at( i ) / vSpacing ) * vSpacing );
338  else
339  out.setY( srcY.at( i ) );
340 
341  if ( hasZ )
342  {
343  if ( dSpacing > 0 )
344  out.setZ( std::round( srcZ.at( i ) / dSpacing ) * dSpacing );
345  else
346  out.setZ( srcZ.at( i ) );
347  }
348 
349  if ( hasM )
350  {
351  if ( mSpacing > 0 )
352  out.setM( std::round( srcM.at( i ) / mSpacing ) * mSpacing );
353  else
354  out.setM( srcM.at( i ) );
355  }
356  };
357 
358 
359  auto append = [hasZ, hasM, &outX, &outY, &outM, &outZ]( QgsPoint const & point )
360  {
361  outX.append( point.x() );
362 
363  outY.append( point.y() );
364 
365  if ( hasZ )
366  outZ.append( point.z() );
367 
368  if ( hasM )
369  outM.append( point.m() );
370  };
371 
372  auto isPointEqual = [dSpacing, mSpacing, hasZ, hasM]( const QgsPoint & a, const QgsPoint & b )
373  {
374  return ( a.x() == b.x() )
375  && ( a.y() == b.y() )
376  && ( !hasZ || dSpacing <= 0 || a.z() == b.z() )
377  && ( !hasM || mSpacing <= 0 || a.m() == b.m() );
378  };
379 
380  // temporary values
381  const QgsWkbTypes::Type pointType = QgsWkbTypes::zmType( QgsWkbTypes::Point, hasZ, hasM );
382  QgsPoint last( pointType );
383  QgsPoint current( pointType );
384 
385  // Actual code (what does all the work)
386  roundVertex( last, 0 );
387  append( last );
388 
389  for ( int i = 1; i < length; ++i )
390  {
391  roundVertex( current, i );
392  if ( !isPointEqual( current, last ) )
393  {
394  append( current );
395  last = current;
396  }
397  }
398 
399  // if it's not closed, with 2 points you get a correct line
400  // if it is, you need at least 4 (3 + the vertex that closes)
401  if ( outX.length() < 2 || ( isClosed() && outX.length() < 4 ) )
402  return false;
403 
404  return true;
405 }
QgsCurve
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
QgsAbstractGeometry::vertices_end
vertex_iterator vertices_end() const
Returns STL-style iterator pointing to the imaginary vertex after the last vertex of the geometry.
Definition: qgsabstractgeometry.h:993
QgsCurve::nextVertex
bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const override
Returns next vertex id and coordinates.
Definition: qgscurve.cpp:87
QgsVertexId::part
int part
Part number.
Definition: qgsvertexid.h:89
QgsCoordinateSequence
QVector< QgsRingSequence > QgsCoordinateSequence
Definition: qgsabstractgeometry.h:57
qgsvertexid.h
QgsVertexId::vertex
int vertex
Vertex number.
Definition: qgsvertexid.h:95
QgsCurve::isRing
virtual bool isRing() const SIP_HOLDGIL
Returns true if the curve is a ring.
Definition: qgscurve.cpp:65
QgsAbstractGeometry::clearCache
virtual void clearCache() const
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
Definition: qgsabstractgeometry.cpp:146
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:360
QgsCurve::scroll
virtual void scroll(int firstVertexIndex)=0
Scrolls the curve vertices so that they start with the vertex at the given index.
QgsCurve::asQPainterPath
QPainterPath asQPainterPath() const override
Returns the geometry represented as a QPainterPath.
Definition: qgscurve.cpp:70
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:48
QgsCurve::operator==
bool operator==(const QgsAbstractGeometry &other) const override
Definition: qgscurve.cpp:27
QgsMultiPoint::addGeometry
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
Definition: qgsmultipoint.cpp:149
geos
Contains geos related utilities and functions.
Definition: qgsgeos.h:41
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:301
QgsPoint::z
double z
Definition: qgspoint.h:71
QgsAbstractGeometry::length
virtual double length() const
Returns the planar, 2-dimensional length of the geometry.
Definition: qgsabstractgeometry.cpp:166
QgsWkbTypes::Type
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:69
QgsCurve::normalize
void normalize() final SIP_HOLDGIL
Reorganizes the geometry into a normalized form (or "canonical" form).
Definition: qgscurve.cpp:211
QgsAbstractGeometry::SegmentationToleranceType
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
Definition: qgsabstractgeometry.h:120
qgspoint.h
QgsAbstractGeometry::compareTo
virtual int compareTo(const QgsAbstractGeometry *other) const
Comparator for sorting of geometry.
Definition: qgsabstractgeometry.cpp:44
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:41
QgsCurve::partCount
int partCount() const override
Returns count of parts contained in the geometry.
Definition: qgscurve.cpp:193
QgsCurve::clearCache
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
Definition: qgscurve.cpp:293
QgsAbstractGeometry::isMeasure
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
Definition: qgsabstractgeometry.h:228
QgsCurve::asKml
QString asKml(int precision=17) const override
Returns a KML representation of the geometry.
Definition: qgscurve.cpp:164
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:112
QgsPoint::y
double y
Definition: qgspoint.h:70
precision
int precision
Definition: qgswfsgetfeature.cpp:103
QgsCurve::orientation
Qgis::AngularDirection orientation() const
Returns the curve's orientation, e.g.
Definition: qgscurve.cpp:286
QgsCurve::childPoint
QgsPoint childPoint(int index) const override
Returns point at index (for geometries without child geometries - i.e.
Definition: qgscurve.cpp:306
QgsCurve::addToPainterPath
virtual void addToPainterPath(QPainterPath &path) const =0
Adds a curve to a painter path.
QgsCurve::pointAt
virtual bool pointAt(int node, QgsPoint &point, Qgis::VertexType &type) const =0
Returns the point and vertex id of a point within the curve.
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:140
QgsCurve::asQPolygonF
virtual QPolygonF asQPolygonF() const
Returns a QPolygonF representing the points.
Definition: qgscurve.cpp:266
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:2265
QgsAbstractGeometry::vertices_begin
vertex_iterator vertices_begin() const
Returns STL-style iterator pointing to the first vertex of the geometry.
Definition: qgsabstractgeometry.h:980
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:103
QgsCurve::isClosed2D
virtual bool isClosed2D() const SIP_HOLDGIL
Returns true if the curve is closed.
Definition: qgscurve.cpp:41
Qgis::AngularDirection::CounterClockwise
@ CounterClockwise
Counter-clockwise direction.
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:831
QgsCurve::vertexAt
QgsPoint vertexAt(QgsVertexId id) const override
Returns the point corresponding to a specified vertex id.
Definition: qgscurve.cpp:198
QgsCurve::isValid
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
Definition: qgscurve.cpp:247
QgsRingSequence
QVector< QgsPointSequence > QgsRingSequence
Definition: qgsabstractgeometry.h:56
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:316
QgsAbstractGeometry::isEmpty
virtual bool isEmpty() const
Returns true if the geometry is empty.
Definition: qgsabstractgeometry.cpp:378
QgsCurve::coordinateSequence
QgsCoordinateSequence coordinateSequence() const override
Retrieves the sequence of geometries, rings and nodes.
Definition: qgscurve.cpp:77
QgsMultiPoint
Multi point geometry collection.
Definition: qgsmultipoint.h:29
QgsAbstractGeometry
Abstract base class for all geometries.
Definition: qgsabstractgeometry.h:79
QgsAbstractGeometry::is3D
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
Definition: qgsabstractgeometry.h:219
QgsCurve::clone
QgsCurve * clone() const override=0
Clones the geometry by performing a deep copy.
Qgis::AngularDirection::Clockwise
@ Clockwise
Clockwise direction.
Qgis::VertexType
VertexType
Types of vertex.
Definition: qgis.h:1356
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:180
QgsPointSequence
QVector< QgsPoint > QgsPointSequence
Definition: qgsabstractgeometry.h:52
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:187
QgsCurve::toCurveType
QgsCurve * toCurveType() const override
Returns the geometry converted to the more generic curve type.
Definition: qgscurve.cpp:206
QgsCurve::boundingBox
QgsRectangle boundingBox() const override
Returns the minimal bounding box for the geometry.
Definition: qgscurve.cpp:238
QgsVertexId
Utility class for identifying a unique vertex within a geometry.
Definition: qgsvertexid.h:30
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:149
QgsVertexId::ring
int ring
Ring number.
Definition: qgsvertexid.h:92
QgsCurve::straightDistance2d
double straightDistance2d() const
Returns the straight distance of the curve, i.e.
Definition: qgscurve.cpp:272
QgsPoint::isEmpty
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
Definition: qgspoint.cpp:767
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::mBoundingBox
QgsRectangle mBoundingBox
Cached bounding box.
Definition: qgscurve.h:342
QgsCurve::segmentize
QgsCurve * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
Definition: qgscurve.cpp:175
QgsCurve::isClosed
virtual bool isClosed() const SIP_HOLDGIL
Returns true if the curve is closed.
Definition: qgscurve.cpp:53
QgsGeometryCollection::reserve
void reserve(int size) SIP_HOLDGIL
Attempts to allocate memory for at least size geometries.
Definition: qgsgeometrycollection.cpp:232
QgsCurve::sinuosity
double sinuosity() const
Returns the curve sinuosity, which is the ratio of the curve length() to curve straightDistance2d().
Definition: qgscurve.cpp:277
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:36
QgsPoint::x
double x
Definition: qgspoint.h:69
QgsRectangle::isNull
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:479
qgsgeos.h
Qgis::AngularDirection
AngularDirection
Angular directions.
Definition: qgis.h:1635
QgsAbstractGeometry::calculateBoundingBox
virtual QgsRectangle calculateBoundingBox() const
Default calculator for the minimal bounding box for the geometry.
Definition: qgsabstractgeometry.cpp:119