QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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 
25 bool QgsCurve::operator==( const QgsAbstractGeometry &other ) const
26 {
27  const QgsCurve *otherCurve = qgsgeometry_cast< const QgsCurve * >( &other );
28  if ( !otherCurve )
29  return false;
30 
31  return equals( *otherCurve );
32 }
33 
34 bool QgsCurve::operator!=( const QgsAbstractGeometry &other ) const
35 {
36  return !operator==( other );
37 }
38 
39 bool QgsCurve::isClosed() const
40 {
41  if ( numPoints() == 0 )
42  return false;
43 
44  //don't consider M-coordinates when testing closedness
45  QgsPoint start = startPoint();
46  QgsPoint end = endPoint();
47 
48  bool closed = qgsDoubleNear( start.x(), end.x(), 1E-8 ) &&
49  qgsDoubleNear( start.y(), end.y(), 1E-8 );
50  if ( is3D() && closed )
51  closed &= qgsDoubleNear( start.z(), end.z(), 1E-8 ) || ( std::isnan( start.z() ) && std::isnan( end.z() ) );
52  return closed;
53 }
54 
55 bool QgsCurve::isRing() const
56 {
57  return ( isClosed() && numPoints() >= 4 );
58 }
59 
61 {
62  QgsCoordinateSequence sequence;
63  sequence.append( QgsRingSequence() );
64  sequence.back().append( QgsPointSequence() );
65  points( sequence.back().back() );
66 
67  return sequence;
68 }
69 
70 bool QgsCurve::nextVertex( QgsVertexId &id, QgsPoint &vertex ) const
71 {
72  if ( id.vertex < 0 )
73  {
74  id.vertex = 0;
75  if ( id.part < 0 )
76  {
77  id.part = 0;
78  }
79  if ( id.ring < 0 )
80  {
81  id.ring = 0;
82  }
83  }
84  else
85  {
86  if ( id.vertex + 1 >= numPoints() )
87  {
88  return false;
89  }
90  ++id.vertex;
91  }
92  return pointAt( id.vertex, vertex, id.type );
93 }
94 
96 {
97  int n = numPoints();
98  if ( vertex.vertex < 0 || vertex.vertex >= n )
99  {
100  previousVertex = QgsVertexId();
101  nextVertex = QgsVertexId();
102  return;
103  }
104 
105  if ( vertex.vertex == 0 )
106  {
107  previousVertex = QgsVertexId();
108  }
109  else
110  {
111  previousVertex = QgsVertexId( vertex.part, vertex.ring, vertex.vertex - 1 );
112  }
113  if ( vertex.vertex == n - 1 )
114  {
115  nextVertex = QgsVertexId();
116  }
117  else
118  {
119  nextVertex = QgsVertexId( vertex.part, vertex.ring, vertex.vertex + 1 );
120  }
121 }
122 
124 {
125  if ( id.part != 0 || id.ring != 0 )
126  return -1;
127  if ( id.vertex < 0 || id.vertex >= numPoints() )
128  return -1;
129  return id.vertex;
130 }
131 
133 {
134  if ( isEmpty() )
135  return nullptr;
136 
137  if ( isClosed() )
138  return nullptr;
139 
140  QgsMultiPoint *multiPoint = new QgsMultiPoint();
141  multiPoint->addGeometry( new QgsPoint( startPoint() ) );
142  multiPoint->addGeometry( new QgsPoint( endPoint() ) );
143  return multiPoint;
144 }
145 
146 QgsCurve *QgsCurve::segmentize( double tolerance, SegmentationToleranceType toleranceType ) const
147 {
148  return curveToLine( tolerance, toleranceType );
149 }
150 
151 int QgsCurve::vertexCount( int part, int ring ) const
152 {
153  Q_UNUSED( part );
154  Q_UNUSED( ring );
155  return numPoints();
156 }
157 
158 int QgsCurve::ringCount( int part ) const
159 {
160  Q_UNUSED( part );
161  return numPoints() > 0 ? 1 : 0;
162 }
163 
165 {
166  return numPoints() > 0 ? 1 : 0;
167 }
168 
170 {
171  QgsPoint v;
173  pointAt( id.vertex, v, type );
174  return v;
175 }
176 
178 {
179  return clone();
180 }
181 
183 {
184  if ( mBoundingBox.isNull() )
185  {
186  mBoundingBox = calculateBoundingBox();
187  }
188  return mBoundingBox;
189 }
190 
191 QPolygonF QgsCurve::asQPolygonF() const
192 {
193  const int nb = numPoints();
194  QPolygonF points;
195  points.reserve( nb );
196  for ( int i = 0; i < nb; ++i )
197  {
198  points << QPointF( xAt( i ), yAt( i ) );
199  }
200  return points;
201 }
202 
204 {
205  return startPoint().distance( endPoint() );
206 }
207 
208 double QgsCurve::sinuosity() const
209 {
210  double d = straightDistance2d();
211  if ( qgsDoubleNear( d, 0.0 ) )
212  return std::numeric_limits<double>::quiet_NaN();
213 
214  return length() / d;
215 }
216 
218 {
219  double a = 0;
220  sumUpArea( a );
221  return a < 0 ? Clockwise : CounterClockwise;
222 }
223 
225 {
226  mBoundingBox = QgsRectangle();
228 }
229 
231 {
232  return numPoints();
233 }
234 
235 QgsPoint QgsCurve::childPoint( int index ) const
236 {
237  QgsPoint point;
239  bool res = pointAt( index, point, type );
240  Q_ASSERT( res );
241  Q_UNUSED( res );
242  return point;
243 }
244 
245 bool QgsCurve::snapToGridPrivate( double hSpacing, double vSpacing, double dSpacing, double mSpacing,
246  const QVector<double> &srcX, const QVector<double> &srcY, const QVector<double> &srcZ, const QVector<double> &srcM,
247  QVector<double> &outX, QVector<double> &outY, QVector<double> &outZ, QVector<double> &outM ) const
248 {
249  int length = numPoints();
250 
251  if ( length <= 0 )
252  return false;
253 
254  bool hasZ = is3D();
255  bool hasM = isMeasure();
256 
257  // helper functions
258  auto roundVertex = [hSpacing, vSpacing, dSpacing, mSpacing, hasZ, hasM, &srcX, &srcY, &srcZ, &srcM]( QgsPoint & out, int i )
259  {
260  if ( hSpacing > 0 )
261  out.setX( std::round( srcX.at( i ) / hSpacing ) * hSpacing );
262  else
263  out.setX( srcX.at( i ) );
264 
265  if ( vSpacing > 0 )
266  out.setY( std::round( srcY.at( i ) / vSpacing ) * vSpacing );
267  else
268  out.setY( srcY.at( i ) );
269 
270  if ( hasZ )
271  {
272  if ( dSpacing > 0 )
273  out.setZ( std::round( srcZ.at( i ) / dSpacing ) * dSpacing );
274  else
275  out.setZ( srcZ.at( i ) );
276  }
277 
278  if ( hasM )
279  {
280  if ( mSpacing > 0 )
281  out.setM( std::round( srcM.at( i ) / mSpacing ) * mSpacing );
282  else
283  out.setM( srcM.at( i ) );
284  }
285  };
286 
287 
288  auto append = [hasZ, hasM, &outX, &outY, &outM, &outZ]( QgsPoint const & point )
289  {
290  outX.append( point.x() );
291 
292  outY.append( point.y() );
293 
294  if ( hasZ )
295  outZ.append( point.z() );
296 
297  if ( hasM )
298  outM.append( point.m() );
299  };
300 
301  auto isPointEqual = [dSpacing, mSpacing, hasZ, hasM]( const QgsPoint & a, const QgsPoint & b )
302  {
303  return ( a.x() == b.x() )
304  && ( a.y() == b.y() )
305  && ( !hasZ || dSpacing <= 0 || a.z() == b.z() )
306  && ( !hasM || mSpacing <= 0 || a.m() == b.m() );
307  };
308 
309  // temporary values
310  QgsWkbTypes::Type pointType = QgsWkbTypes::zmType( QgsWkbTypes::Point, hasZ, hasM );
311  QgsPoint last( pointType );
312  QgsPoint current( pointType );
313 
314  // Actual code (what does all the work)
315  roundVertex( last, 0 );
316  append( last );
317 
318  for ( int i = 1; i < length; ++i )
319  {
320  roundVertex( current, i );
321  if ( !isPointEqual( current, last ) )
322  {
323  append( current );
324  last = current;
325  }
326  }
327 
328  // if it's not closed, with 2 points you get a correct line
329  // if it is, you need at least 4 (3 + the vertex that closes)
330  if ( outX.length() < 2 || ( isClosed() && outX.length() < 4 ) )
331  return false;
332 
333  return true;
334 }
virtual bool isEmpty() const
Returns true if the geometry is empty.
A rectangle specified with double values.
Definition: qgsrectangle.h:40
double y
Definition: qgspoint.h:42
int partCount() const override
Returns count of parts contained in the geometry.
Definition: qgscurve.cpp:164
bool operator==(const QgsAbstractGeometry &other) const override
Definition: qgscurve.cpp:25
Orientation orientation() const
Returns the curve&#39;s orientation, e.g.
Definition: qgscurve.cpp:217
Multi point geometry collection.
Definition: qgsmultipoint.h:29
QVector< QgsRingSequence > QgsCoordinateSequence
bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const override
Returns next vertex id and coordinates.
Definition: qgscurve.cpp:70
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:278
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:435
virtual void sumUpArea(double &sum) const =0
Sums up the area of the curve by iterating over the vertices (shoelace formula).
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
Definition: qgscurve.cpp:224
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle...
virtual bool pointAt(int node, QgsPoint &point, QgsVertexId::VertexType &type) const =0
Returns the point and vertex id of a point within the curve.
virtual bool equals(const QgsCurve &other) const =0
Checks whether this curve exactly equals another curve.
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:245
QgsPoint childPoint(int index) const override
Returns point at index (for geometries without child geometries - i.e.
Definition: qgscurve.cpp:235
virtual QgsRectangle calculateBoundingBox() const
Default calculator for the minimal bounding box for the geometry.
int childCount() const override
Returns number of child geometries (for geometries with child geometries) or child points (for geomet...
Definition: qgscurve.cpp:230
virtual QgsPoint endPoint() const =0
Returns the end point of the curve.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
bool isMeasure() const
Returns true if the geometry contains m values.
Utility class for identifying a unique vertex within a geometry.
double straightDistance2d() const
Returns the straight distance of the curve, i.e.
Definition: qgscurve.cpp:203
virtual QPolygonF asQPolygonF() const
Returns a QPolygonF representing the points.
Definition: qgscurve.cpp:191
int vertexCount(int part=0, int ring=0) const override
Returns the number of vertices of which this geometry is built.
Definition: qgscurve.cpp:151
T qgsgeometry_cast(const QgsAbstractGeometry *geom)
virtual double xAt(int index) const =0
Returns the x-coordinate of the specified node in the line string.
virtual bool isClosed() const
Returns true if the curve is closed.
Definition: qgscurve.cpp:39
Orientation
Curve orientation.
Definition: qgscurve.h:233
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
Abstract base class for all geometries.
virtual void clearCache() const
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
QgsPoint vertexAt(QgsVertexId id) const override
Returns the point corresponding to a specified vertex id.
Definition: qgscurve.cpp:169
Counter-clockwise orientation.
Definition: qgscurve.h:236
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
int vertexNumberFromVertexId(QgsVertexId id) const override
Returns the vertex number corresponding to a vertex id.
Definition: qgscurve.cpp:123
QgsAbstractGeometry * boundary() const override
Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the...
Definition: qgscurve.cpp:132
QgsCoordinateSequence coordinateSequence() const override
Retrieves the sequence of geometries, rings and nodes.
Definition: qgscurve.cpp:60
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
Definition: qgspoint.h:276
Clockwise orientation.
Definition: qgscurve.h:235
virtual double length() const
Returns the length of the geometry.
QVector< QgsPoint > QgsPointSequence
QgsCurve * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
Definition: qgscurve.cpp:146
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
QVector< QgsPointSequence > QgsRingSequence
QgsCurve * toCurveType() const override
Returns the geometry converted to the more generic curve type.
Definition: qgscurve.cpp:177
QgsRectangle boundingBox() const override
Returns the minimal bounding box for the geometry.
Definition: qgscurve.cpp:182
int ringCount(int part=0) const override
Returns the number of rings of which this geometry is built.
Definition: qgscurve.cpp:158
void adjacentVertices(QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex) const override
Returns the vertices adjacent to a specified vertex within a geometry.
Definition: qgscurve.cpp:95
double sinuosity() const
Returns the curve sinuosity, which is the ratio of the curve length() to curve straightDistance2d().
Definition: qgscurve.cpp:208
QgsCurve * clone() const override=0
Clones the geometry by performing a deep copy.
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...
virtual double yAt(int index) const =0
Returns the y-coordinate of the specified node in the line string.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
static Type zmType(Type type, bool hasZ, bool hasM)
Returns the modified input geometry type according to hasZ / hasM.
Definition: qgswkbtypes.h:664
double z
Definition: qgspoint.h:43
virtual QgsPoint startPoint() const =0
Returns the starting point of the curve.
bool operator!=(const QgsAbstractGeometry &other) const override
Definition: qgscurve.cpp:34
virtual bool isRing() const
Returns true if the curve is a ring.
Definition: qgscurve.cpp:55
virtual int numPoints() const =0
Returns the number of points in the curve.
virtual void points(QgsPointSequence &pt) const =0
Returns a list of points within the curve.
double x
Definition: qgspoint.h:41