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();
257 return std::make_unique< QgsLineString >( x, y, z, m );
264 x.resize( polygon.count() );
265 y.resize( polygon.count() );
266 double *
xData = x.data();
267 double *
yData = y.data();
269 const QPointF *src = polygon.data();
270 for (
int i = 0; i < polygon.size(); ++i )
277 return std::make_unique< QgsLineString >( x, y );
302 const int size = mX.size();
306 const double *x = mX.constData();
307 const double *y = mY.constData();
308 const bool useZ =
is3D();
310 const double *z = useZ ? mZ.constData() :
nullptr;
311 const double *m = useM ? mM.constData() :
nullptr;
313 for (
int i = 0; i < size; ++i )
332 error = QObject::tr(
"LineString has less than 2 points and is not empty." );
343 bool res =
snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM, result->mX, result->mY, result->mZ, result->mM, removeRedundantPoints );
345 return result.release();
352 if ( mX.count() <= 2 )
355 double prevX = mX.at( 0 );
356 double prevY = mY.at( 0 );
358 bool useZ = hasZ && useZValues;
359 double prevZ = useZ ? mZ.at( 0 ) : 0;
361 int remaining = mX.count();
362 while ( i < remaining )
364 double currentX = mX.at( i );
365 double currentY = mY.at( i );
366 double currentZ = useZ ? mZ.at( i ) : 0;
400 if (
is3D() && closed )
401 closed &=
qgsDoubleNear( mZ.first(), mZ.last() ) || ( std::isnan( mZ.first() ) && std::isnan( mZ.last() ) );
414 return mBoundingBox.toRectangle().intersects( rectangle );
416 const int nb = mX.size();
425 if ( rectangle.
contains( mX.at( 0 ), mY.at( 0 ) )
426 || rectangle.
contains( mX.at(
static_cast< int >( nb * 0.2 ) ), mY.at(
static_cast< int >( nb * 0.2 ) ) )
427 || rectangle.
contains( mX.at(
static_cast< int >( nb * 0.4 ) ), mY.at(
static_cast< int >( nb * 0.4 ) ) )
428 || rectangle.
contains( mX.at(
static_cast< int >( nb * 0.6 ) ), mY.at(
static_cast< int >( nb * 0.6 ) ) )
429 || rectangle.
contains( mX.at(
static_cast< int >( nb * 0.8 ) ), mY.at(
static_cast< int >( nb * 0.8 ) ) )
430 || rectangle.
contains( mX.at( nb - 1 ), mY.at( nb - 1 ) ) )
439 double xmin = std::numeric_limits<double>::max();
440 double ymin = std::numeric_limits<double>::max();
441 double zmin = -std::numeric_limits<double>::max();
442 double xmax = -std::numeric_limits<double>::max();
443 double ymax = -std::numeric_limits<double>::max();
444 double zmax = -std::numeric_limits<double>::max();
446 const double *x = mX.constData();
447 const double *y = mY.constData();
448 const double *z =
is3D() ? mZ.constData() :
nullptr;
449 bool foundPointInRectangle =
false;
450 for (
int i = 0; i < nb; ++i )
452 const double px = *x++;
453 xmin = std::min( xmin, px );
454 xmax = std::max( xmax, px );
455 const double py = *y++;
456 ymin = std::min( ymin, py );
457 ymax = std::max( ymax, py );
460 const double pz = *z++;
461 zmin = std::min( zmin, pz );
462 zmax = std::max( zmax, pz );
465 if ( !foundPointInRectangle && rectangle.
contains( px, py ) )
467 foundPointInRectangle =
true;
483 if ( foundPointInRectangle )
508 const int nb = mX.size();
517 if ( box3d.
contains( mX.at( 0 ), mY.at( 0 ), mZ.at( 0 ) )
518 || 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 ) ) )
519 || 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 ) ) )
520 || 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 ) ) )
521 || 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 ) ) )
522 || box3d.
contains( mX.at( nb - 1 ), mY.at( nb - 1 ), mZ.at( nb - 1 ) ) )
531 double xmin = std::numeric_limits<double>::max();
532 double ymin = std::numeric_limits<double>::max();
533 double zmin = std::numeric_limits<double>::max();
534 double xmax = -std::numeric_limits<double>::max();
535 double ymax = -std::numeric_limits<double>::max();
536 double zmax = -std::numeric_limits<double>::max();
538 const double *x = mX.constData();
539 const double *y = mY.constData();
540 const double *z = mZ.constData();
541 bool foundPointInBox =
false;
542 for (
int i = 0; i < nb; ++i )
544 const double px = *x++;
545 xmin = std::min( xmin, px );
546 xmax = std::max( xmax, px );
547 const double py = *y++;
548 ymin = std::min( ymin, py );
549 ymax = std::max( ymax, py );
550 const double pz = *z++;
551 zmin = std::min( zmin, pz );
552 zmax = std::max( zmax, pz );
554 if ( !foundPointInBox && box3d.
contains( px, py, pz ) )
556 foundPointInBox =
true;
572 if ( foundPointInBox )
585 QVector< QgsVertexId > res;
586 if ( mX.count() <= 1 )
589 const double *x = mX.constData();
590 const double *y = mY.constData();
592 bool useZ = hasZ && useZValues;
593 const double *z = useZ ? mZ.constData() :
nullptr;
597 double prevZ = z ? *z++ : 0;
600 for (
int i = 1; i < mX.count(); ++i )
602 double currentX = *x++;
603 double currentY = *y++;
604 double currentZ = useZ ? *z++ : 0;
622 const int nb = mX.size();
625 const double *x = mX.constData();
626 const double *y = mY.constData();
627 QPointF *dest =
points.data();
628 for (
int i = 0; i < nb; ++i )
630 *dest++ = QPointF( *x++, *y++ );
636void simplifySection(
int i,
int j,
const double *x,
const double *y, std::vector< bool > &usePoint,
const double distanceToleranceSquared,
const double epsilon )
643 double maxDistanceSquared = -1.0;
648 for (
int k = i + 1; k < j; k++ )
652 if ( distanceSquared > maxDistanceSquared )
654 maxDistanceSquared = distanceSquared;
658 if ( maxDistanceSquared <= distanceToleranceSquared )
660 for (
int k = i + 1; k < j; k++ )
667 simplifySection( i, maxIndex, x, y, usePoint, distanceToleranceSquared, epsilon );
668 simplifySection( maxIndex, j, x, y, usePoint, distanceToleranceSquared, epsilon );
681 const double distanceToleranceSquared = tolerance * tolerance;
682 const double *
xData = mX.constData();
683 const double *
yData = mY.constData();
684 const double *
zData = mZ.constData();
685 const double *
mData = mM.constData();
687 const int size = mX.size();
689 std::vector< bool > usePoint( size,
true );
691 constexpr double epsilon = 4 * std::numeric_limits<double>::epsilon();
694 QVector< double > newX;
695 newX.reserve( size );
696 QVector< double > newY;
697 newY.reserve( size );
699 const bool hasZ =
is3D();
701 QVector< double > newZ;
703 newZ.reserve( size );
704 QVector< double > newM;
706 newM.reserve( size );
708 for (
int i = 0, n = size; i < n; ++i )
710 if ( usePoint[i] || i == n - 1 )
712 newX.append(
xData[i] );
713 newY.append(
yData[i] );
715 newZ.append(
zData[i] );
717 newM.append(
mData[i] );
721 const bool simplifyRing =
isRing();
722 const int newSize = newX.size();
723 if ( simplifyRing && newSize > 3 )
728 if ( distanceSquared <= distanceToleranceSquared )
731 newX.last() = newX.first();
733 newY.last() = newY.first();
737 newZ.last() = newZ.first();
742 newM.last() = newM.first();
763 importVerticesFromWkb( wkbPtr );
774 auto result2D = std::minmax_element( mX.begin(), mX.end() );
775 const double xmin = *result2D.first;
776 const double xmax = *result2D.second;
777 result2D = std::minmax_element( mY.begin(), mY.end() );
778 const double ymin = *result2D.first;
779 const double ymax = *result2D.second;
781 double zmin = std::numeric_limits< double >::quiet_NaN();
782 double zmax = std::numeric_limits< double >::quiet_NaN();
786 auto resultZ = std::minmax_element( mZ.begin(), mZ.end() );
787 zmin = *resultZ.first;
788 zmax = *resultZ.second;
791 return QgsBox3D( xmin, ymin, zmin, xmax, ymax, zmax );
801 const int size = mX.size();
802 if ( index < 1 || index >= size - 1 )
805 const bool useZ =
is3D();
808 QVector<double> newX( size );
809 QVector<double> newY( size );
810 QVector<double> newZ( useZ ? size : 0 );
811 QVector<double> newM( useM ? size : 0 );
812 auto it = std::copy( mX.constBegin() + index, mX.constEnd() - 1, newX.begin() );
813 it = std::copy( mX.constBegin(), mX.constBegin() + index, it );
814 *it = *newX.constBegin();
815 mX = std::move( newX );
817 it = std::copy( mY.constBegin() + index, mY.constEnd() - 1, newY.begin() );
818 it = std::copy( mY.constBegin(), mY.constBegin() + index, it );
819 *it = *newY.constBegin();
820 mY = std::move( newY );
823 it = std::copy( mZ.constBegin() + index, mZ.constEnd() - 1, newZ.begin() );
824 it = std::copy( mZ.constBegin(), mZ.constBegin() + index, it );
825 *it = *newZ.constBegin();
826 mZ = std::move( newZ );
830 it = std::copy( mM.constBegin() + index, mM.constEnd() - 1, newM.begin() );
831 it = std::copy( mM.constBegin(), mM.constBegin() + index, it );
832 *it = *newM.constBegin();
833 mM = std::move( newM );
852 QString secondWithoutParentheses =
parts.second;
853 secondWithoutParentheses = secondWithoutParentheses.remove(
'(' ).remove(
')' ).simplified().remove(
' ' );
854 parts.second =
parts.second.remove(
'(' ).remove(
')' );
855 if ( (
parts.second.compare(
"EMPTY"_L1, Qt::CaseInsensitive ) == 0 ) || secondWithoutParentheses.isEmpty() )
870 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
881 wkb << static_cast<quint32>(
wkbType() );
914 QDomElement elemLineString = doc.createElementNS( ns, u
"LineString"_s );
917 return elemLineString;
921 return elemLineString;
929 QDomElement elemLineString = doc.createElementNS( ns, u
"LineString"_s );
932 return elemLineString;
935 return elemLineString;
950 kml.append(
"<LinearRing>"_L1 );
954 kml.append(
"<LineString>"_L1 );
957 kml.append(
"<altitudeMode>"_L1 );
960 kml.append(
"absolute"_L1 );
964 kml.append(
"clampToGround"_L1 );
966 kml.append(
"</altitudeMode>"_L1 );
967 kml.append(
"<coordinates>"_L1 );
969 int nPoints = mX.size();
970 for (
int i = 0; i < nPoints; ++i )
974 kml.append(
" "_L1 );
977 kml.append(
","_L1 );
981 kml.append(
","_L1 );
986 kml.append(
",0"_L1 );
989 kml.append(
"</coordinates>"_L1 );
992 kml.append(
"</LinearRing>"_L1 );
996 kml.append(
"</LineString>"_L1 );
1010 const int size = mX.size();
1014 const double *x = mX.constData();
1015 const double *y = mY.constData();
1018 double prevX = *x++;
1019 double prevY = *y++;
1021 for (
int i = 1; i < size; ++i )
1025 total += std::sqrt( dx * dx + dy * dy );
1035 const bool useZ =
is3D();
1038 const int size = mX.size();
1040 return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >() );
1042 index = std::clamp( index, 0, size - 1 );
1044 const int part1Size = index + 1;
1045 QVector< double > x1( part1Size );
1046 QVector< double > y1( part1Size );
1047 QVector< double > z1( useZ ? part1Size : 0 );
1048 QVector< double > m1( useM ? part1Size : 0 );
1050 const double *sourceX = mX.constData();
1051 const double *sourceY = mY.constData();
1052 const double *sourceZ = useZ ? mZ.constData() :
nullptr;
1053 const double *sourceM = useM ? mM.constData() :
nullptr;
1055 double *destX = x1.data();
1056 double *destY = y1.data();
1057 double *destZ = useZ ? z1.data() :
nullptr;
1058 double *destM = useM ? m1.data() :
nullptr;
1060 std::copy( sourceX, sourceX + part1Size, destX );
1061 std::copy( sourceY, sourceY + part1Size, destY );
1063 std::copy( sourceZ, sourceZ + part1Size, destZ );
1065 std::copy( sourceM, sourceM + part1Size, destM );
1067 const int part2Size = size - index;
1068 if ( part2Size < 2 )
1069 return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >() );
1071 QVector< double > x2( part2Size );
1072 QVector< double > y2( part2Size );
1073 QVector< double > z2( useZ ? part2Size : 0 );
1074 QVector< double > m2( useM ? part2Size : 0 );
1077 destZ = useZ ? z2.data() :
nullptr;
1078 destM = useM ? m2.data() :
nullptr;
1079 std::copy( sourceX + index, sourceX + size, destX );
1080 std::copy( sourceY + index, sourceY + size, destY );
1082 std::copy( sourceZ + index, sourceZ + size, destZ );
1084 std::copy( sourceM + index, sourceM + size, destM );
1086 if ( part1Size < 2 )
1087 return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
1089 return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
1094 const double *allPointsX =
xData();
1095 const double *allPointsY =
yData();
1097 QVector<double> partX;
1098 QVector<double> partY;
1099 QSet<QgsPointXY> partPointSet;
1101 QVector<QgsLineString *> disjointParts;
1102 for (
size_t i = 0; i < allPointsCount; i++ )
1104 const QgsPointXY point( *allPointsX++, *allPointsY++ );
1105 if ( partPointSet.contains( point ) )
1109 disjointParts.push_back(
new QgsLineString( partX, partY ) );
1111 partX = { partX.last() };
1112 partY = { partY.last() };
1113 partPointSet = {
QgsPointXY( partX[0], partY[0] ) };
1115 partX.push_back( point.
x() );
1116 partY.push_back( point.
y() );
1117 partPointSet.insert( point );
1120 if ( partX.size() > 1 || disjointParts.size() == 0 )
1121 disjointParts.push_back(
new QgsLineString( partX, partY ) );
1123 return disjointParts;
1131 const int size = mX.size();
1135 const double *x = mX.constData();
1136 const double *y = mY.constData();
1137 const double *z = mZ.constData();
1140 double prevX = *x++;
1141 double prevY = *y++;
1142 double prevZ = *z++;
1144 for (
int i = 1; i < size; ++i )
1149 total += std::sqrt( dx * dx + dy * dy + dz * dz );
1189 Q_UNUSED( tolerance )
1190 Q_UNUSED( toleranceType )
1206 if ( i < 0 || i >= mX.size() )
1211 double x = mX.at( i );
1212 double y = mY.at( i );
1213 double z = std::numeric_limits<double>::quiet_NaN();
1214 double m = std::numeric_limits<double>::quiet_NaN();
1232 else if ( hasZ && hasM )
1255 if ( index >= 0 && index < mX.size() )
1256 return mX.at( index );
1263 if ( index >= 0 && index < mY.size() )
1264 return mY.at( index );
1271 if ( index >= 0 && index < mX.size() )
1278 if ( index >= 0 && index < mY.size() )
1293 pts.reserve( nPoints );
1294 for (
int i = 0; i < nPoints; ++i )
1296 pts.push_back(
pointN( i ) );
1310 const bool hasZ =
static_cast< bool >( z );
1311 const bool hasM =
static_cast< bool >( m );
1332 double *destX = mX.data();
1333 double *destY = mY.data();
1334 double *destZ =
nullptr;
1344 double *destM =
nullptr;
1355 for (
size_t i = 0; i < size; ++i )
1382 bool hasZ = firstPt.
is3D();
1387 mX.resize(
points.size() );
1388 mY.resize(
points.size() );
1391 mZ.resize(
points.size() );
1399 mM.resize(
points.size() );
1406 for (
int i = 0; i <
points.size(); ++i )
1408 mX[i] =
points.at( i ).x();
1409 mY[i] =
points.at( i ).y();
1412 double z =
points.at( i ).z();
1413 mZ[i] = std::isnan( z ) ? 0 : z;
1417 double m =
points.at( i ).m();
1418 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() );
1508 const double distance,
const std::function<
bool(
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double )> &visitPoint
1514 double distanceTraversed = 0;
1516 if ( totalPoints == 0 )
1519 const double *x = mX.constData();
1520 const double *y = mY.constData();
1521 const double *z =
is3D() ? mZ.constData() :
nullptr;
1522 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1524 double prevX = *x++;
1525 double prevY = *y++;
1526 double prevZ = z ? *z++ : 0.0;
1527 double prevM = m ? *m++ : 0.0;
1531 visitPoint( prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM );
1535 double pZ = std::numeric_limits<double>::quiet_NaN();
1536 double pM = std::numeric_limits<double>::quiet_NaN();
1537 double nextPointDistance = distance;
1538 const double eps = 4 * nextPointDistance * std::numeric_limits<double>::epsilon();
1539 for (
int i = 1; i < totalPoints; ++i )
1541 double thisX = *x++;
1542 double thisY = *y++;
1543 double thisZ = z ? *z++ : 0.0;
1544 double thisM = m ? *m++ : 0.0;
1550 const double distanceToPoint = std::min( nextPointDistance - distanceTraversed,
segmentLength );
1553 pointOnLineWithDistance( prevX, prevY, thisX, thisY, distanceToPoint, pX, pY, z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &pZ :
nullptr, m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &pM :
nullptr );
1555 if ( !visitPoint( pX, pY, pZ, pM, prevX, prevY, prevZ, prevM, thisX, thisY, thisZ, thisM ) )
1558 nextPointDistance += distance;
1580 std::unique_ptr< QgsPoint > res;
1581 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++;
1624 if ( std::isnan( thisM ) )
1626 if ( haveInterpolatedM )
1630 std::unique_ptr< QgsLineString > interpolatedM(
interpolateM( use3DDistance ) );
1631 return interpolatedM->lineLocatePointByMPrivate( m, x, y, z, distanceFromStart, use3DDistance,
true );
1643 double totalLengthOfSegmentsWithConstantM = 0;
1644 for (
int j = 0; j < ( totalPoints - i ); ++j )
1654 distanceFromStart += totalLengthOfSegmentsWithConstantM / 2;
1664 const double delta = ( m - prevM ) / ( thisM - prevM );
1669 z = prevZ + ( thisZ - prevZ ) * delta;
1670 distanceFromStart += distanceToPoint;
1687 if ( startDistance < 0 && endDistance < 0 )
1690 endDistance = std::max( startDistance, endDistance );
1693 if ( totalPoints == 0 )
1696 QVector< QgsPoint > substringPoints;
1697 substringPoints.reserve( totalPoints );
1705 const double *x = mX.constData();
1706 const double *y = mY.constData();
1707 const double *z =
is3D() ? mZ.constData() :
nullptr;
1708 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1710 double distanceTraversed = 0;
1711 double prevX = *x++;
1712 double prevY = *y++;
1713 double prevZ = z ? *z++ : 0.0;
1714 double prevM = m ? *m++ : 0.0;
1715 bool foundStart =
false;
1717 if ( startDistance < 0 )
1720 for (
int i = 1; i < totalPoints; ++i )
1722 double thisX = *x++;
1723 double thisY = *y++;
1724 double thisZ = z ? *z++ : 0.0;
1725 double thisM = m ? *m++ : 0.0;
1729 if ( distanceTraversed <= startDistance && startDistance < distanceTraversed +
segmentLength )
1732 const double distanceToStart = startDistance - distanceTraversed;
1733 double startX, startY;
1737 pointOnLineWithDistance( prevX, prevY, thisX, thisY, distanceToStart, startX, startY, z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &startZ :
nullptr, m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &startM :
nullptr );
1738 substringPoints <<
QgsPoint( pointType, startX, startY, startZ, startM );
1741 if ( foundStart && ( distanceTraversed +
segmentLength > endDistance ) )
1744 const double distanceToEnd = endDistance - distanceTraversed;
1749 pointOnLineWithDistance( prevX, prevY, thisX, thisY, distanceToEnd, endX, endY, z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &endZ :
nullptr, m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &endM :
nullptr );
1750 substringPoints <<
QgsPoint( pointType, endX, endY, endZ, endM );
1752 else if ( foundStart )
1754 substringPoints <<
QgsPoint( pointType, thisX, thisY, thisZ, thisM );
1762 if ( distanceTraversed >= endDistance )
1767 if ( !foundStart &&
qgsDoubleNear( distanceTraversed, startDistance ) )
1769 substringPoints <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM ) <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1794 if ( path.isEmpty() || path.currentPosition() != QPointF( mX.at( 0 ), mY.at( 0 ) ) )
1796 path.moveTo( mX.at( 0 ), mY.at( 0 ) );
1799 for (
int i = 1; i < nPoints; ++i )
1801 path.lineTo( mX.at( i ), mY.at( i ) );
1814 return compoundCurve;
1819 if ( mX.size() < 2 || mY.size() < 2 )
1822 const bool extendStart = startDistance > 0;
1823 const bool extendEnd = endDistance > 0;
1828 const double currentLen = std::sqrt( std::pow( mX.at( 0 ) - mX.at( 1 ), 2 ) + std::pow( mY.at( 0 ) - mY.at( 1 ), 2 ) );
1829 const double newLen = currentLen + startDistance;
1830 mX[0] = mX.at( 1 ) + ( mX.at( 0 ) - mX.at( 1 ) ) / currentLen * newLen;
1831 mY[0] = mY.at( 1 ) + ( mY.at( 0 ) - mY.at( 1 ) ) / currentLen * newLen;
1836 const int last = mX.size() - 1;
1837 const double currentLen = std::sqrt( std::pow( mX.at( last ) - mX.at( last - 1 ), 2 ) + std::pow( mY.at( last ) - mY.at( last - 1 ), 2 ) );
1838 const double newLen = currentLen + endDistance;
1839 mX[last] = mX.at( last - 1 ) + ( mX.at( last ) - mX.at( last - 1 ) ) / currentLen * newLen;
1840 mY[last] = mY.at( last - 1 ) + ( mY.at( last ) - mY.at( last - 1 ) ) / currentLen * newLen;
1843 if ( extendStart || extendEnd )
1849 auto result = std::make_unique< QgsLineString >();
1851 return result.release();
1860 const int size = mX.size();
1861 const int otherSize = otherLine->mX.size();
1862 if ( size > otherSize )
1866 else if ( size < otherSize )
1871 if (
is3D() && !otherLine->
is3D() )
1873 else if ( !
is3D() && otherLine->
is3D() )
1875 const bool considerZ =
is3D();
1883 for (
int i = 0; i < size; i++ )
1885 const double x = mX[i];
1886 const double otherX = otherLine->mX[i];
1891 else if ( x > otherX )
1896 const double y = mY[i];
1897 const double otherY = otherLine->mY[i];
1902 else if ( y > otherY )
1909 const double z = mZ[i];
1910 const double otherZ = otherLine->mZ[i];
1916 else if ( z > otherZ )
1924 const double m = mM[i];
1925 const double otherM = otherLine->mM[i];
1931 else if ( m > otherM )
1942 return u
"LineString"_s;
1958 double *zArray =
nullptr;
1964 std::unique_ptr< double[] > dummyZ;
1965 if ( !hasZ || !transformZ )
1967 dummyZ = std::make_unique<double[]>( nPoints );
1968 zArray = dummyZ.get();
1983 double *x = mX.data();
1984 double *y = mY.data();
1985 double *z = hasZ ? mZ.data() :
nullptr;
1986 double *m = hasM ? mM.data() :
nullptr;
1987 for (
int i = 0; i < nPoints; ++i )
1990 t.map( *x, *y, &xOut, &yOut );
1995 *z = *z * zScale + zTranslate;
2000 *m = *m * mScale + mTranslate;
2015 if ( position.
vertex < 0 || position.
vertex > mX.size() )
2025 mX.insert( position.
vertex, vertex.
x() );
2026 mY.insert( position.
vertex, vertex.
y() );
2029 mZ.insert( position.
vertex, vertex.
z() );
2033 mM.insert( position.
vertex, vertex.
m() );
2041 if ( position.
vertex < 0 || position.
vertex >= mX.size() )
2045 mX[position.
vertex] = newPos.
x();
2046 mY[position.
vertex] = newPos.
y();
2049 mZ[position.
vertex] = newPos.
z();
2053 mM[position.
vertex] = newPos.
m();
2061 if ( position.
vertex >= mX.size() || position.
vertex < 0 )
2066 mX.remove( position.
vertex );
2067 mY.remove( position.
vertex );
2070 mZ.remove( position.
vertex );
2074 mM.remove( position.
vertex );
2099 mX.append( pt.
x() );
2100 mY.append( pt.
y() );
2103 mZ.append( pt.
z() );
2107 mM.append( pt.
m() );
2114 double sqrDist = std::numeric_limits<double>::max();
2115 double leftOfDist = std::numeric_limits<double>::max();
2117 double prevLeftOfX = 0.0;
2118 double prevLeftOfY = 0.0;
2119 double testDist = 0;
2120 double segmentPtX, segmentPtY;
2125 const int size = mX.size();
2126 if ( size == 0 || size == 1 )
2132 const double *
xData = mX.constData();
2133 const double *
yData = mY.constData();
2134 for (
int i = 1; i < size; ++i )
2136 double prevX =
xData[i - 1];
2137 double prevY =
yData[i - 1];
2138 double currentX =
xData[i];
2139 double currentY =
yData[i];
2141 if ( testDist < sqrDist )
2144 segmentPt.
setX( segmentPtX );
2145 segmentPt.
setY( segmentPtY );
2146 vertexAfter.
part = 0;
2147 vertexAfter.
ring = 0;
2158 if (
qgsDoubleNear( testDist, leftOfDist ) && left != prevLeftOf && prevLeftOf != 0 )
2170 prevLeftOf = *leftOf;
2171 leftOfDist = testDist;
2172 prevLeftOfX = prevX;
2173 prevLeftOfY = prevY;
2175 else if ( testDist < leftOfDist )
2178 leftOfDist = testDist;
2210 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
2212 double totalLineLength = 0.0;
2213 double prevX = mX.at( 0 );
2214 double prevY = mY.at( 0 );
2220 double currentX = mX.at( i );
2221 double currentY = mY.at( i );
2222 double segmentLength = std::sqrt( std::pow( currentX - prevX, 2.0 ) + std::pow( currentY - prevY, 2.0 ) );
2236 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
2238 return QgsPoint( sumX / totalLineLength, sumY / totalLineLength );
2256 const int maxIndex = mX.size();
2263 const double *x = mX.constData();
2264 const double *y = mY.constData();
2265 double prevX = *x++;
2266 double prevY = *y++;
2267 for (
int i = 1; i < maxIndex; ++i )
2269 mSummedUpArea += prevX * ( *y - prevY ) - prevY * ( *x - prevX );
2317 if ( planeNormal.
z() < 0 )
2319 planeNormal = -planeNormal;
2324 if ( planeNormal.
y() < 0 )
2325 planeNormal = -planeNormal;
2329 if ( planeNormal.
x() < 0 )
2330 planeNormal = -planeNormal;
2334 const double *x = mX.constData();
2335 const double *y = mY.constData();
2336 const double *z = mZ.constData();
2338 double prevX = *x++;
2339 double prevY = *y++;
2340 double prevZ = *z++;
2342 double normalX = 0.0;
2343 double normalY = 0.0;
2344 double normalZ = 0.0;
2346 for (
unsigned int i = 1; i < mX.size(); ++i )
2348 normalX += prevY * ( *z - prevZ ) - prevZ * ( *y - prevY );
2349 normalY += prevZ * ( *x - prevX ) - prevX * ( *z - prevZ );
2350 normalZ += prevX * ( *y - prevY ) - prevY * ( *x - prevX );
2357 mSummedUpArea3D = 0.5 * ( normalX * planeNormal.
x() + normalY * planeNormal.
y() + normalZ * planeNormal.
z() );
2363void QgsLineString::importVerticesFromWkb(
const QgsConstWkbPtr &wkb )
2369 mX.resize( nVertices );
2370 mY.resize( nVertices );
2371 hasZ ? mZ.resize( nVertices ) : mZ.clear();
2372 hasM ? mM.resize( nVertices ) : mM.clear();
2373 double *x = mX.data();
2374 double *y = mY.data();
2375 double *m = hasM ? mM.data() :
nullptr;
2376 double *z = hasZ ? mZ.data() :
nullptr;
2377 for (
int i = 0; i < nVertices; ++i )
2410 if ( mX.count() < 2 )
2420 double previousX = mX.at(
numPoints() - 2 );
2421 double previousY = mY.at(
numPoints() - 2 );
2422 double currentX = mX.at( 0 );
2423 double currentY = mY.at( 0 );
2424 double afterX = mX.at( 1 );
2425 double afterY = mY.at( 1 );
2428 else if ( vertex.
vertex == 0 )
2441 double previousX = mX.at( vertex.
vertex - 1 );
2442 double previousY = mY.at( vertex.
vertex - 1 );
2443 double currentX = mX.at( vertex.
vertex );
2444 double currentY = mY.at( vertex.
vertex );
2445 double afterX = mX.at( vertex.
vertex + 1 );
2446 double afterY = mY.at( vertex.
vertex + 1 );
2453 if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 1 )
2456 double dx = mX.at( startVertex.
vertex + 1 ) - mX.at( startVertex.
vertex );
2457 double dy = mY.at( startVertex.
vertex + 1 ) - mY.at( startVertex.
vertex );
2458 return std::sqrt( dx * dx + dy * dy );
2483 mZ.reserve( nPoints );
2484 for (
int i = 0; i < nPoints; ++i )
2514 mM.reserve( nPoints );
2515 for (
int i = 0; i < nPoints; ++i )
2546 std::swap( mX, mY );
2560 addZValue( std::numeric_limits<double>::quiet_NaN() );
2577 int size = mX.size();
2579 double *srcX = mX.data();
2580 double *srcY = mY.data();
2581 double *srcM = hasM ? mM.data() :
nullptr;
2582 double *srcZ = hasZ ? mZ.data() :
nullptr;
2585 for (
int i = 0; i < size; ++i )
2589 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2590 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
2618 int size = mX.size();
2620 double *srcX = mX.data();
2621 double *srcY = mY.data();
2622 double *srcM = hasM ? mM.data() :
nullptr;
2623 double *srcZ = hasZ ? mZ.data() :
nullptr;
2625 double *destX = srcX;
2626 double *destY = srcY;
2627 double *destM = srcM;
2628 double *destZ = srcZ;
2630 int filteredPoints = 0;
2631 for (
int i = 0; i < size; ++i )
2635 double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
2636 double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
2638 if ( filter(
QgsPoint( x, y, z, m ) ) )
2650 mX.resize( filteredPoints );
2651 mY.resize( filteredPoints );
2653 mZ.resize( filteredPoints );
2655 mM.resize( filteredPoints );
2664 int size = mX.size();
2666 double *srcX = mX.data();
2667 double *srcY = mY.data();
2668 double *srcM = hasM ? mM.data() :
nullptr;
2669 double *srcZ = hasZ ? mZ.data() :
nullptr;
2671 for (
int i = 0; i < size; ++i )
2675 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2676 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
2692 std::unique_ptr< QgsLineString > cloned(
clone() );
2699 if (
isEmpty() || ( nbpoints < 2 ) )
2704 const double range = end - start;
2705 double lineLength =
length();
2706 double lengthSoFar = 0.0;
2709 double *mOut = cloned->mM.data();
2711 for (
int i = 1; i < nbpoints; ++i )
2714 if ( lineLength > 0.0 )
2715 *mOut++ = start + range * lengthSoFar / lineLength;
2716 else if ( lineLength == 0.0 && nbpoints > 1 )
2717 *mOut++ = start + range * i / ( nbpoints - 1 );
2731 if ( totalPoints < 2 )
2732 return std::unique_ptr< QgsLineString >(
clone() );
2734 const double *
xData = mX.constData();
2735 const double *
yData = mY.constData();
2736 const double *
mData = mM.constData();
2737 const double *
zData =
is3D() ? mZ.constData() :
nullptr;
2738 use3DDistance &=
static_cast< bool >(
zData );
2740 QVector< double > xOut( totalPoints );
2741 QVector< double > yOut( totalPoints );
2742 QVector< double > mOut( totalPoints );
2743 QVector< double > zOut(
static_cast< bool >(
zData ) ? totalPoints : 0 );
2745 double *xOutData = xOut.data();
2746 double *yOutData = yOut.data();
2747 double *mOutData = mOut.data();
2748 double *zOutData =
static_cast< bool >(
zData ) ? zOut.data() :
nullptr;
2751 double currentSegmentLength = 0;
2752 double lastValidM = std::numeric_limits< double >::quiet_NaN();
2753 double prevX = *
xData;
2754 double prevY = *
yData;
2756 while ( i < totalPoints )
2758 double thisX = *
xData++;
2759 double thisY = *
yData++;
2761 double thisM = *
mData++;
2765 if ( !std::isnan( thisM ) )
2767 *xOutData++ = thisX;
2768 *yOutData++ = thisY;
2769 *mOutData++ = thisM;
2771 *zOutData++ = thisZ;
2778 double scanAheadM = thisM;
2779 while ( i + j + 1 < totalPoints && std::isnan( scanAheadM ) )
2781 scanAheadM =
mData[j];
2784 if ( std::isnan( scanAheadM ) )
2789 *xOutData++ = thisX;
2790 *yOutData++ = thisY;
2791 *mOutData++ = scanAheadM;
2793 *zOutData++ = thisZ;
2794 for ( ; i < j; ++i )
2798 *xOutData++ = thisX;
2799 *yOutData++ = thisY;
2800 *mOutData++ = scanAheadM;
2803 *zOutData++ = *
zData++;
2805 lastValidM = scanAheadM;
2811 double scanAheadX = thisX;
2812 double scanAheadY = thisY;
2813 double scanAheadZ = thisZ;
2814 double distanceToNextValidM = currentSegmentLength;
2815 std::vector< double > scanAheadSegmentLengths;
2816 scanAheadSegmentLengths.emplace_back( currentSegmentLength );
2818 double nextValidM = std::numeric_limits< double >::quiet_NaN();
2819 while ( i + j < totalPoints - 1 )
2821 double nextScanAheadX =
xData[j];
2822 double nextScanAheadY =
yData[j];
2823 double nextScanAheadZ =
zData ?
zData[j] : 0;
2824 double nextScanAheadM =
mData[j];
2825 const double scanAheadSegmentLength = use3DDistance ?
QgsGeometryUtilsBase::distance3D( scanAheadX, scanAheadY, scanAheadZ, nextScanAheadX, nextScanAheadY, nextScanAheadZ )
2827 scanAheadSegmentLengths.emplace_back( scanAheadSegmentLength );
2828 distanceToNextValidM += scanAheadSegmentLength;
2830 if ( !std::isnan( nextScanAheadM ) )
2832 nextValidM = nextScanAheadM;
2836 scanAheadX = nextScanAheadX;
2837 scanAheadY = nextScanAheadY;
2838 scanAheadZ = nextScanAheadZ;
2842 if ( std::isnan( nextValidM ) )
2845 *xOutData++ = thisX;
2846 *yOutData++ = thisY;
2847 *mOutData++ = lastValidM;
2849 *zOutData++ = thisZ;
2851 for ( ; i < totalPoints; ++i )
2853 *xOutData++ = *
xData++;
2854 *yOutData++ = *
yData++;
2855 *mOutData++ = lastValidM;
2857 *zOutData++ = *
zData++;
2864 const double delta = ( nextValidM - lastValidM ) / distanceToNextValidM;
2865 *xOutData++ = thisX;
2866 *yOutData++ = thisY;
2867 *mOutData++ = lastValidM + delta * scanAheadSegmentLengths[0];
2868 double totalScanAheadLength = scanAheadSegmentLengths[0];
2870 *zOutData++ = thisZ;
2871 for (
int k = 1; k <= j; ++i, ++k )
2875 *xOutData++ = thisX;
2876 *yOutData++ = thisY;
2877 totalScanAheadLength += scanAheadSegmentLengths[k];
2878 *mOutData++ = lastValidM + delta * totalScanAheadLength;
2881 *zOutData++ = *
zData++;
2883 lastValidM = nextValidM;
2892 return std::make_unique< QgsLineString >( xOut, yOut, zOut, mOut );
2898 if ( fromVertex.
part != 0 || fromVertex.
ring != 0 || toVertex.
part != 0 || toVertex.
ring != 0 )
2901 const int fromVertexNumber = fromVertex.
vertex;
2902 const int toVertexNumber = toVertex.
vertex;
2905 if ( fromVertexNumber > toVertexNumber )
2911 if ( fromVertexNumber < 0 || fromVertexNumber >= nPoints || toVertexNumber < 0 || toVertexNumber >= nPoints )
2914 if ( fromVertexNumber == toVertexNumber )
2917 const bool is3DGeometry =
is3D();
2918 const double *
xData = mX.constData();
2919 const double *
yData = mY.constData();
2920 const double *
zData = is3DGeometry ? mZ.constData() :
nullptr;
2921 double totalDistance = 0.0;
2924 for (
int i = fromVertexNumber; i < toVertexNumber; ++i )
2935 totalDistance += std::sqrt( dx * dx + dy * dy + dz * dz );
2938 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.