QGIS API Documentation  3.2.0-Bonn (bc43194)
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 *
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  mBoundingBox = QgsRectangle();
221 }
222
224 {
225  return numPoints();
226 }
227
228 QgsPoint QgsCurve::childPoint( int index ) const
229 {
230  QgsPoint point;
232  bool res = pointAt( index, point, type );
233  Q_ASSERT( res );
234  Q_UNUSED( res );
235  return point;
236 }
237
238 bool QgsCurve::snapToGridPrivate( double hSpacing, double vSpacing, double dSpacing, double mSpacing,
239  const QVector<double> &srcX, const QVector<double> &srcY, const QVector<double> &srcZ, const QVector<double> &srcM,
240  QVector<double> &outX, QVector<double> &outY, QVector<double> &outZ, QVector<double> &outM ) const
241 {
242  int length = numPoints();
243
244  if ( length <= 0 )
245  return false;
246
247  bool hasZ = is3D();
248  bool hasM = isMeasure();
249
250  // helper functions
251  auto roundVertex = [hSpacing, vSpacing, dSpacing, mSpacing, hasZ, hasM, &srcX, &srcY, &srcZ, &srcM]( QgsPoint & out, int i )
252  {
253  if ( hSpacing > 0 )
254  out.setX( std::round( srcX.at( i ) / hSpacing ) * hSpacing );
255  else
256  out.setX( srcX.at( i ) );
257
258  if ( vSpacing > 0 )
259  out.setY( std::round( srcY.at( i ) / vSpacing ) * vSpacing );
260  else
261  out.setY( srcY.at( i ) );
262
263  if ( hasZ )
264  {
265  if ( dSpacing > 0 )
266  out.setZ( std::round( srcZ.at( i ) / dSpacing ) * dSpacing );
267  else
268  out.setZ( srcZ.at( i ) );
269  }
270
271  if ( hasM )
272  {
273  if ( mSpacing > 0 )
274  out.setM( std::round( srcM.at( i ) / mSpacing ) * mSpacing );
275  else
276  out.setM( srcM.at( i ) );
277  }
278  };
279
280
281  auto append = [hasZ, hasM, &outX, &outY, &outM, &outZ]( QgsPoint const & point )
282  {
283  outX.append( point.x() );
284
285  outY.append( point.y() );
286
287  if ( hasZ )
288  outZ.append( point.z() );
289
290  if ( hasM )
291  outM.append( point.m() );
292  };
293
294  auto isPointEqual = [dSpacing, mSpacing, hasZ, hasM]( const QgsPoint & a, const QgsPoint & b )
295  {
296  return ( a.x() == b.x() )
297  && ( a.y() == b.y() )
298  && ( !hasZ || dSpacing <= 0 || a.z() == b.z() )
299  && ( !hasM || mSpacing <= 0 || a.m() == b.m() );
300  };
301
302  // temporary values
303  QgsWkbTypes::Type pointType = QgsWkbTypes::zmType( QgsWkbTypes::Point, hasZ, hasM );
304  QgsPoint last( pointType );
305  QgsPoint current( pointType );
306
307  // Actual code (what does all the work)
308  roundVertex( last, 0 );
309  append( last );
310
311  for ( int i = 1; i < length; ++i )
312  {
313  roundVertex( current, i );
314  if ( !isPointEqual( current, last ) )
315  {
316  append( current );
317  last = current;
318  }
319  }
320
321  // if it's not closed, with 2 points you get a correct line
322  // if it is, you need at least 4 (3 + the vertex that closes)
323  if ( outX.length() < 2 || ( isClosed() && outX.length() < 4 ) )
324  return false;
325
326  return true;
327 }
bool isMeasure() const
Returns true if the geometry contains m values.
A rectangle specified with double values.
Definition: qgsrectangle.h:40
double y
Definition: qgspoint.h:42
virtual bool isEmpty() const
Returns true if the geometry is empty.
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
double sinuosity() const
Returns the curve sinuosity, which is the ratio of the curve length() to curve straightDistance2d().
Definition: qgscurve.cpp:208
Multi point geometry collection.
Definition: qgsmultipoint.h:29
QVector< QgsRingSequence > QgsCoordinateSequence
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
Definition: qgspoint.h:276
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:251
virtual bool isRing() const
Returns true if the curve is a ring.
Definition: qgscurve.cpp:55
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
Definition: qgscurve.cpp:217
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.
QgsPoint childPoint(int index) const override
Returns point at index (for geometries without child geometries - i.e.
Definition: qgscurve.cpp:228
int childCount() const override
Returns number of child geometries (for geometries with child geometries) or child points (for geomet...
Definition: qgscurve.cpp:223
virtual QgsPoint endPoint() const =0
Returns the end point of the curve.
virtual QPolygonF asQPolygonF() const
Returns a QPolygonF representing the points.
Definition: qgscurve.cpp:191
virtual double length() const
Returns the length of the geometry.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:67
virtual void clearCache() const
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
Utility class for identifying a unique vertex within a geometry.
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.
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
Abstract base class for all geometries.
QgsPoint vertexAt(QgsVertexId id) const override
Returns the point corresponding to a specified vertex id.
Definition: qgscurve.cpp:169
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
virtual bool isClosed() const
Returns true if the curve is closed.
Definition: qgscurve.cpp:39
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:238
QgsCoordinateSequence coordinateSequence() const override
Retrieves the sequence of geometries, rings and nodes.
Definition: qgscurve.cpp:60
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
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
double straightDistance2d() const
Returns the straight distance of the curve, i.e.
Definition: qgscurve.cpp:203
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
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...
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:429
virtual QgsRectangle calculateBoundingBox() const
Default calculator for the minimal bounding box for the geometry.
virtual double yAt(int index) const =0
Returns the y-coordinate of the specified node in the line string.
static Type zmType(Type type, bool hasZ, bool hasM)
Returns the modified input geometry type according to hasZ / hasM.
Definition: qgswkbtypes.h:526
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 int numPoints() const =0
Returns the number of points in the curve.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
virtual void points(QgsPointSequence &pt) const =0
Returns a list of points within the curve.
double x
Definition: qgspoint.h:41