QGIS API Documentation 3.41.0-Master (fda2aa46e9a)
Loading...
Searching...
No Matches
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"
29
31class 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
44class 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, bool removeRedundantPoints = false ) 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 QgsLineString *simplifyByDistance( double tolerance ) const override SIP_FACTORY;
976 bool fromWkb( QgsConstWkbPtr &wkb ) override;
977 bool fromWkt( const QString &wkt ) override;
978
979 int wkbSize( QgsAbstractGeometry::WkbFlags flags = QgsAbstractGeometry::WkbFlags() ) const override;
980 QByteArray asWkb( QgsAbstractGeometry::WkbFlags flags = QgsAbstractGeometry::WkbFlags() ) const override;
981 QString asWkt( int precision = 17 ) const override;
982 QDomElement asGml2( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const override;
983 QDomElement asGml3( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const override;
984 json asJsonObject( int precision = 17 ) const override SIP_SKIP;
985 QString asKml( int precision = 17 ) const override;
986
987 //curve interface
988 double length() const override SIP_HOLDGIL;
989
990#ifndef SIP_RUN
991 std::tuple< std::unique_ptr< QgsCurve >, std::unique_ptr< QgsCurve > > splitCurveAtVertex( int index ) const final;
992#endif
993
1002 QVector<QgsLineString *> splitToDisjointXYParts() const SIP_FACTORY;
1003
1010 double length3D() const SIP_HOLDGIL;
1011 QgsPoint startPoint() const override SIP_HOLDGIL;
1012 QgsPoint endPoint() const override SIP_HOLDGIL;
1013
1020 QgsLineString *curveToLine( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const override SIP_FACTORY;
1021
1022 int numPoints() const override SIP_HOLDGIL;
1023 int nCoordinates() const override SIP_HOLDGIL;
1024 void points( QgsPointSequence &pt SIP_OUT ) const override;
1025
1026 void draw( QPainter &p ) const override;
1027
1028 void transform( const QgsCoordinateTransform &ct, Qgis::TransformDirection d = Qgis::TransformDirection::Forward, bool transformZ = false ) override SIP_THROW( QgsCsException );
1029 void transform( const QTransform &t, double zTranslate = 0.0, double zScale = 1.0, double mTranslate = 0.0, double mScale = 1.0 ) override;
1030
1031 void addToPainterPath( QPainterPath &path ) const override;
1032 void drawAsPolygon( QPainter &p ) const override;
1033
1034 bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) override;
1035 bool moveVertex( QgsVertexId position, const QgsPoint &newPos ) override;
1036 bool deleteVertex( QgsVertexId position ) override;
1037
1038 QgsLineString *reversed() const override SIP_FACTORY;
1039 QgsPoint *interpolatePoint( double distance ) const override SIP_FACTORY;
1040 QgsLineString *curveSubstring( double startDistance, double endDistance ) const override SIP_FACTORY;
1041
1042 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;
1043 bool pointAt( int node, QgsPoint &point, Qgis::VertexType &type ) const override;
1044
1045 QgsPoint centroid() const override;
1046
1055 void sumUpArea( double &sum SIP_OUT ) const override;
1056
1057 double vertexAngle( QgsVertexId vertex ) const override;
1058 double segmentLength( QgsVertexId startVertex ) const override;
1059 bool addZValue( double zValue = 0 ) override;
1060 bool addMValue( double mValue = 0 ) override;
1061
1062 bool dropZValue() override;
1063 bool dropMValue() override;
1064 void swapXy() override;
1065
1066 bool convertTo( Qgis::WkbType type ) override;
1067
1068 bool transform( QgsAbstractGeometryTransformer *transformer, QgsFeedback *feedback = nullptr ) override;
1069 void scroll( int firstVertexIndex ) final;
1070
1071#ifndef SIP_RUN
1072 void filterVertices( const std::function< bool( const QgsPoint & ) > &filter ) override;
1073 void transformVertices( const std::function< QgsPoint( const QgsPoint & ) > &transform ) override;
1074
1081 inline static const QgsLineString *cast( const QgsAbstractGeometry *geom ) // cppcheck-suppress duplInheritedMember
1082 {
1083 if ( geom && QgsWkbTypes::flatType( geom->wkbType() ) == Qgis::WkbType::LineString )
1084 return static_cast<const QgsLineString *>( geom );
1085 return nullptr;
1086 }
1087#endif
1088
1090
1091#ifdef SIP_RUN
1092 SIP_PYOBJECT __repr__();
1093 % MethodCode
1094 QString wkt = sipCpp->asWkt();
1095 if ( wkt.length() > 1000 )
1096 wkt = wkt.left( 1000 ) + QStringLiteral( "..." );
1097 QString str = QStringLiteral( "<QgsLineString: %1>" ).arg( wkt );
1098 sipRes = PyUnicode_FromString( str.toUtf8().constData() );
1099 % End
1100
1110 SIP_PYOBJECT __getitem__( int index ) SIP_TYPEHINT( QgsPoint );
1111 % MethodCode
1112 const int count = sipCpp->numPoints();
1113 if ( a0 < -count || a0 >= count )
1114 {
1115 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
1116 sipIsErr = 1;
1117 }
1118 else
1119 {
1120 std::unique_ptr< QgsPoint > p;
1121 if ( a0 >= 0 )
1122 p = std::make_unique< QgsPoint >( sipCpp->pointN( a0 ) );
1123 else
1124 p = std::make_unique< QgsPoint >( sipCpp->pointN( count + a0 ) );
1125 sipRes = sipConvertFromType( p.release(), sipType_QgsPoint, Py_None );
1126 }
1127 % End
1128
1138 void __setitem__( int index, const QgsPoint &point );
1139 % MethodCode
1140 const int count = sipCpp->numPoints();
1141 if ( a0 < -count || a0 >= count )
1142 {
1143 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
1144 sipIsErr = 1;
1145 }
1146 else
1147 {
1148 if ( a0 < 0 )
1149 a0 = count + a0;
1150 sipCpp->setXAt( a0, a1->x() );
1151 sipCpp->setYAt( a0, a1->y() );
1152 if ( sipCpp->isMeasure() )
1153 sipCpp->setMAt( a0, a1->m() );
1154 if ( sipCpp->is3D() )
1155 sipCpp->setZAt( a0, a1->z() );
1156 }
1157 % End
1158
1159
1169 void __delitem__( int index );
1170 % MethodCode
1171 const int count = sipCpp->numPoints();
1172 if ( a0 >= 0 && a0 < count )
1173 sipCpp->deleteVertex( QgsVertexId( -1, -1, a0 ) );
1174 else if ( a0 < 0 && a0 >= -count )
1175 sipCpp->deleteVertex( QgsVertexId( -1, -1, count + a0 ) );
1176 else
1177 {
1178 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
1179 sipIsErr = 1;
1180 }
1181 % End
1182
1183#endif
1184
1192 Q_DECL_DEPRECATED QgsBox3D calculateBoundingBox3d() const SIP_DEPRECATED;
1193
1199 QgsBox3D calculateBoundingBox3D() const override;
1200
1207 QgsLineString *measuredLine( double start, double end ) const SIP_FACTORY;
1208
1222 QgsLineString *interpolateM( bool use3DDistance = true ) const SIP_FACTORY;
1223
1248 bool lineLocatePointByM( double m, double &x SIP_OUT, double &y SIP_OUT, double &z SIP_OUT, double &distanceFromStart SIP_OUT, bool use3DDistance = true ) const;
1249
1250 protected:
1251
1252 int compareToSameClass( const QgsAbstractGeometry *other ) const final;
1253
1254 private:
1255 QVector<double> mX;
1256 QVector<double> mY;
1257 QVector<double> mZ;
1258 QVector<double> mM;
1259
1260 void importVerticesFromWkb( const QgsConstWkbPtr &wkb );
1261
1267 void fromWkbPoints( Qgis::WkbType type, const QgsConstWkbPtr &wkb )
1268 {
1269 mWkbType = type;
1270 importVerticesFromWkb( wkb );
1271 }
1272
1273 bool lineLocatePointByMPrivate( double m, double &x, double &y, double &z, double &distanceFromStart, bool use3DDistance, bool haveInterpolatedM ) const;
1274
1275 friend class QgsPolygon;
1276 friend class QgsTriangle;
1277 friend class TestQgsGeometry;
1278
1279};
1280
1281// clazy:excludeall=qstring-allocations
1282
1283#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.
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.
const double * yData() const
Returns a const pointer to the y vertex data.
bool equals(const QgsCurve &other) const override
Checks whether this curve exactly equals another curve.
const double * xData() const
Returns a const pointer to the x 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.
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the linestring does not have z values.
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.
static const QgsLineString * cast(const QgsAbstractGeometry *geom)
Cast the geom to a QgsLineString.
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.
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the linestring does not have m values.
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.
double zAt(int index) const override
Returns the z-coordinate of the specified node in the line string.
A class to represent a 2D point.
Definition qgspointxy.h:60
double y
Definition qgspointxy.h:64
double x
Definition qgspointxy.h:63
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:49
double z
Definition qgspoint.h:54
double x
Definition qgspoint.h:52
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.
Triangle geometry type.
Definition qgstriangle.h:33
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
#define str(x)
Definition qgis.cpp:39
#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
void visitPointsByRegularDistance(const QgsLineString *line, const QgsLineString *linePainterUnits, bool emitFirstPoint, const double distance, const double averageAngleLengthPainterUnits, const VisitPointFunction &visitPoint)
QLineF segment(int index, QRectF rect, double radius)
double closestSegment(const QgsPolylineXY &pl, const QgsPointXY &pt, int &vertexAfter, double epsilon)
Definition qgstracer.cpp:70
int precision
Utility class for identifying a unique vertex within a geometry.
Definition qgsvertexid.h:30