QGIS API Documentation  3.14.0-Pi (9f7028fd23)
qgslinestring.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslinestring.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 "qgslinestring.h"
19 #include "qgsapplication.h"
20 #include "qgscompoundcurve.h"
21 #include "qgscoordinatetransform.h"
22 #include "qgsgeometryutils.h"
23 #include "qgsmaptopixel.h"
24 #include "qgswkbptr.h"
25 #include "qgslinesegment.h"
26 
27 #include <nlohmann/json.hpp>
28 #include <cmath>
29 #include <memory>
30 #include <QPainter>
31 #include <limits>
32 #include <QDomDocument>
33 #include <QJsonObject>
34 
35 
36 /***************************************************************************
37  * This class is considered CRITICAL and any change MUST be accompanied with
38  * full unit tests.
39  * See details in QEP #17
40  ****************************************************************************/
41 
43 {
45 }
46 
47 QgsLineString::QgsLineString( const QVector<QgsPoint> &points )
48 {
49  if ( points.isEmpty() )
50  {
52  return;
53  }
54  QgsWkbTypes::Type ptType = points.at( 0 ).wkbType();
56  mX.resize( points.count() );
57  mY.resize( points.count() );
58  double *x = mX.data();
59  double *y = mY.data();
60  double *z = nullptr;
61  double *m = nullptr;
62  if ( QgsWkbTypes::hasZ( mWkbType ) )
63  {
64  mZ.resize( points.count() );
65  z = mZ.data();
66  }
67  if ( QgsWkbTypes::hasM( mWkbType ) )
68  {
69  mM.resize( points.count() );
70  m = mM.data();
71  }
72 
73  for ( const QgsPoint &pt : points )
74  {
75  *x++ = pt.x();
76  *y++ = pt.y();
77  if ( z )
78  *z++ = pt.z();
79  if ( m )
80  *m++ = pt.m();
81  }
82 }
83 
84 QgsLineString::QgsLineString( const QVector<double> &x, const QVector<double> &y, const QVector<double> &z, const QVector<double> &m, bool is25DType )
85 {
87  int pointCount = std::min( x.size(), y.size() );
88  if ( x.size() == pointCount )
89  {
90  mX = x;
91  }
92  else
93  {
94  mX = x.mid( 0, pointCount );
95  }
96  if ( y.size() == pointCount )
97  {
98  mY = y;
99  }
100  else
101  {
102  mY = y.mid( 0, pointCount );
103  }
104  if ( !z.isEmpty() && z.count() >= pointCount )
105  {
107  if ( z.size() == pointCount )
108  {
109  mZ = z;
110  }
111  else
112  {
113  mZ = z.mid( 0, pointCount );
114  }
115  }
116  if ( !m.isEmpty() && m.count() >= pointCount )
117  {
119  if ( m.size() == pointCount )
120  {
121  mM = m;
122  }
123  else
124  {
125  mM = m.mid( 0, pointCount );
126  }
127  }
128 }
129 
131 {
133  mX.resize( 2 );
134  mX[ 0 ] = p1.x();
135  mX[ 1 ] = p2.x();
136  mY.resize( 2 );
137  mY[ 0 ] = p1.y();
138  mY[ 1 ] = p2.y();
139  if ( p1.is3D() )
140  {
142  mZ.resize( 2 );
143  mZ[ 0 ] = p1.z();
144  mZ[ 1 ] = p2.z();
145  }
146  if ( p1.isMeasure() )
147  {
149  mM.resize( 2 );
150  mM[ 0 ] = p1.m();
151  mM[ 1 ] = p2.m();
152  }
153 }
154 
155 QgsLineString::QgsLineString( const QVector<QgsPointXY> &points )
156 {
158  mX.reserve( points.size() );
159  mY.reserve( points.size() );
160  for ( const QgsPointXY &p : points )
161  {
162  mX << p.x();
163  mY << p.y();
164  }
165 }
166 
168 {
170  mX.resize( 2 );
171  mY.resize( 2 );
172  mX[0] = segment.startX();
173  mX[1] = segment.endX();
174  mY[0] = segment.startY();
175  mY[1] = segment.endY();
176 }
177 
178 static double cubicInterpolate( double a, double b,
179  double A, double B, double C, double D )
180 {
181  return A * b * b * b + 3 * B * b * b * a + 3 * C * b * a * a + D * a * a * a;
182 }
183 
184 QgsLineString *QgsLineString::fromBezierCurve( const QgsPoint &start, const QgsPoint &controlPoint1, const QgsPoint &controlPoint2, const QgsPoint &end, int segments )
185 {
186  if ( segments == 0 )
187  return new QgsLineString();
188 
189  QVector<double> x;
190  x.resize( segments + 1 );
191  QVector<double> y;
192  y.resize( segments + 1 );
193  QVector<double> z;
194  double *zData = nullptr;
195  if ( start.is3D() && end.is3D() && controlPoint1.is3D() && controlPoint2.is3D() )
196  {
197  z.resize( segments + 1 );
198  zData = z.data();
199  }
200  QVector<double> m;
201  double *mData = nullptr;
202  if ( start.isMeasure() && end.isMeasure() && controlPoint1.isMeasure() && controlPoint2.isMeasure() )
203  {
204  m.resize( segments + 1 );
205  mData = m.data();
206  }
207 
208  double *xData = x.data();
209  double *yData = y.data();
210  const double step = 1.0 / segments;
211  double a = 0;
212  double b = 1.0;
213  for ( int i = 0; i < segments; i++, a += step, b -= step )
214  {
215  if ( i == 0 )
216  {
217  *xData++ = start.x();
218  *yData++ = start.y();
219  if ( zData )
220  *zData++ = start.z();
221  if ( mData )
222  *mData++ = start.m();
223  }
224  else
225  {
226  *xData++ = cubicInterpolate( a, b, start.x(), controlPoint1.x(), controlPoint2.x(), end.x() );
227  *yData++ = cubicInterpolate( a, b, start.y(), controlPoint1.y(), controlPoint2.y(), end.y() );
228  if ( zData )
229  *zData++ = cubicInterpolate( a, b, start.z(), controlPoint1.z(), controlPoint2.z(), end.z() );
230  if ( mData )
231  *mData++ = cubicInterpolate( a, b, start.m(), controlPoint1.m(), controlPoint2.m(), end.m() );
232  }
233  }
234 
235  *xData = end.x();
236  *yData = end.y();
237  if ( zData )
238  *zData = end.z();
239  if ( mData )
240  *mData = end.m();
241 
242  return new QgsLineString( x, y, z, m );
243 }
244 
245 QgsLineString *QgsLineString::fromQPolygonF( const QPolygonF &polygon )
246 {
247  QVector< double > x;
248  QVector< double > y;
249  x.resize( polygon.count() );
250  y.resize( polygon.count() );
251  double *xData = x.data();
252  double *yData = y.data();
253 
254  const QPointF *src = polygon.data();
255  for ( int i = 0 ; i < polygon.size(); ++ i )
256  {
257  *xData++ = src->x();
258  *yData++ = src->y();
259  src++;
260  }
261 
262  return new QgsLineString( x, y );
263 }
264 
265 bool QgsLineString::equals( const QgsCurve &other ) const
266 {
267  const QgsLineString *otherLine = qgsgeometry_cast< const QgsLineString * >( &other );
268  if ( !otherLine )
269  return false;
270 
271  if ( mWkbType != otherLine->mWkbType )
272  return false;
273 
274  if ( mX.count() != otherLine->mX.count() )
275  return false;
276 
277  for ( int i = 0; i < mX.count(); ++i )
278  {
279  if ( !qgsDoubleNear( mX.at( i ), otherLine->mX.at( i ) )
280  || !qgsDoubleNear( mY.at( i ), otherLine->mY.at( i ) ) )
281  return false;
282 
283  if ( is3D() && !qgsDoubleNear( mZ.at( i ), otherLine->mZ.at( i ) ) )
284  return false;
285 
286  if ( isMeasure() && !qgsDoubleNear( mM.at( i ), otherLine->mM.at( i ) ) )
287  return false;
288  }
289 
290  return true;
291 }
292 
294 {
295  return new QgsLineString( *this );
296 }
297 
299 {
300  mX.clear();
301  mY.clear();
302  mZ.clear();
303  mM.clear();
305  clearCache();
306 }
307 
309 {
310  return mX.isEmpty();
311 }
312 
313 QgsLineString *QgsLineString::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing ) const
314 {
315  // prepare result
316  std::unique_ptr<QgsLineString> result { createEmptyWithSameType() };
317 
318  bool res = snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM,
319  result->mX, result->mY, result->mZ, result->mM );
320  if ( res )
321  return result.release();
322  else
323  return nullptr;
324 }
325 
326 bool QgsLineString::removeDuplicateNodes( double epsilon, bool useZValues )
327 {
328  if ( mX.count() <= 2 )
329  return false; // don't create degenerate lines
330  bool result = false;
331  double prevX = mX.at( 0 );
332  double prevY = mY.at( 0 );
333  bool hasZ = is3D();
334  bool useZ = hasZ && useZValues;
335  double prevZ = useZ ? mZ.at( 0 ) : 0;
336  int i = 1;
337  int remaining = mX.count();
338  while ( i < remaining )
339  {
340  double currentX = mX.at( i );
341  double currentY = mY.at( i );
342  double currentZ = useZ ? mZ.at( i ) : 0;
343  if ( qgsDoubleNear( currentX, prevX, epsilon ) &&
344  qgsDoubleNear( currentY, prevY, epsilon ) &&
345  ( !useZ || qgsDoubleNear( currentZ, prevZ, epsilon ) ) )
346  {
347  result = true;
348  // remove point
349  mX.removeAt( i );
350  mY.removeAt( i );
351  if ( hasZ )
352  mZ.removeAt( i );
353  remaining--;
354  }
355  else
356  {
357  prevX = currentX;
358  prevY = currentY;
359  prevZ = currentZ;
360  i++;
361  }
362  }
363  return result;
364 }
365 
366 QPolygonF QgsLineString::asQPolygonF() const
367 {
368  const int nb = mX.size();
369  QPolygonF points( nb );
370 
371  const double *x = mX.constData();
372  const double *y = mY.constData();
373  QPointF *dest = points.data();
374  for ( int i = 0; i < nb; ++i )
375  {
376  *dest++ = QPointF( *x++, *y++ );
377  }
378  return points;
379 }
380 
382 {
383  if ( !wkbPtr )
384  {
385  return false;
386  }
387 
388  QgsWkbTypes::Type type = wkbPtr.readHeader();
390  {
391  return false;
392  }
393  mWkbType = type;
394  importVerticesFromWkb( wkbPtr );
395  return true;
396 }
397 
399 {
400  double xmin = std::numeric_limits<double>::max();
401  double ymin = std::numeric_limits<double>::max();
402  double xmax = -std::numeric_limits<double>::max();
403  double ymax = -std::numeric_limits<double>::max();
404 
405  for ( double x : mX )
406  {
407  if ( x < xmin )
408  xmin = x;
409  if ( x > xmax )
410  xmax = x;
411  }
412  for ( double y : mY )
413  {
414  if ( y < ymin )
415  ymin = y;
416  if ( y > ymax )
417  ymax = y;
418  }
419  return QgsRectangle( xmin, ymin, xmax, ymax );
420 }
421 
422 /***************************************************************************
423  * This class is considered CRITICAL and any change MUST be accompanied with
424  * full unit tests.
425  * See details in QEP #17
426  ****************************************************************************/
427 bool QgsLineString::fromWkt( const QString &wkt )
428 {
429  clear();
430 
431  QPair<QgsWkbTypes::Type, QString> parts = QgsGeometryUtils::wktReadBlock( wkt );
432 
434  return false;
435  mWkbType = parts.first;
436 
437  if ( parts.second == "EMPTY" )
438  return true;
439 
441  return true;
442 }
443 
444 QByteArray QgsLineString::asWkb( WkbFlags ) const
445 {
446  int binarySize = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
447  binarySize += numPoints() * ( 2 + is3D() + isMeasure() ) * sizeof( double );
448 
449  QByteArray wkbArray;
450  wkbArray.resize( binarySize );
451  QgsWkbPtr wkb( wkbArray );
452  wkb << static_cast<char>( QgsApplication::endian() );
453  wkb << static_cast<quint32>( wkbType() );
454  QgsPointSequence pts;
455  points( pts );
456  QgsGeometryUtils::pointsToWKB( wkb, pts, is3D(), isMeasure() );
457  return wkbArray;
458 }
459 
460 /***************************************************************************
461  * This class is considered CRITICAL and any change MUST be accompanied with
462  * full unit tests.
463  * See details in QEP #17
464  ****************************************************************************/
465 
466 QString QgsLineString::asWkt( int precision ) const
467 {
468  QString wkt = wktTypeStr() + ' ';
469 
470  if ( isEmpty() )
471  wkt += QStringLiteral( "EMPTY" );
472  else
473  {
474  QgsPointSequence pts;
475  points( pts );
477  }
478  return wkt;
479 }
480 
481 QDomElement QgsLineString::asGml2( QDomDocument &doc, int precision, const QString &ns, const AxisOrder axisOrder ) const
482 {
483  QgsPointSequence pts;
484  points( pts );
485 
486  QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral( "LineString" ) );
487 
488  if ( isEmpty() )
489  return elemLineString;
490 
491  elemLineString.appendChild( QgsGeometryUtils::pointsToGML2( pts, doc, precision, ns, axisOrder ) );
492 
493  return elemLineString;
494 }
495 
496 QDomElement QgsLineString::asGml3( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
497 {
498  QgsPointSequence pts;
499  points( pts );
500 
501  QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral( "LineString" ) );
502 
503  if ( isEmpty() )
504  return elemLineString;
505 
506  elemLineString.appendChild( QgsGeometryUtils::pointsToGML3( pts, doc, precision, ns, is3D(), axisOrder ) );
507  return elemLineString;
508 }
509 
511 {
512  QgsPointSequence pts;
513  points( pts );
514  return
515  {
516  { "type", "LineString" },
517  { "coordinates", QgsGeometryUtils::pointsToJson( pts, precision ) }
518  };
519 }
520 
521 QString QgsLineString::asKml( int precision ) const
522 {
523  QString kml;
524  if ( isRing() )
525  {
526  kml.append( QLatin1String( "<LinearRing>" ) );
527  }
528  else
529  {
530  kml.append( QLatin1String( "<LineString>" ) );
531  }
532  bool z = is3D();
533  kml.append( QLatin1String( "<altitudeMode>" ) );
534  if ( z )
535  {
536  kml.append( QLatin1String( "absolute" ) );
537  }
538  else
539  {
540  kml.append( QLatin1String( "clampToGround" ) );
541  }
542  kml.append( QLatin1String( "</altitudeMode>" ) );
543  kml.append( QLatin1String( "<coordinates>" ) );
544 
545  int nPoints = mX.size();
546  for ( int i = 0; i < nPoints; ++i )
547  {
548  if ( i > 0 )
549  {
550  kml.append( QLatin1String( " " ) );
551  }
552  kml.append( qgsDoubleToString( mX[i], precision ) );
553  kml.append( QLatin1String( "," ) );
554  kml.append( qgsDoubleToString( mY[i], precision ) );
555  if ( z )
556  {
557  kml.append( QLatin1String( "," ) );
558  kml.append( qgsDoubleToString( mZ[i], precision ) );
559  }
560  else
561  {
562  kml.append( QLatin1String( ",0" ) );
563  }
564  }
565  kml.append( QLatin1String( "</coordinates>" ) );
566  if ( isRing() )
567  {
568  kml.append( QLatin1String( "</LinearRing>" ) );
569  }
570  else
571  {
572  kml.append( QLatin1String( "</LineString>" ) );
573  }
574  return kml;
575 }
576 
577 /***************************************************************************
578  * This class is considered CRITICAL and any change MUST be accompanied with
579  * full unit tests.
580  * See details in QEP #17
581  ****************************************************************************/
582 
583 double QgsLineString::length() const
584 {
585  double length = 0;
586  int size = mX.size();
587  double dx, dy;
588  for ( int i = 1; i < size; ++i )
589  {
590  dx = mX.at( i ) - mX.at( i - 1 );
591  dy = mY.at( i ) - mY.at( i - 1 );
592  length += std::sqrt( dx * dx + dy * dy );
593  }
594  return length;
595 }
596 
598 {
599  if ( is3D() )
600  {
601  double length = 0;
602  int size = mX.size();
603  double dx, dy, dz;
604  for ( int i = 1; i < size; ++i )
605  {
606  dx = mX.at( i ) - mX.at( i - 1 );
607  dy = mY.at( i ) - mY.at( i - 1 );
608  dz = mZ.at( i ) - mZ.at( i - 1 );
609  length += std::sqrt( dx * dx + dy * dy + dz * dz );
610  }
611  return length;
612  }
613  else
614  {
615  return length();
616  }
617 }
618 
620 {
621  if ( numPoints() < 1 )
622  {
623  return QgsPoint();
624  }
625  return pointN( 0 );
626 }
627 
629 {
630  if ( numPoints() < 1 )
631  {
632  return QgsPoint();
633  }
634  return pointN( numPoints() - 1 );
635 }
636 
637 /***************************************************************************
638  * This class is considered CRITICAL and any change MUST be accompanied with
639  * full unit tests.
640  * See details in QEP #17
641  ****************************************************************************/
642 
643 QgsLineString *QgsLineString::curveToLine( double tolerance, SegmentationToleranceType toleranceType ) const
644 {
645  Q_UNUSED( tolerance )
646  Q_UNUSED( toleranceType )
647  return clone();
648 }
649 
651 {
652  return mX.size();
653 }
654 
656 {
657  return mX.size();
658 }
659 
661 {
662  if ( i < 0 || i >= mX.size() )
663  {
664  return QgsPoint();
665  }
666 
667  double x = mX.at( i );
668  double y = mY.at( i );
669  double z = std::numeric_limits<double>::quiet_NaN();
670  double m = std::numeric_limits<double>::quiet_NaN();
671 
672  bool hasZ = is3D();
673  if ( hasZ )
674  {
675  z = mZ.at( i );
676  }
677  bool hasM = isMeasure();
678  if ( hasM )
679  {
680  m = mM.at( i );
681  }
682 
685  {
687  }
688  else if ( hasZ && hasM )
689  {
691  }
692  else if ( hasZ )
693  {
695  }
696  else if ( hasM )
697  {
699  }
700  return QgsPoint( t, x, y, z, m );
701 }
702 
703 /***************************************************************************
704  * This class is considered CRITICAL and any change MUST be accompanied with
705  * full unit tests.
706  * See details in QEP #17
707  ****************************************************************************/
708 
709 double QgsLineString::xAt( int index ) const
710 {
711  if ( index >= 0 && index < mX.size() )
712  return mX.at( index );
713  else
714  return 0.0;
715 }
716 
717 double QgsLineString::yAt( int index ) const
718 {
719  if ( index >= 0 && index < mY.size() )
720  return mY.at( index );
721  else
722  return 0.0;
723 }
724 
725 void QgsLineString::setXAt( int index, double x )
726 {
727  if ( index >= 0 && index < mX.size() )
728  mX[ index ] = x;
729  clearCache();
730 }
731 
732 void QgsLineString::setYAt( int index, double y )
733 {
734  if ( index >= 0 && index < mY.size() )
735  mY[ index ] = y;
736  clearCache();
737 }
738 
739 /***************************************************************************
740  * This class is considered CRITICAL and any change MUST be accompanied with
741  * full unit tests.
742  * See details in QEP #17
743  ****************************************************************************/
744 
746 {
747  pts.clear();
748  int nPoints = numPoints();
749  pts.reserve( nPoints );
750  for ( int i = 0; i < nPoints; ++i )
751  {
752  pts.push_back( pointN( i ) );
753  }
754 }
755 
757 {
758  clearCache(); //set bounding box invalid
759 
760  if ( points.isEmpty() )
761  {
762  clear();
763  return;
764  }
765 
766  //get wkb type from first point
767  const QgsPoint &firstPt = points.at( 0 );
768  bool hasZ = firstPt.is3D();
769  bool hasM = firstPt.isMeasure();
770 
772 
773  mX.resize( points.size() );
774  mY.resize( points.size() );
775  if ( hasZ )
776  {
777  mZ.resize( points.size() );
778  }
779  else
780  {
781  mZ.clear();
782  }
783  if ( hasM )
784  {
785  mM.resize( points.size() );
786  }
787  else
788  {
789  mM.clear();
790  }
791 
792  for ( int i = 0; i < points.size(); ++i )
793  {
794  mX[i] = points.at( i ).x();
795  mY[i] = points.at( i ).y();
796  if ( hasZ )
797  {
798  double z = points.at( i ).z();
799  mZ[i] = std::isnan( z ) ? 0 : z;
800  }
801  if ( hasM )
802  {
803  double m = points.at( i ).m();
804  mM[i] = std::isnan( m ) ? 0 : m;
805  }
806  }
807 }
808 
809 /***************************************************************************
810  * This class is considered CRITICAL and any change MUST be accompanied with
811  * full unit tests.
812  * See details in QEP #17
813  ****************************************************************************/
814 
816 {
817  if ( !line )
818  {
819  return;
820  }
821 
822  if ( numPoints() < 1 )
823  {
825  }
826 
827  // do not store duplicit points
828  if ( numPoints() > 0 &&
829  line->numPoints() > 0 &&
830  endPoint() == line->startPoint() )
831  {
832  mX.pop_back();
833  mY.pop_back();
834 
835  if ( is3D() )
836  {
837  mZ.pop_back();
838  }
839  if ( isMeasure() )
840  {
841  mM.pop_back();
842  }
843  }
844 
845  mX += line->mX;
846  mY += line->mY;
847 
848  if ( is3D() )
849  {
850  if ( line->is3D() )
851  {
852  mZ += line->mZ;
853  }
854  else
855  {
856  // if append line does not have z coordinates, fill with NaN to match number of points in final line
857  mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
858  }
859  }
860 
861  if ( isMeasure() )
862  {
863  if ( line->isMeasure() )
864  {
865  mM += line->mM;
866  }
867  else
868  {
869  // if append line does not have m values, fill with NaN to match number of points in final line
870  mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
871  }
872  }
873 
874  clearCache(); //set bounding box invalid
875 }
876 
878 {
879  QgsLineString *copy = clone();
880  std::reverse( copy->mX.begin(), copy->mX.end() );
881  std::reverse( copy->mY.begin(), copy->mY.end() );
882  if ( copy->is3D() )
883  {
884  std::reverse( copy->mZ.begin(), copy->mZ.end() );
885  }
886  if ( copy->isMeasure() )
887  {
888  std::reverse( copy->mM.begin(), copy->mM.end() );
889  }
890  return copy;
891 }
892 
893 void QgsLineString::visitPointsByRegularDistance( const double distance, const std::function<bool ( double, double, double, double, double, double, double, double, double, double, double, double )> &visitPoint ) const
894 {
895  if ( distance < 0 )
896  return;
897 
898  double distanceTraversed = 0;
899  const int totalPoints = numPoints();
900  if ( totalPoints == 0 )
901  return;
902 
903  const double *x = mX.constData();
904  const double *y = mY.constData();
905  const double *z = is3D() ? mZ.constData() : nullptr;
906  const double *m = isMeasure() ? mM.constData() : nullptr;
907 
908  double prevX = *x++;
909  double prevY = *y++;
910  double prevZ = z ? *z++ : 0.0;
911  double prevM = m ? *m++ : 0.0;
912 
913  if ( qgsDoubleNear( distance, 0.0 ) )
914  {
915  visitPoint( prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM );
916  return;
917  }
918 
919  double pZ = std::numeric_limits<double>::quiet_NaN();
920  double pM = std::numeric_limits<double>::quiet_NaN();
921  double nextPointDistance = distance;
922  for ( int i = 1; i < totalPoints; ++i )
923  {
924  double thisX = *x++;
925  double thisY = *y++;
926  double thisZ = z ? *z++ : 0.0;
927  double thisM = m ? *m++ : 0.0;
928 
929  const double segmentLength = std::sqrt( ( thisX - prevX ) * ( thisX - prevX ) + ( thisY - prevY ) * ( thisY - prevY ) );
930  while ( nextPointDistance < distanceTraversed + segmentLength || qgsDoubleNear( nextPointDistance, distanceTraversed + segmentLength ) )
931  {
932  // point falls on this segment - truncate to segment length if qgsDoubleNear test was actually > segment length
933  const double distanceToPoint = std::min( nextPointDistance - distanceTraversed, segmentLength );
934  double pX, pY;
935  QgsGeometryUtils::pointOnLineWithDistance( prevX, prevY, thisX, thisY, distanceToPoint, pX, pY,
936  z ? &prevZ : nullptr, z ? &thisZ : nullptr, z ? &pZ : nullptr,
937  m ? &prevM : nullptr, m ? &thisM : nullptr, m ? &pM : nullptr );
938 
939  if ( !visitPoint( pX, pY, pZ, pM, prevX, prevY, prevZ, prevM, thisX, thisY, thisZ, thisM ) )
940  return;
941 
942  nextPointDistance += distance;
943  }
944 
945  distanceTraversed += segmentLength;
946  prevX = thisX;
947  prevY = thisY;
948  prevZ = thisZ;
949  prevM = thisM;
950  }
951 }
952 
953 QgsPoint *QgsLineString::interpolatePoint( const double distance ) const
954 {
955  if ( distance < 0 )
956  return nullptr;
957 
959  if ( is3D() )
960  pointType = QgsWkbTypes::PointZ;
961  if ( isMeasure() )
962  pointType = QgsWkbTypes::addM( pointType );
963 
964  std::unique_ptr< QgsPoint > res;
965  visitPointsByRegularDistance( distance, [ & ]( double x, double y, double z, double m, double, double, double, double, double, double, double, double )->bool
966  {
967  res = qgis::make_unique< QgsPoint >( pointType, x, y, z, m );
968  return false;
969  } );
970  return res.release();
971 }
972 
973 QgsLineString *QgsLineString::curveSubstring( double startDistance, double endDistance ) const
974 {
975  if ( startDistance < 0 && endDistance < 0 )
976  return createEmptyWithSameType();
977 
978  endDistance = std::max( startDistance, endDistance );
979 
980  double distanceTraversed = 0;
981  const int totalPoints = numPoints();
982  if ( totalPoints == 0 )
983  return clone();
984 
985  QVector< QgsPoint > substringPoints;
986 
988  if ( is3D() )
989  pointType = QgsWkbTypes::PointZ;
990  if ( isMeasure() )
991  pointType = QgsWkbTypes::addM( pointType );
992 
993  const double *x = mX.constData();
994  const double *y = mY.constData();
995  const double *z = is3D() ? mZ.constData() : nullptr;
996  const double *m = isMeasure() ? mM.constData() : nullptr;
997 
998  double prevX = *x++;
999  double prevY = *y++;
1000  double prevZ = z ? *z++ : 0.0;
1001  double prevM = m ? *m++ : 0.0;
1002  bool foundStart = false;
1003 
1004  if ( qgsDoubleNear( startDistance, 0.0 ) || startDistance < 0 )
1005  {
1006  substringPoints << QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1007  foundStart = true;
1008  }
1009 
1010  substringPoints.reserve( totalPoints );
1011 
1012  for ( int i = 1; i < totalPoints; ++i )
1013  {
1014  double thisX = *x++;
1015  double thisY = *y++;
1016  double thisZ = z ? *z++ : 0.0;
1017  double thisM = m ? *m++ : 0.0;
1018 
1019  const double segmentLength = std::sqrt( ( thisX - prevX ) * ( thisX - prevX ) + ( thisY - prevY ) * ( thisY - prevY ) );
1020  if ( distanceTraversed < startDistance && distanceTraversed + segmentLength > startDistance )
1021  {
1022  // start point falls on this segment
1023  const double distanceToStart = startDistance - distanceTraversed;
1024  double startX, startY;
1025  double startZ = 0;
1026  double startM = 0;
1027  QgsGeometryUtils::pointOnLineWithDistance( prevX, prevY, thisX, thisY, distanceToStart, startX, startY,
1028  z ? &prevZ : nullptr, z ? &thisZ : nullptr, z ? &startZ : nullptr,
1029  m ? &prevM : nullptr, m ? &thisM : nullptr, m ? &startM : nullptr );
1030  substringPoints << QgsPoint( pointType, startX, startY, startZ, startM );
1031  foundStart = true;
1032  }
1033  if ( foundStart && ( distanceTraversed + segmentLength > endDistance ) )
1034  {
1035  // end point falls on this segment
1036  const double distanceToEnd = endDistance - distanceTraversed;
1037  double endX, endY;
1038  double endZ = 0;
1039  double endM = 0;
1040  QgsGeometryUtils::pointOnLineWithDistance( prevX, prevY, thisX, thisY, distanceToEnd, endX, endY,
1041  z ? &prevZ : nullptr, z ? &thisZ : nullptr, z ? &endZ : nullptr,
1042  m ? &prevM : nullptr, m ? &thisM : nullptr, m ? &endM : nullptr );
1043  substringPoints << QgsPoint( pointType, endX, endY, endZ, endM );
1044  }
1045  else if ( foundStart )
1046  {
1047  substringPoints << QgsPoint( pointType, thisX, thisY, thisZ, thisM );
1048  }
1049 
1050  distanceTraversed += segmentLength;
1051  if ( distanceTraversed > endDistance )
1052  break;
1053 
1054  prevX = thisX;
1055  prevY = thisY;
1056  prevZ = thisZ;
1057  prevM = thisM;
1058  }
1059 
1060  return new QgsLineString( substringPoints );
1061 }
1062 
1063 /***************************************************************************
1064  * This class is considered CRITICAL and any change MUST be accompanied with
1065  * full unit tests.
1066  * See details in QEP #17
1067  ****************************************************************************/
1068 
1069 void QgsLineString::draw( QPainter &p ) const
1070 {
1071  p.drawPolyline( asQPolygonF() );
1072 }
1073 
1074 void QgsLineString::addToPainterPath( QPainterPath &path ) const
1075 {
1076  int nPoints = numPoints();
1077  if ( nPoints < 1 )
1078  {
1079  return;
1080  }
1081 
1082  if ( path.isEmpty() || path.currentPosition() != QPointF( mX.at( 0 ), mY.at( 0 ) ) )
1083  {
1084  path.moveTo( mX.at( 0 ), mY.at( 0 ) );
1085  }
1086 
1087  for ( int i = 1; i < nPoints; ++i )
1088  {
1089  path.lineTo( mX.at( i ), mY.at( i ) );
1090  }
1091 }
1092 
1093 void QgsLineString::drawAsPolygon( QPainter &p ) const
1094 {
1095  p.drawPolygon( asQPolygonF() );
1096 }
1097 
1099 {
1100  QgsCompoundCurve *compoundCurve = new QgsCompoundCurve();
1101  compoundCurve->addCurve( clone() );
1102  return compoundCurve;
1103 }
1104 
1105 void QgsLineString::extend( double startDistance, double endDistance )
1106 {
1107  if ( mX.size() < 2 || mY.size() < 2 )
1108  return;
1109 
1110  // start of line
1111  if ( startDistance > 0 )
1112  {
1113  double currentLen = std::sqrt( std::pow( mX.at( 0 ) - mX.at( 1 ), 2 ) +
1114  std::pow( mY.at( 0 ) - mY.at( 1 ), 2 ) );
1115  double newLen = currentLen + startDistance;
1116  mX[ 0 ] = mX.at( 1 ) + ( mX.at( 0 ) - mX.at( 1 ) ) / currentLen * newLen;
1117  mY[ 0 ] = mY.at( 1 ) + ( mY.at( 0 ) - mY.at( 1 ) ) / currentLen * newLen;
1118  }
1119  // end of line
1120  if ( endDistance > 0 )
1121  {
1122  int last = mX.size() - 1;
1123  double currentLen = std::sqrt( std::pow( mX.at( last ) - mX.at( last - 1 ), 2 ) +
1124  std::pow( mY.at( last ) - mY.at( last - 1 ), 2 ) );
1125  double newLen = currentLen + endDistance;
1126  mX[ last ] = mX.at( last - 1 ) + ( mX.at( last ) - mX.at( last - 1 ) ) / currentLen * newLen;
1127  mY[ last ] = mY.at( last - 1 ) + ( mY.at( last ) - mY.at( last - 1 ) ) / currentLen * newLen;
1128  }
1129 }
1130 
1132 {
1133  auto result = qgis::make_unique< QgsLineString >();
1134  result->mWkbType = mWkbType;
1135  return result.release();
1136 }
1137 
1139 {
1140  return QStringLiteral( "LineString" );
1141 }
1142 
1144 {
1145  return 1;
1146 }
1147 
1148 /***************************************************************************
1149  * This class is considered CRITICAL and any change MUST be accompanied with
1150  * full unit tests.
1151  * See details in QEP #17
1152  ****************************************************************************/
1153 
1155 {
1156  double *zArray = nullptr;
1157  bool hasZ = is3D();
1158  int nPoints = numPoints();
1159 
1160  // it's possible that transformCoords will throw an exception - so we need to use
1161  // a smart pointer for the dummy z values in order to ensure that they always get cleaned up
1162  std::unique_ptr< double[] > dummyZ;
1163  if ( !hasZ || !transformZ )
1164  {
1165  dummyZ.reset( new double[nPoints]() );
1166  zArray = dummyZ.get();
1167  }
1168  else
1169  {
1170  zArray = mZ.data();
1171  }
1172  ct.transformCoords( nPoints, mX.data(), mY.data(), zArray, d );
1173  clearCache();
1174 }
1175 
1176 void QgsLineString::transform( const QTransform &t, double zTranslate, double zScale, double mTranslate, double mScale )
1177 {
1178  int nPoints = numPoints();
1179  bool hasZ = is3D();
1180  bool hasM = isMeasure();
1181  double *x = mX.data();
1182  double *y = mY.data();
1183  double *z = hasZ ? mZ.data() : nullptr;
1184  double *m = hasM ? mM.data() : nullptr;
1185  for ( int i = 0; i < nPoints; ++i )
1186  {
1187  double xOut, yOut;
1188  t.map( *x, *y, &xOut, &yOut );
1189  *x++ = xOut;
1190  *y++ = yOut;
1191  if ( hasZ )
1192  {
1193  *z = *z * zScale + zTranslate;
1194  z++;
1195  }
1196  if ( hasM )
1197  {
1198  *m = *m * mScale + mTranslate;
1199  m++;
1200  }
1201  }
1202  clearCache();
1203 }
1204 
1205 /***************************************************************************
1206  * This class is considered CRITICAL and any change MUST be accompanied with
1207  * full unit tests.
1208  * See details in QEP #17
1209  ****************************************************************************/
1210 
1211 bool QgsLineString::insertVertex( QgsVertexId position, const QgsPoint &vertex )
1212 {
1213  if ( position.vertex < 0 || position.vertex > mX.size() )
1214  {
1215  return false;
1216  }
1217 
1218  if ( mWkbType == QgsWkbTypes::Unknown || mX.isEmpty() )
1219  {
1221  }
1222 
1223  mX.insert( position.vertex, vertex.x() );
1224  mY.insert( position.vertex, vertex.y() );
1225  if ( is3D() )
1226  {
1227  mZ.insert( position.vertex, vertex.z() );
1228  }
1229  if ( isMeasure() )
1230  {
1231  mM.insert( position.vertex, vertex.m() );
1232  }
1233  clearCache(); //set bounding box invalid
1234  return true;
1235 }
1236 
1237 bool QgsLineString::moveVertex( QgsVertexId position, const QgsPoint &newPos )
1238 {
1239  if ( position.vertex < 0 || position.vertex >= mX.size() )
1240  {
1241  return false;
1242  }
1243  mX[position.vertex] = newPos.x();
1244  mY[position.vertex] = newPos.y();
1245  if ( is3D() && newPos.is3D() )
1246  {
1247  mZ[position.vertex] = newPos.z();
1248  }
1249  if ( isMeasure() && newPos.isMeasure() )
1250  {
1251  mM[position.vertex] = newPos.m();
1252  }
1253  clearCache(); //set bounding box invalid
1254  return true;
1255 }
1256 
1258 {
1259  if ( position.vertex >= mX.size() || position.vertex < 0 )
1260  {
1261  return false;
1262  }
1263 
1264  mX.remove( position.vertex );
1265  mY.remove( position.vertex );
1266  if ( is3D() )
1267  {
1268  mZ.remove( position.vertex );
1269  }
1270  if ( isMeasure() )
1271  {
1272  mM.remove( position.vertex );
1273  }
1274 
1275  if ( numPoints() == 1 )
1276  {
1277  clear();
1278  }
1279 
1280  clearCache(); //set bounding box invalid
1281  return true;
1282 }
1283 
1284 /***************************************************************************
1285  * This class is considered CRITICAL and any change MUST be accompanied with
1286  * full unit tests.
1287  * See details in QEP #17
1288  ****************************************************************************/
1289 
1291 {
1292  if ( mWkbType == QgsWkbTypes::Unknown || mX.isEmpty() )
1293  {
1295  }
1296 
1297  mX.append( pt.x() );
1298  mY.append( pt.y() );
1299  if ( is3D() )
1300  {
1301  mZ.append( pt.z() );
1302  }
1303  if ( isMeasure() )
1304  {
1305  mM.append( pt.m() );
1306  }
1307  clearCache(); //set bounding box invalid
1308 }
1309 
1310 double QgsLineString::closestSegment( const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf, double epsilon ) const
1311 {
1312  double sqrDist = std::numeric_limits<double>::max();
1313  double leftOfDist = std::numeric_limits<double>::max();
1314  int prevLeftOf = 0;
1315  double prevLeftOfX = 0.0;
1316  double prevLeftOfY = 0.0;
1317  double testDist = 0;
1318  double segmentPtX, segmentPtY;
1319 
1320  if ( leftOf )
1321  *leftOf = 0;
1322 
1323  int size = mX.size();
1324  if ( size == 0 || size == 1 )
1325  {
1326  vertexAfter = QgsVertexId( 0, 0, 0 );
1327  return -1;
1328  }
1329  for ( int i = 1; i < size; ++i )
1330  {
1331  double prevX = mX.at( i - 1 );
1332  double prevY = mY.at( i - 1 );
1333  double currentX = mX.at( i );
1334  double currentY = mY.at( i );
1335  testDist = QgsGeometryUtils::sqrDistToLine( pt.x(), pt.y(), prevX, prevY, currentX, currentY, segmentPtX, segmentPtY, epsilon );
1336  if ( testDist < sqrDist )
1337  {
1338  sqrDist = testDist;
1339  segmentPt.setX( segmentPtX );
1340  segmentPt.setY( segmentPtY );
1341  vertexAfter.part = 0;
1342  vertexAfter.ring = 0;
1343  vertexAfter.vertex = i;
1344  }
1345  if ( leftOf && qgsDoubleNear( testDist, sqrDist ) )
1346  {
1347  int left = QgsGeometryUtils::leftOfLine( pt.x(), pt.y(), prevX, prevY, currentX, currentY );
1348  // if left equals 0, the test could not be performed (e.g. point in line with segment or on segment)
1349  // so don't set leftOf in this case, and hope that there's another segment that's the same distance
1350  // where we can perform the check
1351  if ( left != 0 )
1352  {
1353  if ( qgsDoubleNear( testDist, leftOfDist ) && left != prevLeftOf && prevLeftOf != 0 )
1354  {
1355  // we have two possible segments each with equal distance to point, but they disagree
1356  // on whether or not the point is to the left of them.
1357  // so we test the segments themselves and flip the result.
1358  // see https://stackoverflow.com/questions/10583212/elegant-left-of-test-for-polyline
1359  *leftOf = -QgsGeometryUtils::leftOfLine( currentX, currentY, prevLeftOfX, prevLeftOfY, prevX, prevY );
1360  }
1361  else
1362  {
1363  *leftOf = left;
1364  }
1365  prevLeftOf = *leftOf;
1366  leftOfDist = testDist;
1367  prevLeftOfX = prevX;
1368  prevLeftOfY = prevY;
1369  }
1370  else if ( testDist < leftOfDist )
1371  {
1372  *leftOf = left;
1373  leftOfDist = testDist;
1374  prevLeftOf = 0;
1375  }
1376  }
1377  }
1378  return sqrDist;
1379 }
1380 
1381 /***************************************************************************
1382  * This class is considered CRITICAL and any change MUST be accompanied with
1383  * full unit tests.
1384  * See details in QEP #17
1385  ****************************************************************************/
1386 
1387 bool QgsLineString::pointAt( int node, QgsPoint &point, QgsVertexId::VertexType &type ) const
1388 {
1389  if ( node < 0 || node >= numPoints() )
1390  {
1391  return false;
1392  }
1393  point = pointN( node );
1395  return true;
1396 }
1397 
1399 {
1400  if ( mX.isEmpty() )
1401  return QgsPoint();
1402 
1403  int numPoints = mX.count();
1404  if ( numPoints == 1 )
1405  return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
1406 
1407  double totalLineLength = 0.0;
1408  double prevX = mX.at( 0 );
1409  double prevY = mY.at( 0 );
1410  double sumX = 0.0;
1411  double sumY = 0.0;
1412 
1413  for ( int i = 1; i < numPoints ; ++i )
1414  {
1415  double currentX = mX.at( i );
1416  double currentY = mY.at( i );
1417  double segmentLength = std::sqrt( std::pow( currentX - prevX, 2.0 ) +
1418  std::pow( currentY - prevY, 2.0 ) );
1419  if ( qgsDoubleNear( segmentLength, 0.0 ) )
1420  continue;
1421 
1422  totalLineLength += segmentLength;
1423  sumX += segmentLength * 0.5 * ( currentX + prevX );
1424  sumY += segmentLength * 0.5 * ( currentY + prevY );
1425  prevX = currentX;
1426  prevY = currentY;
1427  }
1428 
1429  if ( qgsDoubleNear( totalLineLength, 0.0 ) )
1430  return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
1431  else
1432  return QgsPoint( sumX / totalLineLength, sumY / totalLineLength );
1433 
1434 }
1435 
1436 /***************************************************************************
1437  * This class is considered CRITICAL and any change MUST be accompanied with
1438  * full unit tests.
1439  * See details in QEP #17
1440  ****************************************************************************/
1441 
1442 void QgsLineString::sumUpArea( double &sum ) const
1443 {
1444  int maxIndex = numPoints() - 1;
1445 
1446  for ( int i = 0; i < maxIndex; ++i )
1447  {
1448  sum += 0.5 * ( mX.at( i ) * mY.at( i + 1 ) - mY.at( i ) * mX.at( i + 1 ) );
1449  }
1450 }
1451 
1452 void QgsLineString::importVerticesFromWkb( const QgsConstWkbPtr &wkb )
1453 {
1454  bool hasZ = is3D();
1455  bool hasM = isMeasure();
1456  int nVertices = 0;
1457  wkb >> nVertices;
1458  mX.resize( nVertices );
1459  mY.resize( nVertices );
1460  hasZ ? mZ.resize( nVertices ) : mZ.clear();
1461  hasM ? mM.resize( nVertices ) : mM.clear();
1462  double *x = mX.data();
1463  double *y = mY.data();
1464  double *m = hasM ? mM.data() : nullptr;
1465  double *z = hasZ ? mZ.data() : nullptr;
1466  for ( int i = 0; i < nVertices; ++i )
1467  {
1468  wkb >> *x++;
1469  wkb >> *y++;
1470  if ( hasZ )
1471  {
1472  wkb >> *z++;
1473  }
1474  if ( hasM )
1475  {
1476  wkb >> *m++;
1477  }
1478  }
1479  clearCache(); //set bounding box invalid
1480 }
1481 
1482 /***************************************************************************
1483  * This class is considered CRITICAL and any change MUST be accompanied with
1484  * full unit tests.
1485  * See details in QEP #17
1486  ****************************************************************************/
1487 
1489 {
1490  if ( numPoints() < 1 || isClosed() )
1491  {
1492  return;
1493  }
1494  addVertex( startPoint() );
1495 }
1496 
1498 {
1499  if ( mX.count() < 2 )
1500  {
1501  //undefined
1502  return 0.0;
1503  }
1504 
1505  if ( vertex.vertex == 0 || vertex.vertex >= ( numPoints() - 1 ) )
1506  {
1507  if ( isClosed() )
1508  {
1509  double previousX = mX.at( numPoints() - 2 );
1510  double previousY = mY.at( numPoints() - 2 );
1511  double currentX = mX.at( 0 );
1512  double currentY = mY.at( 0 );
1513  double afterX = mX.at( 1 );
1514  double afterY = mY.at( 1 );
1515  return QgsGeometryUtils::averageAngle( previousX, previousY, currentX, currentY, afterX, afterY );
1516  }
1517  else if ( vertex.vertex == 0 )
1518  {
1519  return QgsGeometryUtils::lineAngle( mX.at( 0 ), mY.at( 0 ), mX.at( 1 ), mY.at( 1 ) );
1520  }
1521  else
1522  {
1523  int a = numPoints() - 2;
1524  int b = numPoints() - 1;
1525  return QgsGeometryUtils::lineAngle( mX.at( a ), mY.at( a ), mX.at( b ), mY.at( b ) );
1526  }
1527  }
1528  else
1529  {
1530  double previousX = mX.at( vertex.vertex - 1 );
1531  double previousY = mY.at( vertex.vertex - 1 );
1532  double currentX = mX.at( vertex.vertex );
1533  double currentY = mY.at( vertex.vertex );
1534  double afterX = mX.at( vertex.vertex + 1 );
1535  double afterY = mY.at( vertex.vertex + 1 );
1536  return QgsGeometryUtils::averageAngle( previousX, previousY, currentX, currentY, afterX, afterY );
1537  }
1538 }
1539 
1540 double QgsLineString::segmentLength( QgsVertexId startVertex ) const
1541 {
1542  if ( startVertex.vertex < 0 || startVertex.vertex >= mX.count() - 1 )
1543  return 0.0;
1544 
1545  double dx = mX.at( startVertex.vertex + 1 ) - mX.at( startVertex.vertex );
1546  double dy = mY.at( startVertex.vertex + 1 ) - mY.at( startVertex.vertex );
1547  return std::sqrt( dx * dx + dy * dy );
1548 }
1549 
1550 /***************************************************************************
1551  * This class is considered CRITICAL and any change MUST be accompanied with
1552  * full unit tests.
1553  * See details in QEP #17
1554  ****************************************************************************/
1555 
1556 bool QgsLineString::addZValue( double zValue )
1557 {
1558  if ( QgsWkbTypes::hasZ( mWkbType ) )
1559  return false;
1560 
1561  clearCache();
1562  if ( mWkbType == QgsWkbTypes::Unknown )
1563  {
1565  return true;
1566  }
1567 
1569 
1570  mZ.clear();
1571  int nPoints = numPoints();
1572  mZ.reserve( nPoints );
1573  for ( int i = 0; i < nPoints; ++i )
1574  {
1575  mZ << zValue;
1576  }
1577  return true;
1578 }
1579 
1580 bool QgsLineString::addMValue( double mValue )
1581 {
1582  if ( QgsWkbTypes::hasM( mWkbType ) )
1583  return false;
1584 
1585  clearCache();
1586  if ( mWkbType == QgsWkbTypes::Unknown )
1587  {
1589  return true;
1590  }
1591 
1593  {
1595  }
1596  else
1597  {
1599  }
1600 
1601  mM.clear();
1602  int nPoints = numPoints();
1603  mM.reserve( nPoints );
1604  for ( int i = 0; i < nPoints; ++i )
1605  {
1606  mM << mValue;
1607  }
1608  return true;
1609 }
1610 
1612 {
1613  if ( !is3D() )
1614  return false;
1615 
1616  clearCache();
1618  mZ.clear();
1619  return true;
1620 }
1621 
1623 {
1624  if ( !isMeasure() )
1625  return false;
1626 
1627  clearCache();
1629  mM.clear();
1630  return true;
1631 }
1632 
1634 {
1635  std::swap( mX, mY );
1636  clearCache();
1637 }
1638 
1640 {
1641  if ( type == mWkbType )
1642  return true;
1643 
1644  clearCache();
1645  if ( type == QgsWkbTypes::LineString25D )
1646  {
1647  //special handling required for conversion to LineString25D
1648  dropMValue();
1649  addZValue( std::numeric_limits<double>::quiet_NaN() );
1651  return true;
1652  }
1653  else
1654  {
1655  return QgsCurve::convertTo( type );
1656  }
1657 }
1658 
1659 void QgsLineString::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
1660 {
1661  bool hasZ = is3D();
1662  bool hasM = isMeasure();
1663  int size = mX.size();
1664 
1665  double *srcX = mX.data();
1666  double *srcY = mY.data();
1667  double *srcM = hasM ? mM.data() : nullptr;
1668  double *srcZ = hasZ ? mZ.data() : nullptr;
1669 
1670  double *destX = srcX;
1671  double *destY = srcY;
1672  double *destM = srcM;
1673  double *destZ = srcZ;
1674 
1675  int filteredPoints = 0;
1676  for ( int i = 0; i < size; ++i )
1677  {
1678  double x = *srcX++;
1679  double y = *srcY++;
1680  double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
1681  double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
1682 
1683  if ( filter( QgsPoint( x, y, z, m ) ) )
1684  {
1685  filteredPoints++;
1686  *destX++ = x;
1687  *destY++ = y;
1688  if ( hasM )
1689  *destM++ = m;
1690  if ( hasZ )
1691  *destZ++ = z;
1692  }
1693  }
1694 
1695  mX.resize( filteredPoints );
1696  mY.resize( filteredPoints );
1697  if ( hasZ )
1698  mZ.resize( filteredPoints );
1699  if ( hasM )
1700  mM.resize( filteredPoints );
1701 
1702  clearCache();
1703 }
1704 
1705 void QgsLineString::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
1706 {
1707  bool hasZ = is3D();
1708  bool hasM = isMeasure();
1709  int size = mX.size();
1710 
1711  double *srcX = mX.data();
1712  double *srcY = mY.data();
1713  double *srcM = hasM ? mM.data() : nullptr;
1714  double *srcZ = hasZ ? mZ.data() : nullptr;
1715 
1716  for ( int i = 0; i < size; ++i )
1717  {
1718  double x = *srcX;
1719  double y = *srcY;
1720  double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
1721  double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
1722  QgsPoint res = transform( QgsPoint( x, y, z, m ) );
1723  *srcX++ = res.x();
1724  *srcY++ = res.y();
1725  if ( hasM )
1726  *srcM++ = res.m();
1727  if ( hasZ )
1728  *srcZ++ = res.z();
1729  }
1730  clearCache();
1731 }
QgsCurve
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
QgsVertexId::part
int part
Definition: qgsabstractgeometry.h:1080
QgsLineSegment2D::endX
double endX() const
Returns the segment's end x-coordinate.
Definition: qgslinesegment.h:97
QgsLineString::transform
void transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) override SIP_THROW(QgsCsException)
Transforms the geometry using a coordinate transform.
Definition: qgslinestring.cpp:1154
QgsPoint::setY
void setY(double y)
Sets the point's y-coordinate.
Definition: qgspoint.h:298
QgsLineString::pointN
QgsPoint pointN(int i) const
Returns the specified point from inside the line string.
Definition: qgslinestring.cpp:660
QgsLineString::setYAt
void setYAt(int index, double y)
Sets the y-coordinate of the specified node in the line string.
Definition: qgslinestring.cpp:732
QgsVertexId::vertex
int vertex
Definition: qgsabstractgeometry.h:1082
QgsLineString::xAt
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
Definition: qgslinestring.cpp:709
QgsLineString::zData
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the linestring does not have z values.
Definition: qgslinestring.h:241
QgsAbstractGeometry::wkbType
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
Definition: qgsabstractgeometry.h:189
QgsLineString::setPoints
void setPoints(const QgsPointSequence &points)
Resets the line string to match the specified list of points.
Definition: qgslinestring.cpp:756
QgsWkbTypes::Point
@ Point
Definition: qgswkbtypes.h:71
QgsGeometryUtils::pointsToJson
static json pointsToJson(const QgsPointSequence &points, int precision)
Returns coordinates as json object.
Definition: qgsgeometryutils.cpp:1268
QgsVertexId::SegmentVertex
@ SegmentVertex
Definition: qgsabstractgeometry.h:1037
QgsLineSegment2D
Definition: qgslinesegment.h:31
QgsLineString::asWkt
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
Definition: qgslinestring.cpp:466
qgslinestring.h
QgsLineString::addMValue
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
Definition: qgslinestring.cpp:1580
QgsWkbTypes::Point25D
@ Point25D
Definition: qgswkbtypes.h:124
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
QgsWkbTypes::LineString25D
@ LineString25D
Definition: qgswkbtypes.h:125
QgsGeometryUtils::pointOnLineWithDistance
static QgsPoint pointOnLineWithDistance(const QgsPoint &startPoint, const QgsPoint &directionPoint, double distance)
Returns a point a specified distance toward a second point.
Definition: qgsgeometryutils.cpp:600
qgswkbptr.h
QgsLineString::asGml2
QDomElement asGml2(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML2 representation of the geometry.
Definition: qgslinestring.cpp:481
qgsmaptopixel.h
QgsLineString::dimension
int dimension() const override
Returns the inherent dimension of the geometry.
Definition: qgslinestring.cpp:1143
QgsLineString::numPoints
int numPoints() const override
Returns the number of points in the curve.
Definition: qgslinestring.cpp:650
QgsLineString::addToPainterPath
void addToPainterPath(QPainterPath &path) const override
Adds a curve to a painter path.
Definition: qgslinestring.cpp:1074
QgsLineString::yAt
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
Definition: qgslinestring.cpp:717
qgscompoundcurve.h
QgsAbstractGeometry::parts
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts of the geometry.
Definition: qgsabstractgeometry.cpp:266
QgsLineString::centroid
QgsPoint centroid() const override
Returns the centroid of the geometry.
Definition: qgslinestring.cpp:1398
QgsCoordinateTransform::TransformDirection
TransformDirection
Enum used to indicate the direction (forward or inverse) of the transform.
Definition: qgscoordinatetransform.h:58
QgsWkbTypes::LineString
@ LineString
Definition: qgswkbtypes.h:72
QgsCompoundCurve::addCurve
void addCurve(QgsCurve *c)
Adds a curve to the geometry (takes ownership)
Definition: qgscompoundcurve.cpp:457
QgsLineString::endPoint
QgsPoint endPoint() const override
Returns the end point of the curve.
Definition: qgslinestring.cpp:628
QgsLineString::snappedToGrid
QgsLineString * snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0) const override
Makes a new geometry with all the points or vertices snapped to the closest point of the grid.
Definition: qgslinestring.cpp:313
QgsLineString::curveToLine
QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a new line string geometry corresponding to a segmentized approximation of the curve.
Definition: qgslinestring.cpp:643
QgsAbstractGeometry::wktTypeStr
QString wktTypeStr() const
Returns the WKT type string of the geometry.
Definition: qgsabstractgeometry.cpp:147
QgsWkbTypes::LineStringM
@ LineStringM
Definition: qgswkbtypes.h:99
QgsPoint::z
double z
Definition: qgspoint.h:60
QgsLineString::drawAsPolygon
void drawAsPolygon(QPainter &p) const override
Draws the curve as a polygon on the specified QPainter.
Definition: qgslinestring.cpp:1093
QgsLineString::yData
const double * yData() const
Returns a const pointer to the y vertex data.
Definition: qgslinestring.h:228
QgsLineString::nCoordinates
int nCoordinates() const override
Returns the number of nodes contained in the geometry.
Definition: qgslinestring.cpp:655
QgsLineString::segmentLength
double segmentLength(QgsVertexId startVertex) const override
Returns the length of the segment of the geometry which begins at startVertex.
Definition: qgslinestring.cpp:1540
QgsWkbTypes::LineStringZ
@ LineStringZ
Definition: qgswkbtypes.h:86
QgsLineString::setXAt
void setXAt(int index, double x)
Sets the x-coordinate of the specified node in the line string.
Definition: qgslinestring.cpp:725
QgsWkbTypes::Type
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
QgsWkbTypes::hasZ
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:1042
QgsAbstractGeometry::SegmentationToleranceType
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
Definition: qgsabstractgeometry.h:112
QgsAbstractGeometry::mWkbType
QgsWkbTypes::Type mWkbType
Definition: qgsabstractgeometry.h:1005
QgsWkbTypes::dropM
static Type dropM(Type type)
Drops the m dimension (if present) for a WKB type and returns the new type.
Definition: qgswkbtypes.h:1212
QgsLineString
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:43
QgsWkbTypes::addM
static Type addM(Type type)
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1163
QgsLineString::draw
void draw(QPainter &p) const override
Draws the geometry using the specified QPainter.
Definition: qgslinestring.cpp:1069
QgsLineString::addZValue
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
Definition: qgslinestring.cpp:1556
QgsLineString::toCurveType
QgsCompoundCurve * toCurveType() const override
Returns the geometry converted to the more generic curve type QgsCompoundCurve.
Definition: qgslinestring.cpp:1098
QgsGeometryUtils::pointsFromWKT
static QgsPointSequence pointsFromWKT(const QString &wktCoordinateList, bool is3D, bool isMeasure)
Returns a list of points contained in a WKT string.
Definition: qgsgeometryutils.cpp:1099
QgsRectangle
Definition: qgsrectangle.h:41
qgslinesegment.h
QgsLineString::xData
const double * xData() const
Returns a const pointer to the x vertex data.
Definition: qgslinestring.h:217
qgsDoubleToString
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:275
QgsCurve::clearCache
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
Definition: qgscurve.cpp:256
qgsapplication.h
QgsLineString::fromBezierCurve
static QgsLineString * fromBezierCurve(const QgsPoint &start, const QgsPoint &controlPoint1, const QgsPoint &controlPoint2, const QgsPoint &end, int segments=30)
Returns a new linestring created by segmentizing the bezier curve between start and end,...
Definition: qgslinestring.cpp:184
QgsWkbTypes::PointM
@ PointM
Definition: qgswkbtypes.h:98
QgsLineSegment2D::startY
double startY() const
Returns the segment's start y-coordinate.
Definition: qgslinesegment.h:87
MathUtils::leftOf
double ANALYSIS_EXPORT leftOf(const QgsPoint &thepoint, const QgsPoint *p1, const QgsPoint *p2)
Returns whether 'thepoint' is left or right of the line from 'p1' to 'p2'. Negative values mean left ...
Definition: MathUtils.cpp:292
QgsPoint::y
double y
Definition: qgspoint.h:59
precision
int precision
Definition: qgswfsgetfeature.cpp:103
QgsWkbTypes::PointZM
@ PointZM
Definition: qgswkbtypes.h:111
QgsLineString::clone
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
Definition: qgslinestring.cpp:293
QgsLineString::asKml
QString asKml(int precision=17) const override
Returns a KML representation of the geometry.
Definition: qgslinestring.cpp:521
QgsLineString::geometryType
QString geometryType() const override
Returns a unique string representing the geometry type.
Definition: qgslinestring.cpp:1138
QgsLineString::pointAt
bool pointAt(int node, QgsPoint &point, QgsVertexId::VertexType &type) const override
Returns the point and vertex id of a point within the curve.
Definition: qgslinestring.cpp:1387
QgsWkbTypes::Unknown
@ Unknown
Definition: qgswkbtypes.h:70
QgsAbstractGeometry::AxisOrder
AxisOrder
Axis order for GML generation.
Definition: qgsabstractgeometry.h:128
QgsLineString::convertTo
bool convertTo(QgsWkbTypes::Type type) override
Converts the geometry to a specified type.
Definition: qgslinestring.cpp:1639
QgsLineString::insertVertex
bool insertVertex(QgsVertexId position, const QgsPoint &vertex) override
Inserts a vertex into the geometry.
Definition: qgslinestring.cpp:1211
QgsGeometryUtils::pointsToWKB
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
Definition: qgsgeometryutils.cpp:1167
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:315
QgsPoint::setX
void setX(double x)
Sets the point's x-coordinate.
Definition: qgspoint.h:287
QgsConstWkbPtr
Definition: qgswkbptr.h:127
QgsLineString::transformVertices
void transformVertices(const std::function< QgsPoint(const QgsPoint &) > &transform) override
Transforms the vertices from the geometry in place, applying the transform function to every vertex.
Definition: qgslinestring.cpp:1705
QgsLineString::moveVertex
bool moveVertex(QgsVertexId position, const QgsPoint &newPos) override
Moves a vertex within the geometry.
Definition: qgslinestring.cpp:1237
QgsLineString::asQPolygonF
QPolygonF asQPolygonF() const override
Returns a QPolygonF representing the points.
Definition: qgslinestring.cpp:366
QgsLineString::asWkb
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Definition: qgslinestring.cpp:444
QgsCurve::isRing
virtual bool isRing() const
Returns true if the curve is a ring.
Definition: qgscurve.cpp:56
QgsGeometryUtils::averageAngle
static double averageAngle(double x1, double y1, double x2, double y2, double x3, double y3)
Calculates the average angle (in radians) between the two linear segments from (x1,...
Definition: qgsgeometryutils.cpp:1506
QgsLineString::asJsonObject
json asJsonObject(int precision=17) const override
Returns a json object representation of the geometry.
Definition: qgslinestring.cpp:510
QgsLineString::fromQPolygonF
static QgsLineString * fromQPolygonF(const QPolygonF &polygon)
Returns a new linestring from a QPolygonF polygon input.
Definition: qgslinestring.cpp:245
QgsLineString::asGml3
QDomElement asGml3(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML3 representation of the geometry.
Definition: qgslinestring.cpp:496
QgsWkbTypes::LineStringZM
@ LineStringZM
Definition: qgswkbtypes.h:112
QgsWkbTypes::PointZ
@ PointZ
Definition: qgswkbtypes.h:85
QgsApplication::endian
static endian_t endian()
Returns whether this machine uses big or little endian.
Definition: qgsapplication.cpp:1230
QgsPoint::m
double m
Definition: qgspoint.h:61
QgsLineString::QgsLineString
QgsLineString()
Definition: qgslinestring.cpp:42
qgscoordinatetransform.h
QgsLineString::clear
void clear() override
Clears the geometry, ie reset it to a null geometry.
Definition: qgslinestring.cpp:298
QgsAbstractGeometry::is3D
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
Definition: qgsabstractgeometry.h:202
QgsGeometryUtils::sqrDistToLine
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.
Definition: qgsgeometryutils.cpp:203
QgsWkbPtr
Definition: qgswkbptr.h:42
QgsCurve::snapToGridPrivate
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:279
QgsCoordinateTransform::transformCoords
void transformCoords(int numPoint, double *x, double *y, double *z, TransformDirection direction=ForwardTransform) const SIP_THROW(QgsCsException)
Transform an array of coordinates to the destination CRS.
Definition: qgscoordinatetransform.cpp:630
QgsLineString::mData
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the linestring does not have m values.
Definition: qgslinestring.h:257
QgsLineString::sumUpArea
void sumUpArea(double &sum) const override
Sums up the area of the curve by iterating over the vertices (shoelace formula).
Definition: qgslinestring.cpp:1442
QgsLineString::startPoint
QgsPoint startPoint() const override
Returns the starting point of the curve.
Definition: qgslinestring.cpp:619
QgsLineString::interpolatePoint
QgsPoint * interpolatePoint(double distance) const override
Returns an interpolated point on the curve at the specified distance.
Definition: qgslinestring.cpp:953
qgsgeometryutils.h
QgsLineString::curveSubstring
QgsLineString * curveSubstring(double startDistance, double endDistance) const override
Returns a new curve representing a substring of this curve.
Definition: qgslinestring.cpp:973
QgsLineString::extend
void extend(double startDistance, double endDistance)
Extends the line geometry by extrapolating out the start or end of the line by a specified distance.
Definition: qgslinestring.cpp:1105
QgsWkbTypes::addZ
static Type addZ(Type type)
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1138
QgsPointXY
Definition: qgspointxy.h:43
QgsLineString::dropMValue
bool dropMValue() override
Drops any measure values which exist in the geometry.
Definition: qgslinestring.cpp:1622
QgsWkbTypes::zmType
static Type zmType(Type type, bool hasZ, bool hasM)
Returns the modified input geometry type according to hasZ / hasM.
Definition: qgswkbtypes.h:800
QgsLineString::isEmpty
bool isEmpty() const override
Returns true if the geometry is empty.
Definition: qgslinestring.cpp:308
QgsGeometryUtils::pointsToGML3
static QDomElement pointsToGML3(const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, bool is3D, QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY)
Returns a gml::posList DOM element.
Definition: qgsgeometryutils.cpp:1230
QgsLineString::fromWkt
bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
Definition: qgslinestring.cpp:427
QgsWkbTypes::hasM
static bool hasM(Type type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1092
QgsLineString::append
void append(const QgsLineString *line)
Appends the contents of another line string to the end of this line string.
Definition: qgslinestring.cpp:815
QgsCurve::isClosed
virtual bool isClosed() const
Returns true if the curve is closed.
Definition: qgscurve.cpp:40
QgsLineString::swapXy
void swapXy() override
Swaps the x and y coordinates from the geometry.
Definition: qgslinestring.cpp:1633
QgsPointSequence
QVector< QgsPoint > QgsPointSequence
Definition: qgsabstractgeometry.h:44
QgsLineString::close
void close()
Closes the line string by appending the first point to the end of the line, if it is not already clos...
Definition: qgslinestring.cpp:1488
QgsLineString::addVertex
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
Definition: qgslinestring.cpp:1290
QgsGeometryUtils::pointsToWKT
static QString pointsToWKT(const QgsPointSequence &points, int precision, bool is3D, bool isMeasure)
Returns a WKT coordinate list.
Definition: qgsgeometryutils.cpp:1184
QgsLineString::filterVertices
void filterVertices(const std::function< bool(const QgsPoint &) > &filter) override
Filters the vertices from the geometry in place, removing any which do not return true for the filter...
Definition: qgslinestring.cpp:1659
QgsVertexId
Utility class for identifying a unique vertex within a geometry.
Definition: qgsabstractgeometry.h:1033
QgsGeometryUtils::pointsToGML2
static QDomElement pointsToGML2(const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY)
Returns a gml::coordinates DOM element.
Definition: qgsgeometryutils.cpp:1203
QgsGeometryUtils::leftOfLine
static int leftOfLine(const double x, const double y, const double x1, const double y1, const double x2, const double y2)
Returns a value < 0 if the point (x, y) is left of the line from (x1, y1) -> (x2, y2).
Definition: qgsgeometryutils.cpp:589
QgsLineString::deleteVertex
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
Definition: qgslinestring.cpp:1257
QgsVertexId::ring
int ring
Definition: qgsabstractgeometry.h:1081
QgsAbstractGeometry::isMeasure
bool isMeasure() const
Returns true if the geometry contains m values.
Definition: qgsabstractgeometry.h:211
QgsVertexId::VertexType
VertexType
Definition: qgsabstractgeometry.h:1035
QgsLineString::calculateBoundingBox
QgsRectangle calculateBoundingBox() const override
Default calculator for the minimal bounding box for the geometry.
Definition: qgslinestring.cpp:398
QgsLineString::fromWkb
bool fromWkb(QgsConstWkbPtr &wkb) override
Sets the geometry from a WKB string.
Definition: qgslinestring.cpp:381
QgsAbstractGeometry::convertTo
virtual bool convertTo(QgsWkbTypes::Type type)
Converts the geometry to a specified type.
Definition: qgsabstractgeometry.cpp:219
QgsLineSegment2D::endY
double endY() const
Returns the segment's end y-coordinate.
Definition: qgslinesegment.h:107
QgsLineSegment2D::startX
double startX() const
Returns the segment's start x-coordinate.
Definition: qgslinesegment.h:77
QgsLineString::equals
bool equals(const QgsCurve &other) const override
Checks whether this curve exactly equals another curve.
Definition: qgslinestring.cpp:265
QgsWkbTypes::dropZ
static Type dropZ(Type type)
Drops the z dimension (if present) for a WKB type and returns the new type.
Definition: qgswkbtypes.h:1194
QgsConstWkbPtr::readHeader
QgsWkbTypes::Type readHeader() const
readHeader
Definition: qgswkbptr.cpp:54
QgsLineString::reversed
QgsLineString * reversed() const override
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
Definition: qgslinestring.cpp:877
QgsGeometryUtils::wktReadBlock
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 (...
Definition: qgsgeometryutils.cpp:1299
QgsAbstractGeometry::setZMTypeFromSubGeometry
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, QgsWkbTypes::Type baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
Definition: qgsabstractgeometry.cpp:43
QgsLineString::closestSegment
double closestSegment(const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf=nullptr, double epsilon=4 *std::numeric_limits< double >::epsilon()) const override
Searches for the closest segment of the geometry to a given point.
Definition: qgslinestring.cpp:1310
QgsLineString::points
void points(QgsPointSequence &pt) const override
Returns a list of points within the curve.
Definition: qgslinestring.cpp:745
QgsCoordinateTransform
Definition: qgscoordinatetransform.h:52
QgsLineString::removeDuplicateNodes
bool removeDuplicateNodes(double epsilon=4 *std::numeric_limits< double >::epsilon(), bool useZValues=false) override
Removes duplicate nodes from the geometry, wherever removing the nodes does not result in a degenerat...
Definition: qgslinestring.cpp:326
QgsLineString::length
double length() const override
Returns the planar, 2-dimensional length of the geometry.
Definition: qgslinestring.cpp:583
QgsLineString::createEmptyWithSameType
QgsLineString * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
Definition: qgslinestring.cpp:1131
QgsLineString::length3D
double length3D() const
Returns the length in 3D world of the line string.
Definition: qgslinestring.cpp:597
QgsPoint::x
double x
Definition: qgspoint.h:58
QgsLineString::vertexAngle
double vertexAngle(QgsVertexId vertex) const override
Returns approximate angle at a vertex.
Definition: qgslinestring.cpp:1497
QgsGeometryUtils::lineAngle
static double lineAngle(double x1, double y1, double x2, double y2)
Calculates the direction of line joining two points in radians, clockwise from the north direction.
Definition: qgsgeometryutils.cpp:1485
QgsWkbTypes::flatType
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:701
QgsCompoundCurve
Compound curve geometry type.
Definition: qgscompoundcurve.h:31
QgsLineString::visitPointsByRegularDistance
void visitPointsByRegularDistance(double distance, const std::function< bool(double x, double y, double z, double m, double startSegmentX, double startSegmentY, double startSegmentZ, double startSegmentM, double endSegmentX, double endSegmentY, double endSegmentZ, double endSegmentM) > &visitPoint) const
Visits regular points along the linestring, spaced by distance.
Definition: qgslinestring.cpp:893
QgsLineString::dropZValue
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
Definition: qgslinestring.cpp:1611