QGIS API Documentation 3.99.0-Master (a8882ad4560)
Loading...
Searching...
No Matches
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 "qgscurve.h"
19
20#include <memory>
21
22#include "qgsgeos.h"
23#include "qgslinestring.h"
24#include "qgsmultipoint.h"
25#include "qgspoint.h"
26#include "qgsvertexid.h"
27
28bool QgsCurve::operator==( const QgsAbstractGeometry &other ) const
29{
30 const QgsCurve *otherCurve = qgsgeometry_cast< const QgsCurve * >( &other );
31 if ( !otherCurve )
32 return false;
33
34 return equals( *otherCurve );
35}
36
37bool QgsCurve::operator!=( const QgsAbstractGeometry &other ) const
38{
39 return !operator==( other );
40}
41
43{
44 if ( numPoints() == 0 )
45 return false;
46
47 //don't consider M-coordinates when testing closedness
48 const QgsPoint start = startPoint();
49 const QgsPoint end = endPoint();
50
51 return qgsDoubleNear( start.x(), end.x() ) &&
52 qgsDoubleNear( start.y(), end.y() );
53}
55{
56 bool closed = isClosed2D();
57 if ( is3D() && closed )
58 {
59 const QgsPoint start = startPoint();
60 const QgsPoint end = endPoint();
61 closed &= qgsDoubleNear( start.z(), end.z() ) || ( std::isnan( start.z() ) && std::isnan( end.z() ) );
62 }
63 return closed;
64}
65
66bool QgsCurve::isRing() const
67{
68 return ( isClosed() && numPoints() >= 4 );
69}
70
71QPainterPath QgsCurve::asQPainterPath() const
72{
73 QPainterPath p;
75 return p;
76}
77
79{
80 QgsCoordinateSequence sequence;
81 sequence.append( QgsRingSequence() );
82 sequence.back().append( QgsPointSequence() );
83 points( sequence.back().back() );
84
85 return sequence;
86}
87
88bool QgsCurve::nextVertex( QgsVertexId &id, QgsPoint &vertex ) const
89{
90 if ( id.vertex < 0 )
91 {
92 id.vertex = 0;
93 if ( id.part < 0 )
94 {
95 id.part = 0;
96 }
97 if ( id.ring < 0 )
98 {
99 id.ring = 0;
100 }
101 }
102 else
103 {
104 if ( id.vertex + 1 >= numPoints() )
105 {
106 return false;
107 }
108 ++id.vertex;
109 }
110 return pointAt( id.vertex, vertex, id.type );
111}
112
114{
115 const int n = numPoints();
116 if ( vertex.vertex < 0 || vertex.vertex >= n )
117 {
118 previousVertex = QgsVertexId();
120 return;
121 }
122
123 if ( vertex.vertex == 0 )
124 {
125 previousVertex = QgsVertexId();
126 }
127 else
128 {
129 previousVertex = QgsVertexId( vertex.part, vertex.ring, vertex.vertex - 1 );
130 }
131 if ( vertex.vertex == n - 1 )
132 {
134 }
135 else
136 {
137 nextVertex = QgsVertexId( vertex.part, vertex.ring, vertex.vertex + 1 );
138 }
139}
140
142{
143 if ( id.part != 0 || id.ring != 0 )
144 return -1;
145 if ( id.vertex < 0 || id.vertex >= numPoints() )
146 return -1;
147 return id.vertex;
148}
149
151{
152 if ( isEmpty() )
153 return nullptr;
154
155 if ( isClosed() )
156 return nullptr;
157
158 QgsMultiPoint *multiPoint = new QgsMultiPoint();
159 multiPoint->reserve( 2 );
160 multiPoint->addGeometry( new QgsPoint( startPoint() ) );
161 multiPoint->addGeometry( new QgsPoint( endPoint() ) );
162 return multiPoint;
163}
164
165QString QgsCurve::asKml( int precision ) const
166{
167 std::unique_ptr<QgsLineString> lineString( curveToLine() );
168 if ( !lineString )
169 {
170 return QString();
171 }
172 QString kml = lineString->asKml( precision );
173 return kml;
174}
175
176QgsCurve *QgsCurve::segmentize( double tolerance, SegmentationToleranceType toleranceType ) const
177{
178 return curveToLine( tolerance, toleranceType );
179}
180
181int QgsCurve::vertexCount( int part, int ring ) const
182{
183 Q_UNUSED( part )
184 Q_UNUSED( ring )
185 return numPoints();
186}
187
188int QgsCurve::ringCount( int part ) const
189{
190 Q_UNUSED( part )
191 return numPoints() > 0 ? 1 : 0;
192}
193
195{
196 return numPoints() > 0 ? 1 : 0;
197}
198
200{
201 QgsPoint v;
202 Qgis::VertexType type;
203 pointAt( id.vertex, v, type );
204 return v;
205}
206
208{
209 return clone();
210}
211
213{
214 if ( isEmpty() )
215 return;
216
217 if ( !isClosed() )
218 {
219 return;
220 }
221
222 int minCoordinateIndex = 0;
223 QgsPoint minCoord;
224 int i = 0;
225 for ( auto it = vertices_begin(); it != vertices_end(); ++it )
226 {
227 const QgsPoint vertex = *it;
228 if ( minCoord.isEmpty() || minCoord.compareTo( &vertex ) > 0 )
229 {
230 minCoord = vertex;
231 minCoordinateIndex = i;
232 }
233 i++;
234 }
235
236 scroll( minCoordinateIndex );
237}
238
240{
241 if ( mBoundingBox.isNull() )
242 {
244 }
245 return mBoundingBox;
246}
247
248bool QgsCurve::isValid( QString &error, Qgis::GeometryValidityFlags flags ) const
249{
250 if ( flags == 0 && mHasCachedValidity )
251 {
252 // use cached validity results
253 error = mValidityFailureReason;
254 return error.isEmpty();
255 }
256
257 const QgsGeos geos( this, 0, Qgis::GeosCreationFlags() );
258 const bool res = geos.isValid( &error, flags & Qgis::GeometryValidityFlag::AllowSelfTouchingHoles, nullptr );
259 if ( flags == 0 )
260 {
261 mValidityFailureReason = !res ? error : QString();
262 mHasCachedValidity = true;
263 }
264 return res;
265}
266
267QPolygonF QgsCurve::asQPolygonF() const
268{
269 std::unique_ptr< QgsLineString > segmentized( curveToLine() );
270 return segmentized->asQPolygonF();
271}
272
274{
275 return startPoint().distance( endPoint() );
276}
277
279{
280 const double d = straightDistance2d();
281 if ( qgsDoubleNear( d, 0.0 ) )
282 return std::numeric_limits<double>::quiet_NaN();
283
284 return length() / d;
285}
286
293
295{
297 mHasCachedValidity = false;
298 mValidityFailureReason.clear();
302}
303
305{
306 return numPoints();
307}
308
310{
311 QgsPoint point;
312 Qgis::VertexType type;
313 const bool res = pointAt( index, point, type );
314 Q_ASSERT( res );
315 Q_UNUSED( res )
316 return point;
317}
318
319bool QgsCurve::snapToGridPrivate( double hSpacing, double vSpacing, double dSpacing, double mSpacing,
320 const QVector<double> &srcX, const QVector<double> &srcY, const QVector<double> &srcZ, const QVector<double> &srcM,
321 QVector<double> &outX, QVector<double> &outY, QVector<double> &outZ, QVector<double> &outM, bool removeRedundantPoints ) const
322{
323 const int length = numPoints();
324 if ( length < 2 )
325 return false;
326
327 const bool hasZ = is3D();
328 const bool hasM = isMeasure();
329
330 outX.reserve( length );
331 outY.reserve( length );
332 if ( hasZ )
333 outZ.reserve( length );
334 if ( hasM )
335 outM.reserve( length );
336
337 const double *xIn = srcX.constData();
338 const double *yIn = srcY.constData();
339 const double *zIn = hasZ ? srcZ.constData() : nullptr;
340 const double *mIn = hasM ? srcM.constData() : nullptr;
341
342 double previousX = 0;
343 double previousY = 0;
344 double previousZ = 0;
345 double previousM = 0;
346 int outSize = 0;
347 for ( int i = 0; i < length; ++i )
348 {
349 const double currentX = *xIn++;
350 const double currentY = *yIn++;
351 const double currentZ = zIn ? *zIn++ : 0;
352 const double currentM = mIn ? *mIn++ : 0;
353
354 const double roundedX = hSpacing > 0 ? ( std::round( currentX / hSpacing ) * hSpacing ) : currentX;
355 const double roundedY = vSpacing > 0 ? ( std::round( currentY / vSpacing ) * vSpacing ) : currentY;
356 const double roundedZ = hasZ && dSpacing > 0 ? ( std::round( currentZ / dSpacing ) * dSpacing ) : currentZ;
357 const double roundedM = hasM && mSpacing > 0 ? ( std::round( currentM / mSpacing ) * mSpacing ) : currentM;
358
359 if ( i == 0 )
360 {
361 outX.append( roundedX );
362 outY.append( roundedY );
363 if ( hasZ )
364 outZ.append( roundedZ );
365 if ( hasM )
366 outM.append( roundedM );
367 outSize++;
368 }
369 else
370 {
371 const bool isPointEqual = qgsDoubleNear( roundedX, previousX )
372 && qgsDoubleNear( roundedY, previousY )
373 && ( !hasZ || dSpacing <= 0 || qgsDoubleNear( roundedZ, previousZ ) )
374 && ( !hasM || mSpacing <= 0 || qgsDoubleNear( roundedM, previousM ) );
375 if ( isPointEqual )
376 continue;
377
378 // maybe previous point is redundant and is just a midpoint on a straight line -- let's check
379 bool previousPointRedundant = false;
380 if ( removeRedundantPoints && outSize > 1 && !hasZ && !hasM )
381 {
382 previousPointRedundant = QgsGeometryUtilsBase::leftOfLine( outX.at( outSize - 1 ),
383 outY.at( outSize - 1 ),
384 outX.at( outSize - 2 ),
385 outY.at( outSize - 2 ),
386 roundedX, roundedY ) == 0;
387 }
388 if ( previousPointRedundant )
389 {
390 outX[ outSize - 1 ] = roundedX;
391 outY[ outSize - 1 ] = roundedY;
392 }
393 else
394 {
395 outX.append( roundedX );
396 outY.append( roundedY );
397 if ( hasZ )
398 outZ.append( roundedZ );
399 if ( hasM )
400 outM.append( roundedM );
401 outSize++;
402 }
403 }
404
405 previousX = roundedX;
406 previousY = roundedY;
407 previousZ = roundedZ;
408 previousM = roundedM;
409 }
410
411 if ( removeRedundantPoints && isClosed() && outSize > 4 && !hasZ && !hasM )
412 {
413 // maybe first/last vertex is redundant, let's try to remove that too
414 const bool firstVertexIsRedundant = QgsGeometryUtilsBase::leftOfLine( outX.at( 0 ),
415 outY.at( 0 ),
416 outX.at( outSize - 2 ),
417 outY.at( outSize - 2 ),
418 outX.at( 1 ), outY.at( 1 ) ) == 0;
419 if ( firstVertexIsRedundant )
420 {
421 outX.removeAt( 0 );
422 outY.removeAt( 0 );
423 outX[ outSize - 2 ] = outX.at( 0 );
424 outY[ outSize - 2 ] = outY.at( 0 );
425 }
426 }
427
428 // we previously reserved size based on a worst case scenario, let's free
429 // unnecessary memory reservation now
430 outX.squeeze();
431 outY.squeeze();
432 if ( hasZ )
433 outZ.squeeze();
434 if ( hasM )
435 outM.squeeze();
436
437 return outSize >= 4 || ( !isClosed() && outSize >= 2 );
438}
@ AllowSelfTouchingHoles
Indicates that self-touching holes are permitted. OGC validity states that self-touching holes are NO...
Definition qgis.h:2118
AngularDirection
Angular directions.
Definition qgis.h:3479
@ CounterClockwise
Counter-clockwise direction.
Definition qgis.h:3481
@ Clockwise
Clockwise direction.
Definition qgis.h:3480
QFlags< GeometryValidityFlag > GeometryValidityFlags
Geometry validity flags.
Definition qgis.h:2121
VertexType
Types of vertex.
Definition qgis.h:3112
QFlags< GeosCreationFlag > GeosCreationFlags
Geos geometry creation behavior flags.
Definition qgis.h:2204
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.
virtual QgsBox3D calculateBoundingBox3D() const
Calculates the minimal 3D bounding box for the geometry.
bool isMeasure() const
Returns true if the geometry contains m values.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
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.
QgsAbstractGeometry()=default
A 3-dimensional box composed of x, y, z coordinates.
Definition qgsbox3d.h:42
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:287
QgsCoordinateSequence coordinateSequence() const override
Retrieves the sequence of geometries, rings and nodes.
Definition qgscurve.cpp:78
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:294
double sinuosity() const
Returns the curve sinuosity, which is the ratio of the curve length() to curve straightDistance2d().
Definition qgscurve.cpp:278
bool mHasCachedSummedUpArea
Definition qgscurve.h:401
void normalize() final
Reorganizes the geometry into a normalized form (or "canonical" form).
Definition qgscurve.cpp:212
QPainterPath asQPainterPath() const override
Returns the geometry represented as a QPainterPath.
Definition qgscurve.cpp:71
QgsPoint childPoint(int index) const override
Returns point at index (for geometries without child geometries - i.e.
Definition qgscurve.cpp:309
int vertexNumberFromVertexId(QgsVertexId id) const override
Returns the vertex number corresponding to a vertex id.
Definition qgscurve.cpp:141
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:194
QgsCurve * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
Definition qgscurve.cpp:176
virtual bool isRing() const
Returns true if the curve is a ring.
Definition qgscurve.cpp:66
virtual bool pointAt(int node, QgsPoint &point, Qgis::VertexType &type) const =0
Returns the point and vertex id of a point within the curve.
int childCount() const override
Returns number of child geometries (for geometries with child geometries) or child points (for geomet...
Definition qgscurve.cpp:304
QgsBox3D boundingBox3D() const override
Returns the 3D bounding box for the geometry.
Definition qgscurve.cpp:239
bool mHasCachedSummedUpArea3D
Definition qgscurve.h:403
virtual bool isClosed() const
Returns true if the curve is closed.
Definition qgscurve.cpp:54
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:248
virtual bool isClosed2D() const
Returns true if the curve is closed.
Definition qgscurve.cpp:42
int vertexCount(int part=0, int ring=0) const override
Returns the number of vertices of which this geometry is built.
Definition qgscurve.cpp:181
QgsPoint vertexAt(QgsVertexId id) const override
Returns the point corresponding to a specified vertex id.
Definition qgscurve.cpp:199
QgsAbstractGeometry * boundary() const override
Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the...
Definition qgscurve.cpp:150
virtual QPolygonF asQPolygonF() const
Returns a QPolygonF representing the points.
Definition qgscurve.cpp:267
void adjacentVertices(QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex) const override
Returns the vertices adjacent to a specified vertex within a geometry.
Definition qgscurve.cpp:113
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:207
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:28
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, bool removeRedundantPoints) const
Helper function for QgsCurve subclasses to snap to grids.
Definition qgscurve.cpp:319
QString asKml(int precision=17) const override
Returns a KML representation of the geometry.
Definition qgscurve.cpp:165
QgsBox3D mBoundingBox
Cached bounding box.
Definition qgscurve.h:399
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:188
virtual QgsPoint startPoint() const =0
Returns the starting point of the curve.
bool operator!=(const QgsAbstractGeometry &other) const override
Definition qgscurve.cpp:37
double straightDistance2d() const
Returns the straight distance of the curve, i.e.
Definition qgscurve.cpp:273
bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const override
Returns next vertex id and coordinates.
Definition qgscurve.cpp:88
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.
QgsCurve()=default
void reserve(int size)
Attempts to allocate memory for at least size geometries.
static int leftOfLine(const double x, const double y, const double x1, const double y1, const double x2, const double y2)
Returns a value < 0 if the point (x, y) is left of the line from (x1, y1) -> (x2, y2).
Does vector analysis using the GEOS library and handles import, export, and exception handling.
Definition qgsgeos.h:141
Multi point geometry collection.
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 z
Definition qgspoint.h:54
double x
Definition qgspoint.h:52
bool isEmpty() const override
Returns true if the geometry is empty.
Definition qgspoint.cpp:739
double distance(double x, double y) const
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
Definition qgspoint.h:387
double y
Definition qgspoint.h:53
Contains geos related utilities and functions.
Definition qgsgeos.h:77
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6888
T qgsgeometry_cast(QgsAbstractGeometry *geom)
QVector< QgsRingSequence > QgsCoordinateSequence
QVector< QgsPointSequence > QgsRingSequence
QVector< QgsPoint > QgsPointSequence
Utility class for identifying a unique vertex within a geometry.
Definition qgsvertexid.h:30
int vertex
Vertex number.
Definition qgsvertexid.h:94
int part
Part number.
Definition qgsvertexid.h:88
int ring
Ring number.
Definition qgsvertexid.h:91