QGIS API Documentation  3.37.0-Master (a5b4d9743e8)
qgslinestring.h
Go to the documentation of this file.
1 /***************************************************************************
2  qgslinestring.h
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 #ifndef QGSLINESTRING_H
19 #define QGSLINESTRING_H
20 
21 
22 #include <QPolygonF>
23 
24 #include "qgis_core.h"
25 #include "qgis_sip.h"
26 #include "qgscurve.h"
27 #include "qgscompoundcurve.h"
28 #include "qgsgeometryutils_base.h"
29 
30 class QgsLineSegment2D;
31 class QgsBox3D;
32 
33 /***************************************************************************
34  * This class is considered CRITICAL and any change MUST be accompanied with
35  * full unit tests in testqgsgeometry.cpp.
36  * See details in QEP #17
37  ****************************************************************************/
38 
44 class CORE_EXPORT QgsLineString: public QgsCurve
45 {
46 
47  public:
48 
53 #ifndef SIP_RUN
54 
60  QgsLineString( const QVector<QgsPoint> &points );
61 
67  QgsLineString( const QVector<QgsPointXY> &points );
68 #else
69 
77  QgsLineString( SIP_PYOBJECT points SIP_TYPEHINT( Sequence[Union[QgsPoint, QgsPointXY, Sequence[float]]] ) ) SIP_HOLDGIL [( const QVector<double> &x, const QVector<double> &y, const QVector<double> &z = QVector<double>(), const QVector<double> &m = QVector<double>(), bool is25DType = false )];
78  % MethodCode
79  if ( !PySequence_Check( a0 ) )
80  {
81  PyErr_SetString( PyExc_TypeError, QStringLiteral( "A sequence of QgsPoint, QgsPointXY or array of floats is expected" ).toUtf8().constData() );
82  sipIsErr = 1;
83  }
84  else
85  {
86  int state;
87  const int size = PySequence_Size( a0 );
88  QVector< double > xl;
89  QVector< double > yl;
90  bool hasZ = false;
91  QVector< double > zl;
92  bool hasM = false;
93  QVector< double > ml;
94  xl.reserve( size );
95  yl.reserve( size );
96 
97  bool is25D = false;
98 
99  sipIsErr = 0;
100  for ( int i = 0; i < size; ++i )
101  {
102  PyObject *value = PySequence_GetItem( a0, i );
103  if ( !value )
104  {
105  PyErr_SetString( PyExc_TypeError, QStringLiteral( "Invalid type at index %1." ).arg( i ) .toUtf8().constData() );
106  sipIsErr = 1;
107  break;
108  }
109 
110  if ( PySequence_Check( value ) )
111  {
112  const int elementSize = PySequence_Size( value );
113  if ( elementSize < 2 || elementSize > 4 )
114  {
115  sipIsErr = 1;
116  PyErr_SetString( PyExc_TypeError, QStringLiteral( "Invalid sequence size at index %1. Expected an array of 2-4 float values, got %2." ).arg( i ).arg( elementSize ).toUtf8().constData() );
117  Py_DECREF( value );
118  break;
119  }
120  else
121  {
122  sipIsErr = 0;
123  for ( int j = 0; j < elementSize; ++j )
124  {
125  PyObject *element = PySequence_GetItem( value, j );
126  if ( !element )
127  {
128  PyErr_SetString( PyExc_TypeError, QStringLiteral( "Invalid type at index %1." ).arg( i ) .toUtf8().constData() );
129  sipIsErr = 1;
130  break;
131  }
132 
133  PyErr_Clear();
134  double d = PyFloat_AsDouble( element );
135  if ( PyErr_Occurred() )
136  {
137  Py_DECREF( value );
138  sipIsErr = 1;
139  break;
140  }
141  if ( j == 0 )
142  xl.append( d );
143  else if ( j == 1 )
144  yl.append( d );
145 
146  if ( i == 0 && j == 2 )
147  {
148  hasZ = true;
149  zl.reserve( size );
150  zl.append( d );
151  }
152  else if ( i > 0 && j == 2 && hasZ )
153  {
154  zl.append( d );
155  }
156 
157  if ( i == 0 && j == 3 )
158  {
159  hasM = true;
160  ml.reserve( size );
161  ml.append( d );
162  }
163  else if ( i > 0 && j == 3 && hasM )
164  {
165  ml.append( d );
166  }
167 
168  Py_DECREF( element );
169  }
170 
171  if ( hasZ && elementSize < 3 )
172  zl.append( std::numeric_limits< double >::quiet_NaN() );
173  if ( hasM && elementSize < 4 )
174  ml.append( std::numeric_limits< double >::quiet_NaN() );
175 
176  Py_DECREF( value );
177  if ( sipIsErr )
178  {
179  break;
180  }
181  }
182  }
183  else
184  {
185  if ( sipCanConvertToType( value, sipType_QgsPointXY, SIP_NOT_NONE ) )
186  {
187  sipIsErr = 0;
188  QgsPointXY *p = reinterpret_cast<QgsPointXY *>( sipConvertToType( value, sipType_QgsPointXY, 0, SIP_NOT_NONE, &state, &sipIsErr ) );
189  if ( !sipIsErr )
190  {
191  xl.append( p->x() );
192  yl.append( p->y() );
193  }
194  sipReleaseType( p, sipType_QgsPointXY, state );
195  }
196  else if ( sipCanConvertToType( value, sipType_QgsPoint, SIP_NOT_NONE ) )
197  {
198  sipIsErr = 0;
199  QgsPoint *p = reinterpret_cast<QgsPoint *>( sipConvertToType( value, sipType_QgsPoint, 0, SIP_NOT_NONE, &state, &sipIsErr ) );
200  if ( !sipIsErr )
201  {
202  xl.append( p->x() );
203  yl.append( p->y() );
204 
205  if ( i == 0 && p->is3D() )
206  {
207  hasZ = true;
208  zl.reserve( size );
209  zl.append( p->z() );
210  }
211  else if ( i > 0 && hasZ )
212  {
213  zl.append( p->z() );
214  }
215 
216  if ( i == 0 && p->isMeasure() )
217  {
218  hasM = true;
219  ml.reserve( size );
220  ml.append( p->m() );
221  }
222  else if ( i > 0 && hasM )
223  {
224  ml.append( p->m() );
225  }
226 
227  if ( i == 0 && p->wkbType() == Qgis::WkbType::Point25D )
228  is25D = true;
229  }
230  sipReleaseType( p, sipType_QgsPoint, state );
231  }
232  else
233  {
234  sipIsErr = 1;
235  }
236 
237  Py_DECREF( value );
238 
239  if ( sipIsErr )
240  {
241  // couldn't convert the sequence value to a QgsPoint or QgsPointXY
242  PyErr_SetString( PyExc_TypeError, QStringLiteral( "Invalid type at index %1. Expected QgsPoint, QgsPointXY or array of floats." ).arg( i ) .toUtf8().constData() );
243  break;
244  }
245  }
246  }
247  if ( sipIsErr == 0 )
248  sipCpp = new sipQgsLineString( QgsLineString( xl, yl, zl, ml, is25D ) );
249  }
250  % End
251 #endif
252 
258 
276  QgsLineString( const QVector<double> &x, const QVector<double> &y,
277  const QVector<double> &z = QVector<double>(),
278  const QVector<double> &m = QVector<double>(), bool is25DType = false ) SIP_HOLDGIL;
279 
284  QgsLineString( const QgsPoint &p1, const QgsPoint &p2 ) SIP_HOLDGIL;
285 
296  static QgsLineString *fromBezierCurve( const QgsPoint &start, const QgsPoint &controlPoint1, const QgsPoint &controlPoint2, const QgsPoint &end, int segments = 30 ) SIP_FACTORY;
297 
303  static QgsLineString *fromQPolygonF( const QPolygonF &polygon ) SIP_FACTORY;
304 #ifndef SIP_RUN
305  private:
306  bool fuzzyHelper( double epsilon,
307  const QgsAbstractGeometry &other,
308  bool is3DFlag,
309  bool isMeasureFlag,
310  std::function<bool( double, double, double, double, double, double, double, double, double )> comparator3DMeasure,
311  std::function<bool( double, double, double, double, double, double, double )> comparator3D,
312  std::function<bool( double, double, double, double, double, double, double )> comparatorMeasure,
313  std::function<bool( double, double, double, double, double )> comparator2D ) const
314  {
315  const QgsLineString *otherLine = qgsgeometry_cast< const QgsLineString * >( &other );
316  if ( !otherLine )
317  return false;
318 
319  if ( mWkbType != otherLine->mWkbType )
320  return false;
321 
322  const int size = mX.count();
323  if ( size != otherLine->mX.count() )
324  return false;
325 
326  bool result = true;
327  const double *xData = mX.constData();
328  const double *yData = mY.constData();
329  const double *zData = is3DFlag ? mZ.constData() : nullptr;
330  const double *mData = isMeasureFlag ? mM.constData() : nullptr;
331  const double *otherXData = otherLine->mX.constData();
332  const double *otherYData = otherLine->mY.constData();
333  const double *otherZData = is3DFlag ? otherLine->mZ.constData() : nullptr;
334  const double *otherMData = isMeasureFlag ? otherLine->mM.constData() : nullptr;
335  for ( int i = 0; i < size; ++i )
336  {
337  if ( is3DFlag && isMeasureFlag )
338  {
339  result &= comparator3DMeasure( epsilon, *xData++, *yData++, *zData++, *mData++,
340  *otherXData++, *otherYData++, *otherZData++, *otherMData++ );
341  }
342  else if ( is3DFlag )
343  {
344  result &= comparator3D( epsilon, *xData++, *yData++, *zData++,
345  *otherXData++, *otherYData++, *otherZData++ );
346  }
347  else if ( isMeasureFlag )
348  {
349  result &= comparatorMeasure( epsilon, *xData++, *yData++, *mData++,
350  *otherXData++, *otherYData++, *otherMData++ );
351  }
352  else
353  {
354  result &= comparator2D( epsilon, *xData++, *yData++,
355  *otherXData++, *otherYData++ );
356  }
357  if ( ! result )
358  {
359  return false;
360  }
361  }
362 
363  return result;
364  }
365 #endif // !SIP_RUN
366 
367  public:
368  bool fuzzyEqual( const QgsAbstractGeometry &other, double epsilon = 1e-8 ) const override SIP_HOLDGIL
369  {
370  return fuzzyHelper(
371  epsilon,
372  other,
373  is3D(),
374  isMeasure(),
375  []( double epsilon, double x1, double y1, double z1, double m1,
376  double x2, double y2, double z2, double m2 )
377  {
378  return QgsGeometryUtilsBase::fuzzyEqual( epsilon, x1, y1, z1, m1, x2, y2, z2, m2 );
379  },
380  []( double epsilon, double x1, double y1, double z1,
381  double x2, double y2, double z2 )
382  {
383  return QgsGeometryUtilsBase::fuzzyEqual( epsilon, x1, y1, z1, x2, y2, z2 );
384  },
385  []( double epsilon, double x1, double y1, double m1,
386  double x2, double y2, double m2 )
387  {
388  return QgsGeometryUtilsBase::fuzzyEqual( epsilon, x1, y1, m1, x2, y2, m2 );
389  },
390  []( double epsilon, double x1, double y1,
391  double x2, double y2 )
392  {
393  return QgsGeometryUtilsBase::fuzzyEqual( epsilon, x1, y1, x2, y2 );
394  } );
395  }
396 
397  bool fuzzyDistanceEqual( const QgsAbstractGeometry &other, double epsilon = 1e-8 ) const override SIP_HOLDGIL
398  {
399  return fuzzyHelper(
400  epsilon,
401  other,
402  is3D(),
403  isMeasure(),
404  []( double epsilon, double x1, double y1, double z1, double m1,
405  double x2, double y2, double z2, double m2 )
406  {
407  return QgsGeometryUtilsBase::fuzzyDistanceEqual( epsilon, x1, y1, z1, m1, x2, y2, z2, m2 );
408  },
409  []( double epsilon, double x1, double y1, double z1,
410  double x2, double y2, double z2 )
411  {
412  return QgsGeometryUtilsBase::fuzzyDistanceEqual( epsilon, x1, y1, z1, x2, y2, z2 );
413  },
414  []( double epsilon, double x1, double y1, double m1,
415  double x2, double y2, double m2 )
416  {
417  return QgsGeometryUtilsBase::fuzzyDistanceEqual( epsilon, x1, y1, m1, x2, y2, m2 );
418  },
419  []( double epsilon, double x1, double y1,
420  double x2, double y2 )
421  {
422  return QgsGeometryUtilsBase::fuzzyDistanceEqual( epsilon, x1, y1, x2, y2 );
423  } );
424  }
425 
426  bool equals( const QgsCurve &other ) const override
427  {
428  return fuzzyEqual( other, 1e-8 );
429  }
430 
431 
432 #ifndef SIP_RUN
433 
438  QgsPoint pointN( int i ) const;
439 #else
440 
449  SIP_PYOBJECT pointN( int i ) const SIP_TYPEHINT( QgsPoint );
450  % MethodCode
451  const int count = sipCpp->numPoints();
452  if ( a0 < -count || a0 >= count )
453  {
454  PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
455  sipIsErr = 1;
456  }
457  else
458  {
459  std::unique_ptr< QgsPoint > p;
460  if ( a0 >= 0 )
461  p = std::make_unique< QgsPoint >( sipCpp->pointN( a0 ) );
462  else // negative index, count backwards from end
463  p = std::make_unique< QgsPoint >( sipCpp->pointN( count + a0 ) );
464  sipRes = sipConvertFromType( p.release(), sipType_QgsPoint, Py_None );
465  }
466  % End
467 #endif
468 
469 #ifndef SIP_RUN
470  double xAt( int index ) const override;
471 #else
472 
481  double xAt( int index ) const override;
482  % MethodCode
483  const int count = sipCpp->numPoints();
484  if ( a0 < -count || a0 >= count )
485  {
486  PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
487  sipIsErr = 1;
488  }
489  else
490  {
491  if ( a0 >= 0 )
492  return PyFloat_FromDouble( sipCpp->xAt( a0 ) );
493  else
494  return PyFloat_FromDouble( sipCpp->xAt( count + a0 ) );
495  }
496  % End
497 #endif
498 
499 #ifndef SIP_RUN
500  double yAt( int index ) const override;
501 #else
502 
511  double yAt( int index ) const override;
512  % MethodCode
513  const int count = sipCpp->numPoints();
514  if ( a0 < -count || a0 >= count )
515  {
516  PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
517  sipIsErr = 1;
518  }
519  else
520  {
521  if ( a0 >= 0 )
522  return PyFloat_FromDouble( sipCpp->yAt( a0 ) );
523  else
524  return PyFloat_FromDouble( sipCpp->yAt( count + a0 ) );
525  }
526  % End
527 #endif
528 
535  const double *xData() const SIP_SKIP
536  {
537  return mX.constData();
538  }
539 
546  const double *yData() const SIP_SKIP
547  {
548  return mY.constData();
549  }
550 
559  const double *zData() const SIP_SKIP
560  {
561  if ( mZ.empty() )
562  return nullptr;
563  else
564  return mZ.constData();
565  }
566 
575  const double *mData() const SIP_SKIP
576  {
577  if ( mM.empty() )
578  return nullptr;
579  else
580  return mM.constData();
581  }
582 
588  QVector< double > xVector() const SIP_SKIP
589  {
590  return mX;
591  }
592 
598  QVector< double > yVector() const SIP_SKIP
599  {
600  return mY;
601  }
602 
608  QVector< double > zVector() const SIP_SKIP
609  {
610  return mZ;
611  }
612 
618  QVector< double > mVector() const SIP_SKIP
619  {
620  return mM;
621  }
622 
623 
624 #ifndef SIP_RUN
625 
633  double zAt( int index ) const override
634  {
635  if ( index >= 0 && index < mZ.size() )
636  return mZ.at( index );
637  else
638  return std::numeric_limits<double>::quiet_NaN();
639  }
640 #else
641 
652  double zAt( int index ) const override;
653  % MethodCode
654  const int count = sipCpp->numPoints();
655  if ( a0 < -count || a0 >= count )
656  {
657  PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
658  sipIsErr = 1;
659  }
660  else
661  {
662  if ( a0 >= 0 )
663  return PyFloat_FromDouble( sipCpp->zAt( a0 ) );
664  else
665  return PyFloat_FromDouble( sipCpp->zAt( count + a0 ) );
666  }
667  % End
668 #endif
669 
670 #ifndef SIP_RUN
671 
679  double mAt( int index ) const override
680  {
681  if ( index >= 0 && index < mM.size() )
682  return mM.at( index );
683  else
684  return std::numeric_limits<double>::quiet_NaN();
685  }
686 #else
687 
698  double mAt( int index ) const override;
699  % MethodCode
700  const int count = sipCpp->numPoints();
701  if ( a0 < -count || a0 >= count )
702  {
703  PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
704  sipIsErr = 1;
705  }
706  else
707  {
708  if ( a0 >= 0 )
709  return PyFloat_FromDouble( sipCpp->mAt( a0 ) );
710  else
711  return PyFloat_FromDouble( sipCpp->mAt( count + a0 ) );
712  }
713  % End
714 #endif
715 
716 #ifndef SIP_RUN
717 
725  void setXAt( int index, double x );
726 #else
727 
739  void setXAt( int index, double x );
740  % MethodCode
741  const int count = sipCpp->numPoints();
742  if ( a0 < -count || a0 >= count )
743  {
744  PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
745  sipIsErr = 1;
746  }
747  else
748  {
749  if ( a0 >= 0 )
750  sipCpp->setXAt( a0, a1 );
751  else
752  sipCpp->setXAt( count + a0, a1 );
753  }
754  % End
755 #endif
756 
757 #ifndef SIP_RUN
758 
766  void setYAt( int index, double y );
767 #else
768 
780  void setYAt( int index, double y );
781  % MethodCode
782  const int count = sipCpp->numPoints();
783  if ( a0 < -count || a0 >= count )
784  {
785  PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
786  sipIsErr = 1;
787  }
788  else
789  {
790  if ( a0 >= 0 )
791  sipCpp->setYAt( a0, a1 );
792  else
793  sipCpp->setYAt( count + a0, a1 );
794  }
795  % End
796 #endif
797 
798 #ifndef SIP_RUN
799 
807  void setZAt( int index, double z )
808  {
809  if ( index >= 0 && index < mZ.size() )
810  mZ[ index ] = z;
811  }
812 #else
813 
824  void setZAt( int index, double z );
825  % MethodCode
826  const int count = sipCpp->numPoints();
827  if ( a0 < -count || a0 >= count )
828  {
829  PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
830  sipIsErr = 1;
831  }
832  else
833  {
834  if ( a0 >= 0 )
835  sipCpp->setZAt( a0, a1 );
836  else
837  sipCpp->setZAt( count + a0, a1 );
838  }
839  % End
840 #endif
841 
842 #ifndef SIP_RUN
843 
851  void setMAt( int index, double m )
852  {
853  if ( index >= 0 && index < mM.size() )
854  mM[ index ] = m;
855  }
856 #else
857 
868  void setMAt( int index, double m );
869  % MethodCode
870  const int count = sipCpp->numPoints();
871  if ( a0 < -count || a0 >= count )
872  {
873  PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
874  sipIsErr = 1;
875  }
876  else
877  {
878  if ( a0 >= 0 )
879  sipCpp->setMAt( a0, a1 );
880  else
881  sipCpp->setMAt( count + a0, a1 );
882  }
883  % End
884 #endif
885 
899  void setPoints( size_t size, const double *x, const double *y, const double *z = nullptr, const double *m = nullptr ) SIP_SKIP;
900 
906  void setPoints( const QgsPointSequence &points );
907 
912  void append( const QgsLineString *line );
913 
918  void addVertex( const QgsPoint &pt );
919 
921  void close();
922 
927  QgsCompoundCurve *toCurveType() const override SIP_FACTORY;
928 
934  void extend( double startDistance, double endDistance );
935 
936 #ifndef SIP_RUN
937 
943  void visitPointsByRegularDistance( double distance, const std::function< bool( double x, double y, double z, double m,
944  double startSegmentX, double startSegmentY, double startSegmentZ, double startSegmentM,
945  double endSegmentX, double endSegmentY, double endSegmentZ, double endSegmentM
946  ) > &visitPoint ) const;
947 #endif
948 
949  //reimplemented methods
950  QString geometryType() const override SIP_HOLDGIL;
951  int dimension() const override SIP_HOLDGIL;
952  QgsLineString *clone() const override SIP_FACTORY;
953  void clear() override;
954  bool isEmpty() const override SIP_HOLDGIL;
955  int indexOf( const QgsPoint &point ) const final;
956  bool isValid( QString &error SIP_OUT, Qgis::GeometryValidityFlags flags = Qgis::GeometryValidityFlags() ) const override;
957  QgsLineString *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const override SIP_FACTORY;
958  bool removeDuplicateNodes( double epsilon = 4 * std::numeric_limits<double>::epsilon(), bool useZValues = false ) override;
959  bool isClosed() const override SIP_HOLDGIL;
960  bool isClosed2D() const override SIP_HOLDGIL;
961  bool boundingBoxIntersects( const QgsRectangle &rectangle ) const override SIP_HOLDGIL;
962  bool boundingBoxIntersects( const QgsBox3D &box3d ) const override SIP_HOLDGIL;
963 
971  QVector< QgsVertexId > collectDuplicateNodes( double epsilon = 4 * std::numeric_limits<double>::epsilon(), bool useZValues = false ) const;
972 
973  QPolygonF asQPolygonF() const override;
974 
975  bool fromWkb( QgsConstWkbPtr &wkb ) override;
976  bool fromWkt( const QString &wkt ) override;
977 
978  int wkbSize( QgsAbstractGeometry::WkbFlags flags = QgsAbstractGeometry::WkbFlags() ) const override;
979  QByteArray asWkb( QgsAbstractGeometry::WkbFlags flags = QgsAbstractGeometry::WkbFlags() ) const override;
980  QString asWkt( int precision = 17 ) const override;
981  QDomElement asGml2( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const override;
982  QDomElement asGml3( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const override;
983  json asJsonObject( int precision = 17 ) const override SIP_SKIP;
984  QString asKml( int precision = 17 ) const override;
985 
986  //curve interface
987  double length() const override SIP_HOLDGIL;
988 
989 #ifndef SIP_RUN
990  std::tuple< std::unique_ptr< QgsCurve >, std::unique_ptr< QgsCurve > > splitCurveAtVertex( int index ) const final;
991 #endif
992 
999  double length3D() const SIP_HOLDGIL;
1000  QgsPoint startPoint() const override SIP_HOLDGIL;
1001  QgsPoint endPoint() const override SIP_HOLDGIL;
1002 
1009  QgsLineString *curveToLine( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const override SIP_FACTORY;
1010 
1011  int numPoints() const override SIP_HOLDGIL;
1012  int nCoordinates() const override SIP_HOLDGIL;
1013  void points( QgsPointSequence &pt SIP_OUT ) const override;
1014 
1015  void draw( QPainter &p ) const override;
1016 
1017  void transform( const QgsCoordinateTransform &ct, Qgis::TransformDirection d = Qgis::TransformDirection::Forward, bool transformZ = false ) override SIP_THROW( QgsCsException );
1018  void transform( const QTransform &t, double zTranslate = 0.0, double zScale = 1.0, double mTranslate = 0.0, double mScale = 1.0 ) override;
1019 
1020  void addToPainterPath( QPainterPath &path ) const override;
1021  void drawAsPolygon( QPainter &p ) const override;
1022 
1023  bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) override;
1024  bool moveVertex( QgsVertexId position, const QgsPoint &newPos ) override;
1025  bool deleteVertex( QgsVertexId position ) override;
1026 
1027  QgsLineString *reversed() const override SIP_FACTORY;
1028  QgsPoint *interpolatePoint( double distance ) const override SIP_FACTORY;
1029  QgsLineString *curveSubstring( double startDistance, double endDistance ) const override SIP_FACTORY;
1030 
1031  double closestSegment( const QgsPoint &pt, QgsPoint &segmentPt SIP_OUT, QgsVertexId &vertexAfter SIP_OUT, int *leftOf SIP_OUT = nullptr, double epsilon = 4 * std::numeric_limits<double>::epsilon() ) const override;
1032  bool pointAt( int node, QgsPoint &point, Qgis::VertexType &type ) const override;
1033 
1034  QgsPoint centroid() const override;
1035 
1044  void sumUpArea( double &sum SIP_OUT ) const override;
1045 
1046  double vertexAngle( QgsVertexId vertex ) const override;
1047  double segmentLength( QgsVertexId startVertex ) const override;
1048  bool addZValue( double zValue = 0 ) override;
1049  bool addMValue( double mValue = 0 ) override;
1050 
1051  bool dropZValue() override;
1052  bool dropMValue() override;
1053  void swapXy() override;
1054 
1055  bool convertTo( Qgis::WkbType type ) override;
1056 
1057  bool transform( QgsAbstractGeometryTransformer *transformer, QgsFeedback *feedback = nullptr ) override;
1058  void scroll( int firstVertexIndex ) final;
1059 
1060 #ifndef SIP_RUN
1061  void filterVertices( const std::function< bool( const QgsPoint & ) > &filter ) override;
1062  void transformVertices( const std::function< QgsPoint( const QgsPoint & ) > &transform ) override;
1063 
1070  inline static const QgsLineString *cast( const QgsAbstractGeometry *geom )
1071  {
1072  if ( geom && QgsWkbTypes::flatType( geom->wkbType() ) == Qgis::WkbType::LineString )
1073  return static_cast<const QgsLineString *>( geom );
1074  return nullptr;
1075  }
1076 #endif
1077 
1079 
1080 #ifdef SIP_RUN
1081  SIP_PYOBJECT __repr__();
1082  % MethodCode
1083  QString wkt = sipCpp->asWkt();
1084  if ( wkt.length() > 1000 )
1085  wkt = wkt.left( 1000 ) + QStringLiteral( "..." );
1086  QString str = QStringLiteral( "<QgsLineString: %1>" ).arg( wkt );
1087  sipRes = PyUnicode_FromString( str.toUtf8().constData() );
1088  % End
1089 
1099  SIP_PYOBJECT __getitem__( int index ) SIP_TYPEHINT( QgsPoint );
1100  % MethodCode
1101  const int count = sipCpp->numPoints();
1102  if ( a0 < -count || a0 >= count )
1103  {
1104  PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
1105  sipIsErr = 1;
1106  }
1107  else
1108  {
1109  std::unique_ptr< QgsPoint > p;
1110  if ( a0 >= 0 )
1111  p = std::make_unique< QgsPoint >( sipCpp->pointN( a0 ) );
1112  else
1113  p = std::make_unique< QgsPoint >( sipCpp->pointN( count + a0 ) );
1114  sipRes = sipConvertFromType( p.release(), sipType_QgsPoint, Py_None );
1115  }
1116  % End
1117 
1127  void __setitem__( int index, const QgsPoint &point );
1128  % MethodCode
1129  const int count = sipCpp->numPoints();
1130  if ( a0 < -count || a0 >= count )
1131  {
1132  PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
1133  sipIsErr = 1;
1134  }
1135  else
1136  {
1137  if ( a0 < 0 )
1138  a0 = count + a0;
1139  sipCpp->setXAt( a0, a1->x() );
1140  sipCpp->setYAt( a0, a1->y() );
1141  if ( sipCpp->isMeasure() )
1142  sipCpp->setMAt( a0, a1->m() );
1143  if ( sipCpp->is3D() )
1144  sipCpp->setZAt( a0, a1->z() );
1145  }
1146  % End
1147 
1148 
1158  void __delitem__( int index );
1159  % MethodCode
1160  const int count = sipCpp->numPoints();
1161  if ( a0 >= 0 && a0 < count )
1162  sipCpp->deleteVertex( QgsVertexId( -1, -1, a0 ) );
1163  else if ( a0 < 0 && a0 >= -count )
1164  sipCpp->deleteVertex( QgsVertexId( -1, -1, count + a0 ) );
1165  else
1166  {
1167  PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
1168  sipIsErr = 1;
1169  }
1170  % End
1171 
1172 #endif
1173 
1181  Q_DECL_DEPRECATED QgsBox3D calculateBoundingBox3d() const SIP_DEPRECATED;
1182 
1188  QgsBox3D calculateBoundingBox3D() const override;
1189 
1190 
1197  QgsLineString *measuredLine( double start, double end ) const SIP_FACTORY;
1198 
1199  protected:
1200 
1201  int compareToSameClass( const QgsAbstractGeometry *other ) const final;
1202 
1203  private:
1204  QVector<double> mX;
1205  QVector<double> mY;
1206  QVector<double> mZ;
1207  QVector<double> mM;
1208 
1209  void importVerticesFromWkb( const QgsConstWkbPtr &wkb );
1210 
1216  void fromWkbPoints( Qgis::WkbType type, const QgsConstWkbPtr &wkb )
1217  {
1218  mWkbType = type;
1219  importVerticesFromWkb( wkb );
1220  }
1221 
1222  friend class QgsPolygon;
1223  friend class QgsTriangle;
1224  friend class TestQgsGeometry;
1225 
1226 };
1227 
1228 // clazy:excludeall=qstring-allocations
1229 
1230 #endif // QGSLINESTRING_H
The Qgis class provides global constants for use throughout the application.
Definition: qgis.h:54
@ LineString
LineString.
@ Point25D
Point25D.
An abstract base class for classes which transform geometries by transforming input points to output ...
Abstract base class for all geometries.
bool isMeasure() const
Returns true if the geometry contains m values.
virtual void transformVertices(const std::function< QgsPoint(const QgsPoint &) > &transform)
Transforms the vertices from the geometry in place, applying the transform function to every vertex.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
virtual QString geometryType() const =0
Returns a unique string representing the geometry type.
virtual QgsAbstractGeometry * createEmptyWithSameType() const =0
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
virtual bool fuzzyEqual(const QgsAbstractGeometry &other, double epsilon=1e-8) const =0
Performs fuzzy comparison between this geometry and other using an epsilon.
virtual void filterVertices(const std::function< bool(const QgsPoint &) > &filter)
Filters the vertices from the geometry in place, removing any which do not return true for the filter...
A 3-dimensional box composed of x, y, z coordinates.
Definition: qgsbox3d.h:43
Compound curve geometry type.
A const WKB pointer.
Definition: qgswkbptr.h:138
Class for doing transforms between two map coordinate systems.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:67
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
virtual double xAt(int index) const =0
Returns the x-coordinate of the specified node in the line string.
virtual std::tuple< std::unique_ptr< QgsCurve >, std::unique_ptr< QgsCurve > > splitCurveAtVertex(int index) const =0
Splits the curve at the specified vertex index, returning two curves which represent the portion of t...
virtual double zAt(int index) const =0
Returns the z-coordinate of the specified node in the line string.
virtual double mAt(int index) const =0
Returns the m-coordinate of the specified node in the line string.
virtual double yAt(int index) const =0
Returns the y-coordinate of the specified node in the line string.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:44
static bool fuzzyEqual(T epsilon, const Args &... args) noexcept
Performs fuzzy comparison between pairs of values within a specified epsilon.
static bool fuzzyDistanceEqual(T epsilon, const Args &... args) noexcept
Compare equality between multiple pairs of values with a specified epsilon.
Represents a single 2D line segment, consisting of a 2D start and end vertex only.
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:45
bool equals(const QgsCurve &other) const override
Checks whether this curve exactly equals another curve.
const double * yData() const
Returns a const pointer to the y vertex data.
bool fuzzyEqual(const QgsAbstractGeometry &other, double epsilon=1e-8) const override
Performs fuzzy comparison between this geometry and other using an epsilon.
QVector< double > xVector() const
Returns the x vertex values as a vector.
static const QgsLineString * cast(const QgsAbstractGeometry *geom)
Cast the geom to a QgsLineString.
QVector< double > yVector() const
Returns the y vertex values as a vector.
bool fuzzyDistanceEqual(const QgsAbstractGeometry &other, double epsilon=1e-8) const override
Performs fuzzy distance comparison between this geometry and other using an epsilon.
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the linestring does not have m values.
void setZAt(int index, double z)
Sets the z-coordinate of the specified node in the line string.
double mAt(int index) const override
Returns the m value of the specified node in the line string.
QVector< double > zVector() const
Returns the z vertex values as a vector.
QVector< double > mVector() const
Returns the m vertex values as a vector.
void setMAt(int index, double m)
Sets the m value of the specified node in the line string.
const double * xData() const
Returns a const pointer to the x vertex data.
double zAt(int index) const override
Returns the z-coordinate of the specified node in the line string.
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the linestring does not have z values.
A class to represent a 2D point.
Definition: qgspointxy.h:60
double y
Definition: qgspointxy.h:64
Q_GADGET double x
Definition: qgspointxy.h:63
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
Q_GADGET double x
Definition: qgspoint.h:52
double z
Definition: qgspoint.h:54
double m
Definition: qgspoint.h:55
double y
Definition: qgspoint.h:53
Polygon geometry type.
Definition: qgspolygon.h:33
A rectangle specified with double values.
Definition: qgsrectangle.h:42
Triangle geometry type.
Definition: qgstriangle.h:33
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:628
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:222
CORE_EXPORT QgsMeshVertex centroid(const QgsMeshFace &face, const QVector< QgsMeshVertex > &vertices)
Returns the centroid of the face.
#define str(x)
Definition: qgis.cpp:38
#define SIP_TYPEHINT(type)
Definition: qgis_sip.h:232
#define SIP_DEPRECATED
Definition: qgis_sip.h:106
#define SIP_SKIP
Definition: qgis_sip.h:126
#define SIP_OUT
Definition: qgis_sip.h:58
#define SIP_HOLDGIL
Definition: qgis_sip.h:171
#define SIP_FACTORY
Definition: qgis_sip.h:76
#define SIP_THROW(name,...)
Definition: qgis_sip.h:203
QVector< QgsPoint > QgsPointSequence
QLineF segment(int index, QRectF rect, double radius)
double closestSegment(const QgsPolylineXY &pl, const QgsPointXY &pt, int &vertexAfter, double epsilon)
Definition: qgstracer.cpp:69
int precision
Utility class for identifying a unique vertex within a geometry.
Definition: qgsvertexid.h:30