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 )];
79 if ( !PySequence_Check( a0 ) )
81 PyErr_SetString( PyExc_TypeError, QStringLiteral(
"A sequence of QgsPoint, QgsPointXY or array of floats is expected" ).toUtf8().constData() );
87 const int size = PySequence_Size( a0 );
100 for (
int i = 0; i < size; ++i )
102 PyObject *value = PySequence_GetItem( a0, i );
105 PyErr_SetString( PyExc_TypeError, QStringLiteral(
"Invalid type at index %1." ).arg( i ) .toUtf8().constData() );
110 if ( PySequence_Check( value ) )
112 const int elementSize = PySequence_Size( value );
113 if ( elementSize < 2 || elementSize > 4 )
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() );
123 for (
int j = 0; j < elementSize; ++j )
125 PyObject *element = PySequence_GetItem( value, j );
128 PyErr_SetString( PyExc_TypeError, QStringLiteral(
"Invalid type at index %1." ).arg( i ) .toUtf8().constData() );
134 double d = PyFloat_AsDouble( element );
135 if ( PyErr_Occurred() )
146 if ( i == 0 && j == 2 )
152 else if ( i > 0 && j == 2 && hasZ )
157 if ( i == 0 && j == 3 )
163 else if ( i > 0 && j == 3 && hasM )
168 Py_DECREF( element );
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() );
185 if ( sipCanConvertToType( value, sipType_QgsPointXY, SIP_NOT_NONE ) )
188 QgsPointXY *p =
reinterpret_cast<QgsPointXY *
>( sipConvertToType( value, sipType_QgsPointXY, 0, SIP_NOT_NONE, &state, &sipIsErr ) );
194 sipReleaseType( p, sipType_QgsPointXY, state );
196 else if ( sipCanConvertToType( value, sipType_QgsPoint, SIP_NOT_NONE ) )
199 QgsPoint *p =
reinterpret_cast<QgsPoint *
>( sipConvertToType( value, sipType_QgsPoint, 0, SIP_NOT_NONE, &state, &sipIsErr ) );
205 if ( i == 0 && p->
is3D() )
211 else if ( i > 0 && hasZ )
222 else if ( i > 0 && hasM )
230 sipReleaseType( p, sipType_QgsPoint, state );
242 PyErr_SetString( PyExc_TypeError, QStringLiteral(
"Invalid type at index %1. Expected QgsPoint, QgsPointXY or array of floats." ).arg( i ) .toUtf8().constData() );
248 sipCpp =
new sipQgsLineString(
QgsLineString( xl, yl, zl, ml, is25D ) );
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;
296 static std::unique_ptr< QgsLineString > fromBezierCurve(
const QgsPoint &start,
const QgsPoint &controlPoint1,
const QgsPoint &controlPoint2,
const QgsPoint &end,
int segments = 30 );
303 static std::unique_ptr< QgsLineString > fromQPolygonF(
const QPolygonF &polygon );
306 bool fuzzyHelper(
double epsilon,
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
315 const QgsLineString *otherLine = qgsgeometry_cast< const QgsLineString * >( &other );
319 if ( mWkbType != otherLine->
mWkbType )
322 const int size = mX.count();
323 if ( size != otherLine->mX.count() )
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 )
337 if ( is3DFlag && isMeasureFlag )
339 result &= comparator3DMeasure( epsilon, *xData++, *yData++, *zData++, *mData++,
340 *otherXData++, *otherYData++, *otherZData++, *otherMData++ );
344 result &= comparator3D( epsilon, *xData++, *yData++, *zData++,
345 *otherXData++, *otherYData++, *otherZData++ );
347 else if ( isMeasureFlag )
349 result &= comparatorMeasure( epsilon, *xData++, *yData++, *mData++,
350 *otherXData++, *otherYData++, *otherMData++ );
354 result &= comparator2D( epsilon, *xData++, *yData++,
355 *otherXData++, *otherYData++ );
375 [](
double epsilon,
double x1,
double y1,
double z1,
double m1,
376 double x2,
double y2,
double z2,
double m2 )
380 [](
double epsilon,
double x1,
double y1,
double z1,
381 double x2,
double y2,
double z2 )
385 [](
double epsilon,
double x1,
double y1,
double m1,
386 double x2,
double y2,
double m2 )
390 [](
double epsilon,
double x1,
double y1,
391 double x2,
double y2 )
404 [](
double epsilon,
double x1,
double y1,
double z1,
double m1,
405 double x2,
double y2,
double z2,
double m2 )
409 [](
double epsilon,
double x1,
double y1,
double z1,
410 double x2,
double y2,
double z2 )
414 [](
double epsilon,
double x1,
double y1,
double m1,
415 double x2,
double y2,
double m2 )
419 [](
double epsilon,
double x1,
double y1,
420 double x2,
double y2 )
451 const int count = sipCpp->numPoints();
452 if ( a0 < -count || a0 >= count )
454 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
459 std::unique_ptr< QgsPoint > p;
461 p = std::make_unique< QgsPoint >( sipCpp->pointN( a0 ) );
463 p = std::make_unique< QgsPoint >( sipCpp->pointN( count + a0 ) );
464 sipRes = sipConvertFromType( p.release(), sipType_QgsPoint, Py_None );
470 double xAt(
int index )
const override;
481 double xAt(
int index )
const override;
483 const int count = sipCpp->numPoints();
484 if ( a0 < -count || a0 >= count )
486 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
492 return PyFloat_FromDouble( sipCpp->xAt( a0 ) );
494 return PyFloat_FromDouble( sipCpp->xAt( count + a0 ) );
500 double yAt(
int index )
const override;
511 double yAt(
int index )
const override;
513 const int count = sipCpp->numPoints();
514 if ( a0 < -count || a0 >= count )
516 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
522 return PyFloat_FromDouble( sipCpp->yAt( a0 ) );
524 return PyFloat_FromDouble( sipCpp->yAt( count + a0 ) );
537 return mX.constData();
548 return mY.constData();
564 return mZ.constData();
580 return mM.constData();
633 double zAt(
int index )
const override
635 if ( index >= 0 && index < mZ.size() )
636 return mZ.at( index );
638 return std::numeric_limits<double>::quiet_NaN();
652 double zAt(
int index )
const override;
654 const int count = sipCpp->numPoints();
655 if ( a0 < -count || a0 >= count )
657 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
663 return PyFloat_FromDouble( sipCpp->zAt( a0 ) );
665 return PyFloat_FromDouble( sipCpp->zAt( count + a0 ) );
679 double mAt(
int index )
const override
681 if ( index >= 0 && index < mM.size() )
682 return mM.at( index );
684 return std::numeric_limits<double>::quiet_NaN();
698 double mAt(
int index )
const override;
700 const int count = sipCpp->numPoints();
701 if ( a0 < -count || a0 >= count )
703 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
709 return PyFloat_FromDouble( sipCpp->mAt( a0 ) );
711 return PyFloat_FromDouble( sipCpp->mAt( count + a0 ) );
725 void setXAt(
int index,
double x );
739 void setXAt(
int index,
double x );
741 const int count = sipCpp->numPoints();
742 if ( a0 < -count || a0 >= count )
744 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
750 sipCpp->setXAt( a0, a1 );
752 sipCpp->setXAt( count + a0, a1 );
766 void setYAt(
int index,
double y );
780 void setYAt(
int index,
double y );
782 const int count = sipCpp->numPoints();
783 if ( a0 < -count || a0 >= count )
785 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
791 sipCpp->setYAt( a0, a1 );
793 sipCpp->setYAt( count + a0, a1 );
809 if ( index >= 0 && index < mZ.size() )
824 void setZAt(
int index,
double z );
826 const int count = sipCpp->numPoints();
827 if ( a0 < -count || a0 >= count )
829 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
835 sipCpp->setZAt( a0, a1 );
837 sipCpp->setZAt( count + a0, a1 );
853 if ( index >= 0 && index < mM.size() )
868 void setMAt(
int index,
double m );
870 const int count = sipCpp->numPoints();
871 if ( a0 < -count || a0 >= count )
873 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
879 sipCpp->setMAt( a0, a1 );
881 sipCpp->setMAt( count + a0, a1 );
899 void setPoints(
size_t size,
const double *x,
const double *y,
const double *z =
nullptr,
const double *m =
nullptr )
SIP_SKIP;
918 void addVertex( const
QgsPoint &pt );
934 void extend(
double startDistance,
double endDistance );
944 double startSegmentX,
double startSegmentY,
double startSegmentZ,
double startSegmentM,
945 double endSegmentX,
double endSegmentY,
double endSegmentZ,
double endSegmentM
946 ) > &visitPoint )
const;
953 void clear() override;
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;
971 QVector<
QgsVertexId > collectDuplicateNodes(
double epsilon = 4 * std::numeric_limits<
double>::epsilon(),
bool useZValues = false ) const;
973 QPolygonF asQPolygonF() const override;
977 bool fromWkt( const QString &wkt ) override;
981 QString asWkt(
int precision = 17 ) const override;
985 QString asKml(
int precision = 17 ) const override;
991 std::tuple< std::unique_ptr< QgsCurve >, std::unique_ptr< QgsCurve > >
splitCurveAtVertex(
int index )
const final;
1002 QVector<QgsLineString *> splitToDisjointXYParts() const
SIP_FACTORY;
1020 QgsLineString *curveToLine(
double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const override
SIP_FACTORY;
1026 void draw( QPainter &p ) const override;
1029 void transform( const QTransform &t,
double zTranslate = 0.0,
double zScale = 1.0,
double mTranslate = 0.0,
double mScale = 1.0 ) override;
1031 void addToPainterPath( QPainterPath &path ) const override;
1032 void drawAsPolygon( QPainter &p ) const override;
1036 bool deleteVertex(
QgsVertexId position ) override;
1043 bool pointAt(
int node,
QgsPoint &point,
Qgis::VertexType &type ) const override;
1045 QgsPoint centroid() const override;
1055 void sumUpArea(
double &sum
SIP_OUT ) const override;
1057 double vertexAngle(
QgsVertexId vertex ) const override;
1058 double segmentLength(
QgsVertexId startVertex ) const override;
1059 bool addZValue(
double zValue = 0 ) override;
1060 bool addMValue(
double mValue = 0 ) override;
1062 bool dropZValue() override;
1063 bool dropMValue() override;
1064 void swapXy() override;
1066 bool convertTo(
Qgis::WkbType type ) override;
1069 void scroll(
int firstVertexIndex ) final;
1092 SIP_PYOBJECT __repr__();
1094 QString wkt = sipCpp->asWkt();
1095 if ( wkt.length() > 1000 )
1096 wkt = wkt.left( 1000 ) + QStringLiteral(
"..." );
1097 QString str = QStringLiteral(
"<QgsLineString: %1>" ).arg( wkt );
1098 sipRes = PyUnicode_FromString( str.toUtf8().constData() );
1112 const int count = sipCpp->numPoints();
1113 if ( a0 < -count || a0 >= count )
1115 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
1120 std::unique_ptr< QgsPoint > p;
1122 p = std::make_unique< QgsPoint >( sipCpp->pointN( a0 ) );
1124 p = std::make_unique< QgsPoint >( sipCpp->pointN( count + a0 ) );
1125 sipRes = sipConvertFromType( p.release(), sipType_QgsPoint, Py_None );
1138 void __setitem__(
int index,
const QgsPoint &point );
1140 const int count = sipCpp->numPoints();
1141 if ( a0 < -count || a0 >= count )
1143 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
1150 sipCpp->setXAt( a0, a1->x() );
1151 sipCpp->setYAt( a0, a1->y() );
1152 if ( sipCpp->isMeasure() )
1153 sipCpp->setMAt( a0, a1->m() );
1154 if ( sipCpp->is3D() )
1155 sipCpp->setZAt( a0, a1->z() );
1169 void __delitem__(
int index );
1171 const int count = sipCpp->numPoints();
1172 if ( a0 >= 0 && a0 < count )
1173 sipCpp->deleteVertex(
QgsVertexId( -1, -1, a0 ) );
1174 else if ( a0 < 0 && a0 >= -count )
1175 sipCpp->deleteVertex(
QgsVertexId( -1, -1, count + a0 ) );
1178 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
1198 QgsBox3D calculateBoundingBox3D() const override;
1206 std::unique_ptr<
QgsLineString > measuredLine(
double start,
double end ) const;
1221 std::unique_ptr<
QgsLineString > interpolateM(
bool use3DDistance = true ) const;
1247 bool lineLocatePointByM(
double m,
double &x
SIP_OUT,
double &y
SIP_OUT,
double &z
SIP_OUT,
double &distanceFromStart
SIP_OUT,
bool use3DDistance = true ) const;
1269 importVerticesFromWkb( wkb );
1272 bool lineLocatePointByMPrivate(
double m,
double &x,
double &y,
double &z,
double &distanceFromStart,
bool use3DDistance,
bool haveInterpolatedM )
const;
1276 friend class TestQgsGeometry;