29#include <nlohmann/json.hpp>
34#include <QDomDocument>
59 mX.resize(
points.count() );
60 mY.resize(
points.count() );
61 double *x = mX.data();
62 double *y = mY.data();
67 mZ.resize(
points.count() );
72 mM.resize(
points.count() );
87QgsLineString::QgsLineString(
const QVector<double> &x,
const QVector<double> &y,
const QVector<double> &z,
const QVector<double> &m,
bool is25DType )
90 int pointCount = std::min( x.size(), y.size() );
91 if ( x.size() == pointCount )
97 mX = x.mid( 0, pointCount );
99 if ( y.size() == pointCount )
105 mY = y.mid( 0, pointCount );
107 if ( !z.isEmpty() && z.count() >= pointCount )
110 if ( z.size() == pointCount )
116 mZ = z.mid( 0, pointCount );
119 if ( !m.isEmpty() && m.count() >= pointCount )
122 if ( m.size() == pointCount )
128 mM = m.mid( 0, pointCount );
87QgsLineString::QgsLineString(
const QVector<double> &x,
const QVector<double> &y,
const QVector<double> &z,
const QVector<double> &m,
bool is25DType ) {
…}
161 mX.reserve(
points.size() );
162 mY.reserve(
points.size() );
181static double cubicInterpolate(
double a,
double b,
182 double A,
double B,
double C,
double D )
184 return A * b * b * b + 3 * B * b * b * a + 3 * C * b * a * a + D * a * a * a;
190 return std::make_unique< QgsLineString >();
193 x.resize( segments + 1 );
195 y.resize( segments + 1 );
197 double *
zData =
nullptr;
198 if ( start.
is3D() && end.
is3D() && controlPoint1.
is3D() && controlPoint2.
is3D() )
200 z.resize( segments + 1 );
204 double *
mData =
nullptr;
207 m.resize( segments + 1 );
211 double *
xData = x.data();
212 double *
yData = y.data();
213 const double step = 1.0 / segments;
216 for (
int i = 0; i < segments; i++, a += step, b -= step )
229 *
xData++ = cubicInterpolate( a, b, start.
x(), controlPoint1.
x(), controlPoint2.
x(), end.
x() );
230 *
yData++ = cubicInterpolate( a, b, start.
y(), controlPoint1.
y(), controlPoint2.
y(), end.
y() );
232 *
zData++ = cubicInterpolate( a, b, start.
z(), controlPoint1.
z(), controlPoint2.
z(), end.
z() );
234 *
mData++ = cubicInterpolate( a, b, start.
m(), controlPoint1.
m(), controlPoint2.
m(), end.
m() );
245 return std::make_unique< QgsLineString >( x, y, z, m );
252 x.resize( polygon.count() );
253 y.resize( polygon.count() );
254 double *
xData = x.data();
255 double *
yData = y.data();
257 const QPointF *src = polygon.data();
258 for (
int i = 0 ; i < polygon.size(); ++ i )
265 return std::make_unique< QgsLineString >( x, y );
290 const int size = mX.size();
294 const double *x = mX.constData();
295 const double *y = mY.constData();
296 const bool useZ =
is3D();
298 const double *z = useZ ? mZ.constData() :
nullptr;
299 const double *m = useM ? mM.constData() :
nullptr;
301 for (
int i = 0; i < size; ++i )
323 error = QObject::tr(
"LineString has less than 2 points and is not empty." );
334 bool res =
snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM,
335 result->mX, result->mY, result->mZ, result->mM, removeRedundantPoints );
337 return result.release();
344 if ( mX.count() <= 2 )
347 double prevX = mX.at( 0 );
348 double prevY = mY.at( 0 );
350 bool useZ = hasZ && useZValues;
351 double prevZ = useZ ? mZ.at( 0 ) : 0;
353 int remaining = mX.count();
354 while ( i < remaining )
356 double currentX = mX.at( i );
357 double currentY = mY.at( i );
358 double currentZ = useZ ? mZ.at( i ) : 0;
395 if (
is3D() && closed )
396 closed &=
qgsDoubleNear( mZ.first(), mZ.last() ) || ( std::isnan( mZ.first() ) && std::isnan( mZ.last() ) );
411 const int nb = mX.size();
420 if ( rectangle.
contains( mX.at( 0 ), mY.at( 0 ) ) ||
421 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.2 ) ), mY.at(
static_cast< int >( nb * 0.2 ) ) ) ||
422 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.4 ) ), mY.at(
static_cast< int >( nb * 0.4 ) ) ) ||
423 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.6 ) ), mY.at(
static_cast< int >( nb * 0.6 ) ) ) ||
424 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.8 ) ), mY.at(
static_cast< int >( nb * 0.8 ) ) ) ||
425 rectangle.
contains( mX.at( nb - 1 ), mY.at( nb - 1 ) ) )
434 double xmin = std::numeric_limits<double>::max();
435 double ymin = std::numeric_limits<double>::max();
436 double xmax = -std::numeric_limits<double>::max();
437 double ymax = -std::numeric_limits<double>::max();
439 const double *x = mX.constData();
440 const double *y = mY.constData();
441 bool foundPointInRectangle =
false;
442 for (
int i = 0; i < nb; ++i )
444 const double px = *x++;
445 xmin = std::min( xmin, px );
446 xmax = std::max( xmax, px );
447 const double py = *y++;
448 ymin = std::min( ymin, py );
449 ymax = std::max( ymax, py );
451 if ( !foundPointInRectangle && rectangle.
contains( px, py ) )
453 foundPointInRectangle =
true;
469 if ( foundPointInRectangle )
494 const int nb = mX.size();
503 if ( box3d.
contains( mX.at( 0 ), mY.at( 0 ), mZ.at( 0 ) ) ||
504 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 ) ) ) ||
505 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 ) ) ) ||
506 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 ) ) ) ||
507 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 ) ) ) ||
508 box3d.
contains( mX.at( nb - 1 ), mY.at( nb - 1 ), mZ.at( nb - 1 ) ) )
517 double xmin = std::numeric_limits<double>::max();
518 double ymin = std::numeric_limits<double>::max();
519 double zmin = std::numeric_limits<double>::max();
520 double xmax = -std::numeric_limits<double>::max();
521 double ymax = -std::numeric_limits<double>::max();
522 double zmax = -std::numeric_limits<double>::max();
524 const double *x = mX.constData();
525 const double *y = mY.constData();
526 const double *z = mZ.constData();
527 bool foundPointInBox =
false;
528 for (
int i = 0; i < nb; ++i )
530 const double px = *x++;
531 xmin = std::min( xmin, px );
532 xmax = std::max( xmax, px );
533 const double py = *y++;
534 ymin = std::min( ymin, py );
535 ymax = std::max( ymax, py );
536 const double pz = *z++;
537 zmin = std::min( zmin, pz );
538 zmax = std::max( zmax, pz );
540 if ( !foundPointInBox && box3d.
contains( px, py, pz ) )
542 foundPointInBox =
true;
558 if ( foundPointInBox )
571 QVector< QgsVertexId > res;
572 if ( mX.count() <= 1 )
575 const double *x = mX.constData();
576 const double *y = mY.constData();
578 bool useZ = hasZ && useZValues;
579 const double *z = useZ ? mZ.constData() :
nullptr;
583 double prevZ = z ? *z++ : 0;
586 for (
int i = 1; i < mX.count(); ++i )
588 double currentX = *x++;
589 double currentY = *y++;
590 double currentZ = useZ ? *z++ : 0;
610 const int nb = mX.size();
613 const double *x = mX.constData();
614 const double *y = mY.constData();
615 QPointF *dest =
points.data();
616 for (
int i = 0; i < nb; ++i )
618 *dest++ = QPointF( *x++, *y++ );
624void simplifySection(
int i,
int j,
const double *x,
const double *y, std::vector< bool > &usePoint,
const double distanceToleranceSquared,
const double epsilon )
631 double maxDistanceSquared = -1.0;
636 for (
int k = i + 1; k < j; k++ )
639 x[k], y[k], x[i], y[i], x[j], y[j], mx, my, epsilon );
641 if ( distanceSquared > maxDistanceSquared )
643 maxDistanceSquared = distanceSquared;
647 if ( maxDistanceSquared <= distanceToleranceSquared )
649 for (
int k = i + 1; k < j; k++ )
656 simplifySection( i, maxIndex, x, y, usePoint, distanceToleranceSquared, epsilon );
657 simplifySection( maxIndex, j, x, y, usePoint, distanceToleranceSquared, epsilon );
624void simplifySection(
int i,
int j,
const double *x,
const double *y, std::vector< bool > &usePoint,
const double distanceToleranceSquared,
const double epsilon ) {
…}
670 const double distanceToleranceSquared = tolerance * tolerance;
671 const double *
xData = mX.constData();
672 const double *
yData = mY.constData();
673 const double *
zData = mZ.constData();
674 const double *
mData = mM.constData();
676 const int size = mX.size();
678 std::vector< bool > usePoint( size,
true );
680 constexpr double epsilon = 4 * std::numeric_limits<double>::epsilon();
683 QVector< double > newX;
684 newX.reserve( size );
685 QVector< double > newY;
686 newY.reserve( size );
688 const bool hasZ =
is3D();
690 QVector< double > newZ;
692 newZ.reserve( size );
693 QVector< double > newM;
695 newM.reserve( size );
697 for (
int i = 0, n = size; i < n; ++i )
699 if ( usePoint[i] || i == n - 1 )
701 newX.append(
xData[i ] );
702 newY.append(
yData[i ] );
704 newZ.append(
zData[i] );
706 newM.append(
mData[i] );
710 const bool simplifyRing =
isRing();
711 const int newSize = newX.size();
712 if ( simplifyRing && newSize > 3 )
717 newX[ newSize - 2], newY[ newSize - 2 ],
718 newX[ 1 ], newY[ 1], mx, my, epsilon );
720 if ( distanceSquared <= distanceToleranceSquared )
723 newX.last() = newX.first();
725 newY.last() = newY.first();
729 newZ.last() = newZ.first();
734 newM.last() = newM.first();
755 importVerticesFromWkb( wkbPtr );
766 auto result2D = std::minmax_element( mX.begin(), mX.end() );
767 const double xmin = *result2D.first;
768 const double xmax = *result2D.second;
769 result2D = std::minmax_element( mY.begin(), mY.end() );
770 const double ymin = *result2D.first;
771 const double ymax = *result2D.second;
773 double zmin = std::numeric_limits< double >::quiet_NaN();
774 double zmax = std::numeric_limits< double >::quiet_NaN();
778 auto resultZ = std::minmax_element( mZ.begin(), mZ.end() );
779 zmin = *resultZ.first;
780 zmax = *resultZ.second;
783 return QgsBox3D( xmin, ymin, zmin, xmax, ymax, zmax );
793 const int size = mX.size();
794 if ( index < 1 || index >= size - 1 )
797 const bool useZ =
is3D();
800 QVector<double> newX( size );
801 QVector<double> newY( size );
802 QVector<double> newZ( useZ ? size : 0 );
803 QVector<double> newM( useM ? size : 0 );
804 auto it = std::copy( mX.constBegin() + index, mX.constEnd() - 1, newX.begin() );
805 it = std::copy( mX.constBegin(), mX.constBegin() + index, it );
806 *it = *newX.constBegin();
807 mX = std::move( newX );
809 it = std::copy( mY.constBegin() + index, mY.constEnd() - 1, newY.begin() );
810 it = std::copy( mY.constBegin(), mY.constBegin() + index, it );
811 *it = *newY.constBegin();
812 mY = std::move( newY );
815 it = std::copy( mZ.constBegin() + index, mZ.constEnd() - 1, newZ.begin() );
816 it = std::copy( mZ.constBegin(), mZ.constBegin() + index, it );
817 *it = *newZ.constBegin();
818 mZ = std::move( newZ );
822 it = std::copy( mM.constBegin() + index, mM.constEnd() - 1, newM.begin() );
823 it = std::copy( mM.constBegin(), mM.constBegin() + index, it );
824 *it = *newM.constBegin();
825 mM = std::move( newM );
844 QString secondWithoutParentheses =
parts.second;
845 secondWithoutParentheses = secondWithoutParentheses.remove(
'(' ).remove(
')' ).simplified().remove(
' ' );
846 parts.second =
parts.second.remove(
'(' ).remove(
')' );
847 if ( (
parts.second.compare( QLatin1String(
"EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
848 secondWithoutParentheses.isEmpty() )
863 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
874 wkb << static_cast<quint32>(
wkbType() );
892 wkt += QLatin1String(
"EMPTY" );
907 QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral(
"LineString" ) );
910 return elemLineString;
914 return elemLineString;
922 QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral(
"LineString" ) );
925 return elemLineString;
928 return elemLineString;
937 {
"type",
"LineString" },
947 kml.append( QLatin1String(
"<LinearRing>" ) );
951 kml.append( QLatin1String(
"<LineString>" ) );
954 kml.append( QLatin1String(
"<altitudeMode>" ) );
957 kml.append( QLatin1String(
"absolute" ) );
961 kml.append( QLatin1String(
"clampToGround" ) );
963 kml.append( QLatin1String(
"</altitudeMode>" ) );
964 kml.append( QLatin1String(
"<coordinates>" ) );
966 int nPoints = mX.size();
967 for (
int i = 0; i < nPoints; ++i )
971 kml.append( QLatin1String(
" " ) );
974 kml.append( QLatin1String(
"," ) );
978 kml.append( QLatin1String(
"," ) );
983 kml.append( QLatin1String(
",0" ) );
986 kml.append( QLatin1String(
"</coordinates>" ) );
989 kml.append( QLatin1String(
"</LinearRing>" ) );
993 kml.append( QLatin1String(
"</LineString>" ) );
1007 const int size = mX.size();
1011 const double *x = mX.constData();
1012 const double *y = mY.constData();
1015 double prevX = *x++;
1016 double prevY = *y++;
1018 for (
int i = 1; i < size; ++i )
1022 total += std::sqrt( dx * dx + dy * dy );
1032 const bool useZ =
is3D();
1035 const int size = mX.size();
1037 return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >() );
1039 index = std::clamp( index, 0, size - 1 );
1041 const int part1Size = index + 1;
1042 QVector< double > x1( part1Size );
1043 QVector< double > y1( part1Size );
1044 QVector< double > z1( useZ ? part1Size : 0 );
1045 QVector< double > m1( useM ? part1Size : 0 );
1047 const double *sourceX = mX.constData();
1048 const double *sourceY = mY.constData();
1049 const double *sourceZ = useZ ? mZ.constData() :
nullptr;
1050 const double *sourceM = useM ? mM.constData() :
nullptr;
1052 double *destX = x1.data();
1053 double *destY = y1.data();
1054 double *destZ = useZ ? z1.data() :
nullptr;
1055 double *destM = useM ? m1.data() :
nullptr;
1057 std::copy( sourceX, sourceX + part1Size, destX );
1058 std::copy( sourceY, sourceY + part1Size, destY );
1060 std::copy( sourceZ, sourceZ + part1Size, destZ );
1062 std::copy( sourceM, sourceM + part1Size, destM );
1064 const int part2Size = size - index;
1065 if ( part2Size < 2 )
1066 return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >() );
1068 QVector< double > x2( part2Size );
1069 QVector< double > y2( part2Size );
1070 QVector< double > z2( useZ ? part2Size : 0 );
1071 QVector< double > m2( useM ? part2Size : 0 );
1074 destZ = useZ ? z2.data() :
nullptr;
1075 destM = useM ? m2.data() :
nullptr;
1076 std::copy( sourceX + index, sourceX + size, destX );
1077 std::copy( sourceY + index, sourceY + size, destY );
1079 std::copy( sourceZ + index, sourceZ + size, destZ );
1081 std::copy( sourceM + index, sourceM + size, destM );
1083 if ( part1Size < 2 )
1084 return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
1086 return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
1091 const double *allPointsX =
xData();
1092 const double *allPointsY =
yData();
1094 QVector<double> partX;
1095 QVector<double> partY;
1096 QSet<QgsPointXY> partPointSet;
1098 QVector<QgsLineString *> disjointParts;
1099 for (
size_t i = 0; i < allPointsCount; i++ )
1101 const QgsPointXY point( *allPointsX++, *allPointsY++ );
1102 if ( partPointSet.contains( point ) )
1106 disjointParts.push_back(
new QgsLineString( partX, partY ) );
1108 partX = { partX.last() };
1109 partY = { partY.last() };
1110 partPointSet = {
QgsPointXY( partX[0], partY[0] ) };
1112 partX.push_back( point.
x() );
1113 partY.push_back( point.
y() );
1114 partPointSet.insert( point );
1117 if ( partX.size() > 1 || disjointParts.size() == 0 )
1118 disjointParts.push_back(
new QgsLineString( partX, partY ) );
1120 return disjointParts;
1128 const int size = mX.size();
1132 const double *x = mX.constData();
1133 const double *y = mY.constData();
1134 const double *z = mZ.constData();
1137 double prevX = *x++;
1138 double prevY = *y++;
1139 double prevZ = *z++;
1141 for (
int i = 1; i < size; ++i )
1146 total += std::sqrt( dx * dx + dy * dy + dz * dz );
1186 Q_UNUSED( tolerance )
1187 Q_UNUSED( toleranceType )
1203 if ( i < 0 || i >= mX.size() )
1208 double x = mX.at( i );
1209 double y = mY.at( i );
1210 double z = std::numeric_limits<double>::quiet_NaN();
1211 double m = std::numeric_limits<double>::quiet_NaN();
1229 else if ( hasZ && hasM )
1252 if ( index >= 0 && index < mX.size() )
1253 return mX.at( index );
1260 if ( index >= 0 && index < mY.size() )
1261 return mY.at( index );
1268 if ( index >= 0 && index < mX.size() )
1275 if ( index >= 0 && index < mY.size() )
1290 pts.reserve( nPoints );
1291 for (
int i = 0; i < nPoints; ++i )
1293 pts.push_back(
pointN( i ) );
1307 const bool hasZ =
static_cast< bool >( z );
1308 const bool hasM =
static_cast< bool >( m );
1329 double *destX = mX.data();
1330 double *destY = mY.data();
1331 double *destZ =
nullptr;
1341 double *destM =
nullptr;
1352 for (
size_t i = 0; i < size; ++i )
1379 bool hasZ = firstPt.
is3D();
1384 mX.resize(
points.size() );
1385 mY.resize(
points.size() );
1388 mZ.resize(
points.size() );
1396 mM.resize(
points.size() );
1403 for (
int i = 0; i <
points.size(); ++i )
1405 mX[i] =
points.at( i ).x();
1406 mY[i] =
points.at( i ).y();
1409 double z =
points.at( i ).z();
1410 mZ[i] = std::isnan( z ) ? 0 : z;
1414 double m =
points.at( i ).m();
1415 mM[i] = std::isnan( m ) ? 0 : m;
1468 mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
1481 mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
1491 std::reverse( copy->mX.begin(), copy->mX.end() );
1492 std::reverse( copy->mY.begin(), copy->mY.end() );
1495 std::reverse( copy->mZ.begin(), copy->mZ.end() );
1499 std::reverse( copy->mM.begin(), copy->mM.end() );
1506void QgsLineString::visitPointsByRegularDistance(
const double distance,
const std::function<
bool (
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double )> &visitPoint )
const
1511 double distanceTraversed = 0;
1513 if ( totalPoints == 0 )
1516 const double *x = mX.constData();
1517 const double *y = mY.constData();
1518 const double *z =
is3D() ? mZ.constData() :
nullptr;
1519 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1521 double prevX = *x++;
1522 double prevY = *y++;
1523 double prevZ = z ? *z++ : 0.0;
1524 double prevM = m ? *m++ : 0.0;
1528 visitPoint( prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM );
1532 double pZ = std::numeric_limits<double>::quiet_NaN();
1533 double pM = std::numeric_limits<double>::quiet_NaN();
1534 double nextPointDistance = distance;
1535 const double eps = 4 * nextPointDistance * std::numeric_limits<double>::epsilon ();
1536 for (
int i = 1; i < totalPoints; ++i )
1538 double thisX = *x++;
1539 double thisY = *y++;
1540 double thisZ = z ? *z++ : 0.0;
1541 double thisM = m ? *m++ : 0.0;
1547 const double distanceToPoint = std::min( nextPointDistance - distanceTraversed,
segmentLength );
1550 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &pZ :
nullptr,
1551 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &pM : nullptr );
1553 if ( !visitPoint( pX, pY, pZ, pM, prevX, prevY, prevZ, prevM, thisX, thisY, thisZ, thisM ) )
1556 nextPointDistance += distance;
1506void QgsLineString::visitPointsByRegularDistance(
const double distance,
const std::function<
bool (
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double )> &visitPoint )
const {
…}
1578 std::unique_ptr< QgsPoint > res;
1579 visitPointsByRegularDistance( distance, [ & ](
double x,
double y,
double z,
double m,
double,
double,
double,
double,
double,
double,
double,
double )->
bool
1581 res = std::make_unique< QgsPoint >( pointType, x, y, z, m );
1584 return res.release();
1589 return lineLocatePointByMPrivate( m, x, y, z, distanceFromStart, use3DDistance,
false );
1592bool QgsLineString::lineLocatePointByMPrivate(
double m,
double &x,
double &y,
double &z,
double &distanceFromStart,
bool use3DDistance,
bool haveInterpolatedM )
const
1597 distanceFromStart = 0;
1599 if ( totalPoints == 0 )
1602 const double *
xData = mX.constData();
1603 const double *
yData = mY.constData();
1604 const double *
mData = mM.constData();
1606 const double *
zData =
is3D() ? mZ.constData() :
nullptr;
1607 use3DDistance &=
static_cast< bool >(
zData );
1609 double prevX = *
xData++;
1610 double prevY = *
yData++;
1612 double prevM = *
mData++;
1615 while ( i < totalPoints )
1617 double thisX = *
xData++;
1618 double thisY = *
yData++;
1620 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 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &startZ :
nullptr,
1738 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &startM : nullptr );
1739 substringPoints <<
QgsPoint( pointType, startX, startY, startZ, startM );
1742 if ( foundStart && ( distanceTraversed +
segmentLength > endDistance ) )
1745 const double distanceToEnd = endDistance - distanceTraversed;
1750 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &endZ :
nullptr,
1751 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &endM : nullptr );
1752 substringPoints <<
QgsPoint( pointType, endX, endY, endZ, endM );
1754 else if ( foundStart )
1756 substringPoints <<
QgsPoint( pointType, thisX, thisY, thisZ, thisM );
1764 if ( distanceTraversed >= endDistance )
1769 if ( !foundStart &&
qgsDoubleNear( distanceTraversed, startDistance ) )
1771 substringPoints <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1772 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1797 if ( path.isEmpty() || path.currentPosition() != QPointF( mX.at( 0 ), mY.at( 0 ) ) )
1799 path.moveTo( mX.at( 0 ), mY.at( 0 ) );
1802 for (
int i = 1; i < nPoints; ++i )
1804 path.lineTo( mX.at( i ), mY.at( i ) );
1817 return compoundCurve;
1822 if ( mX.size() < 2 || mY.size() < 2 )
1825 const bool extendStart = startDistance > 0;
1826 const bool extendEnd = endDistance > 0;
1831 const double currentLen = std::sqrt( std::pow( mX.at( 0 ) - mX.at( 1 ), 2 ) +
1832 std::pow( mY.at( 0 ) - mY.at( 1 ), 2 ) );
1833 const double newLen = currentLen + startDistance;
1834 mX[ 0 ] = mX.at( 1 ) + ( mX.at( 0 ) - mX.at( 1 ) ) / currentLen * newLen;
1835 mY[ 0 ] = mY.at( 1 ) + ( mY.at( 0 ) - mY.at( 1 ) ) / currentLen * newLen;
1840 const int last = mX.size() - 1;
1841 const double currentLen = std::sqrt( std::pow( mX.at( last ) - mX.at( last - 1 ), 2 ) +
1842 std::pow( mY.at( last ) - mY.at( last - 1 ), 2 ) );
1843 const double newLen = currentLen + endDistance;
1844 mX[ last ] = mX.at( last - 1 ) + ( mX.at( last ) - mX.at( last - 1 ) ) / currentLen * newLen;
1845 mY[ last ] = mY.at( last - 1 ) + ( mY.at( last ) - mY.at( last - 1 ) ) / currentLen * newLen;
1848 if ( extendStart || extendEnd )
1854 auto result = std::make_unique< QgsLineString >();
1856 return result.release();
1861 const QgsLineString *otherLine = qgsgeometry_cast<const QgsLineString *>( other );
1865 const int size = mX.size();
1866 const int otherSize = otherLine->mX.size();
1867 if ( size > otherSize )
1871 else if ( size < otherSize )
1876 if (
is3D() && !otherLine->
is3D() )
1878 else if ( !
is3D() && otherLine->
is3D() )
1880 const bool considerZ =
is3D();
1888 for (
int i = 0; i < size; i++ )
1890 const double x = mX[i];
1891 const double otherX = otherLine->mX[i];
1896 else if ( x > otherX )
1901 const double y = mY[i];
1902 const double otherY = otherLine->mY[i];
1907 else if ( y > otherY )
1914 const double z = mZ[i];
1915 const double otherZ = otherLine->mZ[i];
1921 else if ( z > otherZ )
1929 const double m = mM[i];
1930 const double otherM = otherLine->mM[i];
1936 else if ( m > otherM )
1947 return QStringLiteral(
"LineString" );
1963 double *zArray =
nullptr;
1969 std::unique_ptr< double[] > dummyZ;
1970 if ( !hasZ || !transformZ )
1972 dummyZ.reset(
new double[nPoints]() );
1973 zArray = dummyZ.get();
1988 double *x = mX.data();
1989 double *y = mY.data();
1990 double *z = hasZ ? mZ.data() :
nullptr;
1991 double *m = hasM ? mM.data() :
nullptr;
1992 for (
int i = 0; i < nPoints; ++i )
1995 t.map( *x, *y, &xOut, &yOut );
2000 *z = *z * zScale + zTranslate;
2005 *m = *m * mScale + mTranslate;
2020 if ( position.
vertex < 0 || position.
vertex > mX.size() )
2030 mX.insert( position.
vertex, vertex.
x() );
2031 mY.insert( position.
vertex, vertex.
y() );
2034 mZ.insert( position.
vertex, vertex.
z() );
2038 mM.insert( position.
vertex, vertex.
m() );
2046 if ( position.
vertex < 0 || position.
vertex >= mX.size() )
2050 mX[position.
vertex] = newPos.
x();
2051 mY[position.
vertex] = newPos.
y();
2054 mZ[position.
vertex] = newPos.
z();
2058 mM[position.
vertex] = newPos.
m();
2066 if ( position.
vertex >= mX.size() || position.
vertex < 0 )
2071 mX.remove( position.
vertex );
2072 mY.remove( position.
vertex );
2075 mZ.remove( position.
vertex );
2079 mM.remove( position.
vertex );
2104 mX.append( pt.
x() );
2105 mY.append( pt.
y() );
2108 mZ.append( pt.
z() );
2112 mM.append( pt.
m() );
2119 double sqrDist = std::numeric_limits<double>::max();
2120 double leftOfDist = std::numeric_limits<double>::max();
2122 double prevLeftOfX = 0.0;
2123 double prevLeftOfY = 0.0;
2124 double testDist = 0;
2125 double segmentPtX, segmentPtY;
2130 const int size = mX.size();
2131 if ( size == 0 || size == 1 )
2137 const double *
xData = mX.constData();
2138 const double *
yData = mY.constData();
2139 for (
int i = 1; i < size; ++i )
2141 double prevX =
xData[ i - 1 ];
2142 double prevY =
yData[ i - 1 ];
2143 double currentX =
xData[ i ];
2144 double currentY =
yData[ i ];
2146 if ( testDist < sqrDist )
2149 segmentPt.
setX( segmentPtX );
2150 segmentPt.
setY( segmentPtY );
2151 vertexAfter.
part = 0;
2152 vertexAfter.
ring = 0;
2163 if (
qgsDoubleNear( testDist, leftOfDist ) && left != prevLeftOf && prevLeftOf != 0 )
2175 prevLeftOf = *leftOf;
2176 leftOfDist = testDist;
2177 prevLeftOfX = prevX;
2178 prevLeftOfY = prevY;
2180 else if ( testDist < leftOfDist )
2183 leftOfDist = testDist;
2215 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
2217 double totalLineLength = 0.0;
2218 double prevX = mX.at( 0 );
2219 double prevY = mY.at( 0 );
2225 double currentX = mX.at( i );
2226 double currentY = mY.at( i );
2227 double segmentLength = std::sqrt( std::pow( currentX - prevX, 2.0 ) +
2228 std::pow( currentY - prevY, 2.0 ) );
2242 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
2244 return QgsPoint( sumX / totalLineLength, sumY / totalLineLength );
2263 const int maxIndex = mX.size();
2270 const double *x = mX.constData();
2271 const double *y = mY.constData();
2272 double prevX = *x++;
2273 double prevY = *y++;
2274 for (
int i = 1; i < maxIndex; ++i )
2276 mSummedUpArea += prevX * ( *y - prevY ) - prevY * ( *x - prevX );
2286void QgsLineString::importVerticesFromWkb(
const QgsConstWkbPtr &wkb )
2292 mX.resize( nVertices );
2293 mY.resize( nVertices );
2294 hasZ ? mZ.resize( nVertices ) : mZ.clear();
2295 hasM ? mM.resize( nVertices ) : mM.clear();
2296 double *x = mX.data();
2297 double *y = mY.data();
2298 double *m = hasM ? mM.data() :
nullptr;
2299 double *z = hasZ ? mZ.data() :
nullptr;
2300 for (
int i = 0; i < nVertices; ++i )
2333 if ( mX.count() < 2 )
2343 double previousX = mX.at(
numPoints() - 2 );
2344 double previousY = mY.at(
numPoints() - 2 );
2345 double currentX = mX.at( 0 );
2346 double currentY = mY.at( 0 );
2347 double afterX = mX.at( 1 );
2348 double afterY = mY.at( 1 );
2351 else if ( vertex.
vertex == 0 )
2364 double previousX = mX.at( vertex.
vertex - 1 );
2365 double previousY = mY.at( vertex.
vertex - 1 );
2366 double currentX = mX.at( vertex.
vertex );
2367 double currentY = mY.at( vertex.
vertex );
2368 double afterX = mX.at( vertex.
vertex + 1 );
2369 double afterY = mY.at( vertex.
vertex + 1 );
2376 if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 1 )
2379 double dx = mX.at( startVertex.
vertex + 1 ) - mX.at( startVertex.
vertex );
2380 double dy = mY.at( startVertex.
vertex + 1 ) - mY.at( startVertex.
vertex );
2381 return std::sqrt( dx * dx + dy * dy );
2406 mZ.reserve( nPoints );
2407 for (
int i = 0; i < nPoints; ++i )
2437 mM.reserve( nPoints );
2438 for (
int i = 0; i < nPoints; ++i )
2469 std::swap( mX, mY );
2483 addZValue( std::numeric_limits<double>::quiet_NaN() );
2500 int size = mX.size();
2502 double *srcX = mX.data();
2503 double *srcY = mY.data();
2504 double *srcM = hasM ? mM.data() :
nullptr;
2505 double *srcZ = hasZ ? mZ.data() :
nullptr;
2508 for (
int i = 0; i < size; ++i )
2512 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2513 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
2541 int size = mX.size();
2543 double *srcX = mX.data();
2544 double *srcY = mY.data();
2545 double *srcM = hasM ? mM.data() :
nullptr;
2546 double *srcZ = hasZ ? mZ.data() :
nullptr;
2548 double *destX = srcX;
2549 double *destY = srcY;
2550 double *destM = srcM;
2551 double *destZ = srcZ;
2553 int filteredPoints = 0;
2554 for (
int i = 0; i < size; ++i )
2558 double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
2559 double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
2561 if ( filter(
QgsPoint( x, y, z, m ) ) )
2573 mX.resize( filteredPoints );
2574 mY.resize( filteredPoints );
2576 mZ.resize( filteredPoints );
2578 mM.resize( filteredPoints );
2587 int size = mX.size();
2589 double *srcX = mX.data();
2590 double *srcY = mY.data();
2591 double *srcM = hasM ? mM.data() :
nullptr;
2592 double *srcZ = hasZ ? mZ.data() :
nullptr;
2594 for (
int i = 0; i < size; ++i )
2598 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2599 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
2615 std::unique_ptr< QgsLineString > cloned(
clone() );
2622 if (
isEmpty() || ( nbpoints < 2 ) )
2627 const double range = end - start;
2628 double lineLength =
length();
2629 double lengthSoFar = 0.0;
2632 double *mOut = cloned->mM.data();
2634 for (
int i = 1; i < nbpoints ; ++i )
2637 if ( lineLength > 0.0 )
2638 *mOut++ = start + range * lengthSoFar / lineLength;
2639 else if ( lineLength == 0.0 && nbpoints > 1 )
2640 *mOut++ = start + range * i / ( nbpoints - 1 );
2654 if ( totalPoints < 2 )
2655 return std::unique_ptr< QgsLineString >(
clone() );
2657 const double *
xData = mX.constData();
2658 const double *
yData = mY.constData();
2659 const double *
mData = mM.constData();
2660 const double *
zData =
is3D() ? mZ.constData() :
nullptr;
2661 use3DDistance &=
static_cast< bool >(
zData );
2663 QVector< double > xOut( totalPoints );
2664 QVector< double > yOut( totalPoints );
2665 QVector< double > mOut( totalPoints );
2666 QVector< double > zOut(
static_cast< bool >(
zData ) ? totalPoints : 0 );
2668 double *xOutData = xOut.data();
2669 double *yOutData = yOut.data();
2670 double *mOutData = mOut.data();
2671 double *zOutData =
static_cast< bool >(
zData ) ? zOut.data() :
nullptr;
2674 double currentSegmentLength = 0;
2675 double lastValidM = std::numeric_limits< double >::quiet_NaN();
2676 double prevX = *
xData;
2677 double prevY = *
yData;
2679 while ( i < totalPoints )
2681 double thisX = *
xData++;
2682 double thisY = *
yData++;
2684 double thisM = *
mData++;
2686 currentSegmentLength = use3DDistance
2690 if ( !std::isnan( thisM ) )
2692 *xOutData++ = thisX;
2693 *yOutData++ = thisY;
2694 *mOutData++ = thisM;
2696 *zOutData++ = thisZ;
2703 double scanAheadM = thisM;
2704 while ( i + j + 1 < totalPoints && std::isnan( scanAheadM ) )
2706 scanAheadM =
mData[ j ];
2709 if ( std::isnan( scanAheadM ) )
2714 *xOutData++ = thisX;
2715 *yOutData++ = thisY;
2716 *mOutData++ = scanAheadM;
2718 *zOutData++ = thisZ;
2719 for ( ; i < j; ++i )
2723 *xOutData++ = thisX;
2724 *yOutData++ = thisY;
2725 *mOutData++ = scanAheadM;
2728 *zOutData++ = *
zData++;
2730 lastValidM = scanAheadM;
2736 double scanAheadX = thisX;
2737 double scanAheadY = thisY;
2738 double scanAheadZ = thisZ;
2739 double distanceToNextValidM = currentSegmentLength;
2740 std::vector< double > scanAheadSegmentLengths;
2741 scanAheadSegmentLengths.emplace_back( currentSegmentLength );
2743 double nextValidM = std::numeric_limits< double >::quiet_NaN();
2744 while ( i + j < totalPoints - 1 )
2746 double nextScanAheadX =
xData[j];
2747 double nextScanAheadY =
yData[j];
2748 double nextScanAheadZ =
zData ?
zData[j] : 0;
2749 double nextScanAheadM =
mData[ j ];
2750 const double scanAheadSegmentLength = use3DDistance
2753 scanAheadSegmentLengths.emplace_back( scanAheadSegmentLength );
2754 distanceToNextValidM += scanAheadSegmentLength;
2756 if ( !std::isnan( nextScanAheadM ) )
2758 nextValidM = nextScanAheadM;
2762 scanAheadX = nextScanAheadX;
2763 scanAheadY = nextScanAheadY;
2764 scanAheadZ = nextScanAheadZ;
2768 if ( std::isnan( nextValidM ) )
2771 *xOutData++ = thisX;
2772 *yOutData++ = thisY;
2773 *mOutData++ = lastValidM;
2775 *zOutData++ = thisZ;
2777 for ( ; i < totalPoints; ++i )
2779 *xOutData++ = *
xData++;
2780 *yOutData++ = *
yData++;
2781 *mOutData++ = lastValidM;
2783 *zOutData++ = *
zData++;
2790 const double delta = ( nextValidM - lastValidM ) / distanceToNextValidM;
2791 *xOutData++ = thisX;
2792 *yOutData++ = thisY;
2793 *mOutData++ = lastValidM + delta * scanAheadSegmentLengths[0];
2794 double totalScanAheadLength = scanAheadSegmentLengths[0];
2796 *zOutData++ = thisZ;
2797 for (
int k = 1; k <= j; ++i, ++k )
2801 *xOutData++ = thisX;
2802 *yOutData++ = thisY;
2803 totalScanAheadLength += scanAheadSegmentLengths[k];
2804 *mOutData++ = lastValidM + delta * totalScanAheadLength;
2807 *zOutData++ = *
zData++;
2809 lastValidM = nextValidM;
2818 return std::make_unique< QgsLineString >( xOut, yOut, zOut, mOut );
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.
Abstract base class for all geometries.
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.
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 intersects(const QgsBox3D &other) const
Returns true if box intersects with another box.
bool contains(const QgsBox3D &other) const
Returns true when box contains other box.
QgsRectangle toRectangle() const
Converts the box to a 2D rectangle.
bool isNull() const
Test if the box is null (holding no spatial information).
Compound curve geometry type.
void addCurve(QgsCurve *c, bool extendPrevious=false)
Adds a curve to the geometry (takes ownership).
Qgis::WkbType readHeader() const
readHeader
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
bool mHasCachedSummedUpArea
virtual bool isRing() const
Returns true if the curve is a ring.
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
bool snapToGridPrivate(double hSpacing, double vSpacing, double dSpacing, double mSpacing, const QVector< double > &srcX, const QVector< double > &srcY, const QVector< double > &srcZ, const QVector< double > &srcM, QVector< double > &outX, QVector< double > &outY, QVector< double > &outZ, QVector< double > &outM, bool removeRedundantPoints) const
Helper function for QgsCurve subclasses to snap to grids.
QgsBox3D mBoundingBox
Cached bounding box.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const
Tells whether the operation has been canceled already.
Convenience functions for geometry utils.
static void pointOnLineWithDistance(double x1, double y1, double x2, double y2, double distance, double &x, double &y, double *z1=nullptr, double *z2=nullptr, double *z=nullptr, double *m1=nullptr, double *m2=nullptr, double *m=nullptr)
Calculates the point a specified distance from (x1, y1) toward a second point (x2,...
static double distance2D(double x1, double y1, double x2, double y2)
Returns the 2D distance between (x1, y1) and (x2, y2).
static double lineAngle(double x1, double y1, double x2, double y2)
Calculates the direction of line joining two points in radians, clockwise from the north direction.
static double averageAngle(double x1, double y1, double x2, double y2, double x3, double y3)
Calculates the average angle (in radians) between the two linear segments from (x1,...
static double distance3D(double x1, double y1, double z1, double x2, double y2, double z2)
Returns the 3D distance between (x1, y1, z1) and (x2, y2, z2).
static double sqrDistToLine(double ptX, double ptY, double x1, double y1, double x2, double y2, double &minDistX, double &minDistY, double epsilon)
Returns the squared distance between a point and a line.
static int leftOfLine(const double x, const double y, const double x1, const double y1, const double x2, const double y2)
Returns a value < 0 if the point (x, y) is left of the line from (x1, y1) -> (x2, y2).
static json pointsToJson(const QgsPointSequence &points, int precision)
Returns coordinates as json object.
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure, QgsAbstractGeometry::WkbFlags flags)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
static QPair< Qgis::WkbType, QString > wktReadBlock(const QString &wkt)
Parses a WKT block of the format "TYPE( contents )" and returns a pair of geometry type to contents (...
static QgsPointSequence pointsFromWKT(const QString &wktCoordinateList, bool is3D, bool isMeasure)
Returns a list of points contained in a WKT string.
static QDomElement pointsToGML2(const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY)
Returns a gml::coordinates DOM element.
static QDomElement pointsToGML3(const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, bool is3D, QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY)
Returns a gml::posList DOM element.
static QString pointsToWKT(const QgsPointSequence &points, int precision, bool is3D, bool isMeasure)
Returns a WKT coordinate list.
Represents a single 2D line segment, consisting of a 2D start and end vertex only.
Line string geometry type, with support for z-dimension and m-values.
double segmentLength(QgsVertexId startVertex) const override
Returns the length of the segment of the geometry which begins at startVertex.
bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
static std::unique_ptr< QgsLineString > fromBezierCurve(const QgsPoint &start, const QgsPoint &controlPoint1, const QgsPoint &controlPoint2, const QgsPoint &end, int segments=30)
Returns a new linestring created by segmentizing the bezier curve between start and end,...
bool pointAt(int node, QgsPoint &point, Qgis::VertexType &type) const override
Returns the point and vertex id of a point within the curve.
bool isClosed() const override
Returns true if the curve is closed.
void swapXy() override
Swaps the x and y coordinates from the geometry.
const double * yData() const
Returns a const pointer to the y vertex data.
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
QVector< QgsLineString * > splitToDisjointXYParts() const
Divides the linestring into parts that don't share any points or lines.
const double * xData() const
Returns a const pointer to the x vertex data.
bool moveVertex(QgsVertexId position, const QgsPoint &newPos) override
Moves a vertex within the geometry.
double length() const override
Returns the planar, 2-dimensional length of the geometry.
double length3D() const
Returns the length in 3D world of the line string.
void points(QgsPointSequence &pt) const override
Returns a list of points within the curve.
static std::unique_ptr< QgsLineString > fromQPolygonF(const QPolygonF &polygon)
Returns a new linestring from a QPolygonF polygon input.
QgsLineString * simplifyByDistance(double tolerance) const override
Simplifies the geometry by applying the Douglas Peucker simplification by distance algorithm.
int dimension() const override
Returns the inherent dimension of the geometry.
void sumUpArea(double &sum) const override
Calculates the shoelace/triangle formula sum for the points in the linestring.
void clear() override
Clears the geometry, ie reset it to a null geometry.
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the linestring does not have z values.
bool fromWkb(QgsConstWkbPtr &wkb) override
Sets the geometry from a WKB string.
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
QgsPoint startPoint() const override
Returns the starting point of the curve.
void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) override
Transforms the geometry using a coordinate transform.
QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a new line string geometry corresponding to a segmentized approximation of the curve.
bool isEmpty() const override
Returns true if the geometry is empty.
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
int numPoints() const override
Returns the number of points in the curve.
QgsPoint pointN(int i) const
Returns the specified point from inside the line string.
void drawAsPolygon(QPainter &p) const override
Draws the curve as a polygon on the specified QPainter.
int nCoordinates() const override
Returns the number of nodes contained in the geometry.
QgsLineString()
Constructor for an empty linestring geometry.
void draw(QPainter &p) const override
Draws the geometry using the specified QPainter.
QString asKml(int precision=17) const override
Returns a KML representation of the geometry.
std::unique_ptr< QgsLineString > interpolateM(bool use3DDistance=true) const
Returns a copy of this line with all missing (NaN) m values interpolated from m values of surrounding...
int wkbSize(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns the length of the QByteArray returned by asWkb()
void setPoints(size_t size, const double *x, const double *y, const double *z=nullptr, const double *m=nullptr)
Resets the line string to match the specified point data.
QgsPoint centroid() const override
Returns the centroid of the geometry.
QDomElement asGml3(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML3 representation of the geometry.
QPolygonF asQPolygonF() const override
Returns a QPolygonF representing the points.
bool removeDuplicateNodes(double epsilon=4 *std::numeric_limits< double >::epsilon(), bool useZValues=false) override
Removes duplicate nodes from the geometry, wherever removing the nodes does not result in a degenerat...
void scroll(int firstVertexIndex) final
Scrolls the curve vertices so that they start with the vertex at the given index.
bool boundingBoxIntersects(const QgsRectangle &rectangle) const override
Returns true if the bounding box of this geometry intersects with a rectangle.
QString geometryType() const override
Returns a unique string representing the geometry type.
std::unique_ptr< QgsLineString > measuredLine(double start, double end) const
Re-write the measure ordinate (or add one, if it isn't already there) interpolating the measure betwe...
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
QgsPoint endPoint() const override
Returns the end point of the curve.
void setYAt(int index, double y)
Sets the y-coordinate of the specified node in the line string.
QDomElement asGml2(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML2 representation of the geometry.
QgsLineString * reversed() const override
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
void close()
Closes the line string by appending the first point to the end of the line, if it is not already clos...
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
int indexOf(const QgsPoint &point) const final
Returns the index of the first vertex matching the given point, or -1 if a matching vertex is not fou...
double vertexAngle(QgsVertexId vertex) const override
Returns approximate angle at a vertex.
void extend(double startDistance, double endDistance)
Extends the line geometry by extrapolating out the start or end of the line by a specified distance.
QgsCompoundCurve * toCurveType() const override
Returns the geometry converted to the more generic curve type QgsCompoundCurve.
void append(const QgsLineString *line)
Appends the contents of another line string to the end of this line string.
QgsLineString * curveSubstring(double startDistance, double endDistance) const override
Returns a new curve representing a substring of this curve.
QgsBox3D calculateBoundingBox3D() const override
Calculates the minimal 3D bounding box for the geometry.
std::tuple< std::unique_ptr< QgsCurve >, std::unique_ptr< QgsCurve > > splitCurveAtVertex(int index) const final
Splits the curve at the specified vertex index, returning two curves which represent the portion of t...
void addToPainterPath(QPainterPath &path) const override
Adds a curve to a painter path.
bool lineLocatePointByM(double m, double &x, double &y, double &z, double &distanceFromStart, bool use3DDistance=true) const
Attempts to locate a point on the linestring by m value.
void visitPointsByRegularDistance(double distance, const std::function< bool(double x, double y, double z, double m, double startSegmentX, double startSegmentY, double startSegmentZ, double startSegmentM, double endSegmentX, double endSegmentY, double endSegmentZ, double endSegmentM) > &visitPoint) const
Visits regular points along the linestring, spaced by distance.
void setXAt(int index, double x)
Sets the x-coordinate of the specified node in the line string.
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
double closestSegment(const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf=nullptr, double epsilon=4 *std::numeric_limits< double >::epsilon()) const override
Searches for the closest segment of the geometry to a given point.
QVector< QgsVertexId > collectDuplicateNodes(double epsilon=4 *std::numeric_limits< double >::epsilon(), bool useZValues=false) const
Returns a list of any duplicate nodes contained in the geometry, within the specified tolerance.
bool insertVertex(QgsVertexId position, const QgsPoint &vertex) override
Inserts a vertex into the geometry.
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the linestring does not have m values.
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
int compareToSameClass(const QgsAbstractGeometry *other) const final
Compares to an other geometry of the same class, and returns a integer for sorting of the two geometr...
bool dropMValue() override
Drops any measure values which exist in the geometry.
Q_DECL_DEPRECATED QgsBox3D calculateBoundingBox3d() const
Calculates the minimal 3D bounding box for the geometry.
json asJsonObject(int precision=17) const override
Returns a json object representation of the geometry.
void filterVertices(const std::function< bool(const QgsPoint &) > &filter) override
Filters the vertices from the geometry in place, removing any which do not return true for the filter...
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns a WKB representation of the geometry.
void transformVertices(const std::function< QgsPoint(const QgsPoint &) > &transform) override
Transforms the vertices from the geometry in place, applying the transform function to every vertex.
QgsLineString * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
bool convertTo(Qgis::WkbType type) override
Converts the geometry to a specified type.
bool isClosed2D() const override
Returns true if the curve is closed.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
QgsPoint * interpolatePoint(double distance) const override
Returns an interpolated point on the curve at the specified distance.
QgsLineString * snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0, bool removeRedundantPoints=false) const override
Makes a new geometry with all the points or vertices snapped to the closest point of the grid.
Point geometry type, with support for z-dimension and m-values.
void setY(double y)
Sets the point's y-coordinate.
void setX(double x)
Sets the point's x-coordinate.
A rectangle specified with double values.
bool contains(const QgsRectangle &rect) const
Returns true when rectangle contains other rectangle.
static Qgis::WkbType dropM(Qgis::WkbType type)
Drops the m dimension (if present) for a WKB type and returns the new type.
static Qgis::WkbType zmType(Qgis::WkbType type, bool hasZ, bool hasM)
Returns the modified input geometry type according to hasZ / hasM.
static Qgis::WkbType dropZ(Qgis::WkbType type)
Drops the z dimension (if present) for a WKB type and returns the new type.
static Qgis::WkbType addM(Qgis::WkbType type)
Adds the m dimension to a WKB type and returns the new type.
static Qgis::WkbType addZ(Qgis::WkbType type)
Adds the z dimension to a WKB type and returns the new type.
static Q_INVOKABLE bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
static Q_INVOKABLE bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
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.