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 );
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;
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() );
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 )
270 const QgsLineString *otherLine = qgsgeometry_cast< const QgsLineString * >( &other );
277 if ( mX.count() != otherLine->mX.count() )
280 for (
int i = 0; i < mX.count(); ++i )
318 const int size = mX.size();
322 const double *x = mX.constData();
323 const double *y = mY.constData();
324 const bool useZ =
is3D();
326 const double *z = useZ ? mZ.constData() :
nullptr;
327 const double *m = useM ? mM.constData() :
nullptr;
329 for (
int i = 0; i < size; ++i )
351 error = QObject::tr(
"LineString has less than 2 points and is not empty." );
362 bool res =
snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM,
363 result->mX, result->mY, result->mZ, result->mM );
365 return result.release();
372 if ( mX.count() <= 2 )
375 double prevX = mX.at( 0 );
376 double prevY = mY.at( 0 );
378 bool useZ = hasZ && useZValues;
379 double prevZ = useZ ? mZ.at( 0 ) : 0;
381 int remaining = mX.count();
382 while ( i < remaining )
384 double currentX = mX.at( i );
385 double currentY = mY.at( i );
386 double currentZ = useZ ? mZ.at( i ) : 0;
423 if (
is3D() && closed )
424 closed &=
qgsDoubleNear( mZ.first(), mZ.last() ) || ( std::isnan( mZ.first() ) && std::isnan( mZ.last() ) );
437 const int nb = mX.size();
446 if ( rectangle.
contains( mX.at( 0 ), mY.at( 0 ) ) ||
447 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.2 ) ), mY.at(
static_cast< int >( nb * 0.2 ) ) ) ||
448 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.4 ) ), mY.at(
static_cast< int >( nb * 0.4 ) ) ) ||
449 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.6 ) ), mY.at(
static_cast< int >( nb * 0.6 ) ) ) ||
450 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.8 ) ), mY.at(
static_cast< int >( nb * 0.8 ) ) ) ||
451 rectangle.
contains( mX.at( nb - 1 ), mY.at( nb - 1 ) ) )
460 double xmin = std::numeric_limits<double>::max();
461 double ymin = std::numeric_limits<double>::max();
462 double xmax = -std::numeric_limits<double>::max();
463 double ymax = -std::numeric_limits<double>::max();
465 const double *x = mX.constData();
466 const double *y = mY.constData();
467 bool foundPointInRectangle =
false;
468 for (
int i = 0; i < nb; ++i )
470 const double px = *x++;
471 xmin = std::min( xmin, px );
472 xmax = std::max( xmax, px );
473 const double py = *y++;
474 ymin = std::min( ymin, py );
475 ymax = std::max( ymax, py );
477 if ( !foundPointInRectangle && rectangle.
contains( px, py ) )
479 foundPointInRectangle =
true;
495 if ( foundPointInRectangle )
508 QVector< QgsVertexId > res;
509 if ( mX.count() <= 1 )
512 const double *x = mX.constData();
513 const double *y = mY.constData();
515 bool useZ = hasZ && useZValues;
516 const double *z = useZ ? mZ.constData() :
nullptr;
520 double prevZ = z ? *z++ : 0;
523 for (
int i = 1; i < mX.count(); ++i )
525 double currentX = *x++;
526 double currentY = *y++;
527 double currentZ = useZ ? *z++ : 0;
547 const int nb = mX.size();
550 const double *x = mX.constData();
551 const double *y = mY.constData();
552 QPointF *dest =
points.data();
553 for (
int i = 0; i < nb; ++i )
555 *dest++ = QPointF( *x++, *y++ );
573 importVerticesFromWkb( wkbPtr );
583 auto result = std::minmax_element( mX.begin(), mX.end() );
584 const double xmin = *result.first;
585 const double xmax = *result.second;
586 result = std::minmax_element( mY.begin(), mY.end() );
587 const double ymin = *result.first;
588 const double ymax = *result.second;
608 auto result = std::minmax_element( mZ.begin(), mZ.end() );
609 const double zmin = *result.first;
610 const double zmax = *result.second;
622 const int size = mX.size();
623 if ( index < 1 || index >= size - 1 )
626 const bool useZ =
is3D();
629 QVector<double> newX( size );
630 QVector<double> newY( size );
631 QVector<double> newZ( useZ ? size : 0 );
632 QVector<double> newM( useM ? size : 0 );
633 auto it = std::copy( mX.constBegin() + index, mX.constEnd() - 1, newX.begin() );
634 it = std::copy( mX.constBegin(), mX.constBegin() + index, it );
635 *it = *newX.constBegin();
636 mX = std::move( newX );
638 it = std::copy( mY.constBegin() + index, mY.constEnd() - 1, newY.begin() );
639 it = std::copy( mY.constBegin(), mY.constBegin() + index, it );
640 *it = *newY.constBegin();
641 mY = std::move( newY );
644 it = std::copy( mZ.constBegin() + index, mZ.constEnd() - 1, newZ.begin() );
645 it = std::copy( mZ.constBegin(), mZ.constBegin() + index, it );
646 *it = *newZ.constBegin();
647 mZ = std::move( newZ );
651 it = std::copy( mM.constBegin() + index, mM.constEnd() - 1, newM.begin() );
652 it = std::copy( mM.constBegin(), mM.constBegin() + index, it );
653 *it = *newM.constBegin();
654 mM = std::move( newM );
673 QString secondWithoutParentheses =
parts.second;
674 secondWithoutParentheses = secondWithoutParentheses.remove(
'(' ).remove(
')' ).simplified().remove(
' ' );
675 parts.second =
parts.second.remove(
'(' ).remove(
')' );
676 if ( (
parts.second.compare( QLatin1String(
"EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
677 secondWithoutParentheses.isEmpty() )
692 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
703 wkb << static_cast<quint32>(
wkbType() );
721 wkt += QLatin1String(
"EMPTY" );
736 QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral(
"LineString" ) );
739 return elemLineString;
743 return elemLineString;
751 QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral(
"LineString" ) );
754 return elemLineString;
757 return elemLineString;
766 {
"type",
"LineString" },
776 kml.append( QLatin1String(
"<LinearRing>" ) );
780 kml.append( QLatin1String(
"<LineString>" ) );
783 kml.append( QLatin1String(
"<altitudeMode>" ) );
786 kml.append( QLatin1String(
"absolute" ) );
790 kml.append( QLatin1String(
"clampToGround" ) );
792 kml.append( QLatin1String(
"</altitudeMode>" ) );
793 kml.append( QLatin1String(
"<coordinates>" ) );
795 int nPoints = mX.size();
796 for (
int i = 0; i < nPoints; ++i )
800 kml.append( QLatin1String(
" " ) );
803 kml.append( QLatin1String(
"," ) );
807 kml.append( QLatin1String(
"," ) );
812 kml.append( QLatin1String(
",0" ) );
815 kml.append( QLatin1String(
"</coordinates>" ) );
818 kml.append( QLatin1String(
"</LinearRing>" ) );
822 kml.append( QLatin1String(
"</LineString>" ) );
836 const int size = mX.size();
840 const double *x = mX.constData();
841 const double *y = mY.constData();
847 for (
int i = 1; i < size; ++i )
851 total += std::sqrt( dx * dx + dy * dy );
861 const bool useZ =
is3D();
864 const int size = mX.size();
866 return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >() );
868 index = std::clamp( index, 0, size - 1 );
870 const int part1Size = index + 1;
871 QVector< double > x1( part1Size );
872 QVector< double > y1( part1Size );
873 QVector< double > z1( useZ ? part1Size : 0 );
874 QVector< double > m1( useM ? part1Size : 0 );
876 const double *sourceX = mX.constData();
877 const double *sourceY = mY.constData();
878 const double *sourceZ = useZ ? mZ.constData() :
nullptr;
879 const double *sourceM = useM ? mM.constData() :
nullptr;
881 double *destX = x1.data();
882 double *destY = y1.data();
883 double *destZ = useZ ? z1.data() :
nullptr;
884 double *destM = useM ? m1.data() :
nullptr;
886 std::copy( sourceX, sourceX + part1Size, destX );
887 std::copy( sourceY, sourceY + part1Size, destY );
889 std::copy( sourceZ, sourceZ + part1Size, destZ );
891 std::copy( sourceM, sourceM + part1Size, destM );
893 const int part2Size = size - index;
895 return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >() );
897 QVector< double > x2( part2Size );
898 QVector< double > y2( part2Size );
899 QVector< double > z2( useZ ? part2Size : 0 );
900 QVector< double > m2( useM ? part2Size : 0 );
903 destZ = useZ ? z2.data() :
nullptr;
904 destM = useM ? m2.data() :
nullptr;
905 std::copy( sourceX + index, sourceX + size, destX );
906 std::copy( sourceY + index, sourceY + size, destY );
908 std::copy( sourceZ + index, sourceZ + size, destZ );
910 std::copy( sourceM + index, sourceM + size, destM );
913 return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
915 return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
923 const int size = mX.size();
927 const double *x = mX.constData();
928 const double *y = mY.constData();
929 const double *z = mZ.constData();
936 for (
int i = 1; i < size; ++i )
941 total += std::sqrt( dx * dx + dy * dy + dz * dz );
981 Q_UNUSED( tolerance )
982 Q_UNUSED( toleranceType )
998 if ( i < 0 || i >= mX.size() )
1003 double x = mX.at( i );
1004 double y = mY.at( i );
1005 double z = std::numeric_limits<double>::quiet_NaN();
1006 double m = std::numeric_limits<double>::quiet_NaN();
1024 else if ( hasZ && hasM )
1047 if ( index >= 0 && index < mX.size() )
1048 return mX.at( index );
1055 if ( index >= 0 && index < mY.size() )
1056 return mY.at( index );
1063 if ( index >= 0 && index < mX.size() )
1070 if ( index >= 0 && index < mY.size() )
1085 pts.reserve( nPoints );
1086 for (
int i = 0; i < nPoints; ++i )
1088 pts.push_back(
pointN( i ) );
1102 const bool hasZ =
static_cast< bool >( z );
1103 const bool hasM =
static_cast< bool >( m );
1124 double *destX = mX.data();
1125 double *destY = mY.data();
1126 double *destZ =
nullptr;
1136 double *destM =
nullptr;
1147 for (
size_t i = 0; i < size; ++i )
1174 bool hasZ = firstPt.
is3D();
1179 mX.resize(
points.size() );
1180 mY.resize(
points.size() );
1183 mZ.resize(
points.size() );
1191 mM.resize(
points.size() );
1198 for (
int i = 0; i <
points.size(); ++i )
1200 mX[i] =
points.at( i ).x();
1201 mY[i] =
points.at( i ).y();
1204 double z =
points.at( i ).z();
1205 mZ[i] = std::isnan( z ) ? 0 : z;
1209 double m =
points.at( i ).m();
1210 mM[i] = std::isnan( m ) ? 0 : m;
1263 mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
1276 mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
1286 std::reverse( copy->mX.begin(), copy->mX.end() );
1287 std::reverse( copy->mY.begin(), copy->mY.end() );
1290 std::reverse( copy->mZ.begin(), copy->mZ.end() );
1294 std::reverse( copy->mM.begin(), copy->mM.end() );
1299void QgsLineString::visitPointsByRegularDistance(
const double distance,
const std::function<
bool (
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double )> &visitPoint )
const
1304 double distanceTraversed = 0;
1306 if ( totalPoints == 0 )
1309 const double *x = mX.constData();
1310 const double *y = mY.constData();
1311 const double *z =
is3D() ? mZ.constData() :
nullptr;
1312 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1314 double prevX = *x++;
1315 double prevY = *y++;
1316 double prevZ = z ? *z++ : 0.0;
1317 double prevM = m ? *m++ : 0.0;
1321 visitPoint( prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM );
1325 double pZ = std::numeric_limits<double>::quiet_NaN();
1326 double pM = std::numeric_limits<double>::quiet_NaN();
1327 double nextPointDistance = distance;
1328 for (
int i = 1; i < totalPoints; ++i )
1330 double thisX = *x++;
1331 double thisY = *y++;
1332 double thisZ = z ? *z++ : 0.0;
1333 double thisM = m ? *m++ : 0.0;
1335 const double segmentLength = std::sqrt( ( thisX - prevX ) * ( thisX - prevX ) + ( thisY - prevY ) * ( thisY - prevY ) );
1339 const double distanceToPoint = std::min( nextPointDistance - distanceTraversed,
segmentLength );
1342 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &pZ :
nullptr,
1343 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &pM : nullptr );
1345 if ( !visitPoint( pX, pY, pZ, pM, prevX, prevY, prevZ, prevM, thisX, thisY, thisZ, thisM ) )
1348 nextPointDistance += distance;
1370 std::unique_ptr< QgsPoint > res;
1371 visitPointsByRegularDistance( distance, [ & ](
double x,
double y,
double z,
double m,
double,
double,
double,
double,
double,
double,
double,
double )->
bool
1373 res = std::make_unique< QgsPoint >( pointType, x, y, z, m );
1376 return res.release();
1381 if ( startDistance < 0 && endDistance < 0 )
1384 endDistance = std::max( startDistance, endDistance );
1387 if ( totalPoints == 0 )
1390 QVector< QgsPoint > substringPoints;
1391 substringPoints.reserve( totalPoints );
1399 const double *x = mX.constData();
1400 const double *y = mY.constData();
1401 const double *z =
is3D() ? mZ.constData() :
nullptr;
1402 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1404 double distanceTraversed = 0;
1405 double prevX = *x++;
1406 double prevY = *y++;
1407 double prevZ = z ? *z++ : 0.0;
1408 double prevM = m ? *m++ : 0.0;
1409 bool foundStart =
false;
1411 if ( startDistance < 0 )
1414 for (
int i = 1; i < totalPoints; ++i )
1416 double thisX = *x++;
1417 double thisY = *y++;
1418 double thisZ = z ? *z++ : 0.0;
1419 double thisM = m ? *m++ : 0.0;
1421 const double segmentLength = std::sqrt( ( thisX - prevX ) * ( thisX - prevX ) + ( thisY - prevY ) * ( thisY - prevY ) );
1423 if ( distanceTraversed <= startDistance && startDistance < distanceTraversed +
segmentLength )
1426 const double distanceToStart = startDistance - distanceTraversed;
1427 double startX, startY;
1431 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &startZ :
nullptr,
1432 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &startM : nullptr );
1433 substringPoints <<
QgsPoint( pointType, startX, startY, startZ, startM );
1436 if ( foundStart && ( distanceTraversed +
segmentLength > endDistance ) )
1439 const double distanceToEnd = endDistance - distanceTraversed;
1444 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &endZ :
nullptr,
1445 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &endM : nullptr );
1446 substringPoints <<
QgsPoint( pointType, endX, endY, endZ, endM );
1448 else if ( foundStart )
1450 substringPoints <<
QgsPoint( pointType, thisX, thisY, thisZ, thisM );
1458 if ( distanceTraversed >= endDistance )
1463 if ( !foundStart &&
qgsDoubleNear( distanceTraversed, startDistance ) )
1465 substringPoints <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1466 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1491 if ( path.isEmpty() || path.currentPosition() != QPointF( mX.at( 0 ), mY.at( 0 ) ) )
1493 path.moveTo( mX.at( 0 ), mY.at( 0 ) );
1496 for (
int i = 1; i < nPoints; ++i )
1498 path.lineTo( mX.at( i ), mY.at( i ) );
1511 return compoundCurve;
1516 if ( mX.size() < 2 || mY.size() < 2 )
1519 const bool extendStart = startDistance > 0;
1520 const bool extendEnd = endDistance > 0;
1525 const double currentLen = std::sqrt( std::pow( mX.at( 0 ) - mX.at( 1 ), 2 ) +
1526 std::pow( mY.at( 0 ) - mY.at( 1 ), 2 ) );
1527 const double newLen = currentLen + startDistance;
1528 mX[ 0 ] = mX.at( 1 ) + ( mX.at( 0 ) - mX.at( 1 ) ) / currentLen * newLen;
1529 mY[ 0 ] = mY.at( 1 ) + ( mY.at( 0 ) - mY.at( 1 ) ) / currentLen * newLen;
1534 const int last = mX.size() - 1;
1535 const double currentLen = std::sqrt( std::pow( mX.at( last ) - mX.at( last - 1 ), 2 ) +
1536 std::pow( mY.at( last ) - mY.at( last - 1 ), 2 ) );
1537 const double newLen = currentLen + endDistance;
1538 mX[ last ] = mX.at( last - 1 ) + ( mX.at( last ) - mX.at( last - 1 ) ) / currentLen * newLen;
1539 mY[ last ] = mY.at( last - 1 ) + ( mY.at( last ) - mY.at( last - 1 ) ) / currentLen * newLen;
1542 if ( extendStart || extendEnd )
1548 auto result = std::make_unique< QgsLineString >();
1550 return result.release();
1555 const QgsLineString *otherLine = qgsgeometry_cast<const QgsLineString *>( other );
1559 const int size = mX.size();
1560 const int otherSize = otherLine->mX.size();
1561 if ( size > otherSize )
1565 else if ( size < otherSize )
1570 if (
is3D() && !otherLine->
is3D() )
1572 else if ( !
is3D() && otherLine->
is3D() )
1574 const bool considerZ =
is3D();
1582 for (
int i = 0; i < size; i++ )
1584 const double x = mX[i];
1585 const double otherX = otherLine->mX[i];
1590 else if ( x > otherX )
1595 const double y = mY[i];
1596 const double otherY = otherLine->mY[i];
1601 else if ( y > otherY )
1608 const double z = mZ[i];
1609 const double otherZ = otherLine->mZ[i];
1615 else if ( z > otherZ )
1623 const double m = mM[i];
1624 const double otherM = otherLine->mM[i];
1630 else if ( m > otherM )
1641 return QStringLiteral(
"LineString" );
1657 double *zArray =
nullptr;
1663 std::unique_ptr< double[] > dummyZ;
1664 if ( !hasZ || !transformZ )
1666 dummyZ.reset(
new double[nPoints]() );
1667 zArray = dummyZ.get();
1682 double *x = mX.data();
1683 double *y = mY.data();
1684 double *z = hasZ ? mZ.data() :
nullptr;
1685 double *m = hasM ? mM.data() :
nullptr;
1686 for (
int i = 0; i < nPoints; ++i )
1689 t.map( *x, *y, &xOut, &yOut );
1694 *z = *z * zScale + zTranslate;
1699 *m = *m * mScale + mTranslate;
1714 if ( position.
vertex < 0 || position.
vertex > mX.size() )
1724 mX.insert( position.
vertex, vertex.
x() );
1725 mY.insert( position.
vertex, vertex.
y() );
1728 mZ.insert( position.
vertex, vertex.
z() );
1732 mM.insert( position.
vertex, vertex.
m() );
1740 if ( position.
vertex < 0 || position.
vertex >= mX.size() )
1744 mX[position.
vertex] = newPos.
x();
1745 mY[position.
vertex] = newPos.
y();
1748 mZ[position.
vertex] = newPos.
z();
1752 mM[position.
vertex] = newPos.
m();
1760 if ( position.
vertex >= mX.size() || position.
vertex < 0 )
1765 mX.remove( position.
vertex );
1766 mY.remove( position.
vertex );
1769 mZ.remove( position.
vertex );
1773 mM.remove( position.
vertex );
1798 mX.append( pt.
x() );
1799 mY.append( pt.
y() );
1802 mZ.append( pt.
z() );
1806 mM.append( pt.
m() );
1813 double sqrDist = std::numeric_limits<double>::max();
1814 double leftOfDist = std::numeric_limits<double>::max();
1816 double prevLeftOfX = 0.0;
1817 double prevLeftOfY = 0.0;
1818 double testDist = 0;
1819 double segmentPtX, segmentPtY;
1824 int size = mX.size();
1825 if ( size == 0 || size == 1 )
1830 for (
int i = 1; i < size; ++i )
1832 double prevX = mX.at( i - 1 );
1833 double prevY = mY.at( i - 1 );
1834 double currentX = mX.at( i );
1835 double currentY = mY.at( i );
1837 if ( testDist < sqrDist )
1840 segmentPt.
setX( segmentPtX );
1841 segmentPt.
setY( segmentPtY );
1842 vertexAfter.
part = 0;
1843 vertexAfter.
ring = 0;
1854 if (
qgsDoubleNear( testDist, leftOfDist ) && left != prevLeftOf && prevLeftOf != 0 )
1866 prevLeftOf = *leftOf;
1867 leftOfDist = testDist;
1868 prevLeftOfX = prevX;
1869 prevLeftOfY = prevY;
1871 else if ( testDist < leftOfDist )
1874 leftOfDist = testDist;
1906 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
1908 double totalLineLength = 0.0;
1909 double prevX = mX.at( 0 );
1910 double prevY = mY.at( 0 );
1916 double currentX = mX.at( i );
1917 double currentY = mY.at( i );
1918 double segmentLength = std::sqrt( std::pow( currentX - prevX, 2.0 ) +
1919 std::pow( currentY - prevY, 2.0 ) );
1933 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
1935 return QgsPoint( sumX / totalLineLength, sumY / totalLineLength );
1954 const int maxIndex = mX.size();
1955 if ( maxIndex == 0 )
1958 const double *x = mX.constData();
1959 const double *y = mY.constData();
1960 double prevX = *x++;
1961 double prevY = *y++;
1962 for (
int i = 1; i < maxIndex; ++i )
1974void QgsLineString::importVerticesFromWkb(
const QgsConstWkbPtr &wkb )
1980 mX.resize( nVertices );
1981 mY.resize( nVertices );
1982 hasZ ? mZ.resize( nVertices ) : mZ.clear();
1983 hasM ? mM.resize( nVertices ) : mM.clear();
1984 double *x = mX.data();
1985 double *y = mY.data();
1986 double *m = hasM ? mM.data() :
nullptr;
1987 double *z = hasZ ? mZ.data() :
nullptr;
1988 for (
int i = 0; i < nVertices; ++i )
2021 if ( mX.count() < 2 )
2031 double previousX = mX.at(
numPoints() - 2 );
2032 double previousY = mY.at(
numPoints() - 2 );
2033 double currentX = mX.at( 0 );
2034 double currentY = mY.at( 0 );
2035 double afterX = mX.at( 1 );
2036 double afterY = mY.at( 1 );
2039 else if ( vertex.
vertex == 0 )
2052 double previousX = mX.at( vertex.
vertex - 1 );
2053 double previousY = mY.at( vertex.
vertex - 1 );
2054 double currentX = mX.at( vertex.
vertex );
2055 double currentY = mY.at( vertex.
vertex );
2056 double afterX = mX.at( vertex.
vertex + 1 );
2057 double afterY = mY.at( vertex.
vertex + 1 );
2064 if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 1 )
2067 double dx = mX.at( startVertex.
vertex + 1 ) - mX.at( startVertex.
vertex );
2068 double dy = mY.at( startVertex.
vertex + 1 ) - mY.at( startVertex.
vertex );
2069 return std::sqrt( dx * dx + dy * dy );
2094 mZ.reserve( nPoints );
2095 for (
int i = 0; i < nPoints; ++i )
2125 mM.reserve( nPoints );
2126 for (
int i = 0; i < nPoints; ++i )
2157 std::swap( mX, mY );
2171 addZValue( std::numeric_limits<double>::quiet_NaN() );
2188 int size = mX.size();
2190 double *srcX = mX.data();
2191 double *srcY = mY.data();
2192 double *srcM = hasM ? mM.data() :
nullptr;
2193 double *srcZ = hasZ ? mZ.data() :
nullptr;
2196 for (
int i = 0; i < size; ++i )
2200 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2201 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
2229 int size = mX.size();
2231 double *srcX = mX.data();
2232 double *srcY = mY.data();
2233 double *srcM = hasM ? mM.data() :
nullptr;
2234 double *srcZ = hasZ ? mZ.data() :
nullptr;
2236 double *destX = srcX;
2237 double *destY = srcY;
2238 double *destM = srcM;
2239 double *destZ = srcZ;
2241 int filteredPoints = 0;
2242 for (
int i = 0; i < size; ++i )
2246 double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
2247 double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
2249 if ( filter(
QgsPoint( x, y, z, m ) ) )
2261 mX.resize( filteredPoints );
2262 mY.resize( filteredPoints );
2264 mZ.resize( filteredPoints );
2266 mM.resize( filteredPoints );
2275 int size = mX.size();
2277 double *srcX = mX.data();
2278 double *srcY = mY.data();
2279 double *srcM = hasM ? mM.data() :
nullptr;
2280 double *srcZ = hasZ ? mZ.data() :
nullptr;
2282 for (
int i = 0; i < size; ++i )
2286 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2287 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
VertexType
Types of vertex.
@ Segment
The actual start or end point of a segment.
TransformDirection
Flags for raster layer temporal capabilities.
Abstract base class for all geometries.
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
bool isMeasure() const
Returns true if the geometry contains m values.
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.
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
virtual bool convertTo(QgsWkbTypes::Type type)
Converts the geometry to a specified type.
virtual bool boundingBoxIntersects(const QgsRectangle &rectangle) const
Returns true if the bounding box of this geometry intersects with a rectangle.
QgsWkbTypes::Type mWkbType
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts of the geometry.
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, QgsWkbTypes::Type baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
static endian_t endian()
Returns whether this machine uses big or little endian.
A 3-dimensional box composed of x, y, z coordinates.
Compound curve geometry type.
void addCurve(QgsCurve *c, bool extendPrevious=false)
Adds a curve to the geometry (takes ownership).
QgsWkbTypes::Type readHeader() const
readHeader
Abstract base class for curved geometry type.
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 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) const
Helper function for QgsCurve subclasses to snap to grids.
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
QgsRectangle 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.
static QPair< QgsWkbTypes::Type, QString > wktReadBlock(const QString &wkt)
Parses a WKT block of the format "TYPE( contents )" and returns a pair of geometry type to contents (...
static QgsPoint pointOnLineWithDistance(const QgsPoint &startPoint, const QgsPoint &directionPoint, double distance)
Returns a point a specified distance toward a second point.
static json pointsToJson(const QgsPointSequence &points, int precision)
Returns coordinates as json object.
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 void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure, QgsAbstractGeometry::WkbFlags flags)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
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 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.
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 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,...
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.
QgsLineString * snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0) const override
Makes a new geometry with all the points or vertices snapped to the closest point of the grid.
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 equals(const QgsCurve &other) const override
Checks whether this curve exactly equals another curve.
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
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.
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.
static 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 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.
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 convertTo(QgsWkbTypes::Type type) override
Converts the geometry to a specified type.
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.
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.
static QgsLineString * fromQPolygonF(const QPolygonF &polygon)
Returns a new linestring from a QPolygonF polygon input.
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.
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.
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.
QgsBox3d calculateBoundingBox3d() const
Calculates the minimal 3D bounding box for the geometry.
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.
QgsRectangle calculateBoundingBox() const override
Default calculator for the minimal bounding box for the geometry.
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.
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
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 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.
A class to represent a 2D point.
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.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
bool intersects(const QgsRectangle &rect) const
Returns true when rectangle intersects with other rectangle.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double xMaximum() const
Returns the x maximum value (right side of rectangle).
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
static Type addM(Type type)
Adds the m dimension to a WKB type and returns the new type.
static Type dropZ(Type type)
Drops the z dimension (if present) for a WKB type and returns the new type.
static Type dropM(Type type)
Drops the m dimension (if present) for a WKB type and returns the new type.
Type
The WKB type describes the number of dimensions a geometry has.
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
static bool hasM(Type type)
Tests whether a WKB type contains m values.
static Type zmType(Type type, bool hasZ, bool hasM)
Returns the modified input geometry type according to hasZ / hasM.
static Type addZ(Type type)
Adds the z dimension to a WKB type and returns the new type.
static Type flatType(Type 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
QLineF segment(int index, QRectF rect, double radius)
Utility class for identifying a unique vertex within a geometry.