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  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
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