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() ) );
438 const int nb = mX.size();
447 if ( rectangle.
contains( mX.at( 0 ), mY.at( 0 ) ) ||
448 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.2 ) ), mY.at(
static_cast< int >( nb * 0.2 ) ) ) ||
449 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.4 ) ), mY.at(
static_cast< int >( nb * 0.4 ) ) ) ||
450 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.6 ) ), mY.at(
static_cast< int >( nb * 0.6 ) ) ) ||
451 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.8 ) ), mY.at(
static_cast< int >( nb * 0.8 ) ) ) ||
452 rectangle.
contains( mX.at( nb - 1 ), mY.at( nb - 1 ) ) )
461 double xmin = std::numeric_limits<double>::max();
462 double ymin = std::numeric_limits<double>::max();
463 double xmax = -std::numeric_limits<double>::max();
464 double ymax = -std::numeric_limits<double>::max();
466 const double *x = mX.constData();
467 const double *y = mY.constData();
468 bool foundPointInRectangle =
false;
469 for (
int i = 0; i < nb; ++i )
471 const double px = *x++;
472 xmin = std::min( xmin, px );
473 xmax = std::max( xmax, px );
474 const double py = *y++;
475 ymin = std::min( ymin, py );
476 ymax = std::max( ymax, py );
478 if ( !foundPointInRectangle && rectangle.
contains( px, py ) )
480 foundPointInRectangle =
true;
496 if ( foundPointInRectangle )
521 const int nb = mX.size();
530 if ( box3d.
contains( mX.at( 0 ), mY.at( 0 ), mZ.at( 0 ) ) ||
531 box3d.
contains( mX.at(
static_cast< int >( nb * 0.2 ) ), mY.at(
static_cast< int >( nb * 0.2 ) ), mZ.at(
static_cast< int >( nb * 0.2 ) ) ) ||
532 box3d.
contains( mX.at(
static_cast< int >( nb * 0.4 ) ), mY.at(
static_cast< int >( nb * 0.4 ) ), mZ.at(
static_cast< int >( nb * 0.4 ) ) ) ||
533 box3d.
contains( mX.at(
static_cast< int >( nb * 0.6 ) ), mY.at(
static_cast< int >( nb * 0.6 ) ), mZ.at(
static_cast< int >( nb * 0.6 ) ) ) ||
534 box3d.
contains( mX.at(
static_cast< int >( nb * 0.8 ) ), mY.at(
static_cast< int >( nb * 0.8 ) ), mZ.at(
static_cast< int >( nb * 0.8 ) ) ) ||
535 box3d.
contains( mX.at( nb - 1 ), mY.at( nb - 1 ), mZ.at( nb - 1 ) ) )
544 double xmin = std::numeric_limits<double>::max();
545 double ymin = std::numeric_limits<double>::max();
546 double zmin = std::numeric_limits<double>::max();
547 double xmax = -std::numeric_limits<double>::max();
548 double ymax = -std::numeric_limits<double>::max();
549 double zmax = -std::numeric_limits<double>::max();
551 const double *x = mX.constData();
552 const double *y = mY.constData();
553 const double *z = mZ.constData();
554 bool foundPointInBox =
false;
555 for (
int i = 0; i < nb; ++i )
557 const double px = *x++;
558 xmin = std::min( xmin, px );
559 xmax = std::max( xmax, px );
560 const double py = *y++;
561 ymin = std::min( ymin, py );
562 ymax = std::max( ymax, py );
563 const double pz = *z++;
564 zmin = std::min( zmin, pz );
565 zmax = std::max( zmax, pz );
567 if ( !foundPointInBox && box3d.
contains( px, py, pz ) )
569 foundPointInBox =
true;
585 if ( foundPointInBox )
598 QVector< QgsVertexId > res;
599 if ( mX.count() <= 1 )
602 const double *x = mX.constData();
603 const double *y = mY.constData();
605 bool useZ = hasZ && useZValues;
606 const double *z = useZ ? mZ.constData() :
nullptr;
610 double prevZ = z ? *z++ : 0;
613 for (
int i = 1; i < mX.count(); ++i )
615 double currentX = *x++;
616 double currentY = *y++;
617 double currentZ = useZ ? *z++ : 0;
637 const int nb = mX.size();
640 const double *x = mX.constData();
641 const double *y = mY.constData();
642 QPointF *dest =
points.data();
643 for (
int i = 0; i < nb; ++i )
645 *dest++ = QPointF( *x++, *y++ );
663 importVerticesFromWkb( wkbPtr );
674 auto result2D = std::minmax_element( mX.begin(), mX.end() );
675 const double xmin = *result2D.first;
676 const double xmax = *result2D.second;
677 result2D = std::minmax_element( mY.begin(), mY.end() );
678 const double ymin = *result2D.first;
679 const double ymax = *result2D.second;
681 double zmin = std::numeric_limits< double >::quiet_NaN();
682 double zmax = std::numeric_limits< double >::quiet_NaN();
686 auto resultZ = std::minmax_element( mZ.begin(), mZ.end() );
687 zmin = *resultZ.first;
688 zmax = *resultZ.second;
691 return QgsBox3D( xmin, ymin, zmin, xmax, ymax, zmax );
701 const int size = mX.size();
702 if ( index < 1 || index >= size - 1 )
705 const bool useZ =
is3D();
708 QVector<double> newX( size );
709 QVector<double> newY( size );
710 QVector<double> newZ( useZ ? size : 0 );
711 QVector<double> newM( useM ? size : 0 );
712 auto it = std::copy( mX.constBegin() + index, mX.constEnd() - 1, newX.begin() );
713 it = std::copy( mX.constBegin(), mX.constBegin() + index, it );
714 *it = *newX.constBegin();
715 mX = std::move( newX );
717 it = std::copy( mY.constBegin() + index, mY.constEnd() - 1, newY.begin() );
718 it = std::copy( mY.constBegin(), mY.constBegin() + index, it );
719 *it = *newY.constBegin();
720 mY = std::move( newY );
723 it = std::copy( mZ.constBegin() + index, mZ.constEnd() - 1, newZ.begin() );
724 it = std::copy( mZ.constBegin(), mZ.constBegin() + index, it );
725 *it = *newZ.constBegin();
726 mZ = std::move( newZ );
730 it = std::copy( mM.constBegin() + index, mM.constEnd() - 1, newM.begin() );
731 it = std::copy( mM.constBegin(), mM.constBegin() + index, it );
732 *it = *newM.constBegin();
733 mM = std::move( newM );
752 QString secondWithoutParentheses =
parts.second;
753 secondWithoutParentheses = secondWithoutParentheses.remove(
'(' ).remove(
')' ).simplified().remove(
' ' );
754 parts.second =
parts.second.remove(
'(' ).remove(
')' );
755 if ( (
parts.second.compare( QLatin1String(
"EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
756 secondWithoutParentheses.isEmpty() )
771 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
782 wkb << static_cast<quint32>(
wkbType() );
800 wkt += QLatin1String(
"EMPTY" );
815 QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral(
"LineString" ) );
818 return elemLineString;
822 return elemLineString;
830 QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral(
"LineString" ) );
833 return elemLineString;
836 return elemLineString;
845 {
"type",
"LineString" },
855 kml.append( QLatin1String(
"<LinearRing>" ) );
859 kml.append( QLatin1String(
"<LineString>" ) );
862 kml.append( QLatin1String(
"<altitudeMode>" ) );
865 kml.append( QLatin1String(
"absolute" ) );
869 kml.append( QLatin1String(
"clampToGround" ) );
871 kml.append( QLatin1String(
"</altitudeMode>" ) );
872 kml.append( QLatin1String(
"<coordinates>" ) );
874 int nPoints = mX.size();
875 for (
int i = 0; i < nPoints; ++i )
879 kml.append( QLatin1String(
" " ) );
882 kml.append( QLatin1String(
"," ) );
886 kml.append( QLatin1String(
"," ) );
891 kml.append( QLatin1String(
",0" ) );
894 kml.append( QLatin1String(
"</coordinates>" ) );
897 kml.append( QLatin1String(
"</LinearRing>" ) );
901 kml.append( QLatin1String(
"</LineString>" ) );
915 const int size = mX.size();
919 const double *x = mX.constData();
920 const double *y = mY.constData();
926 for (
int i = 1; i < size; ++i )
930 total += std::sqrt( dx * dx + dy * dy );
940 const bool useZ =
is3D();
943 const int size = mX.size();
945 return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >() );
947 index = std::clamp( index, 0, size - 1 );
949 const int part1Size = index + 1;
950 QVector< double > x1( part1Size );
951 QVector< double > y1( part1Size );
952 QVector< double > z1( useZ ? part1Size : 0 );
953 QVector< double > m1( useM ? part1Size : 0 );
955 const double *sourceX = mX.constData();
956 const double *sourceY = mY.constData();
957 const double *sourceZ = useZ ? mZ.constData() :
nullptr;
958 const double *sourceM = useM ? mM.constData() :
nullptr;
960 double *destX = x1.data();
961 double *destY = y1.data();
962 double *destZ = useZ ? z1.data() :
nullptr;
963 double *destM = useM ? m1.data() :
nullptr;
965 std::copy( sourceX, sourceX + part1Size, destX );
966 std::copy( sourceY, sourceY + part1Size, destY );
968 std::copy( sourceZ, sourceZ + part1Size, destZ );
970 std::copy( sourceM, sourceM + part1Size, destM );
972 const int part2Size = size - index;
974 return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >() );
976 QVector< double > x2( part2Size );
977 QVector< double > y2( part2Size );
978 QVector< double > z2( useZ ? part2Size : 0 );
979 QVector< double > m2( useM ? part2Size : 0 );
982 destZ = useZ ? z2.data() :
nullptr;
983 destM = useM ? m2.data() :
nullptr;
984 std::copy( sourceX + index, sourceX + size, destX );
985 std::copy( sourceY + index, sourceY + size, destY );
987 std::copy( sourceZ + index, sourceZ + size, destZ );
989 std::copy( sourceM + index, sourceM + size, destM );
992 return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
994 return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
1002 const int size = mX.size();
1006 const double *x = mX.constData();
1007 const double *y = mY.constData();
1008 const double *z = mZ.constData();
1011 double prevX = *x++;
1012 double prevY = *y++;
1013 double prevZ = *z++;
1015 for (
int i = 1; i < size; ++i )
1020 total += std::sqrt( dx * dx + dy * dy + dz * dz );
1060 Q_UNUSED( tolerance )
1061 Q_UNUSED( toleranceType )
1077 if ( i < 0 || i >= mX.size() )
1082 double x = mX.at( i );
1083 double y = mY.at( i );
1084 double z = std::numeric_limits<double>::quiet_NaN();
1085 double m = std::numeric_limits<double>::quiet_NaN();
1103 else if ( hasZ && hasM )
1126 if ( index >= 0 && index < mX.size() )
1127 return mX.at( index );
1134 if ( index >= 0 && index < mY.size() )
1135 return mY.at( index );
1142 if ( index >= 0 && index < mX.size() )
1149 if ( index >= 0 && index < mY.size() )
1164 pts.reserve( nPoints );
1165 for (
int i = 0; i < nPoints; ++i )
1167 pts.push_back(
pointN( i ) );
1181 const bool hasZ =
static_cast< bool >( z );
1182 const bool hasM =
static_cast< bool >( m );
1203 double *destX = mX.data();
1204 double *destY = mY.data();
1205 double *destZ =
nullptr;
1215 double *destM =
nullptr;
1226 for (
size_t i = 0; i < size; ++i )
1253 bool hasZ = firstPt.
is3D();
1258 mX.resize(
points.size() );
1259 mY.resize(
points.size() );
1262 mZ.resize(
points.size() );
1270 mM.resize(
points.size() );
1277 for (
int i = 0; i <
points.size(); ++i )
1279 mX[i] =
points.at( i ).x();
1280 mY[i] =
points.at( i ).y();
1283 double z =
points.at( i ).z();
1284 mZ[i] = std::isnan( z ) ? 0 : z;
1288 double m =
points.at( i ).m();
1289 mM[i] = std::isnan( m ) ? 0 : m;
1342 mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
1355 mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
1365 std::reverse( copy->mX.begin(), copy->mX.end() );
1366 std::reverse( copy->mY.begin(), copy->mY.end() );
1369 std::reverse( copy->mZ.begin(), copy->mZ.end() );
1373 std::reverse( copy->mM.begin(), copy->mM.end() );
1378void QgsLineString::visitPointsByRegularDistance(
const double distance,
const std::function<
bool (
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double )> &visitPoint )
const
1383 double distanceTraversed = 0;
1385 if ( totalPoints == 0 )
1388 const double *x = mX.constData();
1389 const double *y = mY.constData();
1390 const double *z =
is3D() ? mZ.constData() :
nullptr;
1391 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1393 double prevX = *x++;
1394 double prevY = *y++;
1395 double prevZ = z ? *z++ : 0.0;
1396 double prevM = m ? *m++ : 0.0;
1400 visitPoint( prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM );
1404 double pZ = std::numeric_limits<double>::quiet_NaN();
1405 double pM = std::numeric_limits<double>::quiet_NaN();
1406 double nextPointDistance = distance;
1407 for (
int i = 1; i < totalPoints; ++i )
1409 double thisX = *x++;
1410 double thisY = *y++;
1411 double thisZ = z ? *z++ : 0.0;
1412 double thisM = m ? *m++ : 0.0;
1414 const double segmentLength = std::sqrt( ( thisX - prevX ) * ( thisX - prevX ) + ( thisY - prevY ) * ( thisY - prevY ) );
1418 const double distanceToPoint = std::min( nextPointDistance - distanceTraversed,
segmentLength );
1421 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &pZ :
nullptr,
1422 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &pM : nullptr );
1424 if ( !visitPoint( pX, pY, pZ, pM, prevX, prevY, prevZ, prevM, thisX, thisY, thisZ, thisM ) )
1427 nextPointDistance += distance;
1449 std::unique_ptr< QgsPoint > res;
1450 visitPointsByRegularDistance( distance, [ & ](
double x,
double y,
double z,
double m,
double,
double,
double,
double,
double,
double,
double,
double )->
bool
1452 res = std::make_unique< QgsPoint >( pointType, x, y, z, m );
1455 return res.release();
1460 if ( startDistance < 0 && endDistance < 0 )
1463 endDistance = std::max( startDistance, endDistance );
1466 if ( totalPoints == 0 )
1469 QVector< QgsPoint > substringPoints;
1470 substringPoints.reserve( totalPoints );
1478 const double *x = mX.constData();
1479 const double *y = mY.constData();
1480 const double *z =
is3D() ? mZ.constData() :
nullptr;
1481 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1483 double distanceTraversed = 0;
1484 double prevX = *x++;
1485 double prevY = *y++;
1486 double prevZ = z ? *z++ : 0.0;
1487 double prevM = m ? *m++ : 0.0;
1488 bool foundStart =
false;
1490 if ( startDistance < 0 )
1493 for (
int i = 1; i < totalPoints; ++i )
1495 double thisX = *x++;
1496 double thisY = *y++;
1497 double thisZ = z ? *z++ : 0.0;
1498 double thisM = m ? *m++ : 0.0;
1500 const double segmentLength = std::sqrt( ( thisX - prevX ) * ( thisX - prevX ) + ( thisY - prevY ) * ( thisY - prevY ) );
1502 if ( distanceTraversed <= startDistance && startDistance < distanceTraversed +
segmentLength )
1505 const double distanceToStart = startDistance - distanceTraversed;
1506 double startX, startY;
1510 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &startZ :
nullptr,
1511 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &startM : nullptr );
1512 substringPoints <<
QgsPoint( pointType, startX, startY, startZ, startM );
1515 if ( foundStart && ( distanceTraversed +
segmentLength > endDistance ) )
1518 const double distanceToEnd = endDistance - distanceTraversed;
1523 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &endZ :
nullptr,
1524 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &endM : nullptr );
1525 substringPoints <<
QgsPoint( pointType, endX, endY, endZ, endM );
1527 else if ( foundStart )
1529 substringPoints <<
QgsPoint( pointType, thisX, thisY, thisZ, thisM );
1537 if ( distanceTraversed >= endDistance )
1542 if ( !foundStart &&
qgsDoubleNear( distanceTraversed, startDistance ) )
1544 substringPoints <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1545 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1570 if ( path.isEmpty() || path.currentPosition() != QPointF( mX.at( 0 ), mY.at( 0 ) ) )
1572 path.moveTo( mX.at( 0 ), mY.at( 0 ) );
1575 for (
int i = 1; i < nPoints; ++i )
1577 path.lineTo( mX.at( i ), mY.at( i ) );
1590 return compoundCurve;
1595 if ( mX.size() < 2 || mY.size() < 2 )
1598 const bool extendStart = startDistance > 0;
1599 const bool extendEnd = endDistance > 0;
1604 const double currentLen = std::sqrt( std::pow( mX.at( 0 ) - mX.at( 1 ), 2 ) +
1605 std::pow( mY.at( 0 ) - mY.at( 1 ), 2 ) );
1606 const double newLen = currentLen + startDistance;
1607 mX[ 0 ] = mX.at( 1 ) + ( mX.at( 0 ) - mX.at( 1 ) ) / currentLen * newLen;
1608 mY[ 0 ] = mY.at( 1 ) + ( mY.at( 0 ) - mY.at( 1 ) ) / currentLen * newLen;
1613 const int last = mX.size() - 1;
1614 const double currentLen = std::sqrt( std::pow( mX.at( last ) - mX.at( last - 1 ), 2 ) +
1615 std::pow( mY.at( last ) - mY.at( last - 1 ), 2 ) );
1616 const double newLen = currentLen + endDistance;
1617 mX[ last ] = mX.at( last - 1 ) + ( mX.at( last ) - mX.at( last - 1 ) ) / currentLen * newLen;
1618 mY[ last ] = mY.at( last - 1 ) + ( mY.at( last ) - mY.at( last - 1 ) ) / currentLen * newLen;
1621 if ( extendStart || extendEnd )
1627 auto result = std::make_unique< QgsLineString >();
1629 return result.release();
1634 const QgsLineString *otherLine = qgsgeometry_cast<const QgsLineString *>( other );
1638 const int size = mX.size();
1639 const int otherSize = otherLine->mX.size();
1640 if ( size > otherSize )
1644 else if ( size < otherSize )
1649 if (
is3D() && !otherLine->
is3D() )
1651 else if ( !
is3D() && otherLine->
is3D() )
1653 const bool considerZ =
is3D();
1661 for (
int i = 0; i < size; i++ )
1663 const double x = mX[i];
1664 const double otherX = otherLine->mX[i];
1669 else if ( x > otherX )
1674 const double y = mY[i];
1675 const double otherY = otherLine->mY[i];
1680 else if ( y > otherY )
1687 const double z = mZ[i];
1688 const double otherZ = otherLine->mZ[i];
1694 else if ( z > otherZ )
1702 const double m = mM[i];
1703 const double otherM = otherLine->mM[i];
1709 else if ( m > otherM )
1720 return QStringLiteral(
"LineString" );
1736 double *zArray =
nullptr;
1742 std::unique_ptr< double[] > dummyZ;
1743 if ( !hasZ || !transformZ )
1745 dummyZ.reset(
new double[nPoints]() );
1746 zArray = dummyZ.get();
1761 double *x = mX.data();
1762 double *y = mY.data();
1763 double *z = hasZ ? mZ.data() :
nullptr;
1764 double *m = hasM ? mM.data() :
nullptr;
1765 for (
int i = 0; i < nPoints; ++i )
1768 t.map( *x, *y, &xOut, &yOut );
1773 *z = *z * zScale + zTranslate;
1778 *m = *m * mScale + mTranslate;
1793 if ( position.
vertex < 0 || position.
vertex > mX.size() )
1803 mX.insert( position.
vertex, vertex.
x() );
1804 mY.insert( position.
vertex, vertex.
y() );
1807 mZ.insert( position.
vertex, vertex.
z() );
1811 mM.insert( position.
vertex, vertex.
m() );
1819 if ( position.
vertex < 0 || position.
vertex >= mX.size() )
1823 mX[position.
vertex] = newPos.
x();
1824 mY[position.
vertex] = newPos.
y();
1827 mZ[position.
vertex] = newPos.
z();
1831 mM[position.
vertex] = newPos.
m();
1839 if ( position.
vertex >= mX.size() || position.
vertex < 0 )
1844 mX.remove( position.
vertex );
1845 mY.remove( position.
vertex );
1848 mZ.remove( position.
vertex );
1852 mM.remove( position.
vertex );
1877 mX.append( pt.
x() );
1878 mY.append( pt.
y() );
1881 mZ.append( pt.
z() );
1885 mM.append( pt.
m() );
1892 double sqrDist = std::numeric_limits<double>::max();
1893 double leftOfDist = std::numeric_limits<double>::max();
1895 double prevLeftOfX = 0.0;
1896 double prevLeftOfY = 0.0;
1897 double testDist = 0;
1898 double segmentPtX, segmentPtY;
1903 int size = mX.size();
1904 if ( size == 0 || size == 1 )
1909 for (
int i = 1; i < size; ++i )
1911 double prevX = mX.at( i - 1 );
1912 double prevY = mY.at( i - 1 );
1913 double currentX = mX.at( i );
1914 double currentY = mY.at( i );
1916 if ( testDist < sqrDist )
1919 segmentPt.
setX( segmentPtX );
1920 segmentPt.
setY( segmentPtY );
1921 vertexAfter.
part = 0;
1922 vertexAfter.
ring = 0;
1933 if (
qgsDoubleNear( testDist, leftOfDist ) && left != prevLeftOf && prevLeftOf != 0 )
1945 prevLeftOf = *leftOf;
1946 leftOfDist = testDist;
1947 prevLeftOfX = prevX;
1948 prevLeftOfY = prevY;
1950 else if ( testDist < leftOfDist )
1953 leftOfDist = testDist;
1985 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
1987 double totalLineLength = 0.0;
1988 double prevX = mX.at( 0 );
1989 double prevY = mY.at( 0 );
1995 double currentX = mX.at( i );
1996 double currentY = mY.at( i );
1997 double segmentLength = std::sqrt( std::pow( currentX - prevX, 2.0 ) +
1998 std::pow( currentY - prevY, 2.0 ) );
2012 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
2014 return QgsPoint( sumX / totalLineLength, sumY / totalLineLength );
2033 const int maxIndex = mX.size();
2040 const double *x = mX.constData();
2041 const double *y = mY.constData();
2042 double prevX = *x++;
2043 double prevY = *y++;
2044 for (
int i = 1; i < maxIndex; ++i )
2046 mSummedUpArea += prevX * ( *y - prevY ) - prevY * ( *x - prevX );
2056void QgsLineString::importVerticesFromWkb(
const QgsConstWkbPtr &wkb )
2062 mX.resize( nVertices );
2063 mY.resize( nVertices );
2064 hasZ ? mZ.resize( nVertices ) : mZ.clear();
2065 hasM ? mM.resize( nVertices ) : mM.clear();
2066 double *x = mX.data();
2067 double *y = mY.data();
2068 double *m = hasM ? mM.data() :
nullptr;
2069 double *z = hasZ ? mZ.data() :
nullptr;
2070 for (
int i = 0; i < nVertices; ++i )
2103 if ( mX.count() < 2 )
2113 double previousX = mX.at(
numPoints() - 2 );
2114 double previousY = mY.at(
numPoints() - 2 );
2115 double currentX = mX.at( 0 );
2116 double currentY = mY.at( 0 );
2117 double afterX = mX.at( 1 );
2118 double afterY = mY.at( 1 );
2121 else if ( vertex.
vertex == 0 )
2134 double previousX = mX.at( vertex.
vertex - 1 );
2135 double previousY = mY.at( vertex.
vertex - 1 );
2136 double currentX = mX.at( vertex.
vertex );
2137 double currentY = mY.at( vertex.
vertex );
2138 double afterX = mX.at( vertex.
vertex + 1 );
2139 double afterY = mY.at( vertex.
vertex + 1 );
2146 if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 1 )
2149 double dx = mX.at( startVertex.
vertex + 1 ) - mX.at( startVertex.
vertex );
2150 double dy = mY.at( startVertex.
vertex + 1 ) - mY.at( startVertex.
vertex );
2151 return std::sqrt( dx * dx + dy * dy );
2176 mZ.reserve( nPoints );
2177 for (
int i = 0; i < nPoints; ++i )
2207 mM.reserve( nPoints );
2208 for (
int i = 0; i < nPoints; ++i )
2239 std::swap( mX, mY );
2253 addZValue( std::numeric_limits<double>::quiet_NaN() );
2270 int size = mX.size();
2272 double *srcX = mX.data();
2273 double *srcY = mY.data();
2274 double *srcM = hasM ? mM.data() :
nullptr;
2275 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();
2311 int size = mX.size();
2313 double *srcX = mX.data();
2314 double *srcY = mY.data();
2315 double *srcM = hasM ? mM.data() :
nullptr;
2316 double *srcZ = hasZ ? mZ.data() :
nullptr;
2318 double *destX = srcX;
2319 double *destY = srcY;
2320 double *destM = srcM;
2321 double *destZ = srcZ;
2323 int filteredPoints = 0;
2324 for (
int i = 0; i < size; ++i )
2328 double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
2329 double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
2331 if ( filter(
QgsPoint( x, y, z, m ) ) )
2343 mX.resize( filteredPoints );
2344 mY.resize( filteredPoints );
2346 mZ.resize( filteredPoints );
2348 mM.resize( filteredPoints );
2357 int size = mX.size();
2359 double *srcX = mX.data();
2360 double *srcY = mY.data();
2361 double *srcM = hasM ? mM.data() :
nullptr;
2362 double *srcZ = hasZ ? mZ.data() :
nullptr;
2364 for (
int i = 0; i < size; ++i )
2368 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2369 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
VertexType
Types of vertex.
@ Segment
The actual start or end point of a segment.
WkbType
The WKB type describes the number of dimensions a geometry has.
@ LineString25D
LineString25D.
@ LineStringM
LineStringM.
@ LineStringZM
LineStringZM.
@ LineStringZ
LineStringZ.
TransformDirection
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 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.
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, Qgis::WkbType baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
virtual bool boundingBoxIntersects(const QgsRectangle &rectangle) const
Returns true if the bounding box of this geometry intersects with a rectangle.
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts of the geometry.
static endian_t endian()
Returns whether this machine uses big or little endian.
A 3-dimensional box composed of x, y, z coordinates.
bool intersects(const QgsBox3D &other) const
Returns true if box intersects with another box.
bool contains(const QgsBox3D &other) const
Returns true when box contains other box.
QgsRectangle toRectangle() const
Converts the box to a 2D rectangle.
bool isNull() const
Test if the box is null (holding no spatial information).
Compound curve geometry type.
void addCurve(QgsCurve *c, bool extendPrevious=false)
Adds a curve to the geometry (takes ownership).
Qgis::WkbType readHeader() const
readHeader
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.
QgsBox3D mBoundingBox
Cached bounding box.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const
Tells whether the operation has been canceled already.
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 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 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 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.
QgsBox3D calculateBoundingBox3D() const override
Calculates the minimal 3D bounding box for the geometry.
std::tuple< std::unique_ptr< QgsCurve >, std::unique_ptr< QgsCurve > > splitCurveAtVertex(int index) const final
Splits the curve at the specified vertex index, returning two curves which represent the portion of t...
void addToPainterPath(QPainterPath &path) const override
Adds a curve to a painter path.
void visitPointsByRegularDistance(double distance, const std::function< bool(double x, double y, double z, double m, double startSegmentX, double startSegmentY, double startSegmentZ, double startSegmentM, double endSegmentX, double endSegmentY, double endSegmentZ, double endSegmentM) > &visitPoint) const
Visits regular points along the linestring, spaced by distance.
void setXAt(int index, double x)
Sets the x-coordinate of the specified node in the line string.
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
double closestSegment(const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf=nullptr, double epsilon=4 *std::numeric_limits< double >::epsilon()) const override
Searches for the closest segment of the geometry to a given point.
QVector< QgsVertexId > collectDuplicateNodes(double epsilon=4 *std::numeric_limits< double >::epsilon(), bool useZValues=false) const
Returns a list of any duplicate nodes contained in the geometry, within the specified tolerance.
bool insertVertex(QgsVertexId position, const QgsPoint &vertex) override
Inserts a vertex into the geometry.
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the linestring does not have m values.
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
int compareToSameClass(const QgsAbstractGeometry *other) const final
Compares to an other geometry of the same class, and returns a integer for sorting of the two geometr...
bool dropMValue() override
Drops any measure values which exist in the geometry.
Q_DECL_DEPRECATED QgsBox3D calculateBoundingBox3d() const
Calculates the minimal 3D bounding box for the geometry.
json asJsonObject(int precision=17) const override
Returns a json object representation of the geometry.
void filterVertices(const std::function< bool(const QgsPoint &) > &filter) override
Filters the vertices from the geometry in place, removing any which do not return true for the filter...
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
void transformVertices(const std::function< QgsPoint(const QgsPoint &) > &transform) override
Transforms the vertices from the geometry in place, applying the transform function to every vertex.
QgsLineString * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
bool convertTo(Qgis::WkbType type) override
Converts the geometry to a specified type.
bool isClosed2D() const override
Returns true if the curve is closed.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
QgsPoint * interpolatePoint(double distance) const override
Returns an interpolated point on the curve at the specified distance.
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.
static Qgis::WkbType dropM(Qgis::WkbType type)
Drops the m dimension (if present) for a WKB type and returns the new type.
static Qgis::WkbType zmType(Qgis::WkbType type, bool hasZ, bool hasM)
Returns the modified input geometry type according to hasZ / hasM.
static Qgis::WkbType dropZ(Qgis::WkbType type)
Drops the z dimension (if present) for a WKB type and returns the new type.
static Qgis::WkbType addM(Qgis::WkbType type)
Adds the m dimension to a WKB type and returns the new type.
static Qgis::WkbType addZ(Qgis::WkbType type)
Adds the z dimension to a WKB type and returns the new type.
static bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
static bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QVector< QgsPoint > QgsPointSequence
QLineF segment(int index, QRectF rect, double radius)
Utility class for identifying a unique vertex within a geometry.