QGIS API Documentation 3.99.0-Master (2fe06baccd8)
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 "qgis_core.h"
23#include "qgis_sip.h"
24#include "qgscompoundcurve.h"
25#include "qgscurve.h"
27
28#include <QPolygonF>
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 std::unique_ptr< QgsLineString > fromBezierCurve( const QgsPoint &start, const QgsPoint &controlPoint1, const QgsPoint &controlPoint2, const QgsPoint &end, int segments = 30 );
297
303 static std::unique_ptr< QgsLineString > fromQPolygonF( const QPolygonF &polygon );
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 double distanceBetweenVertices( QgsVertexId fromVertex, QgsVertexId toVertex ) const override;
1060 bool addZValue( double zValue = 0 ) override;
1061 bool addMValue( double mValue = 0 ) override;
1062
1063 bool dropZValue() override;
1064 bool dropMValue() override;
1065 void swapXy() override;
1066
1067 bool convertTo( Qgis::WkbType type ) override;
1068
1069 bool transform( QgsAbstractGeometryTransformer *transformer, QgsFeedback *feedback = nullptr ) override;
1070 void scroll( int firstVertexIndex ) final;
1071
1072#ifndef SIP_RUN
1073 void filterVertices( const std::function< bool( const QgsPoint & ) > &filter ) override;
1074 void transformVertices( const std::function< QgsPoint( const QgsPoint & ) > &transform ) override;
1075
1084 inline static const QgsLineString *cast( const QgsAbstractGeometry *geom ) // cppcheck-suppress duplInheritedMember
1085 {
1086 if ( geom && QgsWkbTypes::flatType( geom->wkbType() ) == Qgis::WkbType::LineString )
1087 return static_cast<const QgsLineString *>( geom );
1088 return nullptr;
1089 }
1090
1099 inline static QgsLineString *cast( QgsAbstractGeometry *geom ) // cppcheck-suppress duplInheritedMember
1100 {
1101 if ( geom && QgsWkbTypes::flatType( geom->wkbType() ) == Qgis::WkbType::LineString )
1102 return static_cast<QgsLineString *>( geom );
1103 return nullptr;
1104 }
1105#endif
1106
1108
1109#ifdef SIP_RUN
1110 SIP_PYOBJECT __repr__();
1111 % MethodCode
1112 QString wkt = sipCpp->asWkt();
1113 if ( wkt.length() > 1000 )
1114 wkt = wkt.left( 1000 ) + QStringLiteral( "..." );
1115 QString str = QStringLiteral( "<QgsLineString: %1>" ).arg( wkt );
1116 sipRes = PyUnicode_FromString( str.toUtf8().constData() );
1117 % End
1118
1128 SIP_PYOBJECT __getitem__( int index ) SIP_TYPEHINT( QgsPoint );
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 std::unique_ptr< QgsPoint > p;
1139 if ( a0 >= 0 )
1140 p = std::make_unique< QgsPoint >( sipCpp->pointN( a0 ) );
1141 else
1142 p = std::make_unique< QgsPoint >( sipCpp->pointN( count + a0 ) );
1143 sipRes = sipConvertFromType( p.release(), sipType_QgsPoint, Py_None );
1144 }
1145 % End
1146
1156 void __setitem__( int index, const QgsPoint &point );
1157 % MethodCode
1158 const int count = sipCpp->numPoints();
1159 if ( a0 < -count || a0 >= count )
1160 {
1161 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
1162 sipIsErr = 1;
1163 }
1164 else
1165 {
1166 if ( a0 < 0 )
1167 a0 = count + a0;
1168 sipCpp->setXAt( a0, a1->x() );
1169 sipCpp->setYAt( a0, a1->y() );
1170 if ( sipCpp->isMeasure() )
1171 sipCpp->setMAt( a0, a1->m() );
1172 if ( sipCpp->is3D() )
1173 sipCpp->setZAt( a0, a1->z() );
1174 }
1175 % End
1176
1177
1187 void __delitem__( int index );
1188 % MethodCode
1189 const int count = sipCpp->numPoints();
1190 if ( a0 >= 0 && a0 < count )
1191 sipCpp->deleteVertex( QgsVertexId( -1, -1, a0 ) );
1192 else if ( a0 < 0 && a0 >= -count )
1193 sipCpp->deleteVertex( QgsVertexId( -1, -1, count + a0 ) );
1194 else
1195 {
1196 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
1197 sipIsErr = 1;
1198 }
1199 % End
1200
1201#endif
1202
1209 Q_DECL_DEPRECATED QgsBox3D calculateBoundingBox3d() const SIP_DEPRECATED;
1210
1216 QgsBox3D calculateBoundingBox3D() const override;
1217
1224 std::unique_ptr< QgsLineString > measuredLine( double start, double end ) const;
1225
1239 std::unique_ptr< QgsLineString > interpolateM( bool use3DDistance = true ) const;
1240
1265 bool lineLocatePointByM( double m, double &x SIP_OUT, double &y SIP_OUT, double &z SIP_OUT, double &distanceFromStart SIP_OUT, bool use3DDistance = true ) const;
1266
1267 protected:
1268
1269 int compareToSameClass( const QgsAbstractGeometry *other ) const final;
1270
1271 private:
1272 QVector<double> mX;
1273 QVector<double> mY;
1274 QVector<double> mZ;
1275 QVector<double> mM;
1276
1277 void importVerticesFromWkb( const QgsConstWkbPtr &wkb );
1278
1284 void fromWkbPoints( Qgis::WkbType type, const QgsConstWkbPtr &wkb )
1285 {
1286 mWkbType = type;
1287 importVerticesFromWkb( wkb );
1288 }
1289
1290 bool lineLocatePointByMPrivate( double m, double &x, double &y, double &z, double &distanceFromStart, bool use3DDistance, bool haveInterpolatedM ) const;
1291
1292 friend class QgsPolygon;
1293 friend class QgsTriangle;
1294 friend class TestQgsGeometry;
1295
1296};
1297
1298// clazy:excludeall=qstring-allocations
1299
1300#endif // QGSLINESTRING_H
@ LineString
LineString.
Definition qgis.h:280
@ Point25D
Point25D.
Definition qgis.h:340
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...
QgsAbstractGeometry()=default
A 3-dimensional box composed of x, y, z coordinates.
Definition qgsbox3d.h:42
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.
QgsCurve()=default
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.
static std::unique_ptr< QgsLineString > fromBezierCurve(const QgsPoint &start, const QgsPoint &controlPoint1, const QgsPoint &controlPoint2, const QgsPoint &end, int segments=30)
Returns a new linestring created by segmentizing the bezier curve between start and end,...
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.
void points(QgsPointSequence &pt) const override
Returns a list of points within the curve.
QVector< double > xVector() const
Returns the x vertex values as a vector.
static std::unique_ptr< QgsLineString > fromQPolygonF(const QPolygonF &polygon)
Returns a new linestring from a QPolygonF polygon input.
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the linestring does not have z values.
QgsLineString()
Constructor for an empty linestring geometry.
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.
friend class TestQgsGeometry
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.
friend class QgsPolygon
QVector< double > zVector() const
Returns the z vertex values as a vector.
static QgsLineString * cast(QgsAbstractGeometry *geom)
Cast the geom to a QgsLineString.
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the linestring does not have m values.
friend class QgsTriangle
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.
Represents 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
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
#define SIP_TYPEHINT(type)
Definition qgis_sip.h:240
#define SIP_DEPRECATED
Definition qgis_sip.h:114
#define SIP_SKIP
Definition qgis_sip.h:134
#define SIP_OUT
Definition qgis_sip.h:58
#define SIP_HOLDGIL
Definition qgis_sip.h:179
#define SIP_FACTORY
Definition qgis_sip.h:84
#define SIP_THROW(name,...)
Definition qgis_sip.h:211
T qgsgeometry_cast(QgsAbstractGeometry *geom)
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:72