QGIS API Documentation  2.12.0-Lyon
qgslinestringv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslinestringv2.cpp
3  -------------------
4  begin : September 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 "qgslinestringv2.h"
19 #include "qgsapplication.h"
20 #include "qgscoordinatetransform.h"
21 #include "qgsgeometryutils.h"
22 #include "qgsmaptopixel.h"
23 #include "qgswkbptr.h"
24 #include <QPainter>
25 #include <limits>
26 #include <QDomDocument>
27 
29 {
31 }
32 
34 {}
35 
37 {
38  return new QgsLineStringV2( *this );
39 }
40 
42 {
43  mCoords.clear();
44  mZ.clear();
45  mM.clear();
47 }
48 
49 bool QgsLineStringV2::fromWkb( const unsigned char* wkb )
50 {
51  if ( !wkb )
52  {
53  return false;
54  }
55  QgsConstWkbPtr wkbPtr( wkb );
56  QgsWKBTypes::Type type = wkbPtr.readHeader();
58  {
59  return false;
60  }
61  mWkbType = type;
62  importVerticesFromWkb( wkbPtr );
63  return true;
64 }
65 
67 {
68  mWkbType = type;
69  importVerticesFromWkb( wkb );
70 }
71 
73 {
74  clear();
75 
77 
78  if ( QgsWKBTypes::flatType( parts.first ) != QgsWKBTypes::parseType( geometryType() ) )
79  return false;
80  mWkbType = parts.first;
81 
83  return true;
84 }
85 
87 {
88  int size = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
89  size += numPoints() * ( 2 + is3D() + isMeasure() ) * sizeof( double );
90  return size;
91 }
92 
93 unsigned char* QgsLineStringV2::asWkb( int& binarySize ) const
94 {
95  binarySize = wkbSize();
96  unsigned char* geomPtr = new unsigned char[binarySize];
97  QgsWkbPtr wkb( geomPtr );
98  wkb << static_cast<char>( QgsApplication::endian() );
99  wkb << static_cast<quint32>( wkbType() );
100  QList<QgsPointV2> pts;
101  points( pts );
102  QgsGeometryUtils::pointsToWKB( wkb, pts, is3D(), isMeasure() );
103  return geomPtr;
104 }
105 
106 QString QgsLineStringV2::asWkt( int precision ) const
107 {
108  QString wkt = wktTypeStr() + " ";
109  QList<QgsPointV2> pts;
110  points( pts );
111  wkt += QgsGeometryUtils::pointsToWKT( pts, precision, is3D(), isMeasure() );
112  return wkt;
113 }
114 
115 QDomElement QgsLineStringV2::asGML2( QDomDocument& doc, int precision, const QString& ns ) const
116 {
117  QList<QgsPointV2> pts;
118  points( pts );
119 
120  QDomElement elemLineString = doc.createElementNS( ns, "LineString" );
121  elemLineString.appendChild( QgsGeometryUtils::pointsToGML2( pts, doc, precision, ns ) );
122 
123  return elemLineString;
124 }
125 
126 QDomElement QgsLineStringV2::asGML3( QDomDocument& doc, int precision, const QString& ns ) const
127 {
128  QList<QgsPointV2> pts;
129  points( pts );
130 
131  QDomElement elemCurve = doc.createElementNS( ns, "Curve" );
132  QDomElement elemSegments = doc.createElementNS( ns, "segments" );
133  QDomElement elemArcString = doc.createElementNS( ns, "LineString" );
134  elemArcString.appendChild( QgsGeometryUtils::pointsToGML3( pts, doc, precision, ns, is3D() ) );
135  elemSegments.appendChild( elemArcString );
136  elemCurve.appendChild( elemSegments );
137 
138  return elemCurve;
139 }
140 
141 QString QgsLineStringV2::asJSON( int precision ) const
142 {
143  QList<QgsPointV2> pts;
144  points( pts );
145 
146  return "{\"type\": \"LineString\", \"coordinates\": " + QgsGeometryUtils::pointsToJSON( pts, precision ) + "}";
147 }
148 
150 {
151  double length = 0;
152  int size = mCoords.size();
153  double dx, dy;
154  for ( int i = 1; i < size; ++i )
155  {
156  dx = mCoords[i].x() - mCoords[ i - 1 ].x();
157  dy = mCoords[i].y() - mCoords[ i - 1 ].y();
158  length += sqrt( dx * dx + dy * dy );
159  }
160  return length;
161 }
162 
164 {
165  if ( numPoints() < 1 )
166  {
167  return QgsPointV2();
168  }
169  return pointN( 0 );
170 }
171 
173 {
174  if ( numPoints() < 1 )
175  {
176  return QgsPointV2();
177  }
178  return pointN( numPoints() - 1 );
179 }
180 
182 {
183  return static_cast<QgsLineStringV2*>( clone() );
184 }
185 
187 {
188  return mCoords.size();
189 }
190 
192 {
193  if ( mCoords.size() <= i )
194  {
195  return QgsPointV2();
196  }
197 
198  const QPointF& pt = mCoords.at( i );
199  double z = 0;
200  double m = 0;
201 
202  bool hasZ = is3D();
203  if ( hasZ )
204  {
205  z = mZ.at( i );
206  }
207  bool hasM = isMeasure();
208  if ( hasM )
209  {
210  m = mM.at( i );
211  }
212 
214  if ( hasZ && hasM )
215  {
217  }
218  else if ( hasZ )
219  {
221  }
222  else if ( hasM )
223  {
225  }
226  return QgsPointV2( t, pt.x(), pt.y(), z, m );
227 }
228 
230 {
231  pts.clear();
232  int nPoints = numPoints();
233  for ( int i = 0; i < nPoints; ++i )
234  {
235  pts.push_back( pointN( i ) );
236  }
237 }
238 
240 {
241  if ( points.size() < 1 )
242  {
244  mCoords.clear();
245  mZ.clear();
246  mM.clear();
247  return;
248  }
249 
250  //get wkb type from first point
251  const QgsPointV2& firstPt = points.at( 0 );
252  bool hasZ = firstPt.is3D();
253  bool hasM = firstPt.isMeasure();
254 
256 
257  mCoords.resize( points.size() );
258  if ( hasZ )
259  {
260  mZ.resize( points.size() );
261  }
262  else
263  {
264  mZ.clear();
265  }
266  if ( hasM )
267  {
268  mM.resize( points.size() );
269  }
270  else
271  {
272  mM.clear();
273  }
274 
275  for ( int i = 0; i < points.size(); ++i )
276  {
277  mCoords[i].rx() = points[i].x();
278  mCoords[i].ry() = points[i].y();
279  if ( hasZ )
280  {
281  mZ[i] = points[i].z();
282  }
283  if ( hasM )
284  {
285  mM[i] = points[i].m();
286  }
287  }
288 }
289 
291 {
292  if ( !line )
293  {
294  return;
295  }
296 
297  if ( numPoints() < 1 )
298  {
300  }
301 
302  mCoords += line->mCoords;
303  mZ += line->mZ;
304  mM += line->mM;
305 }
306 
308 {
309  p.drawPolyline( mCoords );
310 }
311 
313 {
314  int nPoints = numPoints();
315  if ( nPoints < 1 )
316  {
317  return;
318  }
319 
320  if ( path.isEmpty() || path.currentPosition() != mCoords[0] )
321  {
322  path.moveTo( mCoords[0] );
323  }
324 
325  for ( int i = 1; i < nPoints; ++i )
326  {
327  path.lineTo( mCoords[i] );
328  }
329 }
330 
332 {
333  p.drawPolygon( mCoords );
334 }
335 
337 {
338  ct.transformPolygon( mCoords, d );
339 }
340 
342 {
343  mCoords = t.map( mCoords );
344 }
345 
346 bool QgsLineStringV2::insertVertex( const QgsVertexId& position, const QgsPointV2& vertex )
347 {
348  if ( position.vertex < 0 || position.vertex > mCoords.size() )
349  {
350  return false;
351  }
352  mCoords.insert( position.vertex, QPointF( vertex.x(), vertex.y() ) );
353  if ( is3D() )
354  {
355  mZ.insert( position.vertex, vertex.z() );
356  }
357  if ( isMeasure() )
358  {
359  mM.insert( position.vertex, vertex.m() );
360  }
361  mBoundingBox = QgsRectangle(); //set bounding box invalid
362  return true;
363 }
364 
365 bool QgsLineStringV2::moveVertex( const QgsVertexId& position, const QgsPointV2& newPos )
366 {
367  if ( position.vertex < 0 || position.vertex >= mCoords.size() )
368  {
369  return false;
370  }
371  mCoords[position.vertex].rx() = newPos.x();
372  mCoords[position.vertex].ry() = newPos.y();
373  if ( is3D() && newPos.is3D() )
374  {
375  mZ[position.vertex] = newPos.z();
376  }
377  if ( isMeasure() && newPos.isMeasure() )
378  {
379  mM[position.vertex] = newPos.m();
380  }
381  mBoundingBox = QgsRectangle(); //set bounding box invalid
382  return true;
383 }
384 
386 {
387  if ( position.vertex >= mCoords.size() || position.vertex < 0 )
388  {
389  return false;
390  }
391 
392  mCoords.remove( position.vertex );
393  if ( is3D() )
394  {
395  mZ.remove( position.vertex );
396  }
397  if ( isMeasure() )
398  {
399  mM.remove( position.vertex );
400  }
401  mBoundingBox = QgsRectangle(); //set bounding box invalid
402  return true;
403 }
404 
406 {
408  {
410  }
411 
412  mCoords.append( QPointF( pt.x(), pt.y() ) );
413  if ( is3D() )
414  {
415  mZ.append( pt.z() );
416  }
417  if ( isMeasure() )
418  {
419  mM.append( pt.m() );
420  }
421  mBoundingBox = QgsRectangle(); //set bounding box invalid
422 }
423 
424 double QgsLineStringV2::closestSegment( const QgsPointV2& pt, QgsPointV2& segmentPt, QgsVertexId& vertexAfter, bool* leftOf, double epsilon ) const
425 {
426  double sqrDist = std::numeric_limits<double>::max();
427  double testDist = 0;
428  double segmentPtX, segmentPtY;
429 
430  int size = mCoords.size();
431  for ( int i = 1; i < size; ++i )
432  {
433  const QPointF& prev = mCoords.at( i - 1 );
434  const QPointF& currentPt = mCoords.at( i );
435  testDist = QgsGeometryUtils::sqrDistToLine( pt.x(), pt.y(), prev.x(), prev.y(), currentPt.x(), currentPt.y(), segmentPtX, segmentPtY, epsilon );
436  if ( testDist < sqrDist )
437  {
438  sqrDist = testDist;
439  segmentPt.setX( segmentPtX );
440  segmentPt.setY( segmentPtY );
441  if ( leftOf )
442  {
443  *leftOf = ( QgsGeometryUtils::leftOfLine( segmentPtX, segmentPtY, prev.x(), prev.y(), pt.x(), pt.y() ) < 0 );
444  }
445  vertexAfter.part = 0; vertexAfter.ring = 0; vertexAfter.vertex = i;
446  }
447  }
448  return sqrDist;
449 }
450 
452 {
453  if ( i >= numPoints() )
454  {
455  return false;
456  }
457  vertex = pointN( i );
459  return true;
460 }
461 
462 void QgsLineStringV2::sumUpArea( double& sum ) const
463 {
464  int maxIndex = numPoints() - 1;
465  for ( int i = 0; i < maxIndex; ++i )
466  {
467  sum += 0.5 * ( mCoords[i].x() * mCoords[i+1].y() - mCoords[i].y() * mCoords[i+1].x() );
468  }
469 }
470 
471 void QgsLineStringV2::importVerticesFromWkb( const QgsConstWkbPtr& wkb )
472 {
473  bool hasZ = is3D();
474  bool hasM = isMeasure();
475  int nVertices = 0;
476  wkb >> nVertices;
477  mCoords.resize( nVertices );
478  hasZ ? mZ.resize( nVertices ) : mZ.clear();
479  hasM ? mM.resize( nVertices ) : mM.clear();
480  for ( int i = 0; i < nVertices; ++i )
481  {
482  wkb >> mCoords[i].rx();
483  wkb >> mCoords[i].ry();
484  if ( hasZ )
485  {
486  wkb >> mZ[i];
487  }
488  if ( hasM )
489  {
490  wkb >> mM[i];
491  }
492  }
493 }
494 
496 {
497  if ( numPoints() < 1 || isClosed() )
498  {
499  return;
500  }
501  addVertex( startPoint() );
502 }
503 
504 double QgsLineStringV2::vertexAngle( const QgsVertexId& vertex ) const
505 {
506  if ( vertex.vertex == 0 || vertex.vertex >= ( numPoints() - 1 ) )
507  {
508  if ( isClosed() )
509  {
510  QPointF previous = mCoords[numPoints() - 1 ];
511  QPointF current = mCoords[0];
512  QPointF after = mCoords[1];
513  return QgsGeometryUtils::averageAngle( previous.x(), previous.y(), current.x(), current.y(), after.x(), after.y() );
514  }
515  else if ( vertex.vertex == 0 )
516  {
517  return QgsGeometryUtils::linePerpendicularAngle( mCoords[0].x(), mCoords[0].y(), mCoords[1].x(), mCoords[1].y() );
518  }
519  else
520  {
521  int a = numPoints() - 2;
522  int b = numPoints() - 1;
523  return QgsGeometryUtils::linePerpendicularAngle( mCoords[a].x(), mCoords[a].y(), mCoords[b].x(), mCoords[b].y() );
524  }
525  }
526  else
527  {
528  QPointF previous = mCoords[vertex.vertex - 1 ];
529  QPointF current = mCoords[vertex.vertex];
530  QPointF after = mCoords[vertex.vertex + 1];
531  return QgsGeometryUtils::averageAngle( previous.x(), previous.y(), current.x(), current.y(), after.x(), after.y() );
532  }
533 }
534 
535 bool QgsLineStringV2::addZValue( double zValue )
536 {
537  if ( QgsWKBTypes::hasZ( mWkbType ) )
538  return false;
539 
541 
542  mZ.clear();
543  int nPoints = numPoints();
544  mZ.reserve( nPoints );
545  for ( int i = 0; i < nPoints; ++i )
546  {
547  mZ << zValue;
548  }
549  return true;
550 }
551 
552 bool QgsLineStringV2::addMValue( double mValue )
553 {
554  if ( QgsWKBTypes::hasM( mWkbType ) )
555  return false;
556 
558 
559  mM.clear();
560  int nPoints = numPoints();
561  mM.reserve( nPoints );
562  for ( int i = 0; i < nPoints; ++i )
563  {
564  mM << mValue;
565  }
566  return true;
567 }
void clear()
QgsWKBTypes::Type wkbType() const
Returns the WKB type of the geometry.
void close()
Appends first point if not already closed.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
QDomElement asGML2(QDomDocument &doc, int precision=17, const QString &ns="gml") const override
Returns a GML2 representation of the geometry.
QgsPointV2 pointN(int i) const
static QPair< QgsWKBTypes::Type, QString > wktReadBlock(const QString &wkt)
Parses a WKT block of the format "TYPE( contents )" and returns a pair of geometry type to contents (...
virtual bool moveVertex(const QgsVertexId &position, const QgsPointV2 &newPos) override
Moves a vertex within the geometry.
QPointF currentPosition() const
QDomNode appendChild(const QDomNode &newChild)
void append(const T &value)
double x() const
Definition: qgspointv2.h:42
void push_back(const T &value)
void transformPolygon(QPolygonF &poly, TransformDirection direction=ForwardTransform) const
void draw(QPainter &p) const override
Draws the geometry using the specified QPainter.
static double averageAngle(double x1, double y1, double x2, double y2, double x3, double y3)
Angle between two linear segments.
void points(QList< QgsPointV2 > &pt) const override
Returns a list of points within the curve.
QPoint map(const QPoint &point) const
virtual bool insertVertex(const QgsVertexId &position, const QgsPointV2 &vertex) override
Inserts a vertex into the geometry.
void drawPolyline(const QPointF *points, int pointCount)
virtual bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
const T & at(int i) const
static QString pointsToWKT(const QList< QgsPointV2 > &points, int precision, bool is3D, bool isMeasure)
Returns a WKT coordinate list.
static QString pointsToJSON(const QList< QgsPointV2 > &points, int precision)
Returns a geoJSON coordinates string.
void insert(int i, const T &value)
void drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule)
static double linePerpendicularAngle(double x1, double y1, double x2, double y2)
Calculates angle perpendicular to line.
virtual bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
TransformDirection
Enum used to indicate the direction (forward or inverse) of the transform.
void moveTo(const QPointF &point)
void setX(double x)
Definition: qgspointv2.h:47
static double leftOfLine(double x, double y, double x1, double y1, double x2, double y2)
Returns < 0 if point(x/y) is left of the line x1,y1 -> x2,y2.
void append(const QgsLineStringV2 *line)
void transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d=QgsCoordinateTransform::ForwardTransform) override
Transforms the geometry using a coordinate transform.
QDomElement createElementNS(const QString &nsURI, const QString &qName)
virtual QgsPointV2 endPoint() const override
Returns the end point of the curve.
static endian_t endian()
Returns whether this machine uses big or little endian.
QString wktTypeStr() const
Returns the WKT type string of the geometry.
void setY(double y)
Definition: qgspointv2.h:48
int size() const
void addToPainterPath(QPainterPath &path) const override
Adds a curve to a painter path.
double y() const
Definition: qgspointv2.h:43
double ANALYSIS_EXPORT max(double x, double y)
Returns the maximum of two doubles or the first argument if both are equal.
virtual QgsLineStringV2 * curveToLine() const override
Returns a new line string geometry corresponding to a segmentized approximation of the curve...
QgsWKBTypes::Type readHeader() const
Definition: qgswkbptr.cpp:8
double vertexAngle(const QgsVertexId &vertex) const override
Returns approximate rotation angle for a vertex.
bool pointAt(int i, QgsPointV2 &vertex, QgsVertexId::VertexType &type) const override
Returns the point and vertex id of a point within the curve.
void clear()
static Type flatType(Type type)
Definition: qgswkbtypes.cpp:46
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
qreal x() const
qreal y() const
static bool hasM(Type type)
Tests whether a WKB type contains m values.
void resize(int size)
virtual bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
Utility class for identifying a unique vertex within a geometry.
bool isMeasure() const
Returns true if the geometry contains m values.
double z() const
Definition: qgspointv2.h:44
Line string geometry type.
QDomElement asGML3(QDomDocument &doc, int precision=17, const QString &ns="gml") const override
Returns a GML3 representation of the geometry.
void lineTo(const QPointF &endPoint)
static Type addZ(Type type)
Adds the z dimension to a WKB type and returns the new type.
Point geometry type.
Definition: qgspointv2.h:29
void fromWkbPoints(QgsWKBTypes::Type type, const QgsConstWkbPtr &wkb)
void remove(int i)
virtual double length() const override
Returns the length of the geometry.
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
virtual QgsLineStringV2 * clone() const override
Clones the geometry by performing a deep copy.
unsigned char * asWkb(int &binarySize) const override
Returns a WKB representation of the geometry.
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
void setZMTypeFromSubGeometry(const QgsAbstractGeometryV2 *subggeom, QgsWKBTypes::Type baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
virtual QString geometryType() const override
Returns a unique string representing the geometry type.
virtual bool deleteVertex(const QgsVertexId &position) override
Deletes a vertex within the geometry.
QString asJSON(int precision=17) const override
Returns a GeoJSON representation of the geometry.
void reserve(int size)
static QDomElement pointsToGML3(const QList< QgsPointV2 > &points, QDomDocument &doc, int precision, const QString &ns, bool is3D)
Returns a gml::posList DOM element.
double closestSegment(const QgsPointV2 &pt, QgsPointV2 &segmentPt, QgsVertexId &vertexAfter, bool *leftOf, double epsilon) const override
Searches for the closest segment of the geometry to a given point.
virtual QgsPointV2 startPoint() const override
Returns the starting point of the curve.
void addVertex(const QgsPointV2 &pt)
const T & at(int i) const
void setPoints(const QList< QgsPointV2 > &points)
virtual bool isClosed() const
Returns true if the curve is closed.
Definition: qgscurvev2.cpp:27
void drawAsPolygon(QPainter &p) const override
Draws the curve as a polygon on the specified QPainter.
bool isEmpty() const
static QList< QgsPointV2 > pointsFromWKT(const QString &wktCoordinateList, bool is3D, bool isMeasure)
Returns a list of points contained in a WKT string.
Class for doing transforms between two map coordinate systems.
double m() const
Definition: qgspointv2.h:45
static double sqrDistToLine(double ptX, double ptY, double x1, double y1, double x2, double y2, double &minDistX, double &minDistY, double epsilon)
Returns the squared distance between a point and a line.
static Type parseType(const QString &wktStr)
Definition: qgswkbtypes.cpp:56
double ANALYSIS_EXPORT leftOf(Point3D *thepoint, Point3D *p1, Point3D *p2)
Returns whether 'thepoint' is left or right of the line from 'p1' to 'p2'.
virtual bool fromWkb(const unsigned char *wkb) override
Sets the geometry from a WKB string.
int wkbSize() const override
Returns the size of the WKB representation of the geometry.
void sumUpArea(double &sum) const override
Calculates the area of the curve.
Abstract base class for curved geometry type.
Definition: qgscurvev2.h:32
int size() const
static void pointsToWKB(QgsWkbPtr &wkb, const QList< QgsPointV2 > &points, bool is3D, bool isMeasure)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
static QDomElement pointsToGML2(const QList< QgsPointV2 > &points, QDomDocument &doc, int precision, const QString &ns)
Returns a gml::coordinates DOM element.
virtual void clear() override
Clears the geometry, ie reset it to a null geometry.
static Type addM(Type type)
Adds the m dimension to a WKB type and returns the new type.
int numPoints() const override
Returns the number of points in the curve.