QGIS API Documentation 4.1.0-Master (60fea48833c)
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 public:
50 // clang-format off
55 // clang-format on
56#ifndef SIP_RUN
57
63 QgsLineString( const QVector<QgsPoint> &points );
64
70 QgsLineString( const QVector<QgsPointXY> &points );
71#else
72// clang-format off
73
81 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 )];
82 % MethodCode
83 if ( !PySequence_Check( a0 ) )
84 {
85 PyErr_SetString( PyExc_TypeError, u"A sequence of QgsPoint, QgsPointXY or array of floats is expected"_s.toUtf8().constData() );
86 sipIsErr = 1;
87 }
88 else
89 {
90 int state;
91 const int size = PySequence_Size( a0 );
92 QVector< double > xl;
93 QVector< double > yl;
94 bool hasZ = false;
95 QVector< double > zl;
96 bool hasM = false;
97 QVector< double > ml;
98 xl.reserve( size );
99 yl.reserve( size );
100
101 bool is25D = false;
102
103 sipIsErr = 0;
104 for ( int i = 0; i < size; ++i )
105 {
106 PyObject *value = PySequence_GetItem( a0, i );
107 if ( !value )
108 {
109 PyErr_SetString( PyExc_TypeError, u"Invalid type at index %1."_s.arg( i ) .toUtf8().constData() );
110 sipIsErr = 1;
111 break;
112 }
113
114 if ( PySequence_Check( value ) )
115 {
116 const int elementSize = PySequence_Size( value );
117 if ( elementSize < 2 || elementSize > 4 )
118 {
119 sipIsErr = 1;
120 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() );
121 Py_DECREF( value );
122 break;
123 }
124 else
125 {
126 sipIsErr = 0;
127 for ( int j = 0; j < elementSize; ++j )
128 {
129 PyObject *element = PySequence_GetItem( value, j );
130 if ( !element )
131 {
132 PyErr_SetString( PyExc_TypeError, u"Invalid type at index %1."_s.arg( i ) .toUtf8().constData() );
133 sipIsErr = 1;
134 break;
135 }
136
137 PyErr_Clear();
138 double d = PyFloat_AsDouble( element );
139 if ( PyErr_Occurred() )
140 {
141 Py_DECREF( value );
142 sipIsErr = 1;
143 break;
144 }
145 if ( j == 0 )
146 xl.append( d );
147 else if ( j == 1 )
148 yl.append( d );
149
150 if ( i == 0 && j == 2 )
151 {
152 hasZ = true;
153 zl.reserve( size );
154 zl.append( d );
155 }
156 else if ( i > 0 && j == 2 && hasZ )
157 {
158 zl.append( d );
159 }
160
161 if ( i == 0 && j == 3 )
162 {
163 hasM = true;
164 ml.reserve( size );
165 ml.append( d );
166 }
167 else if ( i > 0 && j == 3 && hasM )
168 {
169 ml.append( d );
170 }
171
172 Py_DECREF( element );
173 }
174
175 if ( hasZ && elementSize < 3 )
176 zl.append( std::numeric_limits< double >::quiet_NaN() );
177 if ( hasM && elementSize < 4 )
178 ml.append( std::numeric_limits< double >::quiet_NaN() );
179
180 Py_DECREF( value );
181 if ( sipIsErr )
182 {
183 break;
184 }
185 }
186 }
187 else
188 {
189 if ( sipCanConvertToType( value, sipType_QgsPointXY, SIP_NOT_NONE ) )
190 {
191 sipIsErr = 0;
192 QgsPointXY *p = reinterpret_cast<QgsPointXY *>( sipConvertToType( value, sipType_QgsPointXY, 0, SIP_NOT_NONE, &state, &sipIsErr ) );
193 if ( !sipIsErr )
194 {
195 xl.append( p->x() );
196 yl.append( p->y() );
197 }
198 sipReleaseType( p, sipType_QgsPointXY, state );
199 }
200 else if ( sipCanConvertToType( value, sipType_QgsPoint, SIP_NOT_NONE ) )
201 {
202 sipIsErr = 0;
203 QgsPoint *p = reinterpret_cast<QgsPoint *>( sipConvertToType( value, sipType_QgsPoint, 0, SIP_NOT_NONE, &state, &sipIsErr ) );
204 if ( !sipIsErr )
205 {
206 xl.append( p->x() );
207 yl.append( p->y() );
208
209 if ( i == 0 && p->is3D() )
210 {
211 hasZ = true;
212 zl.reserve( size );
213 zl.append( p->z() );
214 }
215 else if ( i > 0 && hasZ )
216 {
217 zl.append( p->z() );
218 }
219
220 if ( i == 0 && p->isMeasure() )
221 {
222 hasM = true;
223 ml.reserve( size );
224 ml.append( p->m() );
225 }
226 else if ( i > 0 && hasM )
227 {
228 ml.append( p->m() );
229 }
230
231 if ( i == 0 && p->wkbType() == Qgis::WkbType::Point25D )
232 is25D = true;
233 }
234 sipReleaseType( p, sipType_QgsPoint, state );
235 }
236 else
237 {
238 sipIsErr = 1;
239 }
240
241 Py_DECREF( value );
242
243 if ( sipIsErr )
244 {
245 // couldn't convert the sequence value to a QgsPoint or QgsPointXY
246 PyErr_SetString( PyExc_TypeError, u"Invalid type at index %1. Expected QgsPoint, QgsPointXY or array of floats."_s.arg( i ) .toUtf8().constData() );
247 break;
248 }
249 }
250 }
251 if ( sipIsErr == 0 )
252 sipCpp = new sipQgsLineString( QgsLineString( xl, yl, zl, ml, is25D ) );
253 }
254 % End
255// clang-format on
256#endif
257
263
281 QgsLineString( const QVector<double> &x, const QVector<double> &y,
282 const QVector<double> &z = QVector<double>(),
283 const QVector<double> &m = QVector<double>(), bool is25DType = false ) SIP_HOLDGIL;
284
289 QgsLineString( const QgsPoint &p1, const QgsPoint &p2 ) SIP_HOLDGIL;
290
301 static std::unique_ptr< QgsLineString > fromBezierCurve( const QgsPoint &start, const QgsPoint &controlPoint1, const QgsPoint &controlPoint2, const QgsPoint &end, int segments = 30 );
302
308 static std::unique_ptr< QgsLineString > fromQPolygonF( const QPolygonF &polygon );
309#ifndef SIP_RUN
310 private:
311 bool fuzzyHelper( double epsilon,
312 const QgsAbstractGeometry &other,
313 bool is3DFlag,
314 bool isMeasureFlag,
315 std::function<bool( double, double, double, double, double, double, double, double, double )> comparator3DMeasure,
316 std::function<bool( double, double, double, double, double, double, double )> comparator3D,
317 std::function<bool( double, double, double, double, double, double, double )> comparatorMeasure,
318 std::function<bool( double, double, double, double, double )> comparator2D ) const
319 {
320 const QgsLineString *otherLine = qgsgeometry_cast< const QgsLineString * >( &other );
321 if ( !otherLine )
322 return false;
323
324 if ( mWkbType != otherLine->mWkbType )
325 return false;
326
327 const int size = mX.count();
328 if ( size != otherLine->mX.count() )
329 return false;
330
331 bool result = true;
332 const double *xData = mX.constData();
333 const double *yData = mY.constData();
334 const double *zData = is3DFlag ? mZ.constData() : nullptr;
335 const double *mData = isMeasureFlag ? mM.constData() : nullptr;
336 const double *otherXData = otherLine->mX.constData();
337 const double *otherYData = otherLine->mY.constData();
338 const double *otherZData = is3DFlag ? otherLine->mZ.constData() : nullptr;
339 const double *otherMData = isMeasureFlag ? otherLine->mM.constData() : nullptr;
340 for ( int i = 0; i < size; ++i )
341 {
342 if ( is3DFlag && isMeasureFlag )
343 {
344 result &= comparator3DMeasure( epsilon, *xData++, *yData++, *zData++, *mData++,
345 *otherXData++, *otherYData++, *otherZData++, *otherMData++ );
346 }
347 else if ( is3DFlag )
348 {
349 result &= comparator3D( epsilon, *xData++, *yData++, *zData++,
350 *otherXData++, *otherYData++, *otherZData++ );
351 }
352 else if ( isMeasureFlag )
353 {
354 result &= comparatorMeasure( epsilon, *xData++, *yData++, *mData++,
355 *otherXData++, *otherYData++, *otherMData++ );
356 }
357 else
358 {
359 result &= comparator2D( epsilon, *xData++, *yData++,
360 *otherXData++, *otherYData++ );
361 }
362 if ( ! result )
363 {
364 return false;
365 }
366 }
367
368 return result;
369 }
370#endif // !SIP_RUN
371
372 public:
373 bool fuzzyEqual( const QgsAbstractGeometry &other, double epsilon = 1e-8 ) const override SIP_HOLDGIL
374 {
375 return fuzzyHelper(
376 epsilon,
377 other,
378 is3D(),
379 isMeasure(),
380 []( double epsilon, double x1, double y1, double z1, double m1,
381 double x2, double y2, double z2, double m2 )
382 {
383 return QgsGeometryUtilsBase::fuzzyEqual( epsilon, x1, y1, z1, m1, x2, y2, z2, m2 );
384 },
385 []( double epsilon, double x1, double y1, double z1,
386 double x2, double y2, double z2 )
387 {
388 return QgsGeometryUtilsBase::fuzzyEqual( epsilon, x1, y1, z1, x2, y2, z2 );
389 },
390 []( double epsilon, double x1, double y1, double m1,
391 double x2, double y2, double m2 )
392 {
393 return QgsGeometryUtilsBase::fuzzyEqual( epsilon, x1, y1, m1, x2, y2, m2 );
394 },
395 []( double epsilon, double x1, double y1,
396 double x2, double y2 )
397 {
398 return QgsGeometryUtilsBase::fuzzyEqual( epsilon, x1, y1, x2, y2 );
399 } );
400 }
401
402 bool fuzzyDistanceEqual( const QgsAbstractGeometry &other, double epsilon = 1e-8 ) const override SIP_HOLDGIL
403 {
404 return fuzzyHelper(
405 epsilon,
406 other,
407 is3D(),
408 isMeasure(),
409 []( double epsilon, double x1, double y1, double z1, double m1,
410 double x2, double y2, double z2, double m2 )
411 {
412 return QgsGeometryUtilsBase::fuzzyDistanceEqual( epsilon, x1, y1, z1, m1, x2, y2, z2, m2 );
413 },
414 []( double epsilon, double x1, double y1, double z1,
415 double x2, double y2, double z2 )
416 {
417 return QgsGeometryUtilsBase::fuzzyDistanceEqual( epsilon, x1, y1, z1, x2, y2, z2 );
418 },
419 []( double epsilon, double x1, double y1, double m1,
420 double x2, double y2, double m2 )
421 {
422 return QgsGeometryUtilsBase::fuzzyDistanceEqual( epsilon, x1, y1, m1, x2, y2, m2 );
423 },
424 []( double epsilon, double x1, double y1,
425 double x2, double y2 )
426 {
427 return QgsGeometryUtilsBase::fuzzyDistanceEqual( epsilon, x1, y1, x2, y2 );
428 } );
429 }
430
431 bool equals( const QgsCurve &other ) const override
432 {
433 return fuzzyEqual( other, 1e-8 );
434 }
435
436
437#ifndef SIP_RUN
438
443 QgsPoint pointN( int i ) const;
444#else
445// clang-format off
446
455 SIP_PYOBJECT pointN( int i ) const SIP_TYPEHINT( QgsPoint );
456 % MethodCode
457 const int count = sipCpp->numPoints();
458 if ( a0 < -count || a0 >= count )
459 {
460 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
461 sipIsErr = 1;
462 }
463 else
464 {
465 std::unique_ptr< QgsPoint > p;
466 if ( a0 >= 0 )
467 p = std::make_unique< QgsPoint >( sipCpp->pointN( a0 ) );
468 else // negative index, count backwards from end
469 p = std::make_unique< QgsPoint >( sipCpp->pointN( count + a0 ) );
470 sipRes = sipConvertFromType( p.release(), sipType_QgsPoint, Py_None );
471 }
472 % End
473// clang-format on
474#endif
475
476#ifndef SIP_RUN
477 double xAt( int index ) const override;
478#else
479// clang-format off
480
489 double xAt( int index ) const override;
490 % MethodCode
491 const int count = sipCpp->numPoints();
492 if ( a0 < -count || a0 >= count )
493 {
494 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
495 sipIsErr = 1;
496 }
497 else
498 {
499 if ( a0 >= 0 )
500 return PyFloat_FromDouble( sipCpp->xAt( a0 ) );
501 else
502 return PyFloat_FromDouble( sipCpp->xAt( count + a0 ) );
503 }
504 % End
505// clang-format on
506#endif
507
508#ifndef SIP_RUN
509 double yAt( int index ) const override;
510#else
511// clang-format off
512
521 double yAt( int index ) const override;
522 % MethodCode
523 const int count = sipCpp->numPoints();
524 if ( a0 < -count || a0 >= count )
525 {
526 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
527 sipIsErr = 1;
528 }
529 else
530 {
531 if ( a0 >= 0 )
532 return PyFloat_FromDouble( sipCpp->yAt( a0 ) );
533 else
534 return PyFloat_FromDouble( sipCpp->yAt( count + a0 ) );
535 }
536 % End
537// clang-format on
538#endif
539
546 const double *xData() const SIP_SKIP
547 {
548 return mX.constData();
549 }
550
557 const double *yData() const SIP_SKIP
558 {
559 return mY.constData();
560 }
561
570 const double *zData() const SIP_SKIP
571 {
572 if ( mZ.empty() )
573 return nullptr;
574 else
575 return mZ.constData();
576 }
577
586 const double *mData() const SIP_SKIP
587 {
588 if ( mM.empty() )
589 return nullptr;
590 else
591 return mM.constData();
592 }
593
599 QVector< double > xVector() const SIP_SKIP
600 {
601 return mX;
602 }
603
609 QVector< double > yVector() const SIP_SKIP
610 {
611 return mY;
612 }
613
619 QVector< double > zVector() const SIP_SKIP
620 {
621 return mZ;
622 }
623
629 QVector< double > mVector() const SIP_SKIP
630 {
631 return mM;
632 }
633
634
635#ifndef SIP_RUN
636
644 double zAt( int index ) const override
645 {
646 if ( index >= 0 && index < mZ.size() )
647 return mZ.at( index );
648 else
649 return std::numeric_limits<double>::quiet_NaN();
650 }
651#else
652// clang-format off
653
664 double zAt( int index ) const override;
665 % MethodCode
666 const int count = sipCpp->numPoints();
667 if ( a0 < -count || a0 >= count )
668 {
669 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
670 sipIsErr = 1;
671 }
672 else
673 {
674 if ( a0 >= 0 )
675 return PyFloat_FromDouble( sipCpp->zAt( a0 ) );
676 else
677 return PyFloat_FromDouble( sipCpp->zAt( count + a0 ) );
678 }
679 % End
680// clang-format on
681#endif
682
683#ifndef SIP_RUN
684
692 double mAt( int index ) const override
693 {
694 if ( index >= 0 && index < mM.size() )
695 return mM.at( index );
696 else
697 return std::numeric_limits<double>::quiet_NaN();
698 }
699#else
700// clang-format off
701
712 double mAt( int index ) const override;
713 % MethodCode
714 const int count = sipCpp->numPoints();
715 if ( a0 < -count || a0 >= count )
716 {
717 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
718 sipIsErr = 1;
719 }
720 else
721 {
722 if ( a0 >= 0 )
723 return PyFloat_FromDouble( sipCpp->mAt( a0 ) );
724 else
725 return PyFloat_FromDouble( sipCpp->mAt( count + a0 ) );
726 }
727 % End
728// clang-format on
729#endif
730
731#ifndef SIP_RUN
732
740 void setXAt( int index, double x );
741#else
742// clang-format off
743
755 void setXAt( int index, double x );
756 % MethodCode
757 const int count = sipCpp->numPoints();
758 if ( a0 < -count || a0 >= count )
759 {
760 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
761 sipIsErr = 1;
762 }
763 else
764 {
765 if ( a0 >= 0 )
766 sipCpp->setXAt( a0, a1 );
767 else
768 sipCpp->setXAt( count + a0, a1 );
769 }
770 % End
771// clang-format on
772#endif
773
774#ifndef SIP_RUN
775
783 void setYAt( int index, double y );
784#else
785// clang-format off
786
798 void setYAt( int index, double y );
799 % MethodCode
800 const int count = sipCpp->numPoints();
801 if ( a0 < -count || a0 >= count )
802 {
803 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
804 sipIsErr = 1;
805 }
806 else
807 {
808 if ( a0 >= 0 )
809 sipCpp->setYAt( a0, a1 );
810 else
811 sipCpp->setYAt( count + a0, a1 );
812 }
813 % End
814// clang-format on
815#endif
816
817#ifndef SIP_RUN
818
826 void setZAt( int index, double z )
827 {
828 if ( index >= 0 && index < mZ.size() )
829 mZ[ index ] = z;
830 }
831#else
832// clang-format off
833
844 void setZAt( int index, double z );
845 % MethodCode
846 const int count = sipCpp->numPoints();
847 if ( a0 < -count || a0 >= count )
848 {
849 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
850 sipIsErr = 1;
851 }
852 else
853 {
854 if ( a0 >= 0 )
855 sipCpp->setZAt( a0, a1 );
856 else
857 sipCpp->setZAt( count + a0, a1 );
858 }
859 % End
860// clang-format on
861#endif
862
863#ifndef SIP_RUN
864
872 void setMAt( int index, double m )
873 {
874 if ( index >= 0 && index < mM.size() )
875 mM[ index ] = m;
876 }
877#else
878// clang-format off
879
890 void setMAt( int index, double m );
891 % MethodCode
892 const int count = sipCpp->numPoints();
893 if ( a0 < -count || a0 >= count )
894 {
895 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
896 sipIsErr = 1;
897 }
898 else
899 {
900 if ( a0 >= 0 )
901 sipCpp->setMAt( a0, a1 );
902 else
903 sipCpp->setMAt( count + a0, a1 );
904 }
905 % End
906// clang-format on
907#endif
908
922 void setPoints( size_t size, const double *x, const double *y, const double *z = nullptr, const double *m = nullptr ) SIP_SKIP;
923
929 void setPoints( const QgsPointSequence &points );
930
935 void append( const QgsLineString *line );
936
941 void addVertex( const QgsPoint &pt );
942
944 void close();
945
950 QgsCompoundCurve *toCurveType() const override SIP_FACTORY;
951
957 void extend( double startDistance, double endDistance );
958
959#ifndef SIP_RUN
960
966 void visitPointsByRegularDistance( double distance, const std::function< bool( double x, double y, double z, double m,
967 double startSegmentX, double startSegmentY, double startSegmentZ, double startSegmentM,
968 double endSegmentX, double endSegmentY, double endSegmentZ, double endSegmentM
969 ) > &visitPoint ) const;
970#endif
971
972 //reimplemented methods
973 QString geometryType() const override SIP_HOLDGIL;
974 int dimension() const override SIP_HOLDGIL;
975 QgsLineString *clone() const override SIP_FACTORY;
976 void clear() override;
977 bool isEmpty() const override SIP_HOLDGIL;
978 int indexOf( const QgsPoint &point ) const final;
979 bool isValid( QString &error SIP_OUT, Qgis::GeometryValidityFlags flags = Qgis::GeometryValidityFlags() ) const override;
980 QgsLineString *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0, bool removeRedundantPoints = false ) const override SIP_FACTORY;
981 bool removeDuplicateNodes( double epsilon = 4 * std::numeric_limits<double>::epsilon(), bool useZValues = false ) override;
982 bool isClosed() const override SIP_HOLDGIL;
983 bool isClosed2D() const override SIP_HOLDGIL;
984 bool boundingBoxIntersects( const QgsRectangle &rectangle ) const override SIP_HOLDGIL;
985 bool boundingBoxIntersects( const QgsBox3D &box3d ) const override SIP_HOLDGIL;
986
994 QVector< QgsVertexId > collectDuplicateNodes( double epsilon = 4 * std::numeric_limits<double>::epsilon(), bool useZValues = false ) const;
995
996 QPolygonF asQPolygonF() const override;
997
998 QgsLineString *simplifyByDistance( double tolerance ) const override SIP_FACTORY;
999 bool fromWkb( QgsConstWkbPtr &wkb ) override;
1000 bool fromWkt( const QString &wkt ) override;
1001
1002 int wkbSize( QgsAbstractGeometry::WkbFlags flags = QgsAbstractGeometry::WkbFlags() ) const override;
1003 QByteArray asWkb( QgsAbstractGeometry::WkbFlags flags = QgsAbstractGeometry::WkbFlags() ) const override;
1004 QString asWkt( int precision = 17 ) const override;
1005 QDomElement asGml2( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const override;
1006 QDomElement asGml3( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const override;
1007 json asJsonObject( int precision = 17 ) const override SIP_SKIP;
1008 QString asKml( int precision = 17 ) const override;
1009
1010 //curve interface
1011 double length() const override SIP_HOLDGIL;
1012
1013#ifndef SIP_RUN
1014 std::tuple< std::unique_ptr< QgsCurve >, std::unique_ptr< QgsCurve > > splitCurveAtVertex( int index ) const final;
1015#endif
1016
1025 QVector<QgsLineString *> splitToDisjointXYParts() const SIP_FACTORY;
1026
1033 double length3D() const SIP_HOLDGIL;
1034 QgsPoint startPoint() const override SIP_HOLDGIL;
1035 QgsPoint endPoint() const override SIP_HOLDGIL;
1036
1043 QgsLineString *curveToLine( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const override SIP_FACTORY;
1044
1045 int numPoints() const override SIP_HOLDGIL;
1046 int nCoordinates() const override SIP_HOLDGIL;
1047 void points( QgsPointSequence &pt SIP_OUT ) const override;
1048
1049 void draw( QPainter &p ) const override;
1050
1051 void transform( const QgsCoordinateTransform &ct, Qgis::TransformDirection d = Qgis::TransformDirection::Forward, bool transformZ = false ) override SIP_THROW( QgsCsException );
1052 void transform( const QTransform &t, double zTranslate = 0.0, double zScale = 1.0, double mTranslate = 0.0, double mScale = 1.0 ) override;
1053
1054 void addToPainterPath( QPainterPath &path ) const override;
1055 void drawAsPolygon( QPainter &p ) const override;
1056
1057 bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) override;
1058 bool moveVertex( QgsVertexId position, const QgsPoint &newPos ) override;
1059 bool deleteVertex( QgsVertexId position ) override;
1060
1061 QgsLineString *reversed() const override SIP_FACTORY;
1062 QgsPoint *interpolatePoint( double distance ) const override SIP_FACTORY;
1063 QgsLineString *curveSubstring( double startDistance, double endDistance ) const override SIP_FACTORY;
1064
1065 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;
1066 bool pointAt( int node, QgsPoint &point, Qgis::VertexType &type ) const override;
1067
1068 QgsPoint centroid() const override;
1069
1080 void sumUpArea( double &sum SIP_OUT ) const override;
1081
1092 void sumUpArea3D( double &sum SIP_OUT ) const override;
1093
1094 double vertexAngle( QgsVertexId vertex ) const override;
1095 double segmentLength( QgsVertexId startVertex ) const override;
1096 double distanceBetweenVertices( QgsVertexId fromVertex, QgsVertexId toVertex ) const override;
1097 bool addZValue( double zValue = 0 ) override;
1098 bool addMValue( double mValue = 0 ) override;
1099
1100 bool dropZValue() override;
1101 bool dropMValue() override;
1102 void swapXy() override;
1103
1104 bool convertTo( Qgis::WkbType type ) override;
1105
1106 bool transform( QgsAbstractGeometryTransformer *transformer, QgsFeedback *feedback = nullptr ) override;
1107 void scroll( int firstVertexIndex ) final;
1108
1109#ifndef SIP_RUN
1110 void filterVertices( const std::function< bool( const QgsPoint & ) > &filter ) override;
1111 void transformVertices( const std::function< QgsPoint( const QgsPoint & ) > &transform ) override;
1112
1121 inline static const QgsLineString *cast( const QgsAbstractGeometry *geom ) // cppcheck-suppress duplInheritedMember
1122 {
1123 if ( geom && QgsWkbTypes::flatType( geom->wkbType() ) == Qgis::WkbType::LineString )
1124 return static_cast<const QgsLineString *>( geom );
1125 return nullptr;
1126 }
1127
1136 inline static QgsLineString *cast( QgsAbstractGeometry *geom ) // cppcheck-suppress duplInheritedMember
1137 {
1138 if ( geom && QgsWkbTypes::flatType( geom->wkbType() ) == Qgis::WkbType::LineString )
1139 return static_cast<QgsLineString *>( geom );
1140 return nullptr;
1141 }
1142#endif
1143
1145
1146#ifdef SIP_RUN
1147// clang-format off
1148 SIP_PYOBJECT __repr__();
1149 % MethodCode
1150 QString wkt = sipCpp->asWkt();
1151 if ( wkt.length() > 1000 )
1152 wkt = wkt.left( 1000 ) + u"..."_s;
1153 QString str = u"<QgsLineString: %1>"_s.arg( wkt );
1154 sipRes = PyUnicode_FromString( str.toUtf8().constData() );
1155 % End
1156
1166 SIP_PYOBJECT __getitem__( int index ) SIP_TYPEHINT( QgsPoint );
1167 % MethodCode
1168 const int count = sipCpp->numPoints();
1169 if ( a0 < -count || a0 >= count )
1170 {
1171 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
1172 sipIsErr = 1;
1173 }
1174 else
1175 {
1176 std::unique_ptr< QgsPoint > p;
1177 if ( a0 >= 0 )
1178 p = std::make_unique< QgsPoint >( sipCpp->pointN( a0 ) );
1179 else
1180 p = std::make_unique< QgsPoint >( sipCpp->pointN( count + a0 ) );
1181 sipRes = sipConvertFromType( p.release(), sipType_QgsPoint, Py_None );
1182 }
1183 % End
1184
1194 void __setitem__( int index, const QgsPoint &point );
1195 % MethodCode
1196 const int count = sipCpp->numPoints();
1197 if ( a0 < -count || a0 >= count )
1198 {
1199 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
1200 sipIsErr = 1;
1201 }
1202 else
1203 {
1204 if ( a0 < 0 )
1205 a0 = count + a0;
1206 sipCpp->setXAt( a0, a1->x() );
1207 sipCpp->setYAt( a0, a1->y() );
1208 if ( sipCpp->isMeasure() )
1209 sipCpp->setMAt( a0, a1->m() );
1210 if ( sipCpp->is3D() )
1211 sipCpp->setZAt( a0, a1->z() );
1212 }
1213 % End
1214
1215
1225 void __delitem__( int index );
1226 % MethodCode
1227 const int count = sipCpp->numPoints();
1228 if ( a0 >= 0 && a0 < count )
1229 sipCpp->deleteVertex( QgsVertexId( -1, -1, a0 ) );
1230 else if ( a0 < 0 && a0 >= -count )
1231 sipCpp->deleteVertex( QgsVertexId( -1, -1, count + a0 ) );
1232 else
1233 {
1234 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
1235 sipIsErr = 1;
1236 }
1237 % End
1238
1239// clang-format on
1240#endif
1241
1248 Q_DECL_DEPRECATED QgsBox3D calculateBoundingBox3d() const SIP_DEPRECATED;
1249
1255 QgsBox3D calculateBoundingBox3D() const override;
1256
1263 std::unique_ptr< QgsLineString > measuredLine( double start, double end ) const;
1264
1278 std::unique_ptr< QgsLineString > interpolateM( bool use3DDistance = true ) const;
1279
1304 bool lineLocatePointByM( double m, double &x SIP_OUT, double &y SIP_OUT, double &z SIP_OUT, double &distanceFromStart SIP_OUT, bool use3DDistance = true ) const;
1305
1306 protected:
1307
1308 int compareToSameClass( const QgsAbstractGeometry *other ) const final;
1309
1310 private:
1311 QVector<double> mX;
1312 QVector<double> mY;
1313 QVector<double> mZ;
1314 QVector<double> mM;
1315
1316 void importVerticesFromWkb( const QgsConstWkbPtr &wkb );
1317
1323 void fromWkbPoints( Qgis::WkbType type, const QgsConstWkbPtr &wkb )
1324 {
1325 mWkbType = type;
1326 importVerticesFromWkb( wkb );
1327 }
1328
1329 bool lineLocatePointByMPrivate( double m, double &x, double &y, double &z, double &distanceFromStart, bool use3DDistance, bool haveInterpolatedM ) const;
1330
1331 friend class QgsPolygon;
1332 friend class QgsTriangle;
1333 friend class TestQgsGeometry;
1334
1335};
1336
1337// clazy:excludeall=qstring-allocations
1338
1339#endif // QGSLINESTRING_H
@ LineString
LineString.
Definition qgis.h:297
@ Point25D
Point25D.
Definition qgis.h:361
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:239
#define SIP_DEPRECATED
Definition qgis_sip.h:113
#define SIP_SKIP
Definition qgis_sip.h:133
#define SIP_OUT
Definition qgis_sip.h:57
#define SIP_HOLDGIL
Definition qgis_sip.h:178
#define SIP_FACTORY
Definition qgis_sip.h:83
#define SIP_THROW(name,...)
Definition qgis_sip.h:210
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