QGIS API Documentation 3.99.0-Master (21b3aa880ba)
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();
301}
302
304{
305 return numPoints();
306}
307
309{
310 QgsPoint point;
311 Qgis::VertexType type;
312 const bool res = pointAt( index, point, type );
313 Q_ASSERT( res );
314 Q_UNUSED( res )
315 return point;
316}
317
318bool QgsCurve::snapToGridPrivate( double hSpacing, double vSpacing, double dSpacing, double mSpacing,
319 const QVector<double> &srcX, const QVector<double> &srcY, const QVector<double> &srcZ, const QVector<double> &srcM,
320 QVector<double> &outX, QVector<double> &outY, QVector<double> &outZ, QVector<double> &outM, bool removeRedundantPoints ) const
321{
322 const int length = numPoints();
323 if ( length < 2 )
324 return false;
325
326 const bool hasZ = is3D();
327 const bool hasM = isMeasure();
328
329 outX.reserve( length );
330 outY.reserve( length );
331 if ( hasZ )
332 outZ.reserve( length );
333 if ( hasM )
334 outM.reserve( length );
335
336 const double *xIn = srcX.constData();
337 const double *yIn = srcY.constData();
338 const double *zIn = hasZ ? srcZ.constData() : nullptr;
339 const double *mIn = hasM ? srcM.constData() : nullptr;
340
341 double previousX = 0;
342 double previousY = 0;
343 double previousZ = 0;
344 double previousM = 0;
345 int outSize = 0;
346 for ( int i = 0; i < length; ++i )
347 {
348 const double currentX = *xIn++;
349 const double currentY = *yIn++;
350 const double currentZ = zIn ? *zIn++ : 0;
351 const double currentM = mIn ? *mIn++ : 0;
352
353 const double roundedX = hSpacing > 0 ? ( std::round( currentX / hSpacing ) * hSpacing ) : currentX;
354 const double roundedY = vSpacing > 0 ? ( std::round( currentY / vSpacing ) * vSpacing ) : currentY;
355 const double roundedZ = hasZ && dSpacing > 0 ? ( std::round( currentZ / dSpacing ) * dSpacing ) : currentZ;
356 const double roundedM = hasM && mSpacing > 0 ? ( std::round( currentM / mSpacing ) * mSpacing ) : currentM;
357
358 if ( i == 0 )
359 {
360 outX.append( roundedX );
361 outY.append( roundedY );
362 if ( hasZ )
363 outZ.append( roundedZ );
364 if ( hasM )
365 outM.append( roundedM );
366 outSize++;
367 }
368 else
369 {
370 const bool isPointEqual = qgsDoubleNear( roundedX, previousX )
371 && qgsDoubleNear( roundedY, previousY )
372 && ( !hasZ || dSpacing <= 0 || qgsDoubleNear( roundedZ, previousZ ) )
373 && ( !hasM || mSpacing <= 0 || qgsDoubleNear( roundedM, previousM ) );
374 if ( isPointEqual )
375 continue;
376
377 // maybe previous point is redundant and is just a midpoint on a straight line -- let's check
378 bool previousPointRedundant = false;
379 if ( removeRedundantPoints && outSize > 1 && !hasZ && !hasM )
380 {
381 previousPointRedundant = QgsGeometryUtilsBase::leftOfLine( outX.at( outSize - 1 ),
382 outY.at( outSize - 1 ),
383 outX.at( outSize - 2 ),
384 outY.at( outSize - 2 ),
385 roundedX, roundedY ) == 0;
386 }
387 if ( previousPointRedundant )
388 {
389 outX[ outSize - 1 ] = roundedX;
390 outY[ outSize - 1 ] = roundedY;
391 }
392 else
393 {
394 outX.append( roundedX );
395 outY.append( roundedY );
396 if ( hasZ )
397 outZ.append( roundedZ );
398 if ( hasM )
399 outM.append( roundedM );
400 outSize++;
401 }
402 }
403
404 previousX = roundedX;
405 previousY = roundedY;
406 previousZ = roundedZ;
407 previousM = roundedM;
408 }
409
410 if ( removeRedundantPoints && isClosed() && outSize > 4 && !hasZ && !hasM )
411 {
412 // maybe first/last vertex is redundant, let's try to remove that too
413 const bool firstVertexIsRedundant = QgsGeometryUtilsBase::leftOfLine( outX.at( 0 ),
414 outY.at( 0 ),
415 outX.at( outSize - 2 ),
416 outY.at( outSize - 2 ),
417 outX.at( 1 ), outY.at( 1 ) ) == 0;
418 if ( firstVertexIsRedundant )
419 {
420 outX.removeAt( 0 );
421 outY.removeAt( 0 );
422 outX[ outSize - 2 ] = outX.at( 0 );
423 outY[ outSize - 2 ] = outY.at( 0 );
424 }
425 }
426
427 // we previously reserved size based on a worst case scenario, let's free
428 // unnecessary memory reservation now
429 outX.squeeze();
430 outY.squeeze();
431 if ( hasZ )
432 outZ.squeeze();
433 if ( hasM )
434 outM.squeeze();
435
436 return outSize >= 4 || ( !isClosed() && outSize >= 2 );
437}
@ AllowSelfTouchingHoles
Indicates that self-touching holes are permitted. OGC validity states that self-touching holes are NO...
Definition qgis.h:2072
AngularDirection
Angular directions.
Definition qgis.h:3432
@ CounterClockwise
Counter-clockwise direction.
Definition qgis.h:3434
@ Clockwise
Clockwise direction.
Definition qgis.h:3433
QFlags< GeometryValidityFlag > GeometryValidityFlags
Geometry validity flags.
Definition qgis.h:2075
VertexType
Types of vertex.
Definition qgis.h:3066
QFlags< GeosCreationFlag > GeosCreationFlags
Geos geometry creation behavior flags.
Definition qgis.h:2158
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:394
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:308
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:303
QgsBox3D boundingBox3D() const override
Returns the 3D bounding box for the geometry.
Definition qgscurve.cpp:239
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:318
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:392
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:6607
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