QGIS API Documentation 3.39.0-Master (f6cef42644e)
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
1000 double length3D() const SIP_HOLDGIL;
1001 QgsPoint startPoint() const override SIP_HOLDGIL;
1002 QgsPoint endPoint() const override SIP_HOLDGIL;
1003
1010 QgsLineString *curveToLine( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const override SIP_FACTORY;
1011
1012 int numPoints() const override SIP_HOLDGIL;
1013 int nCoordinates() const override SIP_HOLDGIL;
1014 void points( QgsPointSequence &pt SIP_OUT ) const override;
1015
1016 void draw( QPainter &p ) const override;
1017
1018 void transform( const QgsCoordinateTransform &ct, Qgis::TransformDirection d = Qgis::TransformDirection::Forward, bool transformZ = false ) override SIP_THROW( QgsCsException );
1019 void transform( const QTransform &t, double zTranslate = 0.0, double zScale = 1.0, double mTranslate = 0.0, double mScale = 1.0 ) override;
1020
1021 void addToPainterPath( QPainterPath &path ) const override;
1022 void drawAsPolygon( QPainter &p ) const override;
1023
1024 bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) override;
1025 bool moveVertex( QgsVertexId position, const QgsPoint &newPos ) override;
1026 bool deleteVertex( QgsVertexId position ) override;
1027
1028 QgsLineString *reversed() const override SIP_FACTORY;
1029 QgsPoint *interpolatePoint( double distance ) const override SIP_FACTORY;
1030 QgsLineString *curveSubstring( double startDistance, double endDistance ) const override SIP_FACTORY;
1031
1032 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;
1033 bool pointAt( int node, QgsPoint &point, Qgis::VertexType &type ) const override;
1034
1035 QgsPoint centroid() const override;
1036
1045 void sumUpArea( double &sum SIP_OUT ) const override;
1046
1047 double vertexAngle( QgsVertexId vertex ) const override;
1048 double segmentLength( QgsVertexId startVertex ) const override;
1049 bool addZValue( double zValue = 0 ) override;
1050 bool addMValue( double mValue = 0 ) override;
1051
1052 bool dropZValue() override;
1053 bool dropMValue() override;
1054 void swapXy() override;
1055
1056 bool convertTo( Qgis::WkbType type ) override;
1057
1058 bool transform( QgsAbstractGeometryTransformer *transformer, QgsFeedback *feedback = nullptr ) override;
1059 void scroll( int firstVertexIndex ) final;
1060
1061#ifndef SIP_RUN
1062 void filterVertices( const std::function< bool( const QgsPoint & ) > &filter ) override;
1063 void transformVertices( const std::function< QgsPoint( const QgsPoint & ) > &transform ) override;
1064
1071 inline static const QgsLineString *cast( const QgsAbstractGeometry *geom )
1072 {
1073 if ( geom && QgsWkbTypes::flatType( geom->wkbType() ) == Qgis::WkbType::LineString )
1074 return static_cast<const QgsLineString *>( geom );
1075 return nullptr;
1076 }
1077#endif
1078
1080
1081#ifdef SIP_RUN
1082 SIP_PYOBJECT __repr__();
1083 % MethodCode
1084 QString wkt = sipCpp->asWkt();
1085 if ( wkt.length() > 1000 )
1086 wkt = wkt.left( 1000 ) + QStringLiteral( "..." );
1087 QString str = QStringLiteral( "<QgsLineString: %1>" ).arg( wkt );
1088 sipRes = PyUnicode_FromString( str.toUtf8().constData() );
1089 % End
1090
1100 SIP_PYOBJECT __getitem__( int index ) SIP_TYPEHINT( QgsPoint );
1101 % MethodCode
1102 const int count = sipCpp->numPoints();
1103 if ( a0 < -count || a0 >= count )
1104 {
1105 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
1106 sipIsErr = 1;
1107 }
1108 else
1109 {
1110 std::unique_ptr< QgsPoint > p;
1111 if ( a0 >= 0 )
1112 p = std::make_unique< QgsPoint >( sipCpp->pointN( a0 ) );
1113 else
1114 p = std::make_unique< QgsPoint >( sipCpp->pointN( count + a0 ) );
1115 sipRes = sipConvertFromType( p.release(), sipType_QgsPoint, Py_None );
1116 }
1117 % End
1118
1128 void __setitem__( int index, const QgsPoint &point );
1129 % MethodCode
1130 const int count = sipCpp->numPoints();
1131 if ( a0 < -count || a0 >= count )
1132 {
1133 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
1134 sipIsErr = 1;
1135 }
1136 else
1137 {
1138 if ( a0 < 0 )
1139 a0 = count + a0;
1140 sipCpp->setXAt( a0, a1->x() );
1141 sipCpp->setYAt( a0, a1->y() );
1142 if ( sipCpp->isMeasure() )
1143 sipCpp->setMAt( a0, a1->m() );
1144 if ( sipCpp->is3D() )
1145 sipCpp->setZAt( a0, a1->z() );
1146 }
1147 % End
1148
1149
1159 void __delitem__( int index );
1160 % MethodCode
1161 const int count = sipCpp->numPoints();
1162 if ( a0 >= 0 && a0 < count )
1163 sipCpp->deleteVertex( QgsVertexId( -1, -1, a0 ) );
1164 else if ( a0 < 0 && a0 >= -count )
1165 sipCpp->deleteVertex( QgsVertexId( -1, -1, count + a0 ) );
1166 else
1167 {
1168 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
1169 sipIsErr = 1;
1170 }
1171 % End
1172
1173#endif
1174
1182 Q_DECL_DEPRECATED QgsBox3D calculateBoundingBox3d() const SIP_DEPRECATED;
1183
1189 QgsBox3D calculateBoundingBox3D() const override;
1190
1197 QgsLineString *measuredLine( double start, double end ) const SIP_FACTORY;
1198
1211 QgsLineString *interpolateM( bool use3DDistance = true ) const SIP_FACTORY;
1212
1213 protected:
1214
1215 int compareToSameClass( const QgsAbstractGeometry *other ) const final;
1216
1217 private:
1218 QVector<double> mX;
1219 QVector<double> mY;
1220 QVector<double> mZ;
1221 QVector<double> mM;
1222
1223 void importVerticesFromWkb( const QgsConstWkbPtr &wkb );
1224
1230 void fromWkbPoints( Qgis::WkbType type, const QgsConstWkbPtr &wkb )
1231 {
1232 mWkbType = type;
1233 importVerticesFromWkb( wkb );
1234 }
1235
1236 friend class QgsPolygon;
1237 friend class QgsTriangle;
1238 friend class TestQgsGeometry;
1239
1240};
1241
1242// clazy:excludeall=qstring-allocations
1243
1244#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: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