QGIS API Documentation 3.99.0-Master (d270888f95f)
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#include <QString>
30
31using namespace Qt::StringLiterals;
32
34class QgsBox3D;
35
36/***************************************************************************
37 * This class is considered CRITICAL and any change MUST be accompanied with
38 * full unit tests in testqgsgeometry.cpp.
39 * See details in QEP #17
40 ****************************************************************************/
41
47class CORE_EXPORT QgsLineString: public QgsCurve
48{
49
50 public:
51
56#ifndef SIP_RUN
57
63 QgsLineString( const QVector<QgsPoint> &points );
64
70 QgsLineString( const QVector<QgsPointXY> &points );
71#else
72
80 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 )];
81 % MethodCode
82 if ( !PySequence_Check( a0 ) )
83 {
84 PyErr_SetString( PyExc_TypeError, u"A sequence of QgsPoint, QgsPointXY or array of floats is expected"_s.toUtf8().constData() );
85 sipIsErr = 1;
86 }
87 else
88 {
89 int state;
90 const int size = PySequence_Size( a0 );
91 QVector< double > xl;
92 QVector< double > yl;
93 bool hasZ = false;
94 QVector< double > zl;
95 bool hasM = false;
96 QVector< double > ml;
97 xl.reserve( size );
98 yl.reserve( size );
99
100 bool is25D = false;
101
102 sipIsErr = 0;
103 for ( int i = 0; i < size; ++i )
104 {
105 PyObject *value = PySequence_GetItem( a0, i );
106 if ( !value )
107 {
108 PyErr_SetString( PyExc_TypeError, u"Invalid type at index %1."_s.arg( i ) .toUtf8().constData() );
109 sipIsErr = 1;
110 break;
111 }
112
113 if ( PySequence_Check( value ) )
114 {
115 const int elementSize = PySequence_Size( value );
116 if ( elementSize < 2 || elementSize > 4 )
117 {
118 sipIsErr = 1;
119 PyErr_SetString( PyExc_TypeError, u"Invalid sequence size at index %1. Expected an array of 2-4 float values, got %2."_s.arg( i ).arg( elementSize ).toUtf8().constData() );
120 Py_DECREF( value );
121 break;
122 }
123 else
124 {
125 sipIsErr = 0;
126 for ( int j = 0; j < elementSize; ++j )
127 {
128 PyObject *element = PySequence_GetItem( value, j );
129 if ( !element )
130 {
131 PyErr_SetString( PyExc_TypeError, u"Invalid type at index %1."_s.arg( i ) .toUtf8().constData() );
132 sipIsErr = 1;
133 break;
134 }
135
136 PyErr_Clear();
137 double d = PyFloat_AsDouble( element );
138 if ( PyErr_Occurred() )
139 {
140 Py_DECREF( value );
141 sipIsErr = 1;
142 break;
143 }
144 if ( j == 0 )
145 xl.append( d );
146 else if ( j == 1 )
147 yl.append( d );
148
149 if ( i == 0 && j == 2 )
150 {
151 hasZ = true;
152 zl.reserve( size );
153 zl.append( d );
154 }
155 else if ( i > 0 && j == 2 && hasZ )
156 {
157 zl.append( d );
158 }
159
160 if ( i == 0 && j == 3 )
161 {
162 hasM = true;
163 ml.reserve( size );
164 ml.append( d );
165 }
166 else if ( i > 0 && j == 3 && hasM )
167 {
168 ml.append( d );
169 }
170
171 Py_DECREF( element );
172 }
173
174 if ( hasZ && elementSize < 3 )
175 zl.append( std::numeric_limits< double >::quiet_NaN() );
176 if ( hasM && elementSize < 4 )
177 ml.append( std::numeric_limits< double >::quiet_NaN() );
178
179 Py_DECREF( value );
180 if ( sipIsErr )
181 {
182 break;
183 }
184 }
185 }
186 else
187 {
188 if ( sipCanConvertToType( value, sipType_QgsPointXY, SIP_NOT_NONE ) )
189 {
190 sipIsErr = 0;
191 QgsPointXY *p = reinterpret_cast<QgsPointXY *>( sipConvertToType( value, sipType_QgsPointXY, 0, SIP_NOT_NONE, &state, &sipIsErr ) );
192 if ( !sipIsErr )
193 {
194 xl.append( p->x() );
195 yl.append( p->y() );
196 }
197 sipReleaseType( p, sipType_QgsPointXY, state );
198 }
199 else if ( sipCanConvertToType( value, sipType_QgsPoint, SIP_NOT_NONE ) )
200 {
201 sipIsErr = 0;
202 QgsPoint *p = reinterpret_cast<QgsPoint *>( sipConvertToType( value, sipType_QgsPoint, 0, SIP_NOT_NONE, &state, &sipIsErr ) );
203 if ( !sipIsErr )
204 {
205 xl.append( p->x() );
206 yl.append( p->y() );
207
208 if ( i == 0 && p->is3D() )
209 {
210 hasZ = true;
211 zl.reserve( size );
212 zl.append( p->z() );
213 }
214 else if ( i > 0 && hasZ )
215 {
216 zl.append( p->z() );
217 }
218
219 if ( i == 0 && p->isMeasure() )
220 {
221 hasM = true;
222 ml.reserve( size );
223 ml.append( p->m() );
224 }
225 else if ( i > 0 && hasM )
226 {
227 ml.append( p->m() );
228 }
229
230 if ( i == 0 && p->wkbType() == Qgis::WkbType::Point25D )
231 is25D = true;
232 }
233 sipReleaseType( p, sipType_QgsPoint, state );
234 }
235 else
236 {
237 sipIsErr = 1;
238 }
239
240 Py_DECREF( value );
241
242 if ( sipIsErr )
243 {
244 // couldn't convert the sequence value to a QgsPoint or QgsPointXY
245 PyErr_SetString( PyExc_TypeError, u"Invalid type at index %1. Expected QgsPoint, QgsPointXY or array of floats."_s.arg( i ) .toUtf8().constData() );
246 break;
247 }
248 }
249 }
250 if ( sipIsErr == 0 )
251 sipCpp = new sipQgsLineString( QgsLineString( xl, yl, zl, ml, is25D ) );
252 }
253 % End
254#endif
255
261
279 QgsLineString( const QVector<double> &x, const QVector<double> &y,
280 const QVector<double> &z = QVector<double>(),
281 const QVector<double> &m = QVector<double>(), bool is25DType = false ) SIP_HOLDGIL;
282
287 QgsLineString( const QgsPoint &p1, const QgsPoint &p2 ) SIP_HOLDGIL;
288
299 static std::unique_ptr< QgsLineString > fromBezierCurve( const QgsPoint &start, const QgsPoint &controlPoint1, const QgsPoint &controlPoint2, const QgsPoint &end, int segments = 30 );
300
306 static std::unique_ptr< QgsLineString > fromQPolygonF( const QPolygonF &polygon );
307#ifndef SIP_RUN
308 private:
309 bool fuzzyHelper( double epsilon,
310 const QgsAbstractGeometry &other,
311 bool is3DFlag,
312 bool isMeasureFlag,
313 std::function<bool( double, double, double, double, double, double, double, double, double )> comparator3DMeasure,
314 std::function<bool( double, double, double, double, double, double, double )> comparator3D,
315 std::function<bool( double, double, double, double, double, double, double )> comparatorMeasure,
316 std::function<bool( double, double, double, double, double )> comparator2D ) const
317 {
318 const QgsLineString *otherLine = qgsgeometry_cast< const QgsLineString * >( &other );
319 if ( !otherLine )
320 return false;
321
322 if ( mWkbType != otherLine->mWkbType )
323 return false;
324
325 const int size = mX.count();
326 if ( size != otherLine->mX.count() )
327 return false;
328
329 bool result = true;
330 const double *xData = mX.constData();
331 const double *yData = mY.constData();
332 const double *zData = is3DFlag ? mZ.constData() : nullptr;
333 const double *mData = isMeasureFlag ? mM.constData() : nullptr;
334 const double *otherXData = otherLine->mX.constData();
335 const double *otherYData = otherLine->mY.constData();
336 const double *otherZData = is3DFlag ? otherLine->mZ.constData() : nullptr;
337 const double *otherMData = isMeasureFlag ? otherLine->mM.constData() : nullptr;
338 for ( int i = 0; i < size; ++i )
339 {
340 if ( is3DFlag && isMeasureFlag )
341 {
342 result &= comparator3DMeasure( epsilon, *xData++, *yData++, *zData++, *mData++,
343 *otherXData++, *otherYData++, *otherZData++, *otherMData++ );
344 }
345 else if ( is3DFlag )
346 {
347 result &= comparator3D( epsilon, *xData++, *yData++, *zData++,
348 *otherXData++, *otherYData++, *otherZData++ );
349 }
350 else if ( isMeasureFlag )
351 {
352 result &= comparatorMeasure( epsilon, *xData++, *yData++, *mData++,
353 *otherXData++, *otherYData++, *otherMData++ );
354 }
355 else
356 {
357 result &= comparator2D( epsilon, *xData++, *yData++,
358 *otherXData++, *otherYData++ );
359 }
360 if ( ! result )
361 {
362 return false;
363 }
364 }
365
366 return result;
367 }
368#endif // !SIP_RUN
369
370 public:
371 bool fuzzyEqual( const QgsAbstractGeometry &other, double epsilon = 1e-8 ) const override SIP_HOLDGIL
372 {
373 return fuzzyHelper(
374 epsilon,
375 other,
376 is3D(),
377 isMeasure(),
378 []( double epsilon, double x1, double y1, double z1, double m1,
379 double x2, double y2, double z2, double m2 )
380 {
381 return QgsGeometryUtilsBase::fuzzyEqual( epsilon, x1, y1, z1, m1, x2, y2, z2, m2 );
382 },
383 []( double epsilon, double x1, double y1, double z1,
384 double x2, double y2, double z2 )
385 {
386 return QgsGeometryUtilsBase::fuzzyEqual( epsilon, x1, y1, z1, x2, y2, z2 );
387 },
388 []( double epsilon, double x1, double y1, double m1,
389 double x2, double y2, double m2 )
390 {
391 return QgsGeometryUtilsBase::fuzzyEqual( epsilon, x1, y1, m1, x2, y2, m2 );
392 },
393 []( double epsilon, double x1, double y1,
394 double x2, double y2 )
395 {
396 return QgsGeometryUtilsBase::fuzzyEqual( epsilon, x1, y1, x2, y2 );
397 } );
398 }
399
400 bool fuzzyDistanceEqual( const QgsAbstractGeometry &other, double epsilon = 1e-8 ) const override SIP_HOLDGIL
401 {
402 return fuzzyHelper(
403 epsilon,
404 other,
405 is3D(),
406 isMeasure(),
407 []( double epsilon, double x1, double y1, double z1, double m1,
408 double x2, double y2, double z2, double m2 )
409 {
410 return QgsGeometryUtilsBase::fuzzyDistanceEqual( epsilon, x1, y1, z1, m1, x2, y2, z2, m2 );
411 },
412 []( double epsilon, double x1, double y1, double z1,
413 double x2, double y2, double z2 )
414 {
415 return QgsGeometryUtilsBase::fuzzyDistanceEqual( epsilon, x1, y1, z1, x2, y2, z2 );
416 },
417 []( double epsilon, double x1, double y1, double m1,
418 double x2, double y2, double m2 )
419 {
420 return QgsGeometryUtilsBase::fuzzyDistanceEqual( epsilon, x1, y1, m1, x2, y2, m2 );
421 },
422 []( double epsilon, double x1, double y1,
423 double x2, double y2 )
424 {
425 return QgsGeometryUtilsBase::fuzzyDistanceEqual( epsilon, x1, y1, x2, y2 );
426 } );
427 }
428
429 bool equals( const QgsCurve &other ) const override
430 {
431 return fuzzyEqual( other, 1e-8 );
432 }
433
434
435#ifndef SIP_RUN
436
441 QgsPoint pointN( int i ) const;
442#else
443
452 SIP_PYOBJECT pointN( int i ) const SIP_TYPEHINT( QgsPoint );
453 % MethodCode
454 const int count = sipCpp->numPoints();
455 if ( a0 < -count || a0 >= count )
456 {
457 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
458 sipIsErr = 1;
459 }
460 else
461 {
462 std::unique_ptr< QgsPoint > p;
463 if ( a0 >= 0 )
464 p = std::make_unique< QgsPoint >( sipCpp->pointN( a0 ) );
465 else // negative index, count backwards from end
466 p = std::make_unique< QgsPoint >( sipCpp->pointN( count + a0 ) );
467 sipRes = sipConvertFromType( p.release(), sipType_QgsPoint, Py_None );
468 }
469 % End
470#endif
471
472#ifndef SIP_RUN
473 double xAt( int index ) const override;
474#else
475
484 double xAt( int index ) const override;
485 % MethodCode
486 const int count = sipCpp->numPoints();
487 if ( a0 < -count || a0 >= count )
488 {
489 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
490 sipIsErr = 1;
491 }
492 else
493 {
494 if ( a0 >= 0 )
495 return PyFloat_FromDouble( sipCpp->xAt( a0 ) );
496 else
497 return PyFloat_FromDouble( sipCpp->xAt( count + a0 ) );
498 }
499 % End
500#endif
501
502#ifndef SIP_RUN
503 double yAt( int index ) const override;
504#else
505
514 double yAt( int index ) const override;
515 % MethodCode
516 const int count = sipCpp->numPoints();
517 if ( a0 < -count || a0 >= count )
518 {
519 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
520 sipIsErr = 1;
521 }
522 else
523 {
524 if ( a0 >= 0 )
525 return PyFloat_FromDouble( sipCpp->yAt( a0 ) );
526 else
527 return PyFloat_FromDouble( sipCpp->yAt( count + a0 ) );
528 }
529 % End
530#endif
531
538 const double *xData() const SIP_SKIP
539 {
540 return mX.constData();
541 }
542
549 const double *yData() const SIP_SKIP
550 {
551 return mY.constData();
552 }
553
562 const double *zData() const SIP_SKIP
563 {
564 if ( mZ.empty() )
565 return nullptr;
566 else
567 return mZ.constData();
568 }
569
578 const double *mData() const SIP_SKIP
579 {
580 if ( mM.empty() )
581 return nullptr;
582 else
583 return mM.constData();
584 }
585
591 QVector< double > xVector() const SIP_SKIP
592 {
593 return mX;
594 }
595
601 QVector< double > yVector() const SIP_SKIP
602 {
603 return mY;
604 }
605
611 QVector< double > zVector() const SIP_SKIP
612 {
613 return mZ;
614 }
615
621 QVector< double > mVector() const SIP_SKIP
622 {
623 return mM;
624 }
625
626
627#ifndef SIP_RUN
628
636 double zAt( int index ) const override
637 {
638 if ( index >= 0 && index < mZ.size() )
639 return mZ.at( index );
640 else
641 return std::numeric_limits<double>::quiet_NaN();
642 }
643#else
644
655 double zAt( int index ) const override;
656 % MethodCode
657 const int count = sipCpp->numPoints();
658 if ( a0 < -count || a0 >= count )
659 {
660 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
661 sipIsErr = 1;
662 }
663 else
664 {
665 if ( a0 >= 0 )
666 return PyFloat_FromDouble( sipCpp->zAt( a0 ) );
667 else
668 return PyFloat_FromDouble( sipCpp->zAt( count + a0 ) );
669 }
670 % End
671#endif
672
673#ifndef SIP_RUN
674
682 double mAt( int index ) const override
683 {
684 if ( index >= 0 && index < mM.size() )
685 return mM.at( index );
686 else
687 return std::numeric_limits<double>::quiet_NaN();
688 }
689#else
690
701 double mAt( int index ) const override;
702 % MethodCode
703 const int count = sipCpp->numPoints();
704 if ( a0 < -count || a0 >= count )
705 {
706 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
707 sipIsErr = 1;
708 }
709 else
710 {
711 if ( a0 >= 0 )
712 return PyFloat_FromDouble( sipCpp->mAt( a0 ) );
713 else
714 return PyFloat_FromDouble( sipCpp->mAt( count + a0 ) );
715 }
716 % End
717#endif
718
719#ifndef SIP_RUN
720
728 void setXAt( int index, double x );
729#else
730
742 void setXAt( int index, double x );
743 % MethodCode
744 const int count = sipCpp->numPoints();
745 if ( a0 < -count || a0 >= count )
746 {
747 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
748 sipIsErr = 1;
749 }
750 else
751 {
752 if ( a0 >= 0 )
753 sipCpp->setXAt( a0, a1 );
754 else
755 sipCpp->setXAt( count + a0, a1 );
756 }
757 % End
758#endif
759
760#ifndef SIP_RUN
761
769 void setYAt( int index, double y );
770#else
771
783 void setYAt( int index, double y );
784 % MethodCode
785 const int count = sipCpp->numPoints();
786 if ( a0 < -count || a0 >= count )
787 {
788 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
789 sipIsErr = 1;
790 }
791 else
792 {
793 if ( a0 >= 0 )
794 sipCpp->setYAt( a0, a1 );
795 else
796 sipCpp->setYAt( count + a0, a1 );
797 }
798 % End
799#endif
800
801#ifndef SIP_RUN
802
810 void setZAt( int index, double z )
811 {
812 if ( index >= 0 && index < mZ.size() )
813 mZ[ index ] = z;
814 }
815#else
816
827 void setZAt( int index, double z );
828 % MethodCode
829 const int count = sipCpp->numPoints();
830 if ( a0 < -count || a0 >= count )
831 {
832 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
833 sipIsErr = 1;
834 }
835 else
836 {
837 if ( a0 >= 0 )
838 sipCpp->setZAt( a0, a1 );
839 else
840 sipCpp->setZAt( count + a0, a1 );
841 }
842 % End
843#endif
844
845#ifndef SIP_RUN
846
854 void setMAt( int index, double m )
855 {
856 if ( index >= 0 && index < mM.size() )
857 mM[ index ] = m;
858 }
859#else
860
871 void setMAt( int index, double m );
872 % MethodCode
873 const int count = sipCpp->numPoints();
874 if ( a0 < -count || a0 >= count )
875 {
876 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
877 sipIsErr = 1;
878 }
879 else
880 {
881 if ( a0 >= 0 )
882 sipCpp->setMAt( a0, a1 );
883 else
884 sipCpp->setMAt( count + a0, a1 );
885 }
886 % End
887#endif
888
902 void setPoints( size_t size, const double *x, const double *y, const double *z = nullptr, const double *m = nullptr ) SIP_SKIP;
903
909 void setPoints( const QgsPointSequence &points );
910
915 void append( const QgsLineString *line );
916
921 void addVertex( const QgsPoint &pt );
922
924 void close();
925
930 QgsCompoundCurve *toCurveType() const override SIP_FACTORY;
931
937 void extend( double startDistance, double endDistance );
938
939#ifndef SIP_RUN
940
946 void visitPointsByRegularDistance( double distance, const std::function< bool( double x, double y, double z, double m,
947 double startSegmentX, double startSegmentY, double startSegmentZ, double startSegmentM,
948 double endSegmentX, double endSegmentY, double endSegmentZ, double endSegmentM
949 ) > &visitPoint ) const;
950#endif
951
952 //reimplemented methods
953 QString geometryType() const override SIP_HOLDGIL;
954 int dimension() const override SIP_HOLDGIL;
955 QgsLineString *clone() const override SIP_FACTORY;
956 void clear() override;
957 bool isEmpty() const override SIP_HOLDGIL;
958 int indexOf( const QgsPoint &point ) const final;
959 bool isValid( QString &error SIP_OUT, Qgis::GeometryValidityFlags flags = Qgis::GeometryValidityFlags() ) const override;
960 QgsLineString *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0, bool removeRedundantPoints = false ) const override SIP_FACTORY;
961 bool removeDuplicateNodes( double epsilon = 4 * std::numeric_limits<double>::epsilon(), bool useZValues = false ) override;
962 bool isClosed() const override SIP_HOLDGIL;
963 bool isClosed2D() const override SIP_HOLDGIL;
964 bool boundingBoxIntersects( const QgsRectangle &rectangle ) const override SIP_HOLDGIL;
965 bool boundingBoxIntersects( const QgsBox3D &box3d ) const override SIP_HOLDGIL;
966
974 QVector< QgsVertexId > collectDuplicateNodes( double epsilon = 4 * std::numeric_limits<double>::epsilon(), bool useZValues = false ) const;
975
976 QPolygonF asQPolygonF() const override;
977
978 QgsLineString *simplifyByDistance( double tolerance ) const override SIP_FACTORY;
979 bool fromWkb( QgsConstWkbPtr &wkb ) override;
980 bool fromWkt( const QString &wkt ) override;
981
982 int wkbSize( QgsAbstractGeometry::WkbFlags flags = QgsAbstractGeometry::WkbFlags() ) const override;
983 QByteArray asWkb( QgsAbstractGeometry::WkbFlags flags = QgsAbstractGeometry::WkbFlags() ) const override;
984 QString asWkt( int precision = 17 ) const override;
985 QDomElement asGml2( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const override;
986 QDomElement asGml3( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const override;
987 json asJsonObject( int precision = 17 ) const override SIP_SKIP;
988 QString asKml( int precision = 17 ) const override;
989
990 //curve interface
991 double length() const override SIP_HOLDGIL;
992
993#ifndef SIP_RUN
994 std::tuple< std::unique_ptr< QgsCurve >, std::unique_ptr< QgsCurve > > splitCurveAtVertex( int index ) const final;
995#endif
996
1005 QVector<QgsLineString *> splitToDisjointXYParts() const SIP_FACTORY;
1006
1013 double length3D() const SIP_HOLDGIL;
1014 QgsPoint startPoint() const override SIP_HOLDGIL;
1015 QgsPoint endPoint() const override SIP_HOLDGIL;
1016
1023 QgsLineString *curveToLine( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const override SIP_FACTORY;
1024
1025 int numPoints() const override SIP_HOLDGIL;
1026 int nCoordinates() const override SIP_HOLDGIL;
1027 void points( QgsPointSequence &pt SIP_OUT ) const override;
1028
1029 void draw( QPainter &p ) const override;
1030
1031 void transform( const QgsCoordinateTransform &ct, Qgis::TransformDirection d = Qgis::TransformDirection::Forward, bool transformZ = false ) override SIP_THROW( QgsCsException );
1032 void transform( const QTransform &t, double zTranslate = 0.0, double zScale = 1.0, double mTranslate = 0.0, double mScale = 1.0 ) override;
1033
1034 void addToPainterPath( QPainterPath &path ) const override;
1035 void drawAsPolygon( QPainter &p ) const override;
1036
1037 bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) override;
1038 bool moveVertex( QgsVertexId position, const QgsPoint &newPos ) override;
1039 bool deleteVertex( QgsVertexId position ) override;
1040
1041 QgsLineString *reversed() const override SIP_FACTORY;
1042 QgsPoint *interpolatePoint( double distance ) const override SIP_FACTORY;
1043 QgsLineString *curveSubstring( double startDistance, double endDistance ) const override SIP_FACTORY;
1044
1045 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;
1046 bool pointAt( int node, QgsPoint &point, Qgis::VertexType &type ) const override;
1047
1048 QgsPoint centroid() const override;
1049
1060 void sumUpArea( double &sum SIP_OUT ) const override;
1061
1072 void sumUpArea3D( double &sum SIP_OUT ) const override;
1073
1074 double vertexAngle( QgsVertexId vertex ) const override;
1075 double segmentLength( QgsVertexId startVertex ) const override;
1076 double distanceBetweenVertices( QgsVertexId fromVertex, QgsVertexId toVertex ) const override;
1077 bool addZValue( double zValue = 0 ) override;
1078 bool addMValue( double mValue = 0 ) override;
1079
1080 bool dropZValue() override;
1081 bool dropMValue() override;
1082 void swapXy() override;
1083
1084 bool convertTo( Qgis::WkbType type ) override;
1085
1086 bool transform( QgsAbstractGeometryTransformer *transformer, QgsFeedback *feedback = nullptr ) override;
1087 void scroll( int firstVertexIndex ) final;
1088
1089#ifndef SIP_RUN
1090 void filterVertices( const std::function< bool( const QgsPoint & ) > &filter ) override;
1091 void transformVertices( const std::function< QgsPoint( const QgsPoint & ) > &transform ) override;
1092
1101 inline static const QgsLineString *cast( const QgsAbstractGeometry *geom ) // cppcheck-suppress duplInheritedMember
1102 {
1103 if ( geom && QgsWkbTypes::flatType( geom->wkbType() ) == Qgis::WkbType::LineString )
1104 return static_cast<const QgsLineString *>( geom );
1105 return nullptr;
1106 }
1107
1116 inline static QgsLineString *cast( QgsAbstractGeometry *geom ) // cppcheck-suppress duplInheritedMember
1117 {
1118 if ( geom && QgsWkbTypes::flatType( geom->wkbType() ) == Qgis::WkbType::LineString )
1119 return static_cast<QgsLineString *>( geom );
1120 return nullptr;
1121 }
1122#endif
1123
1125
1126#ifdef SIP_RUN
1127 SIP_PYOBJECT __repr__();
1128 % MethodCode
1129 QString wkt = sipCpp->asWkt();
1130 if ( wkt.length() > 1000 )
1131 wkt = wkt.left( 1000 ) + u"..."_s;
1132 QString str = u"<QgsLineString: %1>"_s.arg( wkt );
1133 sipRes = PyUnicode_FromString( str.toUtf8().constData() );
1134 % End
1135
1145 SIP_PYOBJECT __getitem__( int index ) SIP_TYPEHINT( QgsPoint );
1146 % MethodCode
1147 const int count = sipCpp->numPoints();
1148 if ( a0 < -count || a0 >= count )
1149 {
1150 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
1151 sipIsErr = 1;
1152 }
1153 else
1154 {
1155 std::unique_ptr< QgsPoint > p;
1156 if ( a0 >= 0 )
1157 p = std::make_unique< QgsPoint >( sipCpp->pointN( a0 ) );
1158 else
1159 p = std::make_unique< QgsPoint >( sipCpp->pointN( count + a0 ) );
1160 sipRes = sipConvertFromType( p.release(), sipType_QgsPoint, Py_None );
1161 }
1162 % End
1163
1173 void __setitem__( int index, const QgsPoint &point );
1174 % MethodCode
1175 const int count = sipCpp->numPoints();
1176 if ( a0 < -count || a0 >= count )
1177 {
1178 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
1179 sipIsErr = 1;
1180 }
1181 else
1182 {
1183 if ( a0 < 0 )
1184 a0 = count + a0;
1185 sipCpp->setXAt( a0, a1->x() );
1186 sipCpp->setYAt( a0, a1->y() );
1187 if ( sipCpp->isMeasure() )
1188 sipCpp->setMAt( a0, a1->m() );
1189 if ( sipCpp->is3D() )
1190 sipCpp->setZAt( a0, a1->z() );
1191 }
1192 % End
1193
1194
1204 void __delitem__( int index );
1205 % MethodCode
1206 const int count = sipCpp->numPoints();
1207 if ( a0 >= 0 && a0 < count )
1208 sipCpp->deleteVertex( QgsVertexId( -1, -1, a0 ) );
1209 else if ( a0 < 0 && a0 >= -count )
1210 sipCpp->deleteVertex( QgsVertexId( -1, -1, count + a0 ) );
1211 else
1212 {
1213 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
1214 sipIsErr = 1;
1215 }
1216 % End
1217
1218#endif
1219
1226 Q_DECL_DEPRECATED QgsBox3D calculateBoundingBox3d() const SIP_DEPRECATED;
1227
1233 QgsBox3D calculateBoundingBox3D() const override;
1234
1241 std::unique_ptr< QgsLineString > measuredLine( double start, double end ) const;
1242
1256 std::unique_ptr< QgsLineString > interpolateM( bool use3DDistance = true ) const;
1257
1282 bool lineLocatePointByM( double m, double &x SIP_OUT, double &y SIP_OUT, double &z SIP_OUT, double &distanceFromStart SIP_OUT, bool use3DDistance = true ) const;
1283
1284 protected:
1285
1286 int compareToSameClass( const QgsAbstractGeometry *other ) const final;
1287
1288 private:
1289 QVector<double> mX;
1290 QVector<double> mY;
1291 QVector<double> mZ;
1292 QVector<double> mM;
1293
1294 void importVerticesFromWkb( const QgsConstWkbPtr &wkb );
1295
1301 void fromWkbPoints( Qgis::WkbType type, const QgsConstWkbPtr &wkb )
1302 {
1303 mWkbType = type;
1304 importVerticesFromWkb( wkb );
1305 }
1306
1307 bool lineLocatePointByMPrivate( double m, double &x, double &y, double &z, double &distanceFromStart, bool use3DDistance, bool haveInterpolatedM ) const;
1308
1309 friend class QgsPolygon;
1310 friend class QgsTriangle;
1311 friend class TestQgsGeometry;
1312
1313};
1314
1315// clazy:excludeall=qstring-allocations
1316
1317#endif // QGSLINESTRING_H
@ LineString
LineString.
Definition qgis.h:283
@ Point25D
Point25D.
Definition qgis.h:347
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:45
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:62
double y
Definition qgspointxy.h:66
double x
Definition qgspointxy.h:65
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:53
double z
Definition qgspoint.h:58
double x
Definition qgspoint.h:56
double m
Definition qgspoint.h:59
double y
Definition qgspoint.h:57
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:75