QGIS API Documentation 4.1.0-Master (31622b25bb0)
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() ) && 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
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, 0, Qgis::GeosCreationFlags() );
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
267{
268 return id.part == 0 && id.ring == 0 && id.vertex >= 0 && id.vertex < numPoints();
269}
270
271QPolygonF QgsCurve::asQPolygonF() const
272{
273 std::unique_ptr< QgsLineString > segmentized( curveToLine() );
274 return segmentized->asQPolygonF();
275}
276
278{
279 return startPoint().distance( endPoint() );
280}
281
283{
284 const double d = straightDistance2d();
285 if ( qgsDoubleNear( d, 0.0 ) )
286 return std::numeric_limits<double>::quiet_NaN();
287
288 return length() / d;
289}
290
297
299{
301 mHasCachedValidity = false;
302 mValidityFailureReason.clear();
306}
307
309{
310 return numPoints();
311}
312
314{
315 QgsPoint point;
316 Qgis::VertexType type;
317 const bool res = pointAt( index, point, type );
318 Q_ASSERT( res );
319 Q_UNUSED( res )
320 return point;
321}
322
324 double hSpacing,
325 double vSpacing,
326 double dSpacing,
327 double mSpacing,
328 const QVector<double> &srcX,
329 const QVector<double> &srcY,
330 const QVector<double> &srcZ,
331 const QVector<double> &srcM,
332 QVector<double> &outX,
333 QVector<double> &outY,
334 QVector<double> &outZ,
335 QVector<double> &outM,
336 bool removeRedundantPoints
337) const
338{
339 const int length = numPoints();
340 if ( length < 2 )
341 return false;
342
343 const bool hasZ = is3D();
344 const bool hasM = isMeasure();
345
346 outX.reserve( length );
347 outY.reserve( length );
348 if ( hasZ )
349 outZ.reserve( length );
350 if ( hasM )
351 outM.reserve( length );
352
353 const double *xIn = srcX.constData();
354 const double *yIn = srcY.constData();
355 const double *zIn = hasZ ? srcZ.constData() : nullptr;
356 const double *mIn = hasM ? srcM.constData() : nullptr;
357
358 double previousX = 0;
359 double previousY = 0;
360 double previousZ = 0;
361 double previousM = 0;
362 int outSize = 0;
363 for ( int i = 0; i < length; ++i )
364 {
365 const double currentX = *xIn++;
366 const double currentY = *yIn++;
367 const double currentZ = zIn ? *zIn++ : 0;
368 const double currentM = mIn ? *mIn++ : 0;
369
370 const double roundedX = hSpacing > 0 ? ( std::round( currentX / hSpacing ) * hSpacing ) : currentX;
371 const double roundedY = vSpacing > 0 ? ( std::round( currentY / vSpacing ) * vSpacing ) : currentY;
372 const double roundedZ = hasZ && dSpacing > 0 ? ( std::round( currentZ / dSpacing ) * dSpacing ) : currentZ;
373 const double roundedM = hasM && mSpacing > 0 ? ( std::round( currentM / mSpacing ) * mSpacing ) : currentM;
374
375 if ( i == 0 )
376 {
377 outX.append( roundedX );
378 outY.append( roundedY );
379 if ( hasZ )
380 outZ.append( roundedZ );
381 if ( hasM )
382 outM.append( roundedM );
383 outSize++;
384 }
385 else
386 {
387 const bool isPointEqual = qgsDoubleNear( roundedX, previousX )
388 && qgsDoubleNear( roundedY, previousY )
389 && ( !hasZ || dSpacing <= 0 || qgsDoubleNear( roundedZ, previousZ ) )
390 && ( !hasM || mSpacing <= 0 || qgsDoubleNear( roundedM, previousM ) );
391 if ( isPointEqual )
392 continue;
393
394 // maybe previous point is redundant and is just a midpoint on a straight line -- let's check
395 bool previousPointRedundant = false;
396 if ( removeRedundantPoints && outSize > 1 && !hasZ && !hasM )
397 {
398 previousPointRedundant = QgsGeometryUtilsBase::leftOfLine( outX.at( outSize - 1 ), outY.at( outSize - 1 ), outX.at( outSize - 2 ), outY.at( outSize - 2 ), roundedX, roundedY ) == 0;
399 }
400 if ( previousPointRedundant )
401 {
402 outX[outSize - 1] = roundedX;
403 outY[outSize - 1] = roundedY;
404 }
405 else
406 {
407 outX.append( roundedX );
408 outY.append( roundedY );
409 if ( hasZ )
410 outZ.append( roundedZ );
411 if ( hasM )
412 outM.append( roundedM );
413 outSize++;
414 }
415 }
416
417 previousX = roundedX;
418 previousY = roundedY;
419 previousZ = roundedZ;
420 previousM = roundedM;
421 }
422
423 if ( removeRedundantPoints && isClosed() && outSize > 4 && !hasZ && !hasM )
424 {
425 // maybe first/last vertex is redundant, let's try to remove that too
426 const bool firstVertexIsRedundant = QgsGeometryUtilsBase::leftOfLine( outX.at( 0 ), outY.at( 0 ), outX.at( outSize - 2 ), outY.at( outSize - 2 ), outX.at( 1 ), outY.at( 1 ) ) == 0;
427 if ( firstVertexIsRedundant )
428 {
429 outX.removeAt( 0 );
430 outY.removeAt( 0 );
431 outX[outSize - 2] = outX.at( 0 );
432 outY[outSize - 2] = outY.at( 0 );
433 }
434 }
435
436 // we previously reserved size based on a worst case scenario, let's free
437 // unnecessary memory reservation now
438 outX.squeeze();
439 outY.squeeze();
440 if ( hasZ )
441 outZ.squeeze();
442 if ( hasM )
443 outM.squeeze();
444
445 return outSize >= 4 || ( !isClosed() && outSize >= 2 );
446}
@ AllowSelfTouchingHoles
Indicates that self-touching holes are permitted. OGC validity states that self-touching holes are NO...
Definition qgis.h:2192
AngularDirection
Angular directions.
Definition qgis.h:3613
@ CounterClockwise
Counter-clockwise direction.
Definition qgis.h:3615
@ Clockwise
Clockwise direction.
Definition qgis.h:3614
QFlags< GeometryValidityFlag > GeometryValidityFlags
Geometry validity flags.
Definition qgis.h:2196
VertexType
Types of vertex.
Definition qgis.h:3246
QFlags< GeosCreationFlag > GeosCreationFlags
Geos geometry creation behavior flags.
Definition qgis.h:2291
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:45
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:291
QgsCoordinateSequence coordinateSequence() const override
Retrieves the sequence of geometries, rings and nodes.
Definition qgscurve.cpp:77
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:298
double sinuosity() const
Returns the curve sinuosity, which is the ratio of the curve length() to curve straightDistance2d().
Definition qgscurve.cpp:282
bool mHasCachedSummedUpArea
Definition qgscurve.h:405
void normalize() final
Reorganizes the geometry into a normalized form (or "canonical" form).
Definition qgscurve.cpp:211
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:313
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 isRing() const
Returns true if the curve is a ring.
Definition qgscurve.cpp:65
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:308
QgsBox3D boundingBox3D() const override
Returns the 3D bounding box for the geometry.
Definition qgscurve.cpp:238
bool mHasCachedSummedUpArea3D
Definition qgscurve.h:407
virtual bool isClosed() const
Returns true if the curve is closed.
Definition qgscurve.cpp:53
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
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: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:271
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: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:323
QString asKml(int precision=17) const override
Returns a KML representation of the geometry.
Definition qgscurve.cpp:164
QgsBox3D mBoundingBox
Cached bounding box.
Definition qgscurve.h:403
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:37
double straightDistance2d() const
Returns the straight distance of the curve, i.e.
Definition qgscurve.cpp:277
bool hasVertex(QgsVertexId position) const override
Returns true if the geometry contains a vertex matching the given position.
Definition qgscurve.cpp:266
bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const override
Returns next vertex id and coordinates.
Definition qgscurve.cpp:87
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:175
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:53
double z
Definition qgspoint.h:58
double x
Definition qgspoint.h:56
bool isEmpty() const override
Returns true if the geometry is empty.
Definition qgspoint.cpp:777
double distance(double x, double y) const
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
Definition qgspoint.h:466
double y
Definition qgspoint.h:57
Contains geos related utilities and functions.
Definition qgsgeos.h:112
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:7222
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:35
int vertex
Vertex number.
int part
Part number.
Definition qgsvertexid.h:94
int ring
Ring number.
Definition qgsvertexid.h:97