QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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
27bool 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
36bool 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}
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
65bool QgsCurve::isRing() const
66{
67 return ( isClosed() && numPoints() >= 4 );
68}
69
70QPainterPath QgsCurve::asQPainterPath() const
71{
72 QPainterPath 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
87bool 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
112void 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
164QString 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
175QgsCurve *QgsCurve::segmentize( double tolerance, SegmentationToleranceType toleranceType ) const
176{
177 return curveToLine( tolerance, toleranceType );
178}
179
180int QgsCurve::vertexCount( int part, int ring ) const
181{
182 Q_UNUSED( part )
183 Q_UNUSED( ring )
184 return numPoints();
185}
186
187int 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
247bool 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
266QPolygonF 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
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();
300}
301
303{
304 return numPoints();
305}
306
308{
309 QgsPoint point;
310 Qgis::VertexType type;
311 const bool res = pointAt( index, point, type );
312 Q_ASSERT( res );
313 Q_UNUSED( res )
314 return point;
315}
316
317bool QgsCurve::snapToGridPrivate( double hSpacing, double vSpacing, double dSpacing, double mSpacing,
318 const QVector<double> &srcX, const QVector<double> &srcY, const QVector<double> &srcZ, const QVector<double> &srcM,
319 QVector<double> &outX, QVector<double> &outY, QVector<double> &outZ, QVector<double> &outM ) const
320{
321 const int length = numPoints();
322
323 if ( length <= 0 )
324 return false;
325
326 const bool hasZ = is3D();
327 const bool hasM = isMeasure();
328
329 // helper functions
330 auto roundVertex = [hSpacing, vSpacing, dSpacing, mSpacing, hasZ, hasM, &srcX, &srcY, &srcZ, &srcM]( QgsPoint & out, int i )
331 {
332 if ( hSpacing > 0 )
333 out.setX( std::round( srcX.at( i ) / hSpacing ) * hSpacing );
334 else
335 out.setX( srcX.at( i ) );
336
337 if ( vSpacing > 0 )
338 out.setY( std::round( srcY.at( i ) / vSpacing ) * vSpacing );
339 else
340 out.setY( srcY.at( i ) );
341
342 if ( hasZ )
343 {
344 if ( dSpacing > 0 )
345 out.setZ( std::round( srcZ.at( i ) / dSpacing ) * dSpacing );
346 else
347 out.setZ( srcZ.at( i ) );
348 }
349
350 if ( hasM )
351 {
352 if ( mSpacing > 0 )
353 out.setM( std::round( srcM.at( i ) / mSpacing ) * mSpacing );
354 else
355 out.setM( srcM.at( i ) );
356 }
357 };
358
359
360 auto append = [hasZ, hasM, &outX, &outY, &outM, &outZ]( QgsPoint const & point )
361 {
362 outX.append( point.x() );
363
364 outY.append( point.y() );
365
366 if ( hasZ )
367 outZ.append( point.z() );
368
369 if ( hasM )
370 outM.append( point.m() );
371 };
372
373 auto isPointEqual = [dSpacing, mSpacing, hasZ, hasM]( const QgsPoint & a, const QgsPoint & b )
374 {
375 return ( a.x() == b.x() )
376 && ( a.y() == b.y() )
377 && ( !hasZ || dSpacing <= 0 || a.z() == b.z() )
378 && ( !hasM || mSpacing <= 0 || a.m() == b.m() );
379 };
380
381 // temporary values
382 const QgsWkbTypes::Type pointType = QgsWkbTypes::zmType( QgsWkbTypes::Point, hasZ, hasM );
383 QgsPoint last( pointType );
384 QgsPoint current( pointType );
385
386 // Actual code (what does all the work)
387 roundVertex( last, 0 );
388 append( last );
389
390 for ( int i = 1; i < length; ++i )
391 {
392 roundVertex( current, i );
393 if ( !isPointEqual( current, last ) )
394 {
395 append( current );
396 last = current;
397 }
398 }
399
400 // if it's not closed, with 2 points you get a correct line
401 // if it is, you need at least 4 (3 + the vertex that closes)
402 if ( outX.length() < 2 || ( isClosed() && outX.length() < 4 ) )
403 return false;
404
405 return true;
406}
AngularDirection
Angular directions.
Definition: qgis.h:1805
@ CounterClockwise
Counter-clockwise direction.
@ Clockwise
Clockwise direction.
VertexType
Types of vertex.
Definition: qgis.h:1518
Abstract base class for all geometries.
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
vertex_iterator vertices_end() const
Returns STL-style iterator pointing to the imaginary vertex after the last vertex of the geometry.
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.
vertex_iterator vertices_begin() const
Returns STL-style iterator pointing to the first vertex of the geometry.
virtual int compareTo(const QgsAbstractGeometry *other) const
Comparator for sorting of geometry.
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.
Qgis::AngularDirection orientation() const
Returns the curve's orientation, e.g.
Definition: qgscurve.cpp:286
QgsCoordinateSequence coordinateSequence() const override
Retrieves the sequence of geometries, rings and nodes.
Definition: qgscurve.cpp:77
QgsRectangle boundingBox() const override
Returns the minimal bounding box for the geometry.
Definition: qgscurve.cpp:238
void normalize() final SIP_HOLDGIL
Reorganizes the geometry into a normalized form (or "canonical" form).
Definition: qgscurve.cpp:211
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:293
double sinuosity() const
Returns the curve sinuosity, which is the ratio of the curve length() to curve straightDistance2d().
Definition: qgscurve.cpp:277
bool mHasCachedSummedUpArea
Definition: qgscurve.h:344
QPainterPath asQPainterPath() const override
Returns the geometry represented as a QPainterPath.
Definition: qgscurve.cpp:70
QgsPoint childPoint(int index) const override
Returns point at index (for geometries without child geometries - i.e.
Definition: qgscurve.cpp:307
int vertexNumberFromVertexId(QgsVertexId id) const override
Returns the vertex number corresponding to a vertex id.
Definition: qgscurve.cpp:140
virtual void scroll(int firstVertexIndex)=0
Scrolls the curve vertices so that they start with the vertex at the given index.
int partCount() const override
Returns count of parts contained in the geometry.
Definition: qgscurve.cpp:193
QgsCurve * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
Definition: qgscurve.cpp:175
virtual bool pointAt(int node, QgsPoint &point, Qgis::VertexType &type) const =0
Returns the point and vertex id of a point within the curve.
virtual bool isClosed() const SIP_HOLDGIL
Returns true if the curve is closed.
Definition: qgscurve.cpp:53
int childCount() const override
Returns number of child geometries (for geometries with child geometries) or child points (for geomet...
Definition: qgscurve.cpp:302
virtual bool isRing() const SIP_HOLDGIL
Returns true if the curve is a ring.
Definition: qgscurve.cpp:65
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:317
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
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
QgsPoint vertexAt(QgsVertexId id) const override
Returns the point corresponding to a specified vertex id.
Definition: qgscurve.cpp:198
QgsAbstractGeometry * boundary() const override
Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the...
Definition: qgscurve.cpp:149
virtual QPolygonF asQPolygonF() const
Returns a QPolygonF representing the points.
Definition: qgscurve.cpp:266
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
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:206
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:27
virtual bool isClosed2D() const SIP_HOLDGIL
Returns true if the curve is closed.
Definition: qgscurve.cpp:41
QString asKml(int precision=17) const override
Returns a KML representation of the geometry.
Definition: qgscurve.cpp:164
QgsCurve * clone() const override=0
Clones the geometry by performing a deep copy.
int ringCount(int part=0) const override
Returns the number of rings of which this geometry is built.
Definition: qgscurve.cpp:187
virtual QgsPoint startPoint() const =0
Returns the starting point of the curve.
bool operator!=(const QgsAbstractGeometry &other) const override
Definition: qgscurve.cpp:36
double straightDistance2d() const
Returns the straight distance of the curve, i.e.
Definition: qgscurve.cpp:272
bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const override
Returns next vertex id and coordinates.
Definition: qgscurve.cpp:87
QgsRectangle mBoundingBox
Cached bounding box.
Definition: qgscurve.h:342
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.
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.
void reserve(int size) SIP_HOLDGIL
Attempts to allocate memory for at least size geometries.
Does vector analysis using the geos library and handles import, export, exception handling*.
Definition: qgsgeos.h:99
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:49
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:343
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
Definition: qgspoint.cpp:767
Q_GADGET double x
Definition: qgspoint.h:52
double z
Definition: qgspoint.h:54
double y
Definition: qgspoint.h:53
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:479
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:831
Contains geos related utilities and functions.
Definition: qgsgeos.h:37
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2527
QVector< QgsRingSequence > QgsCoordinateSequence
QVector< QgsPointSequence > QgsRingSequence
QVector< QgsPoint > QgsPointSequence
int precision
Utility class for identifying a unique vertex within a geometry.
Definition: qgsvertexid.h:31
int vertex
Vertex number.
Definition: qgsvertexid.h:95
int part
Part number.
Definition: qgsvertexid.h:89
int ring
Ring number.
Definition: qgsvertexid.h:92