28#include <nlohmann/json.hpp>
33#include <QDomDocument>
58 mX.resize(
points.count() );
59 mY.resize(
points.count() );
60 double *x = mX.data();
61 double *y = mY.data();
66 mZ.resize(
points.count() );
71 mM.resize(
points.count() );
86QgsLineString::QgsLineString(
const QVector<double> &x,
const QVector<double> &y,
const QVector<double> &z,
const QVector<double> &m,
bool is25DType )
89 int pointCount = std::min( x.size(), y.size() );
90 if ( x.size() == pointCount )
96 mX = x.mid( 0, pointCount );
98 if ( y.size() == pointCount )
104 mY = y.mid( 0, pointCount );
106 if ( !z.isEmpty() && z.count() >= pointCount )
109 if ( z.size() == pointCount )
115 mZ = z.mid( 0, pointCount );
118 if ( !m.isEmpty() && m.count() >= pointCount )
121 if ( m.size() == pointCount )
127 mM = m.mid( 0, pointCount );
160 mX.reserve(
points.size() );
161 mY.reserve(
points.size() );
180static double cubicInterpolate(
double a,
double b,
181 double A,
double B,
double C,
double D )
183 return A * b * b * b + 3 * B * b * b * a + 3 * C * b * a * a + D * a * a * a;
192 x.resize( segments + 1 );
194 y.resize( segments + 1 );
196 double *
zData =
nullptr;
197 if ( start.
is3D() && end.
is3D() && controlPoint1.
is3D() && controlPoint2.
is3D() )
199 z.resize( segments + 1 );
203 double *
mData =
nullptr;
206 m.resize( segments + 1 );
210 double *
xData = x.data();
211 double *
yData = y.data();
212 const double step = 1.0 / segments;
215 for (
int i = 0; i < segments; i++, a += step, b -= step )
228 *
xData++ = cubicInterpolate( a, b, start.
x(), controlPoint1.
x(), controlPoint2.
x(), end.
x() );
229 *
yData++ = cubicInterpolate( a, b, start.
y(), controlPoint1.
y(), controlPoint2.
y(), end.
y() );
231 *
zData++ = cubicInterpolate( a, b, start.
z(), controlPoint1.
z(), controlPoint2.
z(), end.
z() );
233 *
mData++ = cubicInterpolate( a, b, start.
m(), controlPoint1.
m(), controlPoint2.
m(), end.
m() );
251 x.resize( polygon.count() );
252 y.resize( polygon.count() );
253 double *
xData = x.data();
254 double *
yData = y.data();
256 const QPointF *src = polygon.data();
257 for (
int i = 0 ; i < polygon.size(); ++ i )
269 const QgsLineString *otherLine = qgsgeometry_cast< const QgsLineString * >( &other );
276 if ( mX.count() != otherLine->mX.count() )
279 for (
int i = 0; i < mX.count(); ++i )
317 const int size = mX.size();
321 const double *x = mX.constData();
322 const double *y = mY.constData();
323 const bool useZ =
is3D();
325 const double *z = useZ ? mZ.constData() :
nullptr;
326 const double *m = useM ? mM.constData() :
nullptr;
328 for (
int i = 0; i < size; ++i )
350 error = QObject::tr(
"LineString has less than 2 points and is not empty." );
361 bool res =
snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM,
362 result->mX, result->mY, result->mZ, result->mM );
364 return result.release();
371 if ( mX.count() <= 2 )
374 double prevX = mX.at( 0 );
375 double prevY = mY.at( 0 );
377 bool useZ = hasZ && useZValues;
378 double prevZ = useZ ? mZ.at( 0 ) : 0;
380 int remaining = mX.count();
381 while ( i < remaining )
383 double currentX = mX.at( i );
384 double currentY = mY.at( i );
385 double currentZ = useZ ? mZ.at( i ) : 0;
422 if (
is3D() && closed )
423 closed &=
qgsDoubleNear( mZ.first(), mZ.last() ) || ( std::isnan( mZ.first() ) && std::isnan( mZ.last() ) );
436 const int nb = mX.size();
445 if ( rectangle.
contains( mX.at( 0 ), mY.at( 0 ) ) ||
446 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.2 ) ), mY.at(
static_cast< int >( nb * 0.2 ) ) ) ||
447 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.4 ) ), mY.at(
static_cast< int >( nb * 0.4 ) ) ) ||
448 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.6 ) ), mY.at(
static_cast< int >( nb * 0.6 ) ) ) ||
449 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.8 ) ), mY.at(
static_cast< int >( nb * 0.8 ) ) ) ||
450 rectangle.
contains( mX.at( nb - 1 ), mY.at( nb - 1 ) ) )
459 double xmin = std::numeric_limits<double>::max();
460 double ymin = std::numeric_limits<double>::max();
461 double xmax = -std::numeric_limits<double>::max();
462 double ymax = -std::numeric_limits<double>::max();
464 const double *x = mX.constData();
465 const double *y = mY.constData();
466 bool foundPointInRectangle =
false;
467 for (
int i = 0; i < nb; ++i )
469 const double px = *x++;
470 xmin = std::min( xmin, px );
471 xmax = std::max( xmax, px );
472 const double py = *y++;
473 ymin = std::min( ymin, py );
474 ymax = std::max( ymax, py );
476 if ( !foundPointInRectangle && rectangle.
contains( px, py ) )
478 foundPointInRectangle =
true;
494 if ( foundPointInRectangle )
507 QVector< QgsVertexId > res;
508 if ( mX.count() <= 1 )
511 const double *x = mX.constData();
512 const double *y = mY.constData();
514 bool useZ = hasZ && useZValues;
515 const double *z = useZ ? mZ.constData() :
nullptr;
519 double prevZ = z ? *z++ : 0;
522 for (
int i = 1; i < mX.count(); ++i )
524 double currentX = *x++;
525 double currentY = *y++;
526 double currentZ = useZ ? *z++ : 0;
546 const int nb = mX.size();
549 const double *x = mX.constData();
550 const double *y = mY.constData();
551 QPointF *dest =
points.data();
552 for (
int i = 0; i < nb; ++i )
554 *dest++ = QPointF( *x++, *y++ );
572 importVerticesFromWkb( wkbPtr );
582 auto result = std::minmax_element( mX.begin(), mX.end() );
583 const double xmin = *result.first;
584 const double xmax = *result.second;
585 result = std::minmax_element( mY.begin(), mY.end() );
586 const double ymin = *result.first;
587 const double ymax = *result.second;
607 auto result = std::minmax_element( mZ.begin(), mZ.end() );
608 const double zmin = *result.first;
609 const double zmax = *result.second;
621 const int size = mX.size();
622 if ( index < 1 || index >= size - 1 )
625 const bool useZ =
is3D();
628 QVector<double> newX( size );
629 QVector<double> newY( size );
630 QVector<double> newZ( useZ ? size : 0 );
631 QVector<double> newM( useM ? size : 0 );
632 auto it = std::copy( mX.constBegin() + index, mX.constEnd() - 1, newX.begin() );
633 it = std::copy( mX.constBegin(), mX.constBegin() + index, it );
634 *it = *newX.constBegin();
635 mX = std::move( newX );
637 it = std::copy( mY.constBegin() + index, mY.constEnd() - 1, newY.begin() );
638 it = std::copy( mY.constBegin(), mY.constBegin() + index, it );
639 *it = *newY.constBegin();
640 mY = std::move( newY );
643 it = std::copy( mZ.constBegin() + index, mZ.constEnd() - 1, newZ.begin() );
644 it = std::copy( mZ.constBegin(), mZ.constBegin() + index, it );
645 *it = *newZ.constBegin();
646 mZ = std::move( newZ );
650 it = std::copy( mM.constBegin() + index, mM.constEnd() - 1, newM.begin() );
651 it = std::copy( mM.constBegin(), mM.constBegin() + index, it );
652 *it = *newM.constBegin();
653 mM = std::move( newM );
672 QString secondWithoutParentheses =
parts.second;
673 secondWithoutParentheses = secondWithoutParentheses.remove(
'(' ).remove(
')' ).simplified().remove(
' ' );
674 parts.second =
parts.second.remove(
'(' ).remove(
')' );
675 if ( (
parts.second.compare( QLatin1String(
"EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
676 secondWithoutParentheses.isEmpty() )
691 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
702 wkb << static_cast<quint32>(
wkbType() );
720 wkt += QLatin1String(
"EMPTY" );
735 QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral(
"LineString" ) );
738 return elemLineString;
742 return elemLineString;
750 QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral(
"LineString" ) );
753 return elemLineString;
756 return elemLineString;
765 {
"type",
"LineString" },
775 kml.append( QLatin1String(
"<LinearRing>" ) );
779 kml.append( QLatin1String(
"<LineString>" ) );
782 kml.append( QLatin1String(
"<altitudeMode>" ) );
785 kml.append( QLatin1String(
"absolute" ) );
789 kml.append( QLatin1String(
"clampToGround" ) );
791 kml.append( QLatin1String(
"</altitudeMode>" ) );
792 kml.append( QLatin1String(
"<coordinates>" ) );
794 int nPoints = mX.size();
795 for (
int i = 0; i < nPoints; ++i )
799 kml.append( QLatin1String(
" " ) );
802 kml.append( QLatin1String(
"," ) );
806 kml.append( QLatin1String(
"," ) );
811 kml.append( QLatin1String(
",0" ) );
814 kml.append( QLatin1String(
"</coordinates>" ) );
817 kml.append( QLatin1String(
"</LinearRing>" ) );
821 kml.append( QLatin1String(
"</LineString>" ) );
835 const int size = mX.size();
839 const double *x = mX.constData();
840 const double *y = mY.constData();
846 for (
int i = 1; i < size; ++i )
850 total += std::sqrt( dx * dx + dy * dy );
860 const bool useZ =
is3D();
863 const int size = mX.size();
865 return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >() );
867 index = std::clamp( index, 0, size - 1 );
869 const int part1Size = index + 1;
870 QVector< double > x1( part1Size );
871 QVector< double > y1( part1Size );
872 QVector< double > z1( useZ ? part1Size : 0 );
873 QVector< double > m1( useM ? part1Size : 0 );
875 const double *sourceX = mX.constData();
876 const double *sourceY = mY.constData();
877 const double *sourceZ = useZ ? mZ.constData() :
nullptr;
878 const double *sourceM = useM ? mM.constData() :
nullptr;
880 double *destX = x1.data();
881 double *destY = y1.data();
882 double *destZ = useZ ? z1.data() :
nullptr;
883 double *destM = useM ? m1.data() :
nullptr;
885 std::copy( sourceX, sourceX + part1Size, destX );
886 std::copy( sourceY, sourceY + part1Size, destY );
888 std::copy( sourceZ, sourceZ + part1Size, destZ );
890 std::copy( sourceM, sourceM + part1Size, destM );
892 const int part2Size = size - index;
894 return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >() );
896 QVector< double > x2( part2Size );
897 QVector< double > y2( part2Size );
898 QVector< double > z2( useZ ? part2Size : 0 );
899 QVector< double > m2( useM ? part2Size : 0 );
902 destZ = useZ ? z2.data() :
nullptr;
903 destM = useM ? m2.data() :
nullptr;
904 std::copy( sourceX + index, sourceX + size, destX );
905 std::copy( sourceY + index, sourceY + size, destY );
907 std::copy( sourceZ + index, sourceZ + size, destZ );
909 std::copy( sourceM + index, sourceM + size, destM );
912 return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
914 return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
922 const int size = mX.size();
926 const double *x = mX.constData();
927 const double *y = mY.constData();
928 const double *z = mZ.constData();
935 for (
int i = 1; i < size; ++i )
940 total += std::sqrt( dx * dx + dy * dy + dz * dz );
980 Q_UNUSED( tolerance )
981 Q_UNUSED( toleranceType )
997 if ( i < 0 || i >= mX.size() )
1002 double x = mX.at( i );
1003 double y = mY.at( i );
1004 double z = std::numeric_limits<double>::quiet_NaN();
1005 double m = std::numeric_limits<double>::quiet_NaN();
1023 else if ( hasZ && hasM )
1046 if ( index >= 0 && index < mX.size() )
1047 return mX.at( index );
1054 if ( index >= 0 && index < mY.size() )
1055 return mY.at( index );
1062 if ( index >= 0 && index < mX.size() )
1069 if ( index >= 0 && index < mY.size() )
1084 pts.reserve( nPoints );
1085 for (
int i = 0; i < nPoints; ++i )
1087 pts.push_back(
pointN( i ) );
1101 const bool hasZ =
static_cast< bool >( z );
1102 const bool hasM =
static_cast< bool >( m );
1123 double *destX = mX.data();
1124 double *destY = mY.data();
1125 double *destZ =
nullptr;
1135 double *destM =
nullptr;
1146 for (
size_t i = 0; i < size; ++i )
1173 bool hasZ = firstPt.
is3D();
1178 mX.resize(
points.size() );
1179 mY.resize(
points.size() );
1182 mZ.resize(
points.size() );
1190 mM.resize(
points.size() );
1197 for (
int i = 0; i <
points.size(); ++i )
1199 mX[i] =
points.at( i ).x();
1200 mY[i] =
points.at( i ).y();
1203 double z =
points.at( i ).z();
1204 mZ[i] = std::isnan( z ) ? 0 : z;
1208 double m =
points.at( i ).m();
1209 mM[i] = std::isnan( m ) ? 0 : m;
1262 mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
1275 mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
1285 std::reverse( copy->mX.begin(), copy->mX.end() );
1286 std::reverse( copy->mY.begin(), copy->mY.end() );
1289 std::reverse( copy->mZ.begin(), copy->mZ.end() );
1293 std::reverse( copy->mM.begin(), copy->mM.end() );
1298void QgsLineString::visitPointsByRegularDistance(
const double distance,
const std::function<
bool (
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double )> &visitPoint )
const
1303 double distanceTraversed = 0;
1305 if ( totalPoints == 0 )
1308 const double *x = mX.constData();
1309 const double *y = mY.constData();
1310 const double *z =
is3D() ? mZ.constData() :
nullptr;
1311 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1313 double prevX = *x++;
1314 double prevY = *y++;
1315 double prevZ = z ? *z++ : 0.0;
1316 double prevM = m ? *m++ : 0.0;
1320 visitPoint( prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM );
1324 double pZ = std::numeric_limits<double>::quiet_NaN();
1325 double pM = std::numeric_limits<double>::quiet_NaN();
1326 double nextPointDistance = distance;
1327 for (
int i = 1; i < totalPoints; ++i )
1329 double thisX = *x++;
1330 double thisY = *y++;
1331 double thisZ = z ? *z++ : 0.0;
1332 double thisM = m ? *m++ : 0.0;
1334 const double segmentLength = std::sqrt( ( thisX - prevX ) * ( thisX - prevX ) + ( thisY - prevY ) * ( thisY - prevY ) );
1338 const double distanceToPoint = std::min( nextPointDistance - distanceTraversed,
segmentLength );
1341 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &pZ :
nullptr,
1342 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &pM :
nullptr );
1344 if ( !visitPoint( pX, pY, pZ, pM, prevX, prevY, prevZ, prevM, thisX, thisY, thisZ, thisM ) )
1347 nextPointDistance += distance;
1369 std::unique_ptr< QgsPoint > res;
1370 visitPointsByRegularDistance( distance, [ & ](
double x,
double y,
double z,
double m,
double,
double,
double,
double,
double,
double,
double,
double )->
bool
1372 res = std::make_unique< QgsPoint >( pointType, x, y, z, m );
1375 return res.release();
1380 if ( startDistance < 0 && endDistance < 0 )
1383 endDistance = std::max( startDistance, endDistance );
1386 if ( totalPoints == 0 )
1389 QVector< QgsPoint > substringPoints;
1390 substringPoints.reserve( totalPoints );
1398 const double *x = mX.constData();
1399 const double *y = mY.constData();
1400 const double *z =
is3D() ? mZ.constData() :
nullptr;
1401 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1403 double distanceTraversed = 0;
1404 double prevX = *x++;
1405 double prevY = *y++;
1406 double prevZ = z ? *z++ : 0.0;
1407 double prevM = m ? *m++ : 0.0;
1408 bool foundStart =
false;
1410 if ( startDistance < 0 )
1413 for (
int i = 1; i < totalPoints; ++i )
1415 double thisX = *x++;
1416 double thisY = *y++;
1417 double thisZ = z ? *z++ : 0.0;
1418 double thisM = m ? *m++ : 0.0;
1420 const double segmentLength = std::sqrt( ( thisX - prevX ) * ( thisX - prevX ) + ( thisY - prevY ) * ( thisY - prevY ) );
1422 if ( distanceTraversed <= startDistance && startDistance < distanceTraversed +
segmentLength )
1425 const double distanceToStart = startDistance - distanceTraversed;
1426 double startX, startY;
1430 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &startZ :
nullptr,
1431 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &startM :
nullptr );
1432 substringPoints <<
QgsPoint( pointType, startX, startY, startZ, startM );
1435 if ( foundStart && ( distanceTraversed +
segmentLength > endDistance ) )
1438 const double distanceToEnd = endDistance - distanceTraversed;
1443 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &endZ :
nullptr,
1444 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &endM :
nullptr );
1445 substringPoints <<
QgsPoint( pointType, endX, endY, endZ, endM );
1447 else if ( foundStart )
1449 substringPoints <<
QgsPoint( pointType, thisX, thisY, thisZ, thisM );
1457 if ( distanceTraversed >= endDistance )
1462 if ( !foundStart &&
qgsDoubleNear( distanceTraversed, startDistance ) )
1464 substringPoints <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1465 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1490 if ( path.isEmpty() || path.currentPosition() != QPointF( mX.at( 0 ), mY.at( 0 ) ) )
1492 path.moveTo( mX.at( 0 ), mY.at( 0 ) );
1495 for (
int i = 1; i < nPoints; ++i )
1497 path.lineTo( mX.at( i ), mY.at( i ) );
1510 return compoundCurve;
1515 if ( mX.size() < 2 || mY.size() < 2 )
1519 if ( startDistance > 0 )
1521 double currentLen = std::sqrt( std::pow( mX.at( 0 ) - mX.at( 1 ), 2 ) +
1522 std::pow( mY.at( 0 ) - mY.at( 1 ), 2 ) );
1523 double newLen = currentLen + startDistance;
1524 mX[ 0 ] = mX.at( 1 ) + ( mX.at( 0 ) - mX.at( 1 ) ) / currentLen * newLen;
1525 mY[ 0 ] = mY.at( 1 ) + ( mY.at( 0 ) - mY.at( 1 ) ) / currentLen * newLen;
1528 if ( endDistance > 0 )
1530 int last = mX.size() - 1;
1531 double currentLen = std::sqrt( std::pow( mX.at( last ) - mX.at( last - 1 ), 2 ) +
1532 std::pow( mY.at( last ) - mY.at( last - 1 ), 2 ) );
1533 double newLen = currentLen + endDistance;
1534 mX[ last ] = mX.at( last - 1 ) + ( mX.at( last ) - mX.at( last - 1 ) ) / currentLen * newLen;
1535 mY[ last ] = mY.at( last - 1 ) + ( mY.at( last ) - mY.at( last - 1 ) ) / currentLen * newLen;
1541 auto result = std::make_unique< QgsLineString >();
1543 return result.release();
1548 const QgsLineString *otherLine = qgsgeometry_cast<const QgsLineString *>( other );
1552 const int size = mX.size();
1553 const int otherSize = otherLine->mX.size();
1554 if ( size > otherSize )
1558 else if ( size < otherSize )
1563 if (
is3D() && !otherLine->
is3D() )
1565 else if ( !
is3D() && otherLine->
is3D() )
1567 const bool considerZ =
is3D();
1575 for (
int i = 0; i < size; i++ )
1577 const double x = mX[i];
1578 const double otherX = otherLine->mX[i];
1583 else if ( x > otherX )
1588 const double y = mY[i];
1589 const double otherY = otherLine->mY[i];
1594 else if ( y > otherY )
1601 const double z = mZ[i];
1602 const double otherZ = otherLine->mZ[i];
1608 else if ( z > otherZ )
1616 const double m = mM[i];
1617 const double otherM = otherLine->mM[i];
1623 else if ( m > otherM )
1634 return QStringLiteral(
"LineString" );
1650 double *zArray =
nullptr;
1656 std::unique_ptr< double[] > dummyZ;
1657 if ( !hasZ || !transformZ )
1659 dummyZ.reset(
new double[nPoints]() );
1660 zArray = dummyZ.get();
1675 double *x = mX.data();
1676 double *y = mY.data();
1677 double *z = hasZ ? mZ.data() :
nullptr;
1678 double *m = hasM ? mM.data() :
nullptr;
1679 for (
int i = 0; i < nPoints; ++i )
1682 t.map( *x, *y, &xOut, &yOut );
1687 *z = *z * zScale + zTranslate;
1692 *m = *m * mScale + mTranslate;
1707 if ( position.
vertex < 0 || position.
vertex > mX.size() )
1717 mX.insert( position.
vertex, vertex.
x() );
1718 mY.insert( position.
vertex, vertex.
y() );
1721 mZ.insert( position.
vertex, vertex.
z() );
1725 mM.insert( position.
vertex, vertex.
m() );
1733 if ( position.
vertex < 0 || position.
vertex >= mX.size() )
1737 mX[position.
vertex] = newPos.
x();
1738 mY[position.
vertex] = newPos.
y();
1741 mZ[position.
vertex] = newPos.
z();
1745 mM[position.
vertex] = newPos.
m();
1753 if ( position.
vertex >= mX.size() || position.
vertex < 0 )
1758 mX.remove( position.
vertex );
1759 mY.remove( position.
vertex );
1762 mZ.remove( position.
vertex );
1766 mM.remove( position.
vertex );
1791 mX.append( pt.
x() );
1792 mY.append( pt.
y() );
1795 mZ.append( pt.
z() );
1799 mM.append( pt.
m() );
1806 double sqrDist = std::numeric_limits<double>::max();
1807 double leftOfDist = std::numeric_limits<double>::max();
1809 double prevLeftOfX = 0.0;
1810 double prevLeftOfY = 0.0;
1811 double testDist = 0;
1812 double segmentPtX, segmentPtY;
1817 int size = mX.size();
1818 if ( size == 0 || size == 1 )
1823 for (
int i = 1; i < size; ++i )
1825 double prevX = mX.at( i - 1 );
1826 double prevY = mY.at( i - 1 );
1827 double currentX = mX.at( i );
1828 double currentY = mY.at( i );
1830 if ( testDist < sqrDist )
1833 segmentPt.
setX( segmentPtX );
1834 segmentPt.
setY( segmentPtY );
1835 vertexAfter.
part = 0;
1836 vertexAfter.
ring = 0;
1847 if (
qgsDoubleNear( testDist, leftOfDist ) && left != prevLeftOf && prevLeftOf != 0 )
1860 leftOfDist = testDist;
1861 prevLeftOfX = prevX;
1862 prevLeftOfY = prevY;
1864 else if ( testDist < leftOfDist )
1867 leftOfDist = testDist;
1888 type = Qgis::VertexType::Segment;
1899 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
1901 double totalLineLength = 0.0;
1902 double prevX = mX.at( 0 );
1903 double prevY = mY.at( 0 );
1909 double currentX = mX.at( i );
1910 double currentY = mY.at( i );
1911 double segmentLength = std::sqrt( std::pow( currentX - prevX, 2.0 ) +
1912 std::pow( currentY - prevY, 2.0 ) );
1926 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
1928 return QgsPoint( sumX / totalLineLength, sumY / totalLineLength );
1947 const int maxIndex = mX.size();
1954 const double *x = mX.constData();
1955 const double *y = mY.constData();
1956 double prevX = *x++;
1957 double prevY = *y++;
1958 for (
int i = 1; i < maxIndex; ++i )
1960 mSummedUpArea += prevX * ( *y - prevY ) - prevY * ( *x - prevX );
1970void QgsLineString::importVerticesFromWkb(
const QgsConstWkbPtr &wkb )
1976 mX.resize( nVertices );
1977 mY.resize( nVertices );
1978 hasZ ? mZ.resize( nVertices ) : mZ.clear();
1979 hasM ? mM.resize( nVertices ) : mM.clear();
1980 double *x = mX.data();
1981 double *y = mY.data();
1982 double *m = hasM ? mM.data() :
nullptr;
1983 double *z = hasZ ? mZ.data() :
nullptr;
1984 for (
int i = 0; i < nVertices; ++i )
2017 if ( mX.count() < 2 )
2027 double previousX = mX.at(
numPoints() - 2 );
2028 double previousY = mY.at(
numPoints() - 2 );
2029 double currentX = mX.at( 0 );
2030 double currentY = mY.at( 0 );
2031 double afterX = mX.at( 1 );
2032 double afterY = mY.at( 1 );
2035 else if ( vertex.
vertex == 0 )
2048 double previousX = mX.at( vertex.
vertex - 1 );
2049 double previousY = mY.at( vertex.
vertex - 1 );
2050 double currentX = mX.at( vertex.
vertex );
2051 double currentY = mY.at( vertex.
vertex );
2052 double afterX = mX.at( vertex.
vertex + 1 );
2053 double afterY = mY.at( vertex.
vertex + 1 );
2060 if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 1 )
2063 double dx = mX.at( startVertex.
vertex + 1 ) - mX.at( startVertex.
vertex );
2064 double dy = mY.at( startVertex.
vertex + 1 ) - mY.at( startVertex.
vertex );
2065 return std::sqrt( dx * dx + dy * dy );
2090 mZ.reserve( nPoints );
2091 for (
int i = 0; i < nPoints; ++i )
2121 mM.reserve( nPoints );
2122 for (
int i = 0; i < nPoints; ++i )
2153 std::swap( mX, mY );
2167 addZValue( std::numeric_limits<double>::quiet_NaN() );
2184 int size = mX.size();
2186 double *srcX = mX.data();
2187 double *srcY = mY.data();
2188 double *srcM = hasM ? mM.data() :
nullptr;
2189 double *srcZ = hasZ ? mZ.data() :
nullptr;
2192 for (
int i = 0; i < size; ++i )
2196 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2197 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
2225 int size = mX.size();
2227 double *srcX = mX.data();
2228 double *srcY = mY.data();
2229 double *srcM = hasM ? mM.data() :
nullptr;
2230 double *srcZ = hasZ ? mZ.data() :
nullptr;
2232 double *destX = srcX;
2233 double *destY = srcY;
2234 double *destM = srcM;
2235 double *destZ = srcZ;
2237 int filteredPoints = 0;
2238 for (
int i = 0; i < size; ++i )
2242 double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
2243 double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
2245 if ( filter(
QgsPoint( x, y, z, m ) ) )
2257 mX.resize( filteredPoints );
2258 mY.resize( filteredPoints );
2260 mZ.resize( filteredPoints );
2262 mM.resize( filteredPoints );
2271 int size = mX.size();
2273 double *srcX = mX.data();
2274 double *srcY = mY.data();
2275 double *srcM = hasM ? mM.data() :
nullptr;
2276 double *srcZ = hasZ ? mZ.data() :
nullptr;
2278 for (
int i = 0; i < size; ++i )
2282 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2283 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
VertexType
Types of vertex.
WkbType
The WKB type describes the number of dimensions a geometry has.
@ LineString25D
LineString25D.
@ LineStringM
LineStringM.
@ LineStringZM
LineStringZM.
@ LineStringZ
LineStringZ.
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.
virtual bool convertTo(Qgis::WkbType type)
Converts the geometry to a specified type.
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
virtual bool boundingBoxIntersects(const QgsRectangle &rectangle) const SIP_HOLDGIL
Returns true if the bounding box of this geometry intersects with a rectangle.
AxisOrder
Axis order for GML generation.
QString wktTypeStr() const
Returns the WKT type string 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.
Qgis::WkbType wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts of the geometry.
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains 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).
Qgis::WkbType 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 SIP_HOLDGIL
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 SIP_HOLDGIL
Tells whether the operation has been canceled already.
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 double averageAngle(double x1, double y1, double x2, double y2, double x3, double y3) SIP_HOLDGIL
Calculates the average angle (in radians) between the two linear segments from (x1,...
static double lineAngle(double x1, double y1, double x2, double y2) SIP_HOLDGIL
Calculates the direction of line joining two points in radians, clockwise from the north direction.
static double sqrDistToLine(double ptX, double ptY, double x1, double y1, double x2, double y2, double &minDistX, double &minDistY, double epsilon) SIP_HOLDGIL
Returns the squared distance between a point and a line.
static QgsPoint pointOnLineWithDistance(const QgsPoint &startPoint, const QgsPoint &directionPoint, double distance) SIP_HOLDGIL
Returns a point a specified distance toward a second point.
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 int leftOfLine(const double x, const double y, const double x1, const double y1, const double x2, const double y2) SIP_HOLDGIL
Returns a value < 0 if the point (x, y) is left of the line from (x1, y1) -> (x2, y2).
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.
QgsPoint startPoint() const override SIP_HOLDGIL
Returns the starting point of the curve.
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.
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.
bool isClosed() const override SIP_HOLDGIL
Returns true if the curve is closed.
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.
void points(QgsPointSequence &pt) const override
Returns a list of points within the curve.
int dimension() const override SIP_HOLDGIL
Returns the inherent dimension of the geometry.
double length() const override SIP_HOLDGIL
Returns the planar, 2-dimensional length of the geometry.
void sumUpArea(double &sum) const override
Calculates the shoelace/triangle formula sum for the points in the linestring.
void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) override SIP_THROW(QgsCsException)
Transforms the geometry using a coordinate transform.
QgsPoint endPoint() const override SIP_HOLDGIL
Returns the end point of the curve.
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.
int numPoints() const override SIP_HOLDGIL
Returns the number of points in the curve.
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 boundingBoxIntersects(const QgsRectangle &rectangle) const override SIP_HOLDGIL
Returns true if the bounding box of this geometry intersects with a rectangle.
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.
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.
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
QString geometryType() const override SIP_HOLDGIL
Returns a unique string representing the geometry type.
bool isClosed2D() const override SIP_HOLDGIL
Returns true if the curve is closed.
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 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.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
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.
double length3D() const SIP_HOLDGIL
Returns the length in 3D world of the line string.
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.
QgsLineString() SIP_HOLDGIL
Constructor for an empty linestring geometry.
void setXAt(int index, double x)
Sets the x-coordinate of the specified node in the line string.
int nCoordinates() const override SIP_HOLDGIL
Returns the number of nodes contained in the geometry.
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 convertTo(Qgis::WkbType type) override
Converts the geometry to a specified type.
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 setX(double x) SIP_HOLDGIL
Sets the point's x-coordinate.
void setY(double y) SIP_HOLDGIL
Sets the point's y-coordinate.
A rectangle specified with double values.
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
bool intersects(const QgsRectangle &rect) const SIP_HOLDGIL
Returns true when rectangle intersects with other rectangle.
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
bool contains(const QgsRectangle &rect) const SIP_HOLDGIL
Returns true when rectangle contains other rectangle.
static Qgis::WkbType addZ(Qgis::WkbType type) SIP_HOLDGIL
Adds the z dimension to a WKB type and returns the new type.
static Qgis::WkbType addM(Qgis::WkbType type) SIP_HOLDGIL
Adds the m dimension to a WKB type and returns the new type.
static bool hasZ(Qgis::WkbType type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
static Qgis::WkbType dropZ(Qgis::WkbType type) SIP_HOLDGIL
Drops the z dimension (if present) for a WKB type and returns the new type.
static Qgis::WkbType dropM(Qgis::WkbType type) SIP_HOLDGIL
Drops the m dimension (if present) for a WKB type and returns the new type.
static bool hasM(Qgis::WkbType type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
static Qgis::WkbType flatType(Qgis::WkbType type) SIP_HOLDGIL
Returns the flat type for a WKB type.
static Qgis::WkbType zmType(Qgis::WkbType type, bool hasZ, bool hasM) SIP_HOLDGIL
Returns the modified input geometry type according to hasZ / hasM.
double ANALYSIS_EXPORT leftOf(const QgsPoint &thepoint, const QgsPoint *p1, const QgsPoint *p2)
Returns whether 'thepoint' is left or right of the line from 'p1' to 'p2'. Negative values mean left ...
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.