23#include <nlohmann/json.hpp>
37#include <QDomDocument>
42using namespace Qt::StringLiterals;
64 mX.resize(
points.count() );
65 mY.resize(
points.count() );
66 double *x = mX.data();
67 double *y = mY.data();
72 mZ.resize(
points.count() );
77 mM.resize(
points.count() );
92QgsLineString::QgsLineString(
const QVector<double> &x,
const QVector<double> &y,
const QVector<double> &z,
const QVector<double> &m,
bool is25DType )
95 int pointCount = std::min( x.size(), y.size() );
96 if ( x.size() == pointCount )
102 mX = x.mid( 0, pointCount );
104 if ( y.size() == pointCount )
110 mY = y.mid( 0, pointCount );
112 if ( !z.isEmpty() && z.count() >= pointCount )
115 if ( z.size() == pointCount )
121 mZ = z.mid( 0, pointCount );
124 if ( !m.isEmpty() && m.count() >= pointCount )
127 if ( m.size() == pointCount )
133 mM = m.mid( 0, pointCount );
166 mX.reserve(
points.size() );
167 mY.reserve(
points.size() );
189 return std::make_unique< QgsLineString >();
191 QVector<double> x( segments + 1 );
192 QVector<double> y( segments + 1 );
196 const bool hasZ = start.
is3D() && controlPoint1.
is3D() && controlPoint2.
is3D() && end.
is3D();
199 z.resize( segments + 1 );
205 m.resize( segments + 1 );
208 double *
xData = x.data();
209 double *
yData = y.data();
210 double *
zData = z.data();
211 double *
mData = m.data();
213 const double step = 1.0 / segments;
215 for (
int i = 0; i <= segments; ++i )
217 const double t = i * step;
220 double iz = std::numeric_limits<double>::quiet_NaN();
221 double im = std::numeric_limits<double>::quiet_NaN();
224 start.
x(), start.
y(), start.
z(), start.
m(),
225 controlPoint1.
x(), controlPoint1.
y(), controlPoint1.
z(), controlPoint1.
m(),
226 controlPoint2.
x(), controlPoint2.
y(), controlPoint2.
z(), controlPoint2.
m(),
227 end.
x(), end.
y(), end.
z(), end.
m(),
240 return std::make_unique< QgsLineString >( x, y, z, m );
247 x.resize( polygon.count() );
248 y.resize( polygon.count() );
249 double *
xData = x.data();
250 double *
yData = y.data();
252 const QPointF *src = polygon.data();
253 for (
int i = 0 ; i < polygon.size(); ++ i )
260 return std::make_unique< QgsLineString >( x, y );
285 const int size = mX.size();
289 const double *x = mX.constData();
290 const double *y = mY.constData();
291 const bool useZ =
is3D();
293 const double *z = useZ ? mZ.constData() :
nullptr;
294 const double *m = useM ? mM.constData() :
nullptr;
296 for (
int i = 0; i < size; ++i )
318 error = QObject::tr(
"LineString has less than 2 points and is not empty." );
329 bool res =
snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM,
330 result->mX, result->mY, result->mZ, result->mM, removeRedundantPoints );
332 return result.release();
339 if ( mX.count() <= 2 )
342 double prevX = mX.at( 0 );
343 double prevY = mY.at( 0 );
345 bool useZ = hasZ && useZValues;
346 double prevZ = useZ ? mZ.at( 0 ) : 0;
348 int remaining = mX.count();
349 while ( i < remaining )
351 double currentX = mX.at( i );
352 double currentY = mY.at( i );
353 double currentZ = useZ ? mZ.at( i ) : 0;
390 if (
is3D() && closed )
391 closed &=
qgsDoubleNear( mZ.first(), mZ.last() ) || ( std::isnan( mZ.first() ) && std::isnan( mZ.last() ) );
404 return mBoundingBox.toRectangle().intersects( rectangle );
406 const int nb = mX.size();
415 if ( rectangle.
contains( mX.at( 0 ), mY.at( 0 ) ) ||
416 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.2 ) ), mY.at(
static_cast< int >( nb * 0.2 ) ) ) ||
417 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.4 ) ), mY.at(
static_cast< int >( nb * 0.4 ) ) ) ||
418 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.6 ) ), mY.at(
static_cast< int >( nb * 0.6 ) ) ) ||
419 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.8 ) ), mY.at(
static_cast< int >( nb * 0.8 ) ) ) ||
420 rectangle.
contains( mX.at( nb - 1 ), mY.at( nb - 1 ) ) )
429 double xmin = std::numeric_limits<double>::max();
430 double ymin = std::numeric_limits<double>::max();
431 double zmin = -std::numeric_limits<double>::max();
432 double xmax = -std::numeric_limits<double>::max();
433 double ymax = -std::numeric_limits<double>::max();
434 double zmax = -std::numeric_limits<double>::max();
436 const double *x = mX.constData();
437 const double *y = mY.constData();
438 const double *z =
is3D() ? mZ.constData() :
nullptr;
439 bool foundPointInRectangle =
false;
440 for (
int i = 0; i < nb; ++i )
442 const double px = *x++;
443 xmin = std::min( xmin, px );
444 xmax = std::max( xmax, px );
445 const double py = *y++;
446 ymin = std::min( ymin, py );
447 ymax = std::max( ymax, py );
450 const double pz = *z++;
451 zmin = std::min( zmin, pz );
452 zmax = std::max( zmax, pz );
455 if ( !foundPointInRectangle && rectangle.
contains( px, py ) )
457 foundPointInRectangle =
true;
473 if ( foundPointInRectangle )
498 const int nb = mX.size();
507 if ( box3d.
contains( mX.at( 0 ), mY.at( 0 ), mZ.at( 0 ) ) ||
508 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 ) ) ) ||
509 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 ) ) ) ||
510 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 ) ) ) ||
511 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 ) ) ) ||
512 box3d.
contains( mX.at( nb - 1 ), mY.at( nb - 1 ), mZ.at( nb - 1 ) ) )
521 double xmin = std::numeric_limits<double>::max();
522 double ymin = std::numeric_limits<double>::max();
523 double zmin = std::numeric_limits<double>::max();
524 double xmax = -std::numeric_limits<double>::max();
525 double ymax = -std::numeric_limits<double>::max();
526 double zmax = -std::numeric_limits<double>::max();
528 const double *x = mX.constData();
529 const double *y = mY.constData();
530 const double *z = mZ.constData();
531 bool foundPointInBox =
false;
532 for (
int i = 0; i < nb; ++i )
534 const double px = *x++;
535 xmin = std::min( xmin, px );
536 xmax = std::max( xmax, px );
537 const double py = *y++;
538 ymin = std::min( ymin, py );
539 ymax = std::max( ymax, py );
540 const double pz = *z++;
541 zmin = std::min( zmin, pz );
542 zmax = std::max( zmax, pz );
544 if ( !foundPointInBox && box3d.
contains( px, py, pz ) )
546 foundPointInBox =
true;
562 if ( foundPointInBox )
575 QVector< QgsVertexId > res;
576 if ( mX.count() <= 1 )
579 const double *x = mX.constData();
580 const double *y = mY.constData();
582 bool useZ = hasZ && useZValues;
583 const double *z = useZ ? mZ.constData() :
nullptr;
587 double prevZ = z ? *z++ : 0;
590 for (
int i = 1; i < mX.count(); ++i )
592 double currentX = *x++;
593 double currentY = *y++;
594 double currentZ = useZ ? *z++ : 0;
614 const int nb = mX.size();
617 const double *x = mX.constData();
618 const double *y = mY.constData();
619 QPointF *dest =
points.data();
620 for (
int i = 0; i < nb; ++i )
622 *dest++ = QPointF( *x++, *y++ );
628void simplifySection(
int i,
int j,
const double *x,
const double *y, std::vector< bool > &usePoint,
const double distanceToleranceSquared,
const double epsilon )
635 double maxDistanceSquared = -1.0;
640 for (
int k = i + 1; k < j; k++ )
643 x[k], y[k], x[i], y[i], x[j], y[j], mx, my, epsilon );
645 if ( distanceSquared > maxDistanceSquared )
647 maxDistanceSquared = distanceSquared;
651 if ( maxDistanceSquared <= distanceToleranceSquared )
653 for (
int k = i + 1; k < j; k++ )
660 simplifySection( i, maxIndex, x, y, usePoint, distanceToleranceSquared, epsilon );
661 simplifySection( maxIndex, j, x, y, usePoint, distanceToleranceSquared, epsilon );
674 const double distanceToleranceSquared = tolerance * tolerance;
675 const double *
xData = mX.constData();
676 const double *
yData = mY.constData();
677 const double *
zData = mZ.constData();
678 const double *
mData = mM.constData();
680 const int size = mX.size();
682 std::vector< bool > usePoint( size,
true );
684 constexpr double epsilon = 4 * std::numeric_limits<double>::epsilon();
687 QVector< double > newX;
688 newX.reserve( size );
689 QVector< double > newY;
690 newY.reserve( size );
692 const bool hasZ =
is3D();
694 QVector< double > newZ;
696 newZ.reserve( size );
697 QVector< double > newM;
699 newM.reserve( size );
701 for (
int i = 0, n = size; i < n; ++i )
703 if ( usePoint[i] || i == n - 1 )
705 newX.append(
xData[i ] );
706 newY.append(
yData[i ] );
708 newZ.append(
zData[i] );
710 newM.append(
mData[i] );
714 const bool simplifyRing =
isRing();
715 const int newSize = newX.size();
716 if ( simplifyRing && newSize > 3 )
721 newX[ newSize - 2], newY[ newSize - 2 ],
722 newX[ 1 ], newY[ 1], mx, my, epsilon );
724 if ( distanceSquared <= distanceToleranceSquared )
727 newX.last() = newX.first();
729 newY.last() = newY.first();
733 newZ.last() = newZ.first();
738 newM.last() = newM.first();
759 importVerticesFromWkb( wkbPtr );
770 auto result2D = std::minmax_element( mX.begin(), mX.end() );
771 const double xmin = *result2D.first;
772 const double xmax = *result2D.second;
773 result2D = std::minmax_element( mY.begin(), mY.end() );
774 const double ymin = *result2D.first;
775 const double ymax = *result2D.second;
777 double zmin = std::numeric_limits< double >::quiet_NaN();
778 double zmax = std::numeric_limits< double >::quiet_NaN();
782 auto resultZ = std::minmax_element( mZ.begin(), mZ.end() );
783 zmin = *resultZ.first;
784 zmax = *resultZ.second;
787 return QgsBox3D( xmin, ymin, zmin, xmax, ymax, zmax );
797 const int size = mX.size();
798 if ( index < 1 || index >= size - 1 )
801 const bool useZ =
is3D();
804 QVector<double> newX( size );
805 QVector<double> newY( size );
806 QVector<double> newZ( useZ ? size : 0 );
807 QVector<double> newM( useM ? size : 0 );
808 auto it = std::copy( mX.constBegin() + index, mX.constEnd() - 1, newX.begin() );
809 it = std::copy( mX.constBegin(), mX.constBegin() + index, it );
810 *it = *newX.constBegin();
811 mX = std::move( newX );
813 it = std::copy( mY.constBegin() + index, mY.constEnd() - 1, newY.begin() );
814 it = std::copy( mY.constBegin(), mY.constBegin() + index, it );
815 *it = *newY.constBegin();
816 mY = std::move( newY );
819 it = std::copy( mZ.constBegin() + index, mZ.constEnd() - 1, newZ.begin() );
820 it = std::copy( mZ.constBegin(), mZ.constBegin() + index, it );
821 *it = *newZ.constBegin();
822 mZ = std::move( newZ );
826 it = std::copy( mM.constBegin() + index, mM.constEnd() - 1, newM.begin() );
827 it = std::copy( mM.constBegin(), mM.constBegin() + index, it );
828 *it = *newM.constBegin();
829 mM = std::move( newM );
848 QString secondWithoutParentheses =
parts.second;
849 secondWithoutParentheses = secondWithoutParentheses.remove(
'(' ).remove(
')' ).simplified().remove(
' ' );
850 parts.second =
parts.second.remove(
'(' ).remove(
')' );
851 if ( (
parts.second.compare(
"EMPTY"_L1, Qt::CaseInsensitive ) == 0 ) ||
852 secondWithoutParentheses.isEmpty() )
867 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
878 wkb << static_cast<quint32>(
wkbType() );
911 QDomElement elemLineString = doc.createElementNS( ns, u
"LineString"_s );
914 return elemLineString;
918 return elemLineString;
926 QDomElement elemLineString = doc.createElementNS( ns, u
"LineString"_s );
929 return elemLineString;
932 return elemLineString;
941 {
"type",
"LineString" },
951 kml.append(
"<LinearRing>"_L1 );
955 kml.append(
"<LineString>"_L1 );
958 kml.append(
"<altitudeMode>"_L1 );
961 kml.append(
"absolute"_L1 );
965 kml.append(
"clampToGround"_L1 );
967 kml.append(
"</altitudeMode>"_L1 );
968 kml.append(
"<coordinates>"_L1 );
970 int nPoints = mX.size();
971 for (
int i = 0; i < nPoints; ++i )
975 kml.append(
" "_L1 );
978 kml.append(
","_L1 );
982 kml.append(
","_L1 );
987 kml.append(
",0"_L1 );
990 kml.append(
"</coordinates>"_L1 );
993 kml.append(
"</LinearRing>"_L1 );
997 kml.append(
"</LineString>"_L1 );
1011 const int size = mX.size();
1015 const double *x = mX.constData();
1016 const double *y = mY.constData();
1019 double prevX = *x++;
1020 double prevY = *y++;
1022 for (
int i = 1; i < size; ++i )
1026 total += std::sqrt( dx * dx + dy * dy );
1036 const bool useZ =
is3D();
1039 const int size = mX.size();
1041 return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >() );
1043 index = std::clamp( index, 0, size - 1 );
1045 const int part1Size = index + 1;
1046 QVector< double > x1( part1Size );
1047 QVector< double > y1( part1Size );
1048 QVector< double > z1( useZ ? part1Size : 0 );
1049 QVector< double > m1( useM ? part1Size : 0 );
1051 const double *sourceX = mX.constData();
1052 const double *sourceY = mY.constData();
1053 const double *sourceZ = useZ ? mZ.constData() :
nullptr;
1054 const double *sourceM = useM ? mM.constData() :
nullptr;
1056 double *destX = x1.data();
1057 double *destY = y1.data();
1058 double *destZ = useZ ? z1.data() :
nullptr;
1059 double *destM = useM ? m1.data() :
nullptr;
1061 std::copy( sourceX, sourceX + part1Size, destX );
1062 std::copy( sourceY, sourceY + part1Size, destY );
1064 std::copy( sourceZ, sourceZ + part1Size, destZ );
1066 std::copy( sourceM, sourceM + part1Size, destM );
1068 const int part2Size = size - index;
1069 if ( part2Size < 2 )
1070 return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >() );
1072 QVector< double > x2( part2Size );
1073 QVector< double > y2( part2Size );
1074 QVector< double > z2( useZ ? part2Size : 0 );
1075 QVector< double > m2( useM ? part2Size : 0 );
1078 destZ = useZ ? z2.data() :
nullptr;
1079 destM = useM ? m2.data() :
nullptr;
1080 std::copy( sourceX + index, sourceX + size, destX );
1081 std::copy( sourceY + index, sourceY + size, destY );
1083 std::copy( sourceZ + index, sourceZ + size, destZ );
1085 std::copy( sourceM + index, sourceM + size, destM );
1087 if ( part1Size < 2 )
1088 return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
1090 return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
1095 const double *allPointsX =
xData();
1096 const double *allPointsY =
yData();
1098 QVector<double> partX;
1099 QVector<double> partY;
1100 QSet<QgsPointXY> partPointSet;
1102 QVector<QgsLineString *> disjointParts;
1103 for (
size_t i = 0; i < allPointsCount; i++ )
1105 const QgsPointXY point( *allPointsX++, *allPointsY++ );
1106 if ( partPointSet.contains( point ) )
1110 disjointParts.push_back(
new QgsLineString( partX, partY ) );
1112 partX = { partX.last() };
1113 partY = { partY.last() };
1114 partPointSet = {
QgsPointXY( partX[0], partY[0] ) };
1116 partX.push_back( point.
x() );
1117 partY.push_back( point.
y() );
1118 partPointSet.insert( point );
1121 if ( partX.size() > 1 || disjointParts.size() == 0 )
1122 disjointParts.push_back(
new QgsLineString( partX, partY ) );
1124 return disjointParts;
1132 const int size = mX.size();
1136 const double *x = mX.constData();
1137 const double *y = mY.constData();
1138 const double *z = mZ.constData();
1141 double prevX = *x++;
1142 double prevY = *y++;
1143 double prevZ = *z++;
1145 for (
int i = 1; i < size; ++i )
1150 total += std::sqrt( dx * dx + dy * dy + dz * dz );
1190 Q_UNUSED( tolerance )
1191 Q_UNUSED( toleranceType )
1207 if ( i < 0 || i >= mX.size() )
1212 double x = mX.at( i );
1213 double y = mY.at( i );
1214 double z = std::numeric_limits<double>::quiet_NaN();
1215 double m = std::numeric_limits<double>::quiet_NaN();
1233 else if ( hasZ && hasM )
1256 if ( index >= 0 && index < mX.size() )
1257 return mX.at( index );
1264 if ( index >= 0 && index < mY.size() )
1265 return mY.at( index );
1272 if ( index >= 0 && index < mX.size() )
1279 if ( index >= 0 && index < mY.size() )
1294 pts.reserve( nPoints );
1295 for (
int i = 0; i < nPoints; ++i )
1297 pts.push_back(
pointN( i ) );
1311 const bool hasZ =
static_cast< bool >( z );
1312 const bool hasM =
static_cast< bool >( m );
1333 double *destX = mX.data();
1334 double *destY = mY.data();
1335 double *destZ =
nullptr;
1345 double *destM =
nullptr;
1356 for (
size_t i = 0; i < size; ++i )
1383 bool hasZ = firstPt.
is3D();
1388 mX.resize(
points.size() );
1389 mY.resize(
points.size() );
1392 mZ.resize(
points.size() );
1400 mM.resize(
points.size() );
1407 for (
int i = 0; i <
points.size(); ++i )
1409 mX[i] =
points.at( i ).x();
1410 mY[i] =
points.at( i ).y();
1413 double z =
points.at( i ).z();
1414 mZ[i] = std::isnan( z ) ? 0 : z;
1418 double m =
points.at( i ).m();
1419 mM[i] = std::isnan( m ) ? 0 : m;
1472 mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
1485 mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
1495 std::reverse( copy->mX.begin(), copy->mX.end() );
1496 std::reverse( copy->mY.begin(), copy->mY.end() );
1499 std::reverse( copy->mZ.begin(), copy->mZ.end() );
1503 std::reverse( copy->mM.begin(), copy->mM.end() );
1510void QgsLineString::visitPointsByRegularDistance(
const double distance,
const std::function<
bool (
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double )> &visitPoint )
const
1515 double distanceTraversed = 0;
1517 if ( totalPoints == 0 )
1520 const double *x = mX.constData();
1521 const double *y = mY.constData();
1522 const double *z =
is3D() ? mZ.constData() :
nullptr;
1523 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1525 double prevX = *x++;
1526 double prevY = *y++;
1527 double prevZ = z ? *z++ : 0.0;
1528 double prevM = m ? *m++ : 0.0;
1532 visitPoint( prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM );
1536 double pZ = std::numeric_limits<double>::quiet_NaN();
1537 double pM = std::numeric_limits<double>::quiet_NaN();
1538 double nextPointDistance = distance;
1539 const double eps = 4 * nextPointDistance * std::numeric_limits<double>::epsilon();
1540 for (
int i = 1; i < totalPoints; ++i )
1542 double thisX = *x++;
1543 double thisY = *y++;
1544 double thisZ = z ? *z++ : 0.0;
1545 double thisM = m ? *m++ : 0.0;
1551 const double distanceToPoint = std::min( nextPointDistance - distanceTraversed,
segmentLength );
1554 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &pZ :
nullptr,
1555 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &pM :
nullptr );
1557 if ( !visitPoint( pX, pY, pZ, pM, prevX, prevY, prevZ, prevM, thisX, thisY, thisZ, thisM ) )
1560 nextPointDistance += distance;
1582 std::unique_ptr< QgsPoint > res;
1583 visitPointsByRegularDistance( distance, [ & ](
double x,
double y,
double z,
double m,
double,
double,
double,
double,
double,
double,
double,
double )->
bool
1585 res = std::make_unique< QgsPoint >( pointType, x, y, z, m );
1588 return res.release();
1593 return lineLocatePointByMPrivate( m, x, y, z, distanceFromStart, use3DDistance,
false );
1596bool QgsLineString::lineLocatePointByMPrivate(
double m,
double &x,
double &y,
double &z,
double &distanceFromStart,
bool use3DDistance,
bool haveInterpolatedM )
const
1601 distanceFromStart = 0;
1603 if ( totalPoints == 0 )
1606 const double *
xData = mX.constData();
1607 const double *
yData = mY.constData();
1608 const double *
mData = mM.constData();
1610 const double *
zData =
is3D() ? mZ.constData() :
nullptr;
1611 use3DDistance &=
static_cast< bool >(
zData );
1613 double prevX = *
xData++;
1614 double prevY = *
yData++;
1616 double prevM = *
mData++;
1619 while ( i < totalPoints )
1621 double thisX = *
xData++;
1622 double thisY = *
yData++;
1624 double thisM = *
mData++;
1628 if ( std::isnan( thisM ) )
1630 if ( haveInterpolatedM )
1634 std::unique_ptr< QgsLineString > interpolatedM(
interpolateM( use3DDistance ) );
1635 return interpolatedM->lineLocatePointByMPrivate( m, x, y, z, distanceFromStart, use3DDistance,
true );
1647 double totalLengthOfSegmentsWithConstantM = 0;
1648 for (
int j = 0; j < ( totalPoints - i ); ++j )
1658 distanceFromStart += totalLengthOfSegmentsWithConstantM / 2;
1668 const double delta = ( m - prevM ) / ( thisM - prevM );
1673 z = prevZ + ( thisZ - prevZ ) * delta;
1674 distanceFromStart += distanceToPoint;
1691 if ( startDistance < 0 && endDistance < 0 )
1694 endDistance = std::max( startDistance, endDistance );
1697 if ( totalPoints == 0 )
1700 QVector< QgsPoint > substringPoints;
1701 substringPoints.reserve( totalPoints );
1709 const double *x = mX.constData();
1710 const double *y = mY.constData();
1711 const double *z =
is3D() ? mZ.constData() :
nullptr;
1712 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1714 double distanceTraversed = 0;
1715 double prevX = *x++;
1716 double prevY = *y++;
1717 double prevZ = z ? *z++ : 0.0;
1718 double prevM = m ? *m++ : 0.0;
1719 bool foundStart =
false;
1721 if ( startDistance < 0 )
1724 for (
int i = 1; i < totalPoints; ++i )
1726 double thisX = *x++;
1727 double thisY = *y++;
1728 double thisZ = z ? *z++ : 0.0;
1729 double thisM = m ? *m++ : 0.0;
1733 if ( distanceTraversed <= startDistance && startDistance < distanceTraversed +
segmentLength )
1736 const double distanceToStart = startDistance - distanceTraversed;
1737 double startX, startY;
1741 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &startZ :
nullptr,
1742 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &startM :
nullptr );
1743 substringPoints <<
QgsPoint( pointType, startX, startY, startZ, startM );
1746 if ( foundStart && ( distanceTraversed +
segmentLength > endDistance ) )
1749 const double distanceToEnd = endDistance - distanceTraversed;
1754 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &endZ :
nullptr,
1755 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &endM :
nullptr );
1756 substringPoints <<
QgsPoint( pointType, endX, endY, endZ, endM );
1758 else if ( foundStart )
1760 substringPoints <<
QgsPoint( pointType, thisX, thisY, thisZ, thisM );
1768 if ( distanceTraversed >= endDistance )
1773 if ( !foundStart &&
qgsDoubleNear( distanceTraversed, startDistance ) )
1775 substringPoints <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1776 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1801 if ( path.isEmpty() || path.currentPosition() != QPointF( mX.at( 0 ), mY.at( 0 ) ) )
1803 path.moveTo( mX.at( 0 ), mY.at( 0 ) );
1806 for (
int i = 1; i < nPoints; ++i )
1808 path.lineTo( mX.at( i ), mY.at( i ) );
1821 return compoundCurve;
1826 if ( mX.size() < 2 || mY.size() < 2 )
1829 const bool extendStart = startDistance > 0;
1830 const bool extendEnd = endDistance > 0;
1835 const double currentLen = std::sqrt( std::pow( mX.at( 0 ) - mX.at( 1 ), 2 ) +
1836 std::pow( mY.at( 0 ) - mY.at( 1 ), 2 ) );
1837 const double newLen = currentLen + startDistance;
1838 mX[ 0 ] = mX.at( 1 ) + ( mX.at( 0 ) - mX.at( 1 ) ) / currentLen * newLen;
1839 mY[ 0 ] = mY.at( 1 ) + ( mY.at( 0 ) - mY.at( 1 ) ) / currentLen * newLen;
1844 const int last = mX.size() - 1;
1845 const double currentLen = std::sqrt( std::pow( mX.at( last ) - mX.at( last - 1 ), 2 ) +
1846 std::pow( mY.at( last ) - mY.at( last - 1 ), 2 ) );
1847 const double newLen = currentLen + endDistance;
1848 mX[ last ] = mX.at( last - 1 ) + ( mX.at( last ) - mX.at( last - 1 ) ) / currentLen * newLen;
1849 mY[ last ] = mY.at( last - 1 ) + ( mY.at( last ) - mY.at( last - 1 ) ) / currentLen * newLen;
1852 if ( extendStart || extendEnd )
1858 auto result = std::make_unique< QgsLineString >();
1860 return result.release();
1869 const int size = mX.size();
1870 const int otherSize = otherLine->mX.size();
1871 if ( size > otherSize )
1875 else if ( size < otherSize )
1880 if (
is3D() && !otherLine->
is3D() )
1882 else if ( !
is3D() && otherLine->
is3D() )
1884 const bool considerZ =
is3D();
1892 for (
int i = 0; i < size; i++ )
1894 const double x = mX[i];
1895 const double otherX = otherLine->mX[i];
1900 else if ( x > otherX )
1905 const double y = mY[i];
1906 const double otherY = otherLine->mY[i];
1911 else if ( y > otherY )
1918 const double z = mZ[i];
1919 const double otherZ = otherLine->mZ[i];
1925 else if ( z > otherZ )
1933 const double m = mM[i];
1934 const double otherM = otherLine->mM[i];
1940 else if ( m > otherM )
1951 return u
"LineString"_s;
1967 double *zArray =
nullptr;
1973 std::unique_ptr< double[] > dummyZ;
1974 if ( !hasZ || !transformZ )
1976 dummyZ = std::make_unique<double[]>( nPoints );
1977 zArray = dummyZ.get();
1992 double *x = mX.data();
1993 double *y = mY.data();
1994 double *z = hasZ ? mZ.data() :
nullptr;
1995 double *m = hasM ? mM.data() :
nullptr;
1996 for (
int i = 0; i < nPoints; ++i )
1999 t.map( *x, *y, &xOut, &yOut );
2004 *z = *z * zScale + zTranslate;
2009 *m = *m * mScale + mTranslate;
2024 if ( position.
vertex < 0 || position.
vertex > mX.size() )
2034 mX.insert( position.
vertex, vertex.
x() );
2035 mY.insert( position.
vertex, vertex.
y() );
2038 mZ.insert( position.
vertex, vertex.
z() );
2042 mM.insert( position.
vertex, vertex.
m() );
2050 if ( position.
vertex < 0 || position.
vertex >= mX.size() )
2054 mX[position.
vertex] = newPos.
x();
2055 mY[position.
vertex] = newPos.
y();
2058 mZ[position.
vertex] = newPos.
z();
2062 mM[position.
vertex] = newPos.
m();
2070 if ( position.
vertex >= mX.size() || position.
vertex < 0 )
2075 mX.remove( position.
vertex );
2076 mY.remove( position.
vertex );
2079 mZ.remove( position.
vertex );
2083 mM.remove( position.
vertex );
2108 mX.append( pt.
x() );
2109 mY.append( pt.
y() );
2112 mZ.append( pt.
z() );
2116 mM.append( pt.
m() );
2123 double sqrDist = std::numeric_limits<double>::max();
2124 double leftOfDist = std::numeric_limits<double>::max();
2126 double prevLeftOfX = 0.0;
2127 double prevLeftOfY = 0.0;
2128 double testDist = 0;
2129 double segmentPtX, segmentPtY;
2134 const int size = mX.size();
2135 if ( size == 0 || size == 1 )
2141 const double *
xData = mX.constData();
2142 const double *
yData = mY.constData();
2143 for (
int i = 1; i < size; ++i )
2145 double prevX =
xData[ i - 1 ];
2146 double prevY =
yData[ i - 1 ];
2147 double currentX =
xData[ i ];
2148 double currentY =
yData[ i ];
2150 if ( testDist < sqrDist )
2153 segmentPt.
setX( segmentPtX );
2154 segmentPt.
setY( segmentPtY );
2155 vertexAfter.
part = 0;
2156 vertexAfter.
ring = 0;
2167 if (
qgsDoubleNear( testDist, leftOfDist ) && left != prevLeftOf && prevLeftOf != 0 )
2179 prevLeftOf = *leftOf;
2180 leftOfDist = testDist;
2181 prevLeftOfX = prevX;
2182 prevLeftOfY = prevY;
2184 else if ( testDist < leftOfDist )
2187 leftOfDist = testDist;
2219 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
2221 double totalLineLength = 0.0;
2222 double prevX = mX.at( 0 );
2223 double prevY = mY.at( 0 );
2229 double currentX = mX.at( i );
2230 double currentY = mY.at( i );
2231 double segmentLength = std::sqrt( std::pow( currentX - prevX, 2.0 ) +
2232 std::pow( currentY - prevY, 2.0 ) );
2246 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
2248 return QgsPoint( sumX / totalLineLength, sumY / totalLineLength );
2267 const int maxIndex = mX.size();
2274 const double *x = mX.constData();
2275 const double *y = mY.constData();
2276 double prevX = *x++;
2277 double prevY = *y++;
2278 for (
int i = 1; i < maxIndex; ++i )
2280 mSummedUpArea += prevX * ( *y - prevY ) - prevY * ( *x - prevX );
2328 if ( planeNormal.
z() < 0 )
2330 planeNormal = -planeNormal;
2335 if ( planeNormal.
y() < 0 )
2336 planeNormal = -planeNormal;
2340 if ( planeNormal.
x() < 0 )
2341 planeNormal = - planeNormal;
2345 const double *x = mX.constData();
2346 const double *y = mY.constData();
2347 const double *z = mZ.constData();
2349 double prevX = *x++;
2350 double prevY = *y++;
2351 double prevZ = *z++;
2353 double normalX = 0.0;
2354 double normalY = 0.0;
2355 double normalZ = 0.0;
2357 for (
unsigned int i = 1; i < mX.size(); ++i )
2359 normalX += prevY * ( *z - prevZ ) - prevZ * ( *y - prevY );
2360 normalY += prevZ * ( *x - prevX ) - prevX * ( *z - prevZ );
2361 normalZ += prevX * ( *y - prevY ) - prevY * ( *x - prevX );
2368 mSummedUpArea3D = 0.5 * ( normalX * planeNormal.
x() + normalY * planeNormal.
y() + normalZ * planeNormal.
z() );
2374void QgsLineString::importVerticesFromWkb(
const QgsConstWkbPtr &wkb )
2380 mX.resize( nVertices );
2381 mY.resize( nVertices );
2382 hasZ ? mZ.resize( nVertices ) : mZ.clear();
2383 hasM ? mM.resize( nVertices ) : mM.clear();
2384 double *x = mX.data();
2385 double *y = mY.data();
2386 double *m = hasM ? mM.data() :
nullptr;
2387 double *z = hasZ ? mZ.data() :
nullptr;
2388 for (
int i = 0; i < nVertices; ++i )
2421 if ( mX.count() < 2 )
2431 double previousX = mX.at(
numPoints() - 2 );
2432 double previousY = mY.at(
numPoints() - 2 );
2433 double currentX = mX.at( 0 );
2434 double currentY = mY.at( 0 );
2435 double afterX = mX.at( 1 );
2436 double afterY = mY.at( 1 );
2439 else if ( vertex.
vertex == 0 )
2452 double previousX = mX.at( vertex.
vertex - 1 );
2453 double previousY = mY.at( vertex.
vertex - 1 );
2454 double currentX = mX.at( vertex.
vertex );
2455 double currentY = mY.at( vertex.
vertex );
2456 double afterX = mX.at( vertex.
vertex + 1 );
2457 double afterY = mY.at( vertex.
vertex + 1 );
2464 if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 1 )
2467 double dx = mX.at( startVertex.
vertex + 1 ) - mX.at( startVertex.
vertex );
2468 double dy = mY.at( startVertex.
vertex + 1 ) - mY.at( startVertex.
vertex );
2469 return std::sqrt( dx * dx + dy * dy );
2494 mZ.reserve( nPoints );
2495 for (
int i = 0; i < nPoints; ++i )
2525 mM.reserve( nPoints );
2526 for (
int i = 0; i < nPoints; ++i )
2557 std::swap( mX, mY );
2571 addZValue( std::numeric_limits<double>::quiet_NaN() );
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;
2596 for (
int i = 0; i < size; ++i )
2600 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2601 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
2629 int size = mX.size();
2631 double *srcX = mX.data();
2632 double *srcY = mY.data();
2633 double *srcM = hasM ? mM.data() :
nullptr;
2634 double *srcZ = hasZ ? mZ.data() :
nullptr;
2636 double *destX = srcX;
2637 double *destY = srcY;
2638 double *destM = srcM;
2639 double *destZ = srcZ;
2641 int filteredPoints = 0;
2642 for (
int i = 0; i < size; ++i )
2646 double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
2647 double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
2649 if ( filter(
QgsPoint( x, y, z, m ) ) )
2661 mX.resize( filteredPoints );
2662 mY.resize( filteredPoints );
2664 mZ.resize( filteredPoints );
2666 mM.resize( filteredPoints );
2675 int size = mX.size();
2677 double *srcX = mX.data();
2678 double *srcY = mY.data();
2679 double *srcM = hasM ? mM.data() :
nullptr;
2680 double *srcZ = hasZ ? mZ.data() :
nullptr;
2682 for (
int i = 0; i < size; ++i )
2686 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2687 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
2703 std::unique_ptr< QgsLineString > cloned(
clone() );
2710 if (
isEmpty() || ( nbpoints < 2 ) )
2715 const double range = end - start;
2716 double lineLength =
length();
2717 double lengthSoFar = 0.0;
2720 double *mOut = cloned->mM.data();
2722 for (
int i = 1; i < nbpoints ; ++i )
2725 if ( lineLength > 0.0 )
2726 *mOut++ = start + range * lengthSoFar / lineLength;
2727 else if ( lineLength == 0.0 && nbpoints > 1 )
2728 *mOut++ = start + range * i / ( nbpoints - 1 );
2742 if ( totalPoints < 2 )
2743 return std::unique_ptr< QgsLineString >(
clone() );
2745 const double *
xData = mX.constData();
2746 const double *
yData = mY.constData();
2747 const double *
mData = mM.constData();
2748 const double *
zData =
is3D() ? mZ.constData() :
nullptr;
2749 use3DDistance &=
static_cast< bool >(
zData );
2751 QVector< double > xOut( totalPoints );
2752 QVector< double > yOut( totalPoints );
2753 QVector< double > mOut( totalPoints );
2754 QVector< double > zOut(
static_cast< bool >(
zData ) ? totalPoints : 0 );
2756 double *xOutData = xOut.data();
2757 double *yOutData = yOut.data();
2758 double *mOutData = mOut.data();
2759 double *zOutData =
static_cast< bool >(
zData ) ? zOut.data() :
nullptr;
2762 double currentSegmentLength = 0;
2763 double lastValidM = std::numeric_limits< double >::quiet_NaN();
2764 double prevX = *
xData;
2765 double prevY = *
yData;
2767 while ( i < totalPoints )
2769 double thisX = *
xData++;
2770 double thisY = *
yData++;
2772 double thisM = *
mData++;
2774 currentSegmentLength = use3DDistance
2778 if ( !std::isnan( thisM ) )
2780 *xOutData++ = thisX;
2781 *yOutData++ = thisY;
2782 *mOutData++ = thisM;
2784 *zOutData++ = thisZ;
2791 double scanAheadM = thisM;
2792 while ( i + j + 1 < totalPoints && std::isnan( scanAheadM ) )
2794 scanAheadM =
mData[ j ];
2797 if ( std::isnan( scanAheadM ) )
2802 *xOutData++ = thisX;
2803 *yOutData++ = thisY;
2804 *mOutData++ = scanAheadM;
2806 *zOutData++ = thisZ;
2807 for ( ; i < j; ++i )
2811 *xOutData++ = thisX;
2812 *yOutData++ = thisY;
2813 *mOutData++ = scanAheadM;
2816 *zOutData++ = *
zData++;
2818 lastValidM = scanAheadM;
2824 double scanAheadX = thisX;
2825 double scanAheadY = thisY;
2826 double scanAheadZ = thisZ;
2827 double distanceToNextValidM = currentSegmentLength;
2828 std::vector< double > scanAheadSegmentLengths;
2829 scanAheadSegmentLengths.emplace_back( currentSegmentLength );
2831 double nextValidM = std::numeric_limits< double >::quiet_NaN();
2832 while ( i + j < totalPoints - 1 )
2834 double nextScanAheadX =
xData[j];
2835 double nextScanAheadY =
yData[j];
2836 double nextScanAheadZ =
zData ?
zData[j] : 0;
2837 double nextScanAheadM =
mData[ j ];
2838 const double scanAheadSegmentLength = use3DDistance
2841 scanAheadSegmentLengths.emplace_back( scanAheadSegmentLength );
2842 distanceToNextValidM += scanAheadSegmentLength;
2844 if ( !std::isnan( nextScanAheadM ) )
2846 nextValidM = nextScanAheadM;
2850 scanAheadX = nextScanAheadX;
2851 scanAheadY = nextScanAheadY;
2852 scanAheadZ = nextScanAheadZ;
2856 if ( std::isnan( nextValidM ) )
2859 *xOutData++ = thisX;
2860 *yOutData++ = thisY;
2861 *mOutData++ = lastValidM;
2863 *zOutData++ = thisZ;
2865 for ( ; i < totalPoints; ++i )
2867 *xOutData++ = *
xData++;
2868 *yOutData++ = *
yData++;
2869 *mOutData++ = lastValidM;
2871 *zOutData++ = *
zData++;
2878 const double delta = ( nextValidM - lastValidM ) / distanceToNextValidM;
2879 *xOutData++ = thisX;
2880 *yOutData++ = thisY;
2881 *mOutData++ = lastValidM + delta * scanAheadSegmentLengths[0];
2882 double totalScanAheadLength = scanAheadSegmentLengths[0];
2884 *zOutData++ = thisZ;
2885 for (
int k = 1; k <= j; ++i, ++k )
2889 *xOutData++ = thisX;
2890 *yOutData++ = thisY;
2891 totalScanAheadLength += scanAheadSegmentLengths[k];
2892 *mOutData++ = lastValidM + delta * totalScanAheadLength;
2895 *zOutData++ = *
zData++;
2897 lastValidM = nextValidM;
2906 return std::make_unique< QgsLineString >( xOut, yOut, zOut, mOut );
2912 if ( fromVertex.
part != 0 || fromVertex.
ring != 0 || toVertex.
part != 0 || toVertex.
ring != 0 )
2915 const int fromVertexNumber = fromVertex.
vertex;
2916 const int toVertexNumber = toVertex.
vertex;
2919 if ( fromVertexNumber > toVertexNumber )
2925 if ( fromVertexNumber < 0 || fromVertexNumber >= nPoints || toVertexNumber < 0 || toVertexNumber >= nPoints )
2928 if ( fromVertexNumber == toVertexNumber )
2931 const bool is3DGeometry =
is3D();
2932 const double *
xData = mX.constData();
2933 const double *
yData = mY.constData();
2934 const double *
zData = is3DGeometry ? mZ.constData() :
nullptr;
2935 double totalDistance = 0.0;
2938 for (
int i = fromVertexNumber; i < toVertexNumber; ++i )
2949 totalDistance += std::sqrt( dx * dx + dy * dy + dz * dz );
2952 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 mHasCachedSummedUpArea3D
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 void interpolatePointOnCubicBezier(double p0x, double p0y, double p0z, double p0m, double p1x, double p1y, double p1z, double p1m, double p2x, double p2y, double p2z, double p2m, double p3x, double p3y, double p3z, double p3m, double t, bool hasZ, bool hasM, double &outX, double &outY, double &outZ, double &outM)
Evaluates a point on a cubic Bézier curve defined by four control points.
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 bool checkWeaklyFor3DPlane(const QgsAbstractGeometry *geom, QgsPoint &pt1, QgsPoint &pt2, QgsPoint &pt3, double epsilon=std::numeric_limits< double >::epsilon())
Checks if a 3D geometry has a plane defined by at least 3 non-collinear points.
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.
void sumUpArea3D(double &sum) const override
Calculates the shoelace/triangle formula sum for the points in the linestring.
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.
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
double y() const
Returns Y coordinate.
double z() const
Returns Z coordinate.
double x() const
Returns X coordinate.
void normalize()
Normalizes the current vector in place.
static QgsVector3D crossProduct(const QgsVector3D &v1, const QgsVector3D &v2)
Returns the cross product of two vectors.
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.