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 )
1520 if ( startDistance > 0 )
1522 double currentLen = std::sqrt( std::pow( mX.at( 0 ) - mX.at( 1 ), 2 ) +
1523 std::pow( mY.at( 0 ) - mY.at( 1 ), 2 ) );
1524 double newLen = currentLen + startDistance;
1525 mX[ 0 ] = mX.at( 1 ) + ( mX.at( 0 ) - mX.at( 1 ) ) / currentLen * newLen;
1526 mY[ 0 ] = mY.at( 1 ) + ( mY.at( 0 ) - mY.at( 1 ) ) / currentLen * newLen;
1529 if ( endDistance > 0 )
1531 int last = mX.size() - 1;
1532 double currentLen = std::sqrt( std::pow( mX.at( last ) - mX.at( last - 1 ), 2 ) +
1533 std::pow( mY.at( last ) - mY.at( last - 1 ), 2 ) );
1534 double newLen = currentLen + endDistance;
1535 mX[ last ] = mX.at( last - 1 ) + ( mX.at( last ) - mX.at( last - 1 ) ) / currentLen * newLen;
1536 mY[ last ] = mY.at( last - 1 ) + ( mY.at( last ) - mY.at( last - 1 ) ) / currentLen * newLen;
1542 auto result = std::make_unique< QgsLineString >();
1544 return result.release();
1549 const QgsLineString *otherLine = qgsgeometry_cast<const QgsLineString *>( other );
1553 const int size = mX.size();
1554 const int otherSize = otherLine->mX.size();
1555 if ( size > otherSize )
1559 else if ( size < otherSize )
1564 if (
is3D() && !otherLine->
is3D() )
1566 else if ( !
is3D() && otherLine->
is3D() )
1568 const bool considerZ =
is3D();
1576 for (
int i = 0; i < size; i++ )
1578 const double x = mX[i];
1579 const double otherX = otherLine->mX[i];
1584 else if ( x > otherX )
1589 const double y = mY[i];
1590 const double otherY = otherLine->mY[i];
1595 else if ( y > otherY )
1602 const double z = mZ[i];
1603 const double otherZ = otherLine->mZ[i];
1609 else if ( z > otherZ )
1617 const double m = mM[i];
1618 const double otherM = otherLine->mM[i];
1624 else if ( m > otherM )
1635 return QStringLiteral(
"LineString" );
1651 double *zArray =
nullptr;
1657 std::unique_ptr< double[] > dummyZ;
1658 if ( !hasZ || !transformZ )
1660 dummyZ.reset(
new double[nPoints]() );
1661 zArray = dummyZ.get();
1676 double *x = mX.data();
1677 double *y = mY.data();
1678 double *z = hasZ ? mZ.data() :
nullptr;
1679 double *m = hasM ? mM.data() :
nullptr;
1680 for (
int i = 0; i < nPoints; ++i )
1683 t.map( *x, *y, &xOut, &yOut );
1688 *z = *z * zScale + zTranslate;
1693 *m = *m * mScale + mTranslate;
1708 if ( position.
vertex < 0 || position.
vertex > mX.size() )
1718 mX.insert( position.
vertex, vertex.
x() );
1719 mY.insert( position.
vertex, vertex.
y() );
1722 mZ.insert( position.
vertex, vertex.
z() );
1726 mM.insert( position.
vertex, vertex.
m() );
1734 if ( position.
vertex < 0 || position.
vertex >= mX.size() )
1738 mX[position.
vertex] = newPos.
x();
1739 mY[position.
vertex] = newPos.
y();
1742 mZ[position.
vertex] = newPos.
z();
1746 mM[position.
vertex] = newPos.
m();
1754 if ( position.
vertex >= mX.size() || position.
vertex < 0 )
1759 mX.remove( position.
vertex );
1760 mY.remove( position.
vertex );
1763 mZ.remove( position.
vertex );
1767 mM.remove( position.
vertex );
1792 mX.append( pt.
x() );
1793 mY.append( pt.
y() );
1796 mZ.append( pt.
z() );
1800 mM.append( pt.
m() );
1807 double sqrDist = std::numeric_limits<double>::max();
1808 double leftOfDist = std::numeric_limits<double>::max();
1810 double prevLeftOfX = 0.0;
1811 double prevLeftOfY = 0.0;
1812 double testDist = 0;
1813 double segmentPtX, segmentPtY;
1818 int size = mX.size();
1819 if ( size == 0 || size == 1 )
1824 for (
int i = 1; i < size; ++i )
1826 double prevX = mX.at( i - 1 );
1827 double prevY = mY.at( i - 1 );
1828 double currentX = mX.at( i );
1829 double currentY = mY.at( i );
1831 if ( testDist < sqrDist )
1834 segmentPt.
setX( segmentPtX );
1835 segmentPt.
setY( segmentPtY );
1836 vertexAfter.
part = 0;
1837 vertexAfter.
ring = 0;
1848 if (
qgsDoubleNear( testDist, leftOfDist ) && left != prevLeftOf && prevLeftOf != 0 )
1861 leftOfDist = testDist;
1862 prevLeftOfX = prevX;
1863 prevLeftOfY = prevY;
1865 else if ( testDist < leftOfDist )
1868 leftOfDist = testDist;
1889 type = Qgis::VertexType::Segment;
1900 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
1902 double totalLineLength = 0.0;
1903 double prevX = mX.at( 0 );
1904 double prevY = mY.at( 0 );
1910 double currentX = mX.at( i );
1911 double currentY = mY.at( i );
1912 double segmentLength = std::sqrt( std::pow( currentX - prevX, 2.0 ) +
1913 std::pow( currentY - prevY, 2.0 ) );
1927 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
1929 return QgsPoint( sumX / totalLineLength, sumY / totalLineLength );
1948 const int maxIndex = mX.size();
1949 if ( maxIndex == 0 )
1952 const double *x = mX.constData();
1953 const double *y = mY.constData();
1954 double prevX = *x++;
1955 double prevY = *y++;
1956 for (
int i = 1; i < maxIndex; ++i )
1968void QgsLineString::importVerticesFromWkb(
const QgsConstWkbPtr &wkb )
1974 mX.resize( nVertices );
1975 mY.resize( nVertices );
1976 hasZ ? mZ.resize( nVertices ) : mZ.clear();
1977 hasM ? mM.resize( nVertices ) : mM.clear();
1978 double *x = mX.data();
1979 double *y = mY.data();
1980 double *m = hasM ? mM.data() :
nullptr;
1981 double *z = hasZ ? mZ.data() :
nullptr;
1982 for (
int i = 0; i < nVertices; ++i )
2015 if ( mX.count() < 2 )
2025 double previousX = mX.at(
numPoints() - 2 );
2026 double previousY = mY.at(
numPoints() - 2 );
2027 double currentX = mX.at( 0 );
2028 double currentY = mY.at( 0 );
2029 double afterX = mX.at( 1 );
2030 double afterY = mY.at( 1 );
2033 else if ( vertex.
vertex == 0 )
2046 double previousX = mX.at( vertex.
vertex - 1 );
2047 double previousY = mY.at( vertex.
vertex - 1 );
2048 double currentX = mX.at( vertex.
vertex );
2049 double currentY = mY.at( vertex.
vertex );
2050 double afterX = mX.at( vertex.
vertex + 1 );
2051 double afterY = mY.at( vertex.
vertex + 1 );
2058 if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 1 )
2061 double dx = mX.at( startVertex.
vertex + 1 ) - mX.at( startVertex.
vertex );
2062 double dy = mY.at( startVertex.
vertex + 1 ) - mY.at( startVertex.
vertex );
2063 return std::sqrt( dx * dx + dy * dy );
2088 mZ.reserve( nPoints );
2089 for (
int i = 0; i < nPoints; ++i )
2119 mM.reserve( nPoints );
2120 for (
int i = 0; i < nPoints; ++i )
2151 std::swap( mX, mY );
2165 addZValue( std::numeric_limits<double>::quiet_NaN() );
2182 int size = mX.size();
2184 double *srcX = mX.data();
2185 double *srcY = mY.data();
2186 double *srcM = hasM ? mM.data() :
nullptr;
2187 double *srcZ = hasZ ? mZ.data() :
nullptr;
2190 for (
int i = 0; i < size; ++i )
2194 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2195 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
2223 int size = mX.size();
2225 double *srcX = mX.data();
2226 double *srcY = mY.data();
2227 double *srcM = hasM ? mM.data() :
nullptr;
2228 double *srcZ = hasZ ? mZ.data() :
nullptr;
2230 double *destX = srcX;
2231 double *destY = srcY;
2232 double *destM = srcM;
2233 double *destZ = srcZ;
2235 int filteredPoints = 0;
2236 for (
int i = 0; i < size; ++i )
2240 double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
2241 double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
2243 if ( filter(
QgsPoint( x, y, z, m ) ) )
2255 mX.resize( filteredPoints );
2256 mY.resize( filteredPoints );
2258 mZ.resize( filteredPoints );
2260 mM.resize( filteredPoints );
2269 int size = mX.size();
2271 double *srcX = mX.data();
2272 double *srcY = mY.data();
2273 double *srcM = hasM ? mM.data() :
nullptr;
2274 double *srcZ = hasZ ? mZ.data() :
nullptr;
2276 for (
int i = 0; i < size; ++i )
2280 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2281 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
VertexType
Types of vertex.
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 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.
virtual bool convertTo(QgsWkbTypes::Type type)
Converts the geometry to a specified type.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
QgsWkbTypes::Type mWkbType
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.
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 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 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 json pointsToJson(const QgsPointSequence &points, int precision)
Returns coordinates as json object.
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
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 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.
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.
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 bool hasM(Type type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
Type
The WKB type describes the number of dimensions a geometry has.
static Type zmType(Type type, bool hasZ, bool hasM) SIP_HOLDGIL
Returns the modified input geometry type according to hasZ / hasM.
static Type dropZ(Type type) SIP_HOLDGIL
Drops the z dimension (if present) for a WKB type and returns the new type.
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
static Type addZ(Type type) SIP_HOLDGIL
Adds the z dimension to a WKB type and returns the new type.
static bool hasZ(Type type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
static Type addM(Type type) SIP_HOLDGIL
Adds the m dimension to a WKB type and returns the new type.
static Type dropM(Type type) SIP_HOLDGIL
Drops the m dimension (if present) for a WKB type and returns the new type.
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.