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() ) );
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 xmax = -std::numeric_limits<double>::max();
438 double ymax = -std::numeric_limits<double>::max();
440 const double *x = mX.constData();
441 const double *y = mY.constData();
442 bool foundPointInRectangle =
false;
443 for (
int i = 0; i < nb; ++i )
445 const double px = *x++;
446 xmin = std::min( xmin, px );
447 xmax = std::max( xmax, px );
448 const double py = *y++;
449 ymin = std::min( ymin, py );
450 ymax = std::max( ymax, py );
452 if ( !foundPointInRectangle && rectangle.
contains( px, py ) )
454 foundPointInRectangle =
true;
470 if ( foundPointInRectangle )
495 const int nb = mX.size();
504 if ( box3d.
contains( mX.at( 0 ), mY.at( 0 ), mZ.at( 0 ) ) ||
505 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 ) ) ) ||
506 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 ) ) ) ||
507 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 ) ) ) ||
508 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 ) ) ) ||
509 box3d.
contains( mX.at( nb - 1 ), mY.at( nb - 1 ), mZ.at( nb - 1 ) ) )
518 double xmin = std::numeric_limits<double>::max();
519 double ymin = std::numeric_limits<double>::max();
520 double zmin = std::numeric_limits<double>::max();
521 double xmax = -std::numeric_limits<double>::max();
522 double ymax = -std::numeric_limits<double>::max();
523 double zmax = -std::numeric_limits<double>::max();
525 const double *x = mX.constData();
526 const double *y = mY.constData();
527 const double *z = mZ.constData();
528 bool foundPointInBox =
false;
529 for (
int i = 0; i < nb; ++i )
531 const double px = *x++;
532 xmin = std::min( xmin, px );
533 xmax = std::max( xmax, px );
534 const double py = *y++;
535 ymin = std::min( ymin, py );
536 ymax = std::max( ymax, py );
537 const double pz = *z++;
538 zmin = std::min( zmin, pz );
539 zmax = std::max( zmax, pz );
541 if ( !foundPointInBox && box3d.
contains( px, py, pz ) )
543 foundPointInBox =
true;
559 if ( foundPointInBox )
572 QVector< QgsVertexId > res;
573 if ( mX.count() <= 1 )
576 const double *x = mX.constData();
577 const double *y = mY.constData();
579 bool useZ = hasZ && useZValues;
580 const double *z = useZ ? mZ.constData() :
nullptr;
584 double prevZ = z ? *z++ : 0;
587 for (
int i = 1; i < mX.count(); ++i )
589 double currentX = *x++;
590 double currentY = *y++;
591 double currentZ = useZ ? *z++ : 0;
611 const int nb = mX.size();
614 const double *x = mX.constData();
615 const double *y = mY.constData();
616 QPointF *dest =
points.data();
617 for (
int i = 0; i < nb; ++i )
619 *dest++ = QPointF( *x++, *y++ );
625void simplifySection(
int i,
int j,
const double *x,
const double *y, std::vector< bool > &usePoint,
const double distanceToleranceSquared,
const double epsilon )
632 double maxDistanceSquared = -1.0;
637 for (
int k = i + 1; k < j; k++ )
640 x[k], y[k], x[i], y[i], x[j], y[j], mx, my, epsilon );
642 if ( distanceSquared > maxDistanceSquared )
644 maxDistanceSquared = distanceSquared;
648 if ( maxDistanceSquared <= distanceToleranceSquared )
650 for (
int k = i + 1; k < j; k++ )
657 simplifySection( i, maxIndex, x, y, usePoint, distanceToleranceSquared, epsilon );
658 simplifySection( maxIndex, j, x, y, usePoint, distanceToleranceSquared, epsilon );
671 const double distanceToleranceSquared = tolerance * tolerance;
672 const double *
xData = mX.constData();
673 const double *
yData = mY.constData();
674 const double *
zData = mZ.constData();
675 const double *
mData = mM.constData();
677 const int size = mX.size();
679 std::vector< bool > usePoint( size,
true );
681 constexpr double epsilon = 4 * std::numeric_limits<double>::epsilon();
684 QVector< double > newX;
685 newX.reserve( size );
686 QVector< double > newY;
687 newY.reserve( size );
689 const bool hasZ =
is3D();
691 QVector< double > newZ;
693 newZ.reserve( size );
694 QVector< double > newM;
696 newM.reserve( size );
698 for (
int i = 0, n = size; i < n; ++i )
700 if ( usePoint[i] || i == n - 1 )
702 newX.append(
xData[i ] );
703 newY.append(
yData[i ] );
705 newZ.append(
zData[i] );
707 newM.append(
mData[i] );
711 const bool simplifyRing =
isRing();
712 const int newSize = newX.size();
713 if ( simplifyRing && newSize > 3 )
718 newX[ newSize - 2], newY[ newSize - 2 ],
719 newX[ 1 ], newY[ 1], mx, my, epsilon );
721 if ( distanceSquared <= distanceToleranceSquared )
724 newX.last() = newX.first();
726 newY.last() = newY.first();
730 newZ.last() = newZ.first();
735 newM.last() = newM.first();
756 importVerticesFromWkb( wkbPtr );
767 auto result2D = std::minmax_element( mX.begin(), mX.end() );
768 const double xmin = *result2D.first;
769 const double xmax = *result2D.second;
770 result2D = std::minmax_element( mY.begin(), mY.end() );
771 const double ymin = *result2D.first;
772 const double ymax = *result2D.second;
774 double zmin = std::numeric_limits< double >::quiet_NaN();
775 double zmax = std::numeric_limits< double >::quiet_NaN();
779 auto resultZ = std::minmax_element( mZ.begin(), mZ.end() );
780 zmin = *resultZ.first;
781 zmax = *resultZ.second;
784 return QgsBox3D( xmin, ymin, zmin, xmax, ymax, zmax );
794 const int size = mX.size();
795 if ( index < 1 || index >= size - 1 )
798 const bool useZ =
is3D();
801 QVector<double> newX( size );
802 QVector<double> newY( size );
803 QVector<double> newZ( useZ ? size : 0 );
804 QVector<double> newM( useM ? size : 0 );
805 auto it = std::copy( mX.constBegin() + index, mX.constEnd() - 1, newX.begin() );
806 it = std::copy( mX.constBegin(), mX.constBegin() + index, it );
807 *it = *newX.constBegin();
808 mX = std::move( newX );
810 it = std::copy( mY.constBegin() + index, mY.constEnd() - 1, newY.begin() );
811 it = std::copy( mY.constBegin(), mY.constBegin() + index, it );
812 *it = *newY.constBegin();
813 mY = std::move( newY );
816 it = std::copy( mZ.constBegin() + index, mZ.constEnd() - 1, newZ.begin() );
817 it = std::copy( mZ.constBegin(), mZ.constBegin() + index, it );
818 *it = *newZ.constBegin();
819 mZ = std::move( newZ );
823 it = std::copy( mM.constBegin() + index, mM.constEnd() - 1, newM.begin() );
824 it = std::copy( mM.constBegin(), mM.constBegin() + index, it );
825 *it = *newM.constBegin();
826 mM = std::move( newM );
845 QString secondWithoutParentheses =
parts.second;
846 secondWithoutParentheses = secondWithoutParentheses.remove(
'(' ).remove(
')' ).simplified().remove(
' ' );
847 parts.second =
parts.second.remove(
'(' ).remove(
')' );
848 if ( (
parts.second.compare( QLatin1String(
"EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
849 secondWithoutParentheses.isEmpty() )
864 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
875 wkb << static_cast<quint32>(
wkbType() );
893 wkt += QLatin1String(
"EMPTY" );
908 QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral(
"LineString" ) );
911 return elemLineString;
915 return elemLineString;
923 QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral(
"LineString" ) );
926 return elemLineString;
929 return elemLineString;
938 {
"type",
"LineString" },
948 kml.append( QLatin1String(
"<LinearRing>" ) );
952 kml.append( QLatin1String(
"<LineString>" ) );
955 kml.append( QLatin1String(
"<altitudeMode>" ) );
958 kml.append( QLatin1String(
"absolute" ) );
962 kml.append( QLatin1String(
"clampToGround" ) );
964 kml.append( QLatin1String(
"</altitudeMode>" ) );
965 kml.append( QLatin1String(
"<coordinates>" ) );
967 int nPoints = mX.size();
968 for (
int i = 0; i < nPoints; ++i )
972 kml.append( QLatin1String(
" " ) );
975 kml.append( QLatin1String(
"," ) );
979 kml.append( QLatin1String(
"," ) );
984 kml.append( QLatin1String(
",0" ) );
987 kml.append( QLatin1String(
"</coordinates>" ) );
990 kml.append( QLatin1String(
"</LinearRing>" ) );
994 kml.append( QLatin1String(
"</LineString>" ) );
1008 const int size = mX.size();
1012 const double *x = mX.constData();
1013 const double *y = mY.constData();
1016 double prevX = *x++;
1017 double prevY = *y++;
1019 for (
int i = 1; i < size; ++i )
1023 total += std::sqrt( dx * dx + dy * dy );
1033 const bool useZ =
is3D();
1036 const int size = mX.size();
1038 return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >() );
1040 index = std::clamp( index, 0, size - 1 );
1042 const int part1Size = index + 1;
1043 QVector< double > x1( part1Size );
1044 QVector< double > y1( part1Size );
1045 QVector< double > z1( useZ ? part1Size : 0 );
1046 QVector< double > m1( useM ? part1Size : 0 );
1048 const double *sourceX = mX.constData();
1049 const double *sourceY = mY.constData();
1050 const double *sourceZ = useZ ? mZ.constData() :
nullptr;
1051 const double *sourceM = useM ? mM.constData() :
nullptr;
1053 double *destX = x1.data();
1054 double *destY = y1.data();
1055 double *destZ = useZ ? z1.data() :
nullptr;
1056 double *destM = useM ? m1.data() :
nullptr;
1058 std::copy( sourceX, sourceX + part1Size, destX );
1059 std::copy( sourceY, sourceY + part1Size, destY );
1061 std::copy( sourceZ, sourceZ + part1Size, destZ );
1063 std::copy( sourceM, sourceM + part1Size, destM );
1065 const int part2Size = size - index;
1066 if ( part2Size < 2 )
1067 return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >() );
1069 QVector< double > x2( part2Size );
1070 QVector< double > y2( part2Size );
1071 QVector< double > z2( useZ ? part2Size : 0 );
1072 QVector< double > m2( useM ? part2Size : 0 );
1075 destZ = useZ ? z2.data() :
nullptr;
1076 destM = useM ? m2.data() :
nullptr;
1077 std::copy( sourceX + index, sourceX + size, destX );
1078 std::copy( sourceY + index, sourceY + size, destY );
1080 std::copy( sourceZ + index, sourceZ + size, destZ );
1082 std::copy( sourceM + index, sourceM + size, destM );
1084 if ( part1Size < 2 )
1085 return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
1087 return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
1092 const double *allPointsX =
xData();
1093 const double *allPointsY =
yData();
1095 QVector<double> partX;
1096 QVector<double> partY;
1097 QSet<QgsPointXY> partPointSet;
1099 QVector<QgsLineString *> disjointParts;
1100 for (
size_t i = 0; i < allPointsCount; i++ )
1102 const QgsPointXY point( *allPointsX++, *allPointsY++ );
1103 if ( partPointSet.contains( point ) )
1107 disjointParts.push_back(
new QgsLineString( partX, partY ) );
1109 partX = { partX.last() };
1110 partY = { partY.last() };
1111 partPointSet = {
QgsPointXY( partX[0], partY[0] ) };
1113 partX.push_back( point.
x() );
1114 partY.push_back( point.
y() );
1115 partPointSet.insert( point );
1118 if ( partX.size() > 1 || disjointParts.size() == 0 )
1119 disjointParts.push_back(
new QgsLineString( partX, partY ) );
1121 return disjointParts;
1129 const int size = mX.size();
1133 const double *x = mX.constData();
1134 const double *y = mY.constData();
1135 const double *z = mZ.constData();
1138 double prevX = *x++;
1139 double prevY = *y++;
1140 double prevZ = *z++;
1142 for (
int i = 1; i < size; ++i )
1147 total += std::sqrt( dx * dx + dy * dy + dz * dz );
1187 Q_UNUSED( tolerance )
1188 Q_UNUSED( toleranceType )
1204 if ( i < 0 || i >= mX.size() )
1209 double x = mX.at( i );
1210 double y = mY.at( i );
1211 double z = std::numeric_limits<double>::quiet_NaN();
1212 double m = std::numeric_limits<double>::quiet_NaN();
1230 else if ( hasZ && hasM )
1253 if ( index >= 0 && index < mX.size() )
1254 return mX.at( index );
1261 if ( index >= 0 && index < mY.size() )
1262 return mY.at( index );
1269 if ( index >= 0 && index < mX.size() )
1276 if ( index >= 0 && index < mY.size() )
1291 pts.reserve( nPoints );
1292 for (
int i = 0; i < nPoints; ++i )
1294 pts.push_back(
pointN( i ) );
1308 const bool hasZ =
static_cast< bool >( z );
1309 const bool hasM =
static_cast< bool >( m );
1330 double *destX = mX.data();
1331 double *destY = mY.data();
1332 double *destZ =
nullptr;
1342 double *destM =
nullptr;
1353 for (
size_t i = 0; i < size; ++i )
1380 bool hasZ = firstPt.
is3D();
1385 mX.resize(
points.size() );
1386 mY.resize(
points.size() );
1389 mZ.resize(
points.size() );
1397 mM.resize(
points.size() );
1404 for (
int i = 0; i <
points.size(); ++i )
1406 mX[i] =
points.at( i ).x();
1407 mY[i] =
points.at( i ).y();
1410 double z =
points.at( i ).z();
1411 mZ[i] = std::isnan( z ) ? 0 : z;
1415 double m =
points.at( i ).m();
1416 mM[i] = std::isnan( m ) ? 0 : m;
1469 mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
1482 mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
1492 std::reverse( copy->mX.begin(), copy->mX.end() );
1493 std::reverse( copy->mY.begin(), copy->mY.end() );
1496 std::reverse( copy->mZ.begin(), copy->mZ.end() );
1500 std::reverse( copy->mM.begin(), copy->mM.end() );
1507void QgsLineString::visitPointsByRegularDistance(
const double distance,
const std::function<
bool (
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double )> &visitPoint )
const
1512 double distanceTraversed = 0;
1514 if ( totalPoints == 0 )
1517 const double *x = mX.constData();
1518 const double *y = mY.constData();
1519 const double *z =
is3D() ? mZ.constData() :
nullptr;
1520 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1522 double prevX = *x++;
1523 double prevY = *y++;
1524 double prevZ = z ? *z++ : 0.0;
1525 double prevM = m ? *m++ : 0.0;
1529 visitPoint( prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM );
1533 double pZ = std::numeric_limits<double>::quiet_NaN();
1534 double pM = std::numeric_limits<double>::quiet_NaN();
1535 double nextPointDistance = distance;
1536 const double eps = 4 * nextPointDistance * std::numeric_limits<double>::epsilon();
1537 for (
int i = 1; i < totalPoints; ++i )
1539 double thisX = *x++;
1540 double thisY = *y++;
1541 double thisZ = z ? *z++ : 0.0;
1542 double thisM = m ? *m++ : 0.0;
1548 const double distanceToPoint = std::min( nextPointDistance - distanceTraversed,
segmentLength );
1551 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &pZ :
nullptr,
1552 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &pM :
nullptr );
1554 if ( !visitPoint( pX, pY, pZ, pM, prevX, prevY, prevZ, prevM, thisX, thisY, thisZ, thisM ) )
1557 nextPointDistance += distance;
1579 std::unique_ptr< QgsPoint > res;
1580 visitPointsByRegularDistance( distance, [ & ](
double x,
double y,
double z,
double m,
double,
double,
double,
double,
double,
double,
double,
double )->
bool
1582 res = std::make_unique< QgsPoint >( pointType, x, y, z, m );
1585 return res.release();
1590 return lineLocatePointByMPrivate( m, x, y, z, distanceFromStart, use3DDistance,
false );
1593bool QgsLineString::lineLocatePointByMPrivate(
double m,
double &x,
double &y,
double &z,
double &distanceFromStart,
bool use3DDistance,
bool haveInterpolatedM )
const
1598 distanceFromStart = 0;
1600 if ( totalPoints == 0 )
1603 const double *
xData = mX.constData();
1604 const double *
yData = mY.constData();
1605 const double *
mData = mM.constData();
1607 const double *
zData =
is3D() ? mZ.constData() :
nullptr;
1608 use3DDistance &=
static_cast< bool >(
zData );
1610 double prevX = *
xData++;
1611 double prevY = *
yData++;
1613 double prevM = *
mData++;
1616 while ( i < totalPoints )
1618 double thisX = *
xData++;
1619 double thisY = *
yData++;
1621 double thisM = *
mData++;
1625 if ( std::isnan( thisM ) )
1627 if ( haveInterpolatedM )
1631 std::unique_ptr< QgsLineString > interpolatedM(
interpolateM( use3DDistance ) );
1632 return interpolatedM->lineLocatePointByMPrivate( m, x, y, z, distanceFromStart, use3DDistance,
true );
1644 double totalLengthOfSegmentsWithConstantM = 0;
1645 for (
int j = 0; j < ( totalPoints - i ); ++j )
1655 distanceFromStart += totalLengthOfSegmentsWithConstantM / 2;
1665 const double delta = ( m - prevM ) / ( thisM - prevM );
1670 z = prevZ + ( thisZ - prevZ ) * delta;
1671 distanceFromStart += distanceToPoint;
1688 if ( startDistance < 0 && endDistance < 0 )
1691 endDistance = std::max( startDistance, endDistance );
1694 if ( totalPoints == 0 )
1697 QVector< QgsPoint > substringPoints;
1698 substringPoints.reserve( totalPoints );
1706 const double *x = mX.constData();
1707 const double *y = mY.constData();
1708 const double *z =
is3D() ? mZ.constData() :
nullptr;
1709 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1711 double distanceTraversed = 0;
1712 double prevX = *x++;
1713 double prevY = *y++;
1714 double prevZ = z ? *z++ : 0.0;
1715 double prevM = m ? *m++ : 0.0;
1716 bool foundStart =
false;
1718 if ( startDistance < 0 )
1721 for (
int i = 1; i < totalPoints; ++i )
1723 double thisX = *x++;
1724 double thisY = *y++;
1725 double thisZ = z ? *z++ : 0.0;
1726 double thisM = m ? *m++ : 0.0;
1730 if ( distanceTraversed <= startDistance && startDistance < distanceTraversed +
segmentLength )
1733 const double distanceToStart = startDistance - distanceTraversed;
1734 double startX, startY;
1738 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &startZ :
nullptr,
1739 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &startM :
nullptr );
1740 substringPoints <<
QgsPoint( pointType, startX, startY, startZ, startM );
1743 if ( foundStart && ( distanceTraversed +
segmentLength > endDistance ) )
1746 const double distanceToEnd = endDistance - distanceTraversed;
1751 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &endZ :
nullptr,
1752 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &endM :
nullptr );
1753 substringPoints <<
QgsPoint( pointType, endX, endY, endZ, endM );
1755 else if ( foundStart )
1757 substringPoints <<
QgsPoint( pointType, thisX, thisY, thisZ, thisM );
1765 if ( distanceTraversed >= endDistance )
1770 if ( !foundStart &&
qgsDoubleNear( distanceTraversed, startDistance ) )
1772 substringPoints <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1773 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1798 if ( path.isEmpty() || path.currentPosition() != QPointF( mX.at( 0 ), mY.at( 0 ) ) )
1800 path.moveTo( mX.at( 0 ), mY.at( 0 ) );
1803 for (
int i = 1; i < nPoints; ++i )
1805 path.lineTo( mX.at( i ), mY.at( i ) );
1818 return compoundCurve;
1823 if ( mX.size() < 2 || mY.size() < 2 )
1826 const bool extendStart = startDistance > 0;
1827 const bool extendEnd = endDistance > 0;
1832 const double currentLen = std::sqrt( std::pow( mX.at( 0 ) - mX.at( 1 ), 2 ) +
1833 std::pow( mY.at( 0 ) - mY.at( 1 ), 2 ) );
1834 const double newLen = currentLen + startDistance;
1835 mX[ 0 ] = mX.at( 1 ) + ( mX.at( 0 ) - mX.at( 1 ) ) / currentLen * newLen;
1836 mY[ 0 ] = mY.at( 1 ) + ( mY.at( 0 ) - mY.at( 1 ) ) / currentLen * newLen;
1841 const int last = mX.size() - 1;
1842 const double currentLen = std::sqrt( std::pow( mX.at( last ) - mX.at( last - 1 ), 2 ) +
1843 std::pow( mY.at( last ) - mY.at( last - 1 ), 2 ) );
1844 const double newLen = currentLen + endDistance;
1845 mX[ last ] = mX.at( last - 1 ) + ( mX.at( last ) - mX.at( last - 1 ) ) / currentLen * newLen;
1846 mY[ last ] = mY.at( last - 1 ) + ( mY.at( last ) - mY.at( last - 1 ) ) / currentLen * newLen;
1849 if ( extendStart || extendEnd )
1855 auto result = std::make_unique< QgsLineString >();
1857 return result.release();
1866 const int size = mX.size();
1867 const int otherSize = otherLine->mX.size();
1868 if ( size > otherSize )
1872 else if ( size < otherSize )
1877 if (
is3D() && !otherLine->
is3D() )
1879 else if ( !
is3D() && otherLine->
is3D() )
1881 const bool considerZ =
is3D();
1889 for (
int i = 0; i < size; i++ )
1891 const double x = mX[i];
1892 const double otherX = otherLine->mX[i];
1897 else if ( x > otherX )
1902 const double y = mY[i];
1903 const double otherY = otherLine->mY[i];
1908 else if ( y > otherY )
1915 const double z = mZ[i];
1916 const double otherZ = otherLine->mZ[i];
1922 else if ( z > otherZ )
1930 const double m = mM[i];
1931 const double otherM = otherLine->mM[i];
1937 else if ( m > otherM )
1948 return QStringLiteral(
"LineString" );
1964 double *zArray =
nullptr;
1970 std::unique_ptr< double[] > dummyZ;
1971 if ( !hasZ || !transformZ )
1973 dummyZ = std::make_unique<double[]>( nPoints );
1974 zArray = dummyZ.get();
1989 double *x = mX.data();
1990 double *y = mY.data();
1991 double *z = hasZ ? mZ.data() :
nullptr;
1992 double *m = hasM ? mM.data() :
nullptr;
1993 for (
int i = 0; i < nPoints; ++i )
1996 t.map( *x, *y, &xOut, &yOut );
2001 *z = *z * zScale + zTranslate;
2006 *m = *m * mScale + mTranslate;
2021 if ( position.
vertex < 0 || position.
vertex > mX.size() )
2031 mX.insert( position.
vertex, vertex.
x() );
2032 mY.insert( position.
vertex, vertex.
y() );
2035 mZ.insert( position.
vertex, vertex.
z() );
2039 mM.insert( position.
vertex, vertex.
m() );
2047 if ( position.
vertex < 0 || position.
vertex >= mX.size() )
2051 mX[position.
vertex] = newPos.
x();
2052 mY[position.
vertex] = newPos.
y();
2055 mZ[position.
vertex] = newPos.
z();
2059 mM[position.
vertex] = newPos.
m();
2067 if ( position.
vertex >= mX.size() || position.
vertex < 0 )
2072 mX.remove( position.
vertex );
2073 mY.remove( position.
vertex );
2076 mZ.remove( position.
vertex );
2080 mM.remove( position.
vertex );
2105 mX.append( pt.
x() );
2106 mY.append( pt.
y() );
2109 mZ.append( pt.
z() );
2113 mM.append( pt.
m() );
2120 double sqrDist = std::numeric_limits<double>::max();
2121 double leftOfDist = std::numeric_limits<double>::max();
2123 double prevLeftOfX = 0.0;
2124 double prevLeftOfY = 0.0;
2125 double testDist = 0;
2126 double segmentPtX, segmentPtY;
2131 const int size = mX.size();
2132 if ( size == 0 || size == 1 )
2138 const double *
xData = mX.constData();
2139 const double *
yData = mY.constData();
2140 for (
int i = 1; i < size; ++i )
2142 double prevX =
xData[ i - 1 ];
2143 double prevY =
yData[ i - 1 ];
2144 double currentX =
xData[ i ];
2145 double currentY =
yData[ i ];
2147 if ( testDist < sqrDist )
2150 segmentPt.
setX( segmentPtX );
2151 segmentPt.
setY( segmentPtY );
2152 vertexAfter.
part = 0;
2153 vertexAfter.
ring = 0;
2164 if (
qgsDoubleNear( testDist, leftOfDist ) && left != prevLeftOf && prevLeftOf != 0 )
2176 prevLeftOf = *leftOf;
2177 leftOfDist = testDist;
2178 prevLeftOfX = prevX;
2179 prevLeftOfY = prevY;
2181 else if ( testDist < leftOfDist )
2184 leftOfDist = testDist;
2216 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
2218 double totalLineLength = 0.0;
2219 double prevX = mX.at( 0 );
2220 double prevY = mY.at( 0 );
2226 double currentX = mX.at( i );
2227 double currentY = mY.at( i );
2228 double segmentLength = std::sqrt( std::pow( currentX - prevX, 2.0 ) +
2229 std::pow( currentY - prevY, 2.0 ) );
2243 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
2245 return QgsPoint( sumX / totalLineLength, sumY / totalLineLength );
2264 const int maxIndex = mX.size();
2271 const double *x = mX.constData();
2272 const double *y = mY.constData();
2273 double prevX = *x++;
2274 double prevY = *y++;
2275 for (
int i = 1; i < maxIndex; ++i )
2277 mSummedUpArea += prevX * ( *y - prevY ) - prevY * ( *x - prevX );
2287void QgsLineString::importVerticesFromWkb(
const QgsConstWkbPtr &wkb )
2293 mX.resize( nVertices );
2294 mY.resize( nVertices );
2295 hasZ ? mZ.resize( nVertices ) : mZ.clear();
2296 hasM ? mM.resize( nVertices ) : mM.clear();
2297 double *x = mX.data();
2298 double *y = mY.data();
2299 double *m = hasM ? mM.data() :
nullptr;
2300 double *z = hasZ ? mZ.data() :
nullptr;
2301 for (
int i = 0; i < nVertices; ++i )
2334 if ( mX.count() < 2 )
2344 double previousX = mX.at(
numPoints() - 2 );
2345 double previousY = mY.at(
numPoints() - 2 );
2346 double currentX = mX.at( 0 );
2347 double currentY = mY.at( 0 );
2348 double afterX = mX.at( 1 );
2349 double afterY = mY.at( 1 );
2352 else if ( vertex.
vertex == 0 )
2365 double previousX = mX.at( vertex.
vertex - 1 );
2366 double previousY = mY.at( vertex.
vertex - 1 );
2367 double currentX = mX.at( vertex.
vertex );
2368 double currentY = mY.at( vertex.
vertex );
2369 double afterX = mX.at( vertex.
vertex + 1 );
2370 double afterY = mY.at( vertex.
vertex + 1 );
2377 if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 1 )
2380 double dx = mX.at( startVertex.
vertex + 1 ) - mX.at( startVertex.
vertex );
2381 double dy = mY.at( startVertex.
vertex + 1 ) - mY.at( startVertex.
vertex );
2382 return std::sqrt( dx * dx + dy * dy );
2407 mZ.reserve( nPoints );
2408 for (
int i = 0; i < nPoints; ++i )
2438 mM.reserve( nPoints );
2439 for (
int i = 0; i < nPoints; ++i )
2470 std::swap( mX, mY );
2484 addZValue( std::numeric_limits<double>::quiet_NaN() );
2501 int size = mX.size();
2503 double *srcX = mX.data();
2504 double *srcY = mY.data();
2505 double *srcM = hasM ? mM.data() :
nullptr;
2506 double *srcZ = hasZ ? mZ.data() :
nullptr;
2509 for (
int i = 0; i < size; ++i )
2513 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2514 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
2542 int size = mX.size();
2544 double *srcX = mX.data();
2545 double *srcY = mY.data();
2546 double *srcM = hasM ? mM.data() :
nullptr;
2547 double *srcZ = hasZ ? mZ.data() :
nullptr;
2549 double *destX = srcX;
2550 double *destY = srcY;
2551 double *destM = srcM;
2552 double *destZ = srcZ;
2554 int filteredPoints = 0;
2555 for (
int i = 0; i < size; ++i )
2559 double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
2560 double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
2562 if ( filter(
QgsPoint( x, y, z, m ) ) )
2574 mX.resize( filteredPoints );
2575 mY.resize( filteredPoints );
2577 mZ.resize( filteredPoints );
2579 mM.resize( filteredPoints );
2588 int size = mX.size();
2590 double *srcX = mX.data();
2591 double *srcY = mY.data();
2592 double *srcM = hasM ? mM.data() :
nullptr;
2593 double *srcZ = hasZ ? mZ.data() :
nullptr;
2595 for (
int i = 0; i < size; ++i )
2599 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2600 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
2616 std::unique_ptr< QgsLineString > cloned(
clone() );
2623 if (
isEmpty() || ( nbpoints < 2 ) )
2628 const double range = end - start;
2629 double lineLength =
length();
2630 double lengthSoFar = 0.0;
2633 double *mOut = cloned->mM.data();
2635 for (
int i = 1; i < nbpoints ; ++i )
2638 if ( lineLength > 0.0 )
2639 *mOut++ = start + range * lengthSoFar / lineLength;
2640 else if ( lineLength == 0.0 && nbpoints > 1 )
2641 *mOut++ = start + range * i / ( nbpoints - 1 );
2655 if ( totalPoints < 2 )
2656 return std::unique_ptr< QgsLineString >(
clone() );
2658 const double *
xData = mX.constData();
2659 const double *
yData = mY.constData();
2660 const double *
mData = mM.constData();
2661 const double *
zData =
is3D() ? mZ.constData() :
nullptr;
2662 use3DDistance &=
static_cast< bool >(
zData );
2664 QVector< double > xOut( totalPoints );
2665 QVector< double > yOut( totalPoints );
2666 QVector< double > mOut( totalPoints );
2667 QVector< double > zOut(
static_cast< bool >(
zData ) ? totalPoints : 0 );
2669 double *xOutData = xOut.data();
2670 double *yOutData = yOut.data();
2671 double *mOutData = mOut.data();
2672 double *zOutData =
static_cast< bool >(
zData ) ? zOut.data() :
nullptr;
2675 double currentSegmentLength = 0;
2676 double lastValidM = std::numeric_limits< double >::quiet_NaN();
2677 double prevX = *
xData;
2678 double prevY = *
yData;
2680 while ( i < totalPoints )
2682 double thisX = *
xData++;
2683 double thisY = *
yData++;
2685 double thisM = *
mData++;
2687 currentSegmentLength = use3DDistance
2691 if ( !std::isnan( thisM ) )
2693 *xOutData++ = thisX;
2694 *yOutData++ = thisY;
2695 *mOutData++ = thisM;
2697 *zOutData++ = thisZ;
2704 double scanAheadM = thisM;
2705 while ( i + j + 1 < totalPoints && std::isnan( scanAheadM ) )
2707 scanAheadM =
mData[ j ];
2710 if ( std::isnan( scanAheadM ) )
2715 *xOutData++ = thisX;
2716 *yOutData++ = thisY;
2717 *mOutData++ = scanAheadM;
2719 *zOutData++ = thisZ;
2720 for ( ; i < j; ++i )
2724 *xOutData++ = thisX;
2725 *yOutData++ = thisY;
2726 *mOutData++ = scanAheadM;
2729 *zOutData++ = *
zData++;
2731 lastValidM = scanAheadM;
2737 double scanAheadX = thisX;
2738 double scanAheadY = thisY;
2739 double scanAheadZ = thisZ;
2740 double distanceToNextValidM = currentSegmentLength;
2741 std::vector< double > scanAheadSegmentLengths;
2742 scanAheadSegmentLengths.emplace_back( currentSegmentLength );
2744 double nextValidM = std::numeric_limits< double >::quiet_NaN();
2745 while ( i + j < totalPoints - 1 )
2747 double nextScanAheadX =
xData[j];
2748 double nextScanAheadY =
yData[j];
2749 double nextScanAheadZ =
zData ?
zData[j] : 0;
2750 double nextScanAheadM =
mData[ j ];
2751 const double scanAheadSegmentLength = use3DDistance
2754 scanAheadSegmentLengths.emplace_back( scanAheadSegmentLength );
2755 distanceToNextValidM += scanAheadSegmentLength;
2757 if ( !std::isnan( nextScanAheadM ) )
2759 nextValidM = nextScanAheadM;
2763 scanAheadX = nextScanAheadX;
2764 scanAheadY = nextScanAheadY;
2765 scanAheadZ = nextScanAheadZ;
2769 if ( std::isnan( nextValidM ) )
2772 *xOutData++ = thisX;
2773 *yOutData++ = thisY;
2774 *mOutData++ = lastValidM;
2776 *zOutData++ = thisZ;
2778 for ( ; i < totalPoints; ++i )
2780 *xOutData++ = *
xData++;
2781 *yOutData++ = *
yData++;
2782 *mOutData++ = lastValidM;
2784 *zOutData++ = *
zData++;
2791 const double delta = ( nextValidM - lastValidM ) / distanceToNextValidM;
2792 *xOutData++ = thisX;
2793 *yOutData++ = thisY;
2794 *mOutData++ = lastValidM + delta * scanAheadSegmentLengths[0];
2795 double totalScanAheadLength = scanAheadSegmentLengths[0];
2797 *zOutData++ = thisZ;
2798 for (
int k = 1; k <= j; ++i, ++k )
2802 *xOutData++ = thisX;
2803 *yOutData++ = thisY;
2804 totalScanAheadLength += scanAheadSegmentLengths[k];
2805 *mOutData++ = lastValidM + delta * totalScanAheadLength;
2808 *zOutData++ = *
zData++;
2810 lastValidM = nextValidM;
2819 return std::make_unique< QgsLineString >( xOut, yOut, zOut, mOut );
2825 if ( fromVertex.
part != 0 || fromVertex.
ring != 0 || toVertex.
part != 0 || toVertex.
ring != 0 )
2828 const int fromVertexNumber = fromVertex.
vertex;
2829 const int toVertexNumber = toVertex.
vertex;
2832 if ( fromVertexNumber > toVertexNumber )
2838 if ( fromVertexNumber < 0 || fromVertexNumber >= nPoints || toVertexNumber < 0 || toVertexNumber >= nPoints )
2841 if ( fromVertexNumber == toVertexNumber )
2844 const bool is3DGeometry =
is3D();
2845 const double *
xData = mX.constData();
2846 const double *
yData = mY.constData();
2847 const double *
zData = is3DGeometry ? mZ.constData() :
nullptr;
2848 double totalDistance = 0.0;
2851 for (
int i = fromVertexNumber; i < toVertexNumber; ++i )
2862 totalDistance += std::sqrt( dx * dx + dy * dy + dz * dz );
2865 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.