QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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 ) 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
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
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