23#include <nlohmann/json.hpp>
36#include <QDomDocument>
60 mX.resize(
points.count() );
61 mY.resize(
points.count() );
62 double *x = mX.data();
63 double *y = mY.data();
68 mZ.resize(
points.count() );
73 mM.resize(
points.count() );
88QgsLineString::QgsLineString(
const QVector<double> &x,
const QVector<double> &y,
const QVector<double> &z,
const QVector<double> &m,
bool is25DType )
91 int pointCount = std::min( x.size(), y.size() );
92 if ( x.size() == pointCount )
98 mX = x.mid( 0, pointCount );
100 if ( y.size() == pointCount )
106 mY = y.mid( 0, pointCount );
108 if ( !z.isEmpty() && z.count() >= pointCount )
111 if ( z.size() == pointCount )
117 mZ = z.mid( 0, pointCount );
120 if ( !m.isEmpty() && m.count() >= pointCount )
123 if ( m.size() == pointCount )
129 mM = m.mid( 0, pointCount );
162 mX.reserve(
points.size() );
163 mY.reserve(
points.size() );
182static double cubicInterpolate(
double a,
double b,
183 double A,
double B,
double C,
double D )
185 return A * b * b * b + 3 * B * b * b * a + 3 * C * b * a * a + D * a * a * a;
191 return std::make_unique< QgsLineString >();
194 x.resize( segments + 1 );
196 y.resize( segments + 1 );
198 double *
zData =
nullptr;
199 if ( start.
is3D() && end.
is3D() && controlPoint1.
is3D() && controlPoint2.
is3D() )
201 z.resize( segments + 1 );
205 double *
mData =
nullptr;
208 m.resize( segments + 1 );
212 double *
xData = x.data();
213 double *
yData = y.data();
214 const double step = 1.0 / segments;
217 for (
int i = 0; i < segments; i++, a += step, b -= step )
230 *
xData++ = cubicInterpolate( a, b, start.
x(), controlPoint1.
x(), controlPoint2.
x(), end.
x() );
231 *
yData++ = cubicInterpolate( a, b, start.
y(), controlPoint1.
y(), controlPoint2.
y(), end.
y() );
233 *
zData++ = cubicInterpolate( a, b, start.
z(), controlPoint1.
z(), controlPoint2.
z(), end.
z() );
235 *
mData++ = cubicInterpolate( a, b, start.
m(), controlPoint1.
m(), controlPoint2.
m(), end.
m() );
246 return std::make_unique< QgsLineString >( x, y, z, m );
253 x.resize( polygon.count() );
254 y.resize( polygon.count() );
255 double *
xData = x.data();
256 double *
yData = y.data();
258 const QPointF *src = polygon.data();
259 for (
int i = 0 ; i < polygon.size(); ++ i )
266 return std::make_unique< QgsLineString >( x, y );
291 const int size = mX.size();
295 const double *x = mX.constData();
296 const double *y = mY.constData();
297 const bool useZ =
is3D();
299 const double *z = useZ ? mZ.constData() :
nullptr;
300 const double *m = useM ? mM.constData() :
nullptr;
302 for (
int i = 0; i < size; ++i )
324 error = QObject::tr(
"LineString has less than 2 points and is not empty." );
335 bool res =
snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM,
336 result->mX, result->mY, result->mZ, result->mM, removeRedundantPoints );
338 return result.release();
345 if ( mX.count() <= 2 )
348 double prevX = mX.at( 0 );
349 double prevY = mY.at( 0 );
351 bool useZ = hasZ && useZValues;
352 double prevZ = useZ ? mZ.at( 0 ) : 0;
354 int remaining = mX.count();
355 while ( i < remaining )
357 double currentX = mX.at( i );
358 double currentY = mY.at( i );
359 double currentZ = useZ ? mZ.at( i ) : 0;
396 if (
is3D() && closed )
397 closed &=
qgsDoubleNear( mZ.first(), mZ.last() ) || ( std::isnan( mZ.first() ) && std::isnan( mZ.last() ) );
410 return mBoundingBox.toRectangle().intersects( rectangle );
412 const int nb = mX.size();
421 if ( rectangle.
contains( mX.at( 0 ), mY.at( 0 ) ) ||
422 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.2 ) ), mY.at(
static_cast< int >( nb * 0.2 ) ) ) ||
423 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.4 ) ), mY.at(
static_cast< int >( nb * 0.4 ) ) ) ||
424 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.6 ) ), mY.at(
static_cast< int >( nb * 0.6 ) ) ) ||
425 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.8 ) ), mY.at(
static_cast< int >( nb * 0.8 ) ) ) ||
426 rectangle.
contains( mX.at( nb - 1 ), mY.at( nb - 1 ) ) )
435 double xmin = std::numeric_limits<double>::max();
436 double ymin = std::numeric_limits<double>::max();
437 double zmin = -std::numeric_limits<double>::max();
438 double xmax = -std::numeric_limits<double>::max();
439 double ymax = -std::numeric_limits<double>::max();
440 double zmax = -std::numeric_limits<double>::max();
442 const double *x = mX.constData();
443 const double *y = mY.constData();
444 const double *z =
is3D() ? mZ.constData() :
nullptr;
445 bool foundPointInRectangle =
false;
446 for (
int i = 0; i < nb; ++i )
448 const double px = *x++;
449 xmin = std::min( xmin, px );
450 xmax = std::max( xmax, px );
451 const double py = *y++;
452 ymin = std::min( ymin, py );
453 ymax = std::max( ymax, py );
456 const double pz = *z++;
457 zmin = std::min( zmin, pz );
458 zmax = std::max( zmax, pz );
461 if ( !foundPointInRectangle && rectangle.
contains( px, py ) )
463 foundPointInRectangle =
true;
479 if ( foundPointInRectangle )
504 const int nb = mX.size();
513 if ( box3d.
contains( mX.at( 0 ), mY.at( 0 ), mZ.at( 0 ) ) ||
514 box3d.
contains( mX.at(
static_cast< int >( nb * 0.2 ) ), mY.at(
static_cast< int >( nb * 0.2 ) ), mZ.at(
static_cast< int >( nb * 0.2 ) ) ) ||
515 box3d.
contains( mX.at(
static_cast< int >( nb * 0.4 ) ), mY.at(
static_cast< int >( nb * 0.4 ) ), mZ.at(
static_cast< int >( nb * 0.4 ) ) ) ||
516 box3d.
contains( mX.at(
static_cast< int >( nb * 0.6 ) ), mY.at(
static_cast< int >( nb * 0.6 ) ), mZ.at(
static_cast< int >( nb * 0.6 ) ) ) ||
517 box3d.
contains( mX.at(
static_cast< int >( nb * 0.8 ) ), mY.at(
static_cast< int >( nb * 0.8 ) ), mZ.at(
static_cast< int >( nb * 0.8 ) ) ) ||
518 box3d.
contains( mX.at( nb - 1 ), mY.at( nb - 1 ), mZ.at( nb - 1 ) ) )
527 double xmin = std::numeric_limits<double>::max();
528 double ymin = std::numeric_limits<double>::max();
529 double zmin = std::numeric_limits<double>::max();
530 double xmax = -std::numeric_limits<double>::max();
531 double ymax = -std::numeric_limits<double>::max();
532 double zmax = -std::numeric_limits<double>::max();
534 const double *x = mX.constData();
535 const double *y = mY.constData();
536 const double *z = mZ.constData();
537 bool foundPointInBox =
false;
538 for (
int i = 0; i < nb; ++i )
540 const double px = *x++;
541 xmin = std::min( xmin, px );
542 xmax = std::max( xmax, px );
543 const double py = *y++;
544 ymin = std::min( ymin, py );
545 ymax = std::max( ymax, py );
546 const double pz = *z++;
547 zmin = std::min( zmin, pz );
548 zmax = std::max( zmax, pz );
550 if ( !foundPointInBox && box3d.
contains( px, py, pz ) )
552 foundPointInBox =
true;
568 if ( foundPointInBox )
581 QVector< QgsVertexId > res;
582 if ( mX.count() <= 1 )
585 const double *x = mX.constData();
586 const double *y = mY.constData();
588 bool useZ = hasZ && useZValues;
589 const double *z = useZ ? mZ.constData() :
nullptr;
593 double prevZ = z ? *z++ : 0;
596 for (
int i = 1; i < mX.count(); ++i )
598 double currentX = *x++;
599 double currentY = *y++;
600 double currentZ = useZ ? *z++ : 0;
620 const int nb = mX.size();
623 const double *x = mX.constData();
624 const double *y = mY.constData();
625 QPointF *dest =
points.data();
626 for (
int i = 0; i < nb; ++i )
628 *dest++ = QPointF( *x++, *y++ );
634void simplifySection(
int i,
int j,
const double *x,
const double *y, std::vector< bool > &usePoint,
const double distanceToleranceSquared,
const double epsilon )
641 double maxDistanceSquared = -1.0;
646 for (
int k = i + 1; k < j; k++ )
649 x[k], y[k], x[i], y[i], x[j], y[j], mx, my, epsilon );
651 if ( distanceSquared > maxDistanceSquared )
653 maxDistanceSquared = distanceSquared;
657 if ( maxDistanceSquared <= distanceToleranceSquared )
659 for (
int k = i + 1; k < j; k++ )
666 simplifySection( i, maxIndex, x, y, usePoint, distanceToleranceSquared, epsilon );
667 simplifySection( maxIndex, j, x, y, usePoint, distanceToleranceSquared, epsilon );
680 const double distanceToleranceSquared = tolerance * tolerance;
681 const double *
xData = mX.constData();
682 const double *
yData = mY.constData();
683 const double *
zData = mZ.constData();
684 const double *
mData = mM.constData();
686 const int size = mX.size();
688 std::vector< bool > usePoint( size,
true );
690 constexpr double epsilon = 4 * std::numeric_limits<double>::epsilon();
693 QVector< double > newX;
694 newX.reserve( size );
695 QVector< double > newY;
696 newY.reserve( size );
698 const bool hasZ =
is3D();
700 QVector< double > newZ;
702 newZ.reserve( size );
703 QVector< double > newM;
705 newM.reserve( size );
707 for (
int i = 0, n = size; i < n; ++i )
709 if ( usePoint[i] || i == n - 1 )
711 newX.append(
xData[i ] );
712 newY.append(
yData[i ] );
714 newZ.append(
zData[i] );
716 newM.append(
mData[i] );
720 const bool simplifyRing =
isRing();
721 const int newSize = newX.size();
722 if ( simplifyRing && newSize > 3 )
727 newX[ newSize - 2], newY[ newSize - 2 ],
728 newX[ 1 ], newY[ 1], mx, my, epsilon );
730 if ( distanceSquared <= distanceToleranceSquared )
733 newX.last() = newX.first();
735 newY.last() = newY.first();
739 newZ.last() = newZ.first();
744 newM.last() = newM.first();
765 importVerticesFromWkb( wkbPtr );
776 auto result2D = std::minmax_element( mX.begin(), mX.end() );
777 const double xmin = *result2D.first;
778 const double xmax = *result2D.second;
779 result2D = std::minmax_element( mY.begin(), mY.end() );
780 const double ymin = *result2D.first;
781 const double ymax = *result2D.second;
783 double zmin = std::numeric_limits< double >::quiet_NaN();
784 double zmax = std::numeric_limits< double >::quiet_NaN();
788 auto resultZ = std::minmax_element( mZ.begin(), mZ.end() );
789 zmin = *resultZ.first;
790 zmax = *resultZ.second;
793 return QgsBox3D( xmin, ymin, zmin, xmax, ymax, zmax );
803 const int size = mX.size();
804 if ( index < 1 || index >= size - 1 )
807 const bool useZ =
is3D();
810 QVector<double> newX( size );
811 QVector<double> newY( size );
812 QVector<double> newZ( useZ ? size : 0 );
813 QVector<double> newM( useM ? size : 0 );
814 auto it = std::copy( mX.constBegin() + index, mX.constEnd() - 1, newX.begin() );
815 it = std::copy( mX.constBegin(), mX.constBegin() + index, it );
816 *it = *newX.constBegin();
817 mX = std::move( newX );
819 it = std::copy( mY.constBegin() + index, mY.constEnd() - 1, newY.begin() );
820 it = std::copy( mY.constBegin(), mY.constBegin() + index, it );
821 *it = *newY.constBegin();
822 mY = std::move( newY );
825 it = std::copy( mZ.constBegin() + index, mZ.constEnd() - 1, newZ.begin() );
826 it = std::copy( mZ.constBegin(), mZ.constBegin() + index, it );
827 *it = *newZ.constBegin();
828 mZ = std::move( newZ );
832 it = std::copy( mM.constBegin() + index, mM.constEnd() - 1, newM.begin() );
833 it = std::copy( mM.constBegin(), mM.constBegin() + index, it );
834 *it = *newM.constBegin();
835 mM = std::move( newM );
854 QString secondWithoutParentheses =
parts.second;
855 secondWithoutParentheses = secondWithoutParentheses.remove(
'(' ).remove(
')' ).simplified().remove(
' ' );
856 parts.second =
parts.second.remove(
'(' ).remove(
')' );
857 if ( (
parts.second.compare( QLatin1String(
"EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
858 secondWithoutParentheses.isEmpty() )
873 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
884 wkb << static_cast<quint32>(
wkbType() );
902 wkt += QLatin1String(
"EMPTY" );
917 QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral(
"LineString" ) );
920 return elemLineString;
924 return elemLineString;
932 QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral(
"LineString" ) );
935 return elemLineString;
938 return elemLineString;
947 {
"type",
"LineString" },
957 kml.append( QLatin1String(
"<LinearRing>" ) );
961 kml.append( QLatin1String(
"<LineString>" ) );
964 kml.append( QLatin1String(
"<altitudeMode>" ) );
967 kml.append( QLatin1String(
"absolute" ) );
971 kml.append( QLatin1String(
"clampToGround" ) );
973 kml.append( QLatin1String(
"</altitudeMode>" ) );
974 kml.append( QLatin1String(
"<coordinates>" ) );
976 int nPoints = mX.size();
977 for (
int i = 0; i < nPoints; ++i )
981 kml.append( QLatin1String(
" " ) );
984 kml.append( QLatin1String(
"," ) );
988 kml.append( QLatin1String(
"," ) );
993 kml.append( QLatin1String(
",0" ) );
996 kml.append( QLatin1String(
"</coordinates>" ) );
999 kml.append( QLatin1String(
"</LinearRing>" ) );
1003 kml.append( QLatin1String(
"</LineString>" ) );
1017 const int size = mX.size();
1021 const double *x = mX.constData();
1022 const double *y = mY.constData();
1025 double prevX = *x++;
1026 double prevY = *y++;
1028 for (
int i = 1; i < size; ++i )
1032 total += std::sqrt( dx * dx + dy * dy );
1042 const bool useZ =
is3D();
1045 const int size = mX.size();
1047 return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >() );
1049 index = std::clamp( index, 0, size - 1 );
1051 const int part1Size = index + 1;
1052 QVector< double > x1( part1Size );
1053 QVector< double > y1( part1Size );
1054 QVector< double > z1( useZ ? part1Size : 0 );
1055 QVector< double > m1( useM ? part1Size : 0 );
1057 const double *sourceX = mX.constData();
1058 const double *sourceY = mY.constData();
1059 const double *sourceZ = useZ ? mZ.constData() :
nullptr;
1060 const double *sourceM = useM ? mM.constData() :
nullptr;
1062 double *destX = x1.data();
1063 double *destY = y1.data();
1064 double *destZ = useZ ? z1.data() :
nullptr;
1065 double *destM = useM ? m1.data() :
nullptr;
1067 std::copy( sourceX, sourceX + part1Size, destX );
1068 std::copy( sourceY, sourceY + part1Size, destY );
1070 std::copy( sourceZ, sourceZ + part1Size, destZ );
1072 std::copy( sourceM, sourceM + part1Size, destM );
1074 const int part2Size = size - index;
1075 if ( part2Size < 2 )
1076 return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >() );
1078 QVector< double > x2( part2Size );
1079 QVector< double > y2( part2Size );
1080 QVector< double > z2( useZ ? part2Size : 0 );
1081 QVector< double > m2( useM ? part2Size : 0 );
1084 destZ = useZ ? z2.data() :
nullptr;
1085 destM = useM ? m2.data() :
nullptr;
1086 std::copy( sourceX + index, sourceX + size, destX );
1087 std::copy( sourceY + index, sourceY + size, destY );
1089 std::copy( sourceZ + index, sourceZ + size, destZ );
1091 std::copy( sourceM + index, sourceM + size, destM );
1093 if ( part1Size < 2 )
1094 return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
1096 return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
1101 const double *allPointsX =
xData();
1102 const double *allPointsY =
yData();
1104 QVector<double> partX;
1105 QVector<double> partY;
1106 QSet<QgsPointXY> partPointSet;
1108 QVector<QgsLineString *> disjointParts;
1109 for (
size_t i = 0; i < allPointsCount; i++ )
1111 const QgsPointXY point( *allPointsX++, *allPointsY++ );
1112 if ( partPointSet.contains( point ) )
1116 disjointParts.push_back(
new QgsLineString( partX, partY ) );
1118 partX = { partX.last() };
1119 partY = { partY.last() };
1120 partPointSet = {
QgsPointXY( partX[0], partY[0] ) };
1122 partX.push_back( point.
x() );
1123 partY.push_back( point.
y() );
1124 partPointSet.insert( point );
1127 if ( partX.size() > 1 || disjointParts.size() == 0 )
1128 disjointParts.push_back(
new QgsLineString( partX, partY ) );
1130 return disjointParts;
1138 const int size = mX.size();
1142 const double *x = mX.constData();
1143 const double *y = mY.constData();
1144 const double *z = mZ.constData();
1147 double prevX = *x++;
1148 double prevY = *y++;
1149 double prevZ = *z++;
1151 for (
int i = 1; i < size; ++i )
1156 total += std::sqrt( dx * dx + dy * dy + dz * dz );
1196 Q_UNUSED( tolerance )
1197 Q_UNUSED( toleranceType )
1213 if ( i < 0 || i >= mX.size() )
1218 double x = mX.at( i );
1219 double y = mY.at( i );
1220 double z = std::numeric_limits<double>::quiet_NaN();
1221 double m = std::numeric_limits<double>::quiet_NaN();
1239 else if ( hasZ && hasM )
1262 if ( index >= 0 && index < mX.size() )
1263 return mX.at( index );
1270 if ( index >= 0 && index < mY.size() )
1271 return mY.at( index );
1278 if ( index >= 0 && index < mX.size() )
1285 if ( index >= 0 && index < mY.size() )
1300 pts.reserve( nPoints );
1301 for (
int i = 0; i < nPoints; ++i )
1303 pts.push_back(
pointN( i ) );
1317 const bool hasZ =
static_cast< bool >( z );
1318 const bool hasM =
static_cast< bool >( m );
1339 double *destX = mX.data();
1340 double *destY = mY.data();
1341 double *destZ =
nullptr;
1351 double *destM =
nullptr;
1362 for (
size_t i = 0; i < size; ++i )
1389 bool hasZ = firstPt.
is3D();
1394 mX.resize(
points.size() );
1395 mY.resize(
points.size() );
1398 mZ.resize(
points.size() );
1406 mM.resize(
points.size() );
1413 for (
int i = 0; i <
points.size(); ++i )
1415 mX[i] =
points.at( i ).x();
1416 mY[i] =
points.at( i ).y();
1419 double z =
points.at( i ).z();
1420 mZ[i] = std::isnan( z ) ? 0 : z;
1424 double m =
points.at( i ).m();
1425 mM[i] = std::isnan( m ) ? 0 : m;
1478 mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
1491 mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
1501 std::reverse( copy->mX.begin(), copy->mX.end() );
1502 std::reverse( copy->mY.begin(), copy->mY.end() );
1505 std::reverse( copy->mZ.begin(), copy->mZ.end() );
1509 std::reverse( copy->mM.begin(), copy->mM.end() );
1516void QgsLineString::visitPointsByRegularDistance(
const double distance,
const std::function<
bool (
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double )> &visitPoint )
const
1521 double distanceTraversed = 0;
1523 if ( totalPoints == 0 )
1526 const double *x = mX.constData();
1527 const double *y = mY.constData();
1528 const double *z =
is3D() ? mZ.constData() :
nullptr;
1529 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1531 double prevX = *x++;
1532 double prevY = *y++;
1533 double prevZ = z ? *z++ : 0.0;
1534 double prevM = m ? *m++ : 0.0;
1538 visitPoint( prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM );
1542 double pZ = std::numeric_limits<double>::quiet_NaN();
1543 double pM = std::numeric_limits<double>::quiet_NaN();
1544 double nextPointDistance = distance;
1545 const double eps = 4 * nextPointDistance * std::numeric_limits<double>::epsilon();
1546 for (
int i = 1; i < totalPoints; ++i )
1548 double thisX = *x++;
1549 double thisY = *y++;
1550 double thisZ = z ? *z++ : 0.0;
1551 double thisM = m ? *m++ : 0.0;
1557 const double distanceToPoint = std::min( nextPointDistance - distanceTraversed,
segmentLength );
1560 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &pZ :
nullptr,
1561 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &pM :
nullptr );
1563 if ( !visitPoint( pX, pY, pZ, pM, prevX, prevY, prevZ, prevM, thisX, thisY, thisZ, thisM ) )
1566 nextPointDistance += distance;
1588 std::unique_ptr< QgsPoint > res;
1589 visitPointsByRegularDistance( distance, [ & ](
double x,
double y,
double z,
double m,
double,
double,
double,
double,
double,
double,
double,
double )->
bool
1591 res = std::make_unique< QgsPoint >( pointType, x, y, z, m );
1594 return res.release();
1599 return lineLocatePointByMPrivate( m, x, y, z, distanceFromStart, use3DDistance,
false );
1602bool QgsLineString::lineLocatePointByMPrivate(
double m,
double &x,
double &y,
double &z,
double &distanceFromStart,
bool use3DDistance,
bool haveInterpolatedM )
const
1607 distanceFromStart = 0;
1609 if ( totalPoints == 0 )
1612 const double *
xData = mX.constData();
1613 const double *
yData = mY.constData();
1614 const double *
mData = mM.constData();
1616 const double *
zData =
is3D() ? mZ.constData() :
nullptr;
1617 use3DDistance &=
static_cast< bool >(
zData );
1619 double prevX = *
xData++;
1620 double prevY = *
yData++;
1622 double prevM = *
mData++;
1625 while ( i < totalPoints )
1627 double thisX = *
xData++;
1628 double thisY = *
yData++;
1630 double thisM = *
mData++;
1634 if ( std::isnan( thisM ) )
1636 if ( haveInterpolatedM )
1640 std::unique_ptr< QgsLineString > interpolatedM(
interpolateM( use3DDistance ) );
1641 return interpolatedM->lineLocatePointByMPrivate( m, x, y, z, distanceFromStart, use3DDistance,
true );
1653 double totalLengthOfSegmentsWithConstantM = 0;
1654 for (
int j = 0; j < ( totalPoints - i ); ++j )
1664 distanceFromStart += totalLengthOfSegmentsWithConstantM / 2;
1674 const double delta = ( m - prevM ) / ( thisM - prevM );
1679 z = prevZ + ( thisZ - prevZ ) * delta;
1680 distanceFromStart += distanceToPoint;
1697 if ( startDistance < 0 && endDistance < 0 )
1700 endDistance = std::max( startDistance, endDistance );
1703 if ( totalPoints == 0 )
1706 QVector< QgsPoint > substringPoints;
1707 substringPoints.reserve( totalPoints );
1715 const double *x = mX.constData();
1716 const double *y = mY.constData();
1717 const double *z =
is3D() ? mZ.constData() :
nullptr;
1718 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1720 double distanceTraversed = 0;
1721 double prevX = *x++;
1722 double prevY = *y++;
1723 double prevZ = z ? *z++ : 0.0;
1724 double prevM = m ? *m++ : 0.0;
1725 bool foundStart =
false;
1727 if ( startDistance < 0 )
1730 for (
int i = 1; i < totalPoints; ++i )
1732 double thisX = *x++;
1733 double thisY = *y++;
1734 double thisZ = z ? *z++ : 0.0;
1735 double thisM = m ? *m++ : 0.0;
1739 if ( distanceTraversed <= startDistance && startDistance < distanceTraversed +
segmentLength )
1742 const double distanceToStart = startDistance - distanceTraversed;
1743 double startX, startY;
1747 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &startZ :
nullptr,
1748 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &startM :
nullptr );
1749 substringPoints <<
QgsPoint( pointType, startX, startY, startZ, startM );
1752 if ( foundStart && ( distanceTraversed +
segmentLength > endDistance ) )
1755 const double distanceToEnd = endDistance - distanceTraversed;
1760 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &endZ :
nullptr,
1761 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &endM :
nullptr );
1762 substringPoints <<
QgsPoint( pointType, endX, endY, endZ, endM );
1764 else if ( foundStart )
1766 substringPoints <<
QgsPoint( pointType, thisX, thisY, thisZ, thisM );
1774 if ( distanceTraversed >= endDistance )
1779 if ( !foundStart &&
qgsDoubleNear( distanceTraversed, startDistance ) )
1781 substringPoints <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1782 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1807 if ( path.isEmpty() || path.currentPosition() != QPointF( mX.at( 0 ), mY.at( 0 ) ) )
1809 path.moveTo( mX.at( 0 ), mY.at( 0 ) );
1812 for (
int i = 1; i < nPoints; ++i )
1814 path.lineTo( mX.at( i ), mY.at( i ) );
1827 return compoundCurve;
1832 if ( mX.size() < 2 || mY.size() < 2 )
1835 const bool extendStart = startDistance > 0;
1836 const bool extendEnd = endDistance > 0;
1841 const double currentLen = std::sqrt( std::pow( mX.at( 0 ) - mX.at( 1 ), 2 ) +
1842 std::pow( mY.at( 0 ) - mY.at( 1 ), 2 ) );
1843 const double newLen = currentLen + startDistance;
1844 mX[ 0 ] = mX.at( 1 ) + ( mX.at( 0 ) - mX.at( 1 ) ) / currentLen * newLen;
1845 mY[ 0 ] = mY.at( 1 ) + ( mY.at( 0 ) - mY.at( 1 ) ) / currentLen * newLen;
1850 const int last = mX.size() - 1;
1851 const double currentLen = std::sqrt( std::pow( mX.at( last ) - mX.at( last - 1 ), 2 ) +
1852 std::pow( mY.at( last ) - mY.at( last - 1 ), 2 ) );
1853 const double newLen = currentLen + endDistance;
1854 mX[ last ] = mX.at( last - 1 ) + ( mX.at( last ) - mX.at( last - 1 ) ) / currentLen * newLen;
1855 mY[ last ] = mY.at( last - 1 ) + ( mY.at( last ) - mY.at( last - 1 ) ) / currentLen * newLen;
1858 if ( extendStart || extendEnd )
1864 auto result = std::make_unique< QgsLineString >();
1866 return result.release();
1875 const int size = mX.size();
1876 const int otherSize = otherLine->mX.size();
1877 if ( size > otherSize )
1881 else if ( size < otherSize )
1886 if (
is3D() && !otherLine->
is3D() )
1888 else if ( !
is3D() && otherLine->
is3D() )
1890 const bool considerZ =
is3D();
1898 for (
int i = 0; i < size; i++ )
1900 const double x = mX[i];
1901 const double otherX = otherLine->mX[i];
1906 else if ( x > otherX )
1911 const double y = mY[i];
1912 const double otherY = otherLine->mY[i];
1917 else if ( y > otherY )
1924 const double z = mZ[i];
1925 const double otherZ = otherLine->mZ[i];
1931 else if ( z > otherZ )
1939 const double m = mM[i];
1940 const double otherM = otherLine->mM[i];
1946 else if ( m > otherM )
1957 return QStringLiteral(
"LineString" );
1973 double *zArray =
nullptr;
1979 std::unique_ptr< double[] > dummyZ;
1980 if ( !hasZ || !transformZ )
1982 dummyZ = std::make_unique<double[]>( nPoints );
1983 zArray = dummyZ.get();
1998 double *x = mX.data();
1999 double *y = mY.data();
2000 double *z = hasZ ? mZ.data() :
nullptr;
2001 double *m = hasM ? mM.data() :
nullptr;
2002 for (
int i = 0; i < nPoints; ++i )
2005 t.map( *x, *y, &xOut, &yOut );
2010 *z = *z * zScale + zTranslate;
2015 *m = *m * mScale + mTranslate;
2030 if ( position.
vertex < 0 || position.
vertex > mX.size() )
2040 mX.insert( position.
vertex, vertex.
x() );
2041 mY.insert( position.
vertex, vertex.
y() );
2044 mZ.insert( position.
vertex, vertex.
z() );
2048 mM.insert( position.
vertex, vertex.
m() );
2056 if ( position.
vertex < 0 || position.
vertex >= mX.size() )
2060 mX[position.
vertex] = newPos.
x();
2061 mY[position.
vertex] = newPos.
y();
2064 mZ[position.
vertex] = newPos.
z();
2068 mM[position.
vertex] = newPos.
m();
2076 if ( position.
vertex >= mX.size() || position.
vertex < 0 )
2081 mX.remove( position.
vertex );
2082 mY.remove( position.
vertex );
2085 mZ.remove( position.
vertex );
2089 mM.remove( position.
vertex );
2114 mX.append( pt.
x() );
2115 mY.append( pt.
y() );
2118 mZ.append( pt.
z() );
2122 mM.append( pt.
m() );
2129 double sqrDist = std::numeric_limits<double>::max();
2130 double leftOfDist = std::numeric_limits<double>::max();
2132 double prevLeftOfX = 0.0;
2133 double prevLeftOfY = 0.0;
2134 double testDist = 0;
2135 double segmentPtX, segmentPtY;
2140 const int size = mX.size();
2141 if ( size == 0 || size == 1 )
2147 const double *
xData = mX.constData();
2148 const double *
yData = mY.constData();
2149 for (
int i = 1; i < size; ++i )
2151 double prevX =
xData[ i - 1 ];
2152 double prevY =
yData[ i - 1 ];
2153 double currentX =
xData[ i ];
2154 double currentY =
yData[ i ];
2156 if ( testDist < sqrDist )
2159 segmentPt.
setX( segmentPtX );
2160 segmentPt.
setY( segmentPtY );
2161 vertexAfter.
part = 0;
2162 vertexAfter.
ring = 0;
2173 if (
qgsDoubleNear( testDist, leftOfDist ) && left != prevLeftOf && prevLeftOf != 0 )
2185 prevLeftOf = *leftOf;
2186 leftOfDist = testDist;
2187 prevLeftOfX = prevX;
2188 prevLeftOfY = prevY;
2190 else if ( testDist < leftOfDist )
2193 leftOfDist = testDist;
2225 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
2227 double totalLineLength = 0.0;
2228 double prevX = mX.at( 0 );
2229 double prevY = mY.at( 0 );
2235 double currentX = mX.at( i );
2236 double currentY = mY.at( i );
2237 double segmentLength = std::sqrt( std::pow( currentX - prevX, 2.0 ) +
2238 std::pow( currentY - prevY, 2.0 ) );
2252 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
2254 return QgsPoint( sumX / totalLineLength, sumY / totalLineLength );
2273 const int maxIndex = mX.size();
2280 const double *x = mX.constData();
2281 const double *y = mY.constData();
2282 double prevX = *x++;
2283 double prevY = *y++;
2284 for (
int i = 1; i < maxIndex; ++i )
2286 mSummedUpArea += prevX * ( *y - prevY ) - prevY * ( *x - prevX );
2296void QgsLineString::importVerticesFromWkb(
const QgsConstWkbPtr &wkb )
2302 mX.resize( nVertices );
2303 mY.resize( nVertices );
2304 hasZ ? mZ.resize( nVertices ) : mZ.clear();
2305 hasM ? mM.resize( nVertices ) : mM.clear();
2306 double *x = mX.data();
2307 double *y = mY.data();
2308 double *m = hasM ? mM.data() :
nullptr;
2309 double *z = hasZ ? mZ.data() :
nullptr;
2310 for (
int i = 0; i < nVertices; ++i )
2343 if ( mX.count() < 2 )
2353 double previousX = mX.at(
numPoints() - 2 );
2354 double previousY = mY.at(
numPoints() - 2 );
2355 double currentX = mX.at( 0 );
2356 double currentY = mY.at( 0 );
2357 double afterX = mX.at( 1 );
2358 double afterY = mY.at( 1 );
2361 else if ( vertex.
vertex == 0 )
2374 double previousX = mX.at( vertex.
vertex - 1 );
2375 double previousY = mY.at( vertex.
vertex - 1 );
2376 double currentX = mX.at( vertex.
vertex );
2377 double currentY = mY.at( vertex.
vertex );
2378 double afterX = mX.at( vertex.
vertex + 1 );
2379 double afterY = mY.at( vertex.
vertex + 1 );
2386 if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 1 )
2389 double dx = mX.at( startVertex.
vertex + 1 ) - mX.at( startVertex.
vertex );
2390 double dy = mY.at( startVertex.
vertex + 1 ) - mY.at( startVertex.
vertex );
2391 return std::sqrt( dx * dx + dy * dy );
2416 mZ.reserve( nPoints );
2417 for (
int i = 0; i < nPoints; ++i )
2447 mM.reserve( nPoints );
2448 for (
int i = 0; i < nPoints; ++i )
2479 std::swap( mX, mY );
2493 addZValue( std::numeric_limits<double>::quiet_NaN() );
2510 int size = mX.size();
2512 double *srcX = mX.data();
2513 double *srcY = mY.data();
2514 double *srcM = hasM ? mM.data() :
nullptr;
2515 double *srcZ = hasZ ? mZ.data() :
nullptr;
2518 for (
int i = 0; i < size; ++i )
2522 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2523 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
2551 int size = mX.size();
2553 double *srcX = mX.data();
2554 double *srcY = mY.data();
2555 double *srcM = hasM ? mM.data() :
nullptr;
2556 double *srcZ = hasZ ? mZ.data() :
nullptr;
2558 double *destX = srcX;
2559 double *destY = srcY;
2560 double *destM = srcM;
2561 double *destZ = srcZ;
2563 int filteredPoints = 0;
2564 for (
int i = 0; i < size; ++i )
2568 double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
2569 double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
2571 if ( filter(
QgsPoint( x, y, z, m ) ) )
2583 mX.resize( filteredPoints );
2584 mY.resize( filteredPoints );
2586 mZ.resize( filteredPoints );
2588 mM.resize( filteredPoints );
2597 int size = mX.size();
2599 double *srcX = mX.data();
2600 double *srcY = mY.data();
2601 double *srcM = hasM ? mM.data() :
nullptr;
2602 double *srcZ = hasZ ? mZ.data() :
nullptr;
2604 for (
int i = 0; i < size; ++i )
2608 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2609 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
2625 std::unique_ptr< QgsLineString > cloned(
clone() );
2632 if (
isEmpty() || ( nbpoints < 2 ) )
2637 const double range = end - start;
2638 double lineLength =
length();
2639 double lengthSoFar = 0.0;
2642 double *mOut = cloned->mM.data();
2644 for (
int i = 1; i < nbpoints ; ++i )
2647 if ( lineLength > 0.0 )
2648 *mOut++ = start + range * lengthSoFar / lineLength;
2649 else if ( lineLength == 0.0 && nbpoints > 1 )
2650 *mOut++ = start + range * i / ( nbpoints - 1 );
2664 if ( totalPoints < 2 )
2665 return std::unique_ptr< QgsLineString >(
clone() );
2667 const double *
xData = mX.constData();
2668 const double *
yData = mY.constData();
2669 const double *
mData = mM.constData();
2670 const double *
zData =
is3D() ? mZ.constData() :
nullptr;
2671 use3DDistance &=
static_cast< bool >(
zData );
2673 QVector< double > xOut( totalPoints );
2674 QVector< double > yOut( totalPoints );
2675 QVector< double > mOut( totalPoints );
2676 QVector< double > zOut(
static_cast< bool >(
zData ) ? totalPoints : 0 );
2678 double *xOutData = xOut.data();
2679 double *yOutData = yOut.data();
2680 double *mOutData = mOut.data();
2681 double *zOutData =
static_cast< bool >(
zData ) ? zOut.data() :
nullptr;
2684 double currentSegmentLength = 0;
2685 double lastValidM = std::numeric_limits< double >::quiet_NaN();
2686 double prevX = *
xData;
2687 double prevY = *
yData;
2689 while ( i < totalPoints )
2691 double thisX = *
xData++;
2692 double thisY = *
yData++;
2694 double thisM = *
mData++;
2696 currentSegmentLength = use3DDistance
2700 if ( !std::isnan( thisM ) )
2702 *xOutData++ = thisX;
2703 *yOutData++ = thisY;
2704 *mOutData++ = thisM;
2706 *zOutData++ = thisZ;
2713 double scanAheadM = thisM;
2714 while ( i + j + 1 < totalPoints && std::isnan( scanAheadM ) )
2716 scanAheadM =
mData[ j ];
2719 if ( std::isnan( scanAheadM ) )
2724 *xOutData++ = thisX;
2725 *yOutData++ = thisY;
2726 *mOutData++ = scanAheadM;
2728 *zOutData++ = thisZ;
2729 for ( ; i < j; ++i )
2733 *xOutData++ = thisX;
2734 *yOutData++ = thisY;
2735 *mOutData++ = scanAheadM;
2738 *zOutData++ = *
zData++;
2740 lastValidM = scanAheadM;
2746 double scanAheadX = thisX;
2747 double scanAheadY = thisY;
2748 double scanAheadZ = thisZ;
2749 double distanceToNextValidM = currentSegmentLength;
2750 std::vector< double > scanAheadSegmentLengths;
2751 scanAheadSegmentLengths.emplace_back( currentSegmentLength );
2753 double nextValidM = std::numeric_limits< double >::quiet_NaN();
2754 while ( i + j < totalPoints - 1 )
2756 double nextScanAheadX =
xData[j];
2757 double nextScanAheadY =
yData[j];
2758 double nextScanAheadZ =
zData ?
zData[j] : 0;
2759 double nextScanAheadM =
mData[ j ];
2760 const double scanAheadSegmentLength = use3DDistance
2763 scanAheadSegmentLengths.emplace_back( scanAheadSegmentLength );
2764 distanceToNextValidM += scanAheadSegmentLength;
2766 if ( !std::isnan( nextScanAheadM ) )
2768 nextValidM = nextScanAheadM;
2772 scanAheadX = nextScanAheadX;
2773 scanAheadY = nextScanAheadY;
2774 scanAheadZ = nextScanAheadZ;
2778 if ( std::isnan( nextValidM ) )
2781 *xOutData++ = thisX;
2782 *yOutData++ = thisY;
2783 *mOutData++ = lastValidM;
2785 *zOutData++ = thisZ;
2787 for ( ; i < totalPoints; ++i )
2789 *xOutData++ = *
xData++;
2790 *yOutData++ = *
yData++;
2791 *mOutData++ = lastValidM;
2793 *zOutData++ = *
zData++;
2800 const double delta = ( nextValidM - lastValidM ) / distanceToNextValidM;
2801 *xOutData++ = thisX;
2802 *yOutData++ = thisY;
2803 *mOutData++ = lastValidM + delta * scanAheadSegmentLengths[0];
2804 double totalScanAheadLength = scanAheadSegmentLengths[0];
2806 *zOutData++ = thisZ;
2807 for (
int k = 1; k <= j; ++i, ++k )
2811 *xOutData++ = thisX;
2812 *yOutData++ = thisY;
2813 totalScanAheadLength += scanAheadSegmentLengths[k];
2814 *mOutData++ = lastValidM + delta * totalScanAheadLength;
2817 *zOutData++ = *
zData++;
2819 lastValidM = nextValidM;
2828 return std::make_unique< QgsLineString >( xOut, yOut, zOut, mOut );
2834 if ( fromVertex.
part != 0 || fromVertex.
ring != 0 || toVertex.
part != 0 || toVertex.
ring != 0 )
2837 const int fromVertexNumber = fromVertex.
vertex;
2838 const int toVertexNumber = toVertex.
vertex;
2841 if ( fromVertexNumber > toVertexNumber )
2847 if ( fromVertexNumber < 0 || fromVertexNumber >= nPoints || toVertexNumber < 0 || toVertexNumber >= nPoints )
2850 if ( fromVertexNumber == toVertexNumber )
2853 const bool is3DGeometry =
is3D();
2854 const double *
xData = mX.constData();
2855 const double *
yData = mY.constData();
2856 const double *
zData = is3DGeometry ? mZ.constData() :
nullptr;
2857 double totalDistance = 0.0;
2860 for (
int i = fromVertexNumber; i < toVertexNumber; ++i )
2871 totalDistance += std::sqrt( dx * dx + dy * dy + dz * dz );
2874 return totalDistance;
QFlags< GeometryValidityFlag > GeometryValidityFlags
Geometry validity flags.
VertexType
Types of vertex.
@ Segment
The actual start or end point of a segment.
WkbType
The WKB type describes the number of dimensions a geometry has.
@ LineString25D
LineString25D.
@ LineStringM
LineStringM.
@ LineStringZM
LineStringZM.
@ LineStringZ
LineStringZ.
TransformDirection
Indicates the direction (forward or inverse) of a transform.
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
virtual bool convertTo(Qgis::WkbType type)
Converts the geometry to a specified type.
bool isMeasure() const
Returns true if the geometry contains m values.
QFlags< WkbFlag > WkbFlags
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
AxisOrder
Axis order for GML generation.
QString wktTypeStr() const
Returns the WKT type string of the geometry.
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, Qgis::WkbType baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
virtual bool boundingBoxIntersects(const QgsRectangle &rectangle) const
Returns true if the bounding box of this geometry intersects with a rectangle.
QgsAbstractGeometry()=default
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts of the geometry.
static endian_t endian()
Returns whether this machine uses big or little endian.
A 3-dimensional box composed of x, y, z coordinates.
bool contains(const QgsBox3D &other) const
Returns true when box contains other box.
QgsRectangle toRectangle() const
Converts the box to a 2D rectangle.
Compound curve geometry type.
void addCurve(QgsCurve *c, bool extendPrevious=false)
Adds a curve to the geometry (takes ownership).
Qgis::WkbType readHeader() const
readHeader
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
bool mHasCachedSummedUpArea
virtual bool isRing() const
Returns true if the curve is a ring.
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
bool snapToGridPrivate(double hSpacing, double vSpacing, double dSpacing, double mSpacing, const QVector< double > &srcX, const QVector< double > &srcY, const QVector< double > &srcZ, const QVector< double > &srcM, QVector< double > &outX, QVector< double > &outY, QVector< double > &outZ, QVector< double > &outM, bool removeRedundantPoints) const
Helper function for QgsCurve subclasses to snap to grids.
QgsBox3D mBoundingBox
Cached bounding box.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const
Tells whether the operation has been canceled already.
Convenience functions for geometry utils.
static void pointOnLineWithDistance(double x1, double y1, double x2, double y2, double distance, double &x, double &y, double *z1=nullptr, double *z2=nullptr, double *z=nullptr, double *m1=nullptr, double *m2=nullptr, double *m=nullptr)
Calculates the point a specified distance from (x1, y1) toward a second point (x2,...
static double distance2D(double x1, double y1, double x2, double y2)
Returns the 2D distance between (x1, y1) and (x2, y2).
static double lineAngle(double x1, double y1, double x2, double y2)
Calculates the direction of line joining two points in radians, clockwise from the north direction.
static double averageAngle(double x1, double y1, double x2, double y2, double x3, double y3)
Calculates the average angle (in radians) between the two linear segments from (x1,...
static double distance3D(double x1, double y1, double z1, double x2, double y2, double z2)
Returns the 3D distance between (x1, y1, z1) and (x2, y2, z2).
static double sqrDistToLine(double ptX, double ptY, double x1, double y1, double x2, double y2, double &minDistX, double &minDistY, double epsilon)
Returns the squared distance between a point and a line.
static int leftOfLine(const double x, const double y, const double x1, const double y1, const double x2, const double y2)
Returns a value < 0 if the point (x, y) is left of the line from (x1, y1) -> (x2, y2).
static json pointsToJson(const QgsPointSequence &points, int precision)
Returns coordinates as json object.
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure, QgsAbstractGeometry::WkbFlags flags)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
static QPair< Qgis::WkbType, QString > wktReadBlock(const QString &wkt)
Parses a WKT block of the format "TYPE( contents )" and returns a pair of geometry type to contents (...
static QgsPointSequence pointsFromWKT(const QString &wktCoordinateList, bool is3D, bool isMeasure)
Returns a list of points contained in a WKT string.
static QDomElement pointsToGML2(const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY)
Returns a gml::coordinates DOM element.
static QDomElement pointsToGML3(const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, bool is3D, QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY)
Returns a gml::posList DOM element.
static QString pointsToWKT(const QgsPointSequence &points, int precision, bool is3D, bool isMeasure)
Returns a WKT coordinate list.
Represents a single 2D line segment, consisting of a 2D start and end vertex only.
double segmentLength(QgsVertexId startVertex) const override
Returns the length of the segment of the geometry which begins at startVertex.
bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
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,...
bool pointAt(int node, QgsPoint &point, Qgis::VertexType &type) const override
Returns the point and vertex id of a point within the curve.
bool isClosed() const override
Returns true if the curve is closed.
void swapXy() override
Swaps the x and y coordinates from the geometry.
const double * yData() const
Returns a const pointer to the y vertex data.
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
QVector< QgsLineString * > splitToDisjointXYParts() const
Divides the linestring into parts that don't share any points or lines.
const double * xData() const
Returns a const pointer to the x vertex data.
bool moveVertex(QgsVertexId position, const QgsPoint &newPos) override
Moves a vertex within the geometry.
double length() const override
Returns the planar, 2-dimensional length of the geometry.
double length3D() const
Returns the length in 3D world of the line string.
void points(QgsPointSequence &pt) const override
Returns a list of points within the curve.
static std::unique_ptr< QgsLineString > fromQPolygonF(const QPolygonF &polygon)
Returns a new linestring from a QPolygonF polygon input.
QgsLineString * simplifyByDistance(double tolerance) const override
Simplifies the geometry by applying the Douglas Peucker simplification by distance algorithm.
int dimension() const override
Returns the inherent dimension of the geometry.
void sumUpArea(double &sum) const override
Calculates the shoelace/triangle formula sum for the points in the linestring.
void clear() override
Clears the geometry, ie reset it to a null geometry.
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the linestring does not have z values.
bool fromWkb(QgsConstWkbPtr &wkb) override
Sets the geometry from a WKB string.
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
QgsPoint startPoint() const override
Returns the starting point of the curve.
void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) override
Transforms the geometry using a coordinate transform.
QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a new line string geometry corresponding to a segmentized approximation of the curve.
bool isEmpty() const override
Returns true if the geometry is empty.
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
int numPoints() const override
Returns the number of points in the curve.
QgsPoint pointN(int i) const
Returns the specified point from inside the line string.
void drawAsPolygon(QPainter &p) const override
Draws the curve as a polygon on the specified QPainter.
int nCoordinates() const override
Returns the number of nodes contained in the geometry.
QgsLineString()
Constructor for an empty linestring geometry.
void draw(QPainter &p) const override
Draws the geometry using the specified QPainter.
QString asKml(int precision=17) const override
Returns a KML representation of the geometry.
std::unique_ptr< QgsLineString > interpolateM(bool use3DDistance=true) const
Returns a copy of this line with all missing (NaN) m values interpolated from m values of surrounding...
int wkbSize(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns the length of the QByteArray returned by asWkb().
void setPoints(size_t size, const double *x, const double *y, const double *z=nullptr, const double *m=nullptr)
Resets the line string to match the specified point data.
QgsPoint centroid() const override
Returns the centroid of the geometry.
QDomElement asGml3(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML3 representation of the geometry.
QPolygonF asQPolygonF() const override
Returns a QPolygonF representing the points.
bool removeDuplicateNodes(double epsilon=4 *std::numeric_limits< double >::epsilon(), bool useZValues=false) override
Removes duplicate nodes from the geometry, wherever removing the nodes does not result in a degenerat...
void scroll(int firstVertexIndex) final
Scrolls the curve vertices so that they start with the vertex at the given index.
bool boundingBoxIntersects(const QgsRectangle &rectangle) const override
Returns true if the bounding box of this geometry intersects with a rectangle.
QString geometryType() const override
Returns a unique string representing the geometry type.
std::unique_ptr< QgsLineString > measuredLine(double start, double end) const
Re-write the measure ordinate (or add one, if it isn't already there) interpolating the measure betwe...
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
QgsPoint endPoint() const override
Returns the end point of the curve.
void setYAt(int index, double y)
Sets the y-coordinate of the specified node in the line string.
QDomElement asGml2(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML2 representation of the geometry.
QgsLineString * reversed() const override
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
void close()
Closes the line string by appending the first point to the end of the line, if it is not already clos...
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
int indexOf(const QgsPoint &point) const final
Returns the index of the first vertex matching the given point, or -1 if a matching vertex is not fou...
double vertexAngle(QgsVertexId vertex) const override
Returns approximate angle at a vertex.
void extend(double startDistance, double endDistance)
Extends the line geometry by extrapolating out the start or end of the line by a specified distance.
QgsCompoundCurve * toCurveType() const override
Returns the geometry converted to the more generic curve type QgsCompoundCurve.
double distanceBetweenVertices(QgsVertexId fromVertex, QgsVertexId toVertex) const override
Returns the distance along the curve between two vertices.
void append(const QgsLineString *line)
Appends the contents of another line string to the end of this line string.
QgsLineString * curveSubstring(double startDistance, double endDistance) const override
Returns a new curve representing a substring of this curve.
QgsBox3D calculateBoundingBox3D() const override
Calculates the minimal 3D bounding box for the geometry.
std::tuple< std::unique_ptr< QgsCurve >, std::unique_ptr< QgsCurve > > splitCurveAtVertex(int index) const final
Splits the curve at the specified vertex index, returning two curves which represent the portion of t...
void addToPainterPath(QPainterPath &path) const override
Adds a curve to a painter path.
bool lineLocatePointByM(double m, double &x, double &y, double &z, double &distanceFromStart, bool use3DDistance=true) const
Attempts to locate a point on the linestring by m value.
void visitPointsByRegularDistance(double distance, const std::function< bool(double x, double y, double z, double m, double startSegmentX, double startSegmentY, double startSegmentZ, double startSegmentM, double endSegmentX, double endSegmentY, double endSegmentZ, double endSegmentM) > &visitPoint) const
Visits regular points along the linestring, spaced by distance.
void setXAt(int index, double x)
Sets the x-coordinate of the specified node in the line string.
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
double closestSegment(const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf=nullptr, double epsilon=4 *std::numeric_limits< double >::epsilon()) const override
Searches for the closest segment of the geometry to a given point.
QVector< QgsVertexId > collectDuplicateNodes(double epsilon=4 *std::numeric_limits< double >::epsilon(), bool useZValues=false) const
Returns a list of any duplicate nodes contained in the geometry, within the specified tolerance.
bool insertVertex(QgsVertexId position, const QgsPoint &vertex) override
Inserts a vertex into the geometry.
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the linestring does not have m values.
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
int compareToSameClass(const QgsAbstractGeometry *other) const final
Compares to an other geometry of the same class, and returns a integer for sorting of the two geometr...
bool dropMValue() override
Drops any measure values which exist in the geometry.
Q_DECL_DEPRECATED QgsBox3D calculateBoundingBox3d() const
Calculates the minimal 3D bounding box for the geometry.
json asJsonObject(int precision=17) const override
Returns a json object representation of the geometry.
void filterVertices(const std::function< bool(const QgsPoint &) > &filter) override
Filters the vertices from the geometry in place, removing any which do not return true for the filter...
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns a WKB representation of the geometry.
void transformVertices(const std::function< QgsPoint(const QgsPoint &) > &transform) override
Transforms the vertices from the geometry in place, applying the transform function to every vertex.
QgsLineString * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
bool convertTo(Qgis::WkbType type) override
Converts the geometry to a specified type.
bool isClosed2D() const override
Returns true if the curve is closed.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
QgsPoint * interpolatePoint(double distance) const override
Returns an interpolated point on the curve at the specified distance.
QgsLineString * snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0, bool removeRedundantPoints=false) const override
Makes a new geometry with all the points or vertices snapped to the closest point of the grid.
Point geometry type, with support for z-dimension and m-values.
void setY(double y)
Sets the point's y-coordinate.
void setX(double x)
Sets the point's x-coordinate.
A rectangle specified with double values.
bool contains(const QgsRectangle &rect) const
Returns true when rectangle contains other rectangle.
static Qgis::WkbType dropM(Qgis::WkbType type)
Drops the m dimension (if present) for a WKB type and returns the new type.
static Qgis::WkbType zmType(Qgis::WkbType type, bool hasZ, bool hasM)
Returns the modified input geometry type according to hasZ / hasM.
static Qgis::WkbType dropZ(Qgis::WkbType type)
Drops the z dimension (if present) for a WKB type and returns the new type.
static Qgis::WkbType addM(Qgis::WkbType type)
Adds the m dimension to a WKB type and returns the new type.
static Qgis::WkbType addZ(Qgis::WkbType type)
Adds the z dimension to a WKB type and returns the new type.
static Q_INVOKABLE bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
static Q_INVOKABLE bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
T qgsgeometry_cast(QgsAbstractGeometry *geom)
QVector< QgsPoint > QgsPointSequence
void simplifySection(int i, int j, const double *x, const double *y, std::vector< bool > &usePoint, const double distanceToleranceSquared, const double epsilon)
QLineF segment(int index, QRectF rect, double radius)
double distance2D(const QgsPolylineXY &coords)
Utility class for identifying a unique vertex within a geometry.