QGIS API Documentation  3.0.2-Girona (307d082)
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  mBoundingBox = QgsRectangle();
207 }
208 
210 {
211  return numPoints();
212 }
213 
214 QgsPoint QgsCurve::childPoint( int index ) const
215 {
216  QgsPoint point;
218  bool res = pointAt( index, point, type );
219  Q_ASSERT( res );
220  Q_UNUSED( res );
221  return point;
222 }
223 
224 bool QgsCurve::snapToGridPrivate( double hSpacing, double vSpacing, double dSpacing, double mSpacing,
225  const QVector<double> &srcX, const QVector<double> &srcY, const QVector<double> &srcZ, const QVector<double> &srcM,
226  QVector<double> &outX, QVector<double> &outY, QVector<double> &outZ, QVector<double> &outM ) const
227 {
228  int length = numPoints();
229 
230  if ( length <= 0 )
231  return false;
232 
233  bool hasZ = is3D();
234  bool hasM = isMeasure();
235 
236  // helper functions
237  auto roundVertex = [hSpacing, vSpacing, dSpacing, mSpacing, hasZ, hasM, &srcX, &srcY, &srcZ, &srcM]( QgsPoint & out, int i )
238  {
239  if ( hSpacing > 0 )
240  out.setX( std::round( srcX.at( i ) / hSpacing ) * hSpacing );
241  else
242  out.setX( srcX.at( i ) );
243 
244  if ( vSpacing > 0 )
245  out.setY( std::round( srcY.at( i ) / vSpacing ) * vSpacing );
246  else
247  out.setY( srcY.at( i ) );
248 
249  if ( hasZ )
250  {
251  if ( dSpacing > 0 )
252  out.setZ( std::round( srcZ.at( i ) / dSpacing ) * dSpacing );
253  else
254  out.setZ( srcZ.at( i ) );
255  }
256 
257  if ( hasM )
258  {
259  if ( mSpacing > 0 )
260  out.setM( std::round( srcM.at( i ) / mSpacing ) * mSpacing );
261  else
262  out.setM( srcM.at( i ) );
263  }
264  };
265 
266 
267  auto append = [hasZ, hasM, &outX, &outY, &outM, &outZ]( QgsPoint const & point )
268  {
269  outX.append( point.x() );
270 
271  outY.append( point.y() );
272 
273  if ( hasZ )
274  outZ.append( point.z() );
275 
276  if ( hasM )
277  outM.append( point.m() );
278  };
279 
280  auto isPointEqual = [dSpacing, mSpacing, hasZ, hasM]( const QgsPoint & a, const QgsPoint & b )
281  {
282  return ( a.x() == b.x() )
283  && ( a.y() == b.y() )
284  && ( !hasZ || dSpacing <= 0 || a.z() == b.z() )
285  && ( !hasM || mSpacing <= 0 || a.m() == b.m() );
286  };
287 
288  // temporary values
289  QgsWkbTypes::Type pointType = QgsWkbTypes::zmType( QgsWkbTypes::Point, hasZ, hasM );
290  QgsPoint last( pointType );
291  QgsPoint current( pointType );
292 
293  // Actual code (what does all the work)
294  roundVertex( last, 0 );
295  append( last );
296 
297  for ( int i = 1; i < length; ++i )
298  {
299  roundVertex( current, i );
300  if ( !isPointEqual( current, last ) )
301  {
302  append( current );
303  last = current;
304  }
305  }
306 
307  // if it's not closed, with 2 points you get a correct line
308  // if it is, you need at least 4 (3 + the vertex that closes)
309  if ( outX.length() < 2 || ( isClosed() && outX.length() < 4 ) )
310  return false;
311 
312  return true;
313 }
bool isMeasure() const
Returns true if the geometry contains m values.
A rectangle specified with double values.
Definition: qgsrectangle.h:39
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
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
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:203
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:214
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:251
int childCount() const override
Returns number of child geometries (for geometries with child geometries) or child points (for geomet...
Definition: qgscurve.cpp:209
virtual QgsPoint endPoint() const =0
Returns the end point of the curve.
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:224
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
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
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()).
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