29#include <nlohmann/json.hpp>
34#include <QDomDocument>
59 mX.resize(
points.count() );
60 mY.resize(
points.count() );
61 double *x = mX.data();
62 double *y = mY.data();
67 mZ.resize(
points.count() );
72 mM.resize(
points.count() );
87QgsLineString::QgsLineString(
const QVector<double> &x,
const QVector<double> &y,
const QVector<double> &z,
const QVector<double> &m,
bool is25DType )
90 int pointCount = std::min( x.size(), y.size() );
91 if ( x.size() == pointCount )
97 mX = x.mid( 0, pointCount );
99 if ( y.size() == pointCount )
105 mY = y.mid( 0, pointCount );
107 if ( !z.isEmpty() && z.count() >= pointCount )
110 if ( z.size() == pointCount )
116 mZ = z.mid( 0, pointCount );
119 if ( !m.isEmpty() && m.count() >= pointCount )
122 if ( m.size() == pointCount )
128 mM = m.mid( 0, pointCount );
87QgsLineString::QgsLineString(
const QVector<double> &x,
const QVector<double> &y,
const QVector<double> &z,
const QVector<double> &m,
bool is25DType ) {
…}
161 mX.reserve(
points.size() );
162 mY.reserve(
points.size() );
181static double cubicInterpolate(
double a,
double b,
182 double A,
double B,
double C,
double D )
184 return A * b * b * b + 3 * B * b * b * a + 3 * C * b * a * a + D * a * a * a;
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 )
290 const int size = mX.size();
294 const double *x = mX.constData();
295 const double *y = mY.constData();
296 const bool useZ =
is3D();
298 const double *z = useZ ? mZ.constData() :
nullptr;
299 const double *m = useM ? mM.constData() :
nullptr;
301 for (
int i = 0; i < size; ++i )
323 error = QObject::tr(
"LineString has less than 2 points and is not empty." );
334 bool res =
snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM,
335 result->mX, result->mY, result->mZ, result->mM );
337 return result.release();
344 if ( mX.count() <= 2 )
347 double prevX = mX.at( 0 );
348 double prevY = mY.at( 0 );
350 bool useZ = hasZ && useZValues;
351 double prevZ = useZ ? mZ.at( 0 ) : 0;
353 int remaining = mX.count();
354 while ( i < remaining )
356 double currentX = mX.at( i );
357 double currentY = mY.at( i );
358 double currentZ = useZ ? mZ.at( i ) : 0;
395 if (
is3D() && closed )
396 closed &=
qgsDoubleNear( mZ.first(), mZ.last() ) || ( std::isnan( mZ.first() ) && std::isnan( mZ.last() ) );
411 const int nb = mX.size();
420 if ( rectangle.
contains( mX.at( 0 ), mY.at( 0 ) ) ||
421 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.2 ) ), mY.at(
static_cast< int >( nb * 0.2 ) ) ) ||
422 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.4 ) ), mY.at(
static_cast< int >( nb * 0.4 ) ) ) ||
423 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.6 ) ), mY.at(
static_cast< int >( nb * 0.6 ) ) ) ||
424 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.8 ) ), mY.at(
static_cast< int >( nb * 0.8 ) ) ) ||
425 rectangle.
contains( mX.at( nb - 1 ), mY.at( nb - 1 ) ) )
434 double xmin = std::numeric_limits<double>::max();
435 double ymin = std::numeric_limits<double>::max();
436 double xmax = -std::numeric_limits<double>::max();
437 double ymax = -std::numeric_limits<double>::max();
439 const double *x = mX.constData();
440 const double *y = mY.constData();
441 bool foundPointInRectangle =
false;
442 for (
int i = 0; i < nb; ++i )
444 const double px = *x++;
445 xmin = std::min( xmin, px );
446 xmax = std::max( xmax, px );
447 const double py = *y++;
448 ymin = std::min( ymin, py );
449 ymax = std::max( ymax, py );
451 if ( !foundPointInRectangle && rectangle.
contains( px, py ) )
453 foundPointInRectangle =
true;
469 if ( foundPointInRectangle )
494 const int nb = mX.size();
503 if ( box3d.
contains( mX.at( 0 ), mY.at( 0 ), mZ.at( 0 ) ) ||
504 box3d.
contains( mX.at(
static_cast< int >( nb * 0.2 ) ), mY.at(
static_cast< int >( nb * 0.2 ) ), mZ.at(
static_cast< int >( nb * 0.2 ) ) ) ||
505 box3d.
contains( mX.at(
static_cast< int >( nb * 0.4 ) ), mY.at(
static_cast< int >( nb * 0.4 ) ), mZ.at(
static_cast< int >( nb * 0.4 ) ) ) ||
506 box3d.
contains( mX.at(
static_cast< int >( nb * 0.6 ) ), mY.at(
static_cast< int >( nb * 0.6 ) ), mZ.at(
static_cast< int >( nb * 0.6 ) ) ) ||
507 box3d.
contains( mX.at(
static_cast< int >( nb * 0.8 ) ), mY.at(
static_cast< int >( nb * 0.8 ) ), mZ.at(
static_cast< int >( nb * 0.8 ) ) ) ||
508 box3d.
contains( mX.at( nb - 1 ), mY.at( nb - 1 ), mZ.at( nb - 1 ) ) )
517 double xmin = std::numeric_limits<double>::max();
518 double ymin = std::numeric_limits<double>::max();
519 double zmin = std::numeric_limits<double>::max();
520 double xmax = -std::numeric_limits<double>::max();
521 double ymax = -std::numeric_limits<double>::max();
522 double zmax = -std::numeric_limits<double>::max();
524 const double *x = mX.constData();
525 const double *y = mY.constData();
526 const double *z = mZ.constData();
527 bool foundPointInBox =
false;
528 for (
int i = 0; i < nb; ++i )
530 const double px = *x++;
531 xmin = std::min( xmin, px );
532 xmax = std::max( xmax, px );
533 const double py = *y++;
534 ymin = std::min( ymin, py );
535 ymax = std::max( ymax, py );
536 const double pz = *z++;
537 zmin = std::min( zmin, pz );
538 zmax = std::max( zmax, pz );
540 if ( !foundPointInBox && box3d.
contains( px, py, pz ) )
542 foundPointInBox =
true;
558 if ( foundPointInBox )
571 QVector< QgsVertexId > res;
572 if ( mX.count() <= 1 )
575 const double *x = mX.constData();
576 const double *y = mY.constData();
578 bool useZ = hasZ && useZValues;
579 const double *z = useZ ? mZ.constData() :
nullptr;
583 double prevZ = z ? *z++ : 0;
586 for (
int i = 1; i < mX.count(); ++i )
588 double currentX = *x++;
589 double currentY = *y++;
590 double currentZ = useZ ? *z++ : 0;
610 const int nb = mX.size();
613 const double *x = mX.constData();
614 const double *y = mY.constData();
615 QPointF *dest =
points.data();
616 for (
int i = 0; i < nb; ++i )
618 *dest++ = QPointF( *x++, *y++ );
636 importVerticesFromWkb( wkbPtr );
647 auto result2D = std::minmax_element( mX.begin(), mX.end() );
648 const double xmin = *result2D.first;
649 const double xmax = *result2D.second;
650 result2D = std::minmax_element( mY.begin(), mY.end() );
651 const double ymin = *result2D.first;
652 const double ymax = *result2D.second;
654 double zmin = std::numeric_limits< double >::quiet_NaN();
655 double zmax = std::numeric_limits< double >::quiet_NaN();
659 auto resultZ = std::minmax_element( mZ.begin(), mZ.end() );
660 zmin = *resultZ.first;
661 zmax = *resultZ.second;
664 return QgsBox3D( xmin, ymin, zmin, xmax, ymax, zmax );
674 const int size = mX.size();
675 if ( index < 1 || index >= size - 1 )
678 const bool useZ =
is3D();
681 QVector<double> newX( size );
682 QVector<double> newY( size );
683 QVector<double> newZ( useZ ? size : 0 );
684 QVector<double> newM( useM ? size : 0 );
685 auto it = std::copy( mX.constBegin() + index, mX.constEnd() - 1, newX.begin() );
686 it = std::copy( mX.constBegin(), mX.constBegin() + index, it );
687 *it = *newX.constBegin();
688 mX = std::move( newX );
690 it = std::copy( mY.constBegin() + index, mY.constEnd() - 1, newY.begin() );
691 it = std::copy( mY.constBegin(), mY.constBegin() + index, it );
692 *it = *newY.constBegin();
693 mY = std::move( newY );
696 it = std::copy( mZ.constBegin() + index, mZ.constEnd() - 1, newZ.begin() );
697 it = std::copy( mZ.constBegin(), mZ.constBegin() + index, it );
698 *it = *newZ.constBegin();
699 mZ = std::move( newZ );
703 it = std::copy( mM.constBegin() + index, mM.constEnd() - 1, newM.begin() );
704 it = std::copy( mM.constBegin(), mM.constBegin() + index, it );
705 *it = *newM.constBegin();
706 mM = std::move( newM );
725 QString secondWithoutParentheses =
parts.second;
726 secondWithoutParentheses = secondWithoutParentheses.remove(
'(' ).remove(
')' ).simplified().remove(
' ' );
727 parts.second =
parts.second.remove(
'(' ).remove(
')' );
728 if ( (
parts.second.compare( QLatin1String(
"EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
729 secondWithoutParentheses.isEmpty() )
744 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
755 wkb << static_cast<quint32>(
wkbType() );
773 wkt += QLatin1String(
"EMPTY" );
788 QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral(
"LineString" ) );
791 return elemLineString;
795 return elemLineString;
803 QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral(
"LineString" ) );
806 return elemLineString;
809 return elemLineString;
818 {
"type",
"LineString" },
828 kml.append( QLatin1String(
"<LinearRing>" ) );
832 kml.append( QLatin1String(
"<LineString>" ) );
835 kml.append( QLatin1String(
"<altitudeMode>" ) );
838 kml.append( QLatin1String(
"absolute" ) );
842 kml.append( QLatin1String(
"clampToGround" ) );
844 kml.append( QLatin1String(
"</altitudeMode>" ) );
845 kml.append( QLatin1String(
"<coordinates>" ) );
847 int nPoints = mX.size();
848 for (
int i = 0; i < nPoints; ++i )
852 kml.append( QLatin1String(
" " ) );
855 kml.append( QLatin1String(
"," ) );
859 kml.append( QLatin1String(
"," ) );
864 kml.append( QLatin1String(
",0" ) );
867 kml.append( QLatin1String(
"</coordinates>" ) );
870 kml.append( QLatin1String(
"</LinearRing>" ) );
874 kml.append( QLatin1String(
"</LineString>" ) );
888 const int size = mX.size();
892 const double *x = mX.constData();
893 const double *y = mY.constData();
899 for (
int i = 1; i < size; ++i )
903 total += std::sqrt( dx * dx + dy * dy );
913 const bool useZ =
is3D();
916 const int size = mX.size();
918 return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >() );
920 index = std::clamp( index, 0, size - 1 );
922 const int part1Size = index + 1;
923 QVector< double > x1( part1Size );
924 QVector< double > y1( part1Size );
925 QVector< double > z1( useZ ? part1Size : 0 );
926 QVector< double > m1( useM ? part1Size : 0 );
928 const double *sourceX = mX.constData();
929 const double *sourceY = mY.constData();
930 const double *sourceZ = useZ ? mZ.constData() :
nullptr;
931 const double *sourceM = useM ? mM.constData() :
nullptr;
933 double *destX = x1.data();
934 double *destY = y1.data();
935 double *destZ = useZ ? z1.data() :
nullptr;
936 double *destM = useM ? m1.data() :
nullptr;
938 std::copy( sourceX, sourceX + part1Size, destX );
939 std::copy( sourceY, sourceY + part1Size, destY );
941 std::copy( sourceZ, sourceZ + part1Size, destZ );
943 std::copy( sourceM, sourceM + part1Size, destM );
945 const int part2Size = size - index;
947 return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >() );
949 QVector< double > x2( part2Size );
950 QVector< double > y2( part2Size );
951 QVector< double > z2( useZ ? part2Size : 0 );
952 QVector< double > m2( useM ? part2Size : 0 );
955 destZ = useZ ? z2.data() :
nullptr;
956 destM = useM ? m2.data() :
nullptr;
957 std::copy( sourceX + index, sourceX + size, destX );
958 std::copy( sourceY + index, sourceY + size, destY );
960 std::copy( sourceZ + index, sourceZ + size, destZ );
962 std::copy( sourceM + index, sourceM + size, destM );
965 return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
967 return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
975 const int size = mX.size();
979 const double *x = mX.constData();
980 const double *y = mY.constData();
981 const double *z = mZ.constData();
988 for (
int i = 1; i < size; ++i )
993 total += std::sqrt( dx * dx + dy * dy + dz * dz );
1033 Q_UNUSED( tolerance )
1034 Q_UNUSED( toleranceType )
1050 if ( i < 0 || i >= mX.size() )
1055 double x = mX.at( i );
1056 double y = mY.at( i );
1057 double z = std::numeric_limits<double>::quiet_NaN();
1058 double m = std::numeric_limits<double>::quiet_NaN();
1076 else if ( hasZ && hasM )
1099 if ( index >= 0 && index < mX.size() )
1100 return mX.at( index );
1107 if ( index >= 0 && index < mY.size() )
1108 return mY.at( index );
1115 if ( index >= 0 && index < mX.size() )
1122 if ( index >= 0 && index < mY.size() )
1137 pts.reserve( nPoints );
1138 for (
int i = 0; i < nPoints; ++i )
1140 pts.push_back(
pointN( i ) );
1154 const bool hasZ =
static_cast< bool >( z );
1155 const bool hasM =
static_cast< bool >( m );
1176 double *destX = mX.data();
1177 double *destY = mY.data();
1178 double *destZ =
nullptr;
1188 double *destM =
nullptr;
1199 for (
size_t i = 0; i < size; ++i )
1226 bool hasZ = firstPt.
is3D();
1231 mX.resize(
points.size() );
1232 mY.resize(
points.size() );
1235 mZ.resize(
points.size() );
1243 mM.resize(
points.size() );
1250 for (
int i = 0; i <
points.size(); ++i )
1252 mX[i] =
points.at( i ).x();
1253 mY[i] =
points.at( i ).y();
1256 double z =
points.at( i ).z();
1257 mZ[i] = std::isnan( z ) ? 0 : z;
1261 double m =
points.at( i ).m();
1262 mM[i] = std::isnan( m ) ? 0 : m;
1315 mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
1328 mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
1338 std::reverse( copy->mX.begin(), copy->mX.end() );
1339 std::reverse( copy->mY.begin(), copy->mY.end() );
1342 std::reverse( copy->mZ.begin(), copy->mZ.end() );
1346 std::reverse( copy->mM.begin(), copy->mM.end() );
1351void QgsLineString::visitPointsByRegularDistance(
const double distance,
const std::function<
bool (
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double )> &visitPoint )
const
1356 double distanceTraversed = 0;
1358 if ( totalPoints == 0 )
1361 const double *x = mX.constData();
1362 const double *y = mY.constData();
1363 const double *z =
is3D() ? mZ.constData() :
nullptr;
1364 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1366 double prevX = *x++;
1367 double prevY = *y++;
1368 double prevZ = z ? *z++ : 0.0;
1369 double prevM = m ? *m++ : 0.0;
1373 visitPoint( prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM );
1377 double pZ = std::numeric_limits<double>::quiet_NaN();
1378 double pM = std::numeric_limits<double>::quiet_NaN();
1379 double nextPointDistance = distance;
1380 for (
int i = 1; i < totalPoints; ++i )
1382 double thisX = *x++;
1383 double thisY = *y++;
1384 double thisZ = z ? *z++ : 0.0;
1385 double thisM = m ? *m++ : 0.0;
1391 const double distanceToPoint = std::min( nextPointDistance - distanceTraversed,
segmentLength );
1394 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &pZ :
nullptr,
1395 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &pM : nullptr );
1397 if ( !visitPoint( pX, pY, pZ, pM, prevX, prevY, prevZ, prevM, thisX, thisY, thisZ, thisM ) )
1400 nextPointDistance += distance;
1351void QgsLineString::visitPointsByRegularDistance(
const double distance,
const std::function<
bool (
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double )> &visitPoint )
const {
…}
1422 std::unique_ptr< QgsPoint > res;
1423 visitPointsByRegularDistance( distance, [ & ](
double x,
double y,
double z,
double m,
double,
double,
double,
double,
double,
double,
double,
double )->
bool
1425 res = std::make_unique< QgsPoint >( pointType, x, y, z, m );
1428 return res.release();
1433 if ( startDistance < 0 && endDistance < 0 )
1436 endDistance = std::max( startDistance, endDistance );
1439 if ( totalPoints == 0 )
1442 QVector< QgsPoint > substringPoints;
1443 substringPoints.reserve( totalPoints );
1451 const double *x = mX.constData();
1452 const double *y = mY.constData();
1453 const double *z =
is3D() ? mZ.constData() :
nullptr;
1454 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1456 double distanceTraversed = 0;
1457 double prevX = *x++;
1458 double prevY = *y++;
1459 double prevZ = z ? *z++ : 0.0;
1460 double prevM = m ? *m++ : 0.0;
1461 bool foundStart =
false;
1463 if ( startDistance < 0 )
1466 for (
int i = 1; i < totalPoints; ++i )
1468 double thisX = *x++;
1469 double thisY = *y++;
1470 double thisZ = z ? *z++ : 0.0;
1471 double thisM = m ? *m++ : 0.0;
1475 if ( distanceTraversed <= startDistance && startDistance < distanceTraversed +
segmentLength )
1478 const double distanceToStart = startDistance - distanceTraversed;
1479 double startX, startY;
1483 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &startZ :
nullptr,
1484 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &startM : nullptr );
1485 substringPoints <<
QgsPoint( pointType, startX, startY, startZ, startM );
1488 if ( foundStart && ( distanceTraversed +
segmentLength > endDistance ) )
1491 const double distanceToEnd = endDistance - distanceTraversed;
1496 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &endZ :
nullptr,
1497 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &endM : nullptr );
1498 substringPoints <<
QgsPoint( pointType, endX, endY, endZ, endM );
1500 else if ( foundStart )
1502 substringPoints <<
QgsPoint( pointType, thisX, thisY, thisZ, thisM );
1510 if ( distanceTraversed >= endDistance )
1515 if ( !foundStart &&
qgsDoubleNear( distanceTraversed, startDistance ) )
1517 substringPoints <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1518 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1543 if ( path.isEmpty() || path.currentPosition() != QPointF( mX.at( 0 ), mY.at( 0 ) ) )
1545 path.moveTo( mX.at( 0 ), mY.at( 0 ) );
1548 for (
int i = 1; i < nPoints; ++i )
1550 path.lineTo( mX.at( i ), mY.at( i ) );
1563 return compoundCurve;
1568 if ( mX.size() < 2 || mY.size() < 2 )
1571 const bool extendStart = startDistance > 0;
1572 const bool extendEnd = endDistance > 0;
1577 const double currentLen = std::sqrt( std::pow( mX.at( 0 ) - mX.at( 1 ), 2 ) +
1578 std::pow( mY.at( 0 ) - mY.at( 1 ), 2 ) );
1579 const double newLen = currentLen + startDistance;
1580 mX[ 0 ] = mX.at( 1 ) + ( mX.at( 0 ) - mX.at( 1 ) ) / currentLen * newLen;
1581 mY[ 0 ] = mY.at( 1 ) + ( mY.at( 0 ) - mY.at( 1 ) ) / currentLen * newLen;
1586 const int last = mX.size() - 1;
1587 const double currentLen = std::sqrt( std::pow( mX.at( last ) - mX.at( last - 1 ), 2 ) +
1588 std::pow( mY.at( last ) - mY.at( last - 1 ), 2 ) );
1589 const double newLen = currentLen + endDistance;
1590 mX[ last ] = mX.at( last - 1 ) + ( mX.at( last ) - mX.at( last - 1 ) ) / currentLen * newLen;
1591 mY[ last ] = mY.at( last - 1 ) + ( mY.at( last ) - mY.at( last - 1 ) ) / currentLen * newLen;
1594 if ( extendStart || extendEnd )
1600 auto result = std::make_unique< QgsLineString >();
1602 return result.release();
1607 const QgsLineString *otherLine = qgsgeometry_cast<const QgsLineString *>( other );
1611 const int size = mX.size();
1612 const int otherSize = otherLine->mX.size();
1613 if ( size > otherSize )
1617 else if ( size < otherSize )
1622 if (
is3D() && !otherLine->
is3D() )
1624 else if ( !
is3D() && otherLine->
is3D() )
1626 const bool considerZ =
is3D();
1634 for (
int i = 0; i < size; i++ )
1636 const double x = mX[i];
1637 const double otherX = otherLine->mX[i];
1642 else if ( x > otherX )
1647 const double y = mY[i];
1648 const double otherY = otherLine->mY[i];
1653 else if ( y > otherY )
1660 const double z = mZ[i];
1661 const double otherZ = otherLine->mZ[i];
1667 else if ( z > otherZ )
1675 const double m = mM[i];
1676 const double otherM = otherLine->mM[i];
1682 else if ( m > otherM )
1693 return QStringLiteral(
"LineString" );
1709 double *zArray =
nullptr;
1715 std::unique_ptr< double[] > dummyZ;
1716 if ( !hasZ || !transformZ )
1718 dummyZ.reset(
new double[nPoints]() );
1719 zArray = dummyZ.get();
1734 double *x = mX.data();
1735 double *y = mY.data();
1736 double *z = hasZ ? mZ.data() :
nullptr;
1737 double *m = hasM ? mM.data() :
nullptr;
1738 for (
int i = 0; i < nPoints; ++i )
1741 t.map( *x, *y, &xOut, &yOut );
1746 *z = *z * zScale + zTranslate;
1751 *m = *m * mScale + mTranslate;
1766 if ( position.
vertex < 0 || position.
vertex > mX.size() )
1776 mX.insert( position.
vertex, vertex.
x() );
1777 mY.insert( position.
vertex, vertex.
y() );
1780 mZ.insert( position.
vertex, vertex.
z() );
1784 mM.insert( position.
vertex, vertex.
m() );
1792 if ( position.
vertex < 0 || position.
vertex >= mX.size() )
1796 mX[position.
vertex] = newPos.
x();
1797 mY[position.
vertex] = newPos.
y();
1800 mZ[position.
vertex] = newPos.
z();
1804 mM[position.
vertex] = newPos.
m();
1812 if ( position.
vertex >= mX.size() || position.
vertex < 0 )
1817 mX.remove( position.
vertex );
1818 mY.remove( position.
vertex );
1821 mZ.remove( position.
vertex );
1825 mM.remove( position.
vertex );
1850 mX.append( pt.
x() );
1851 mY.append( pt.
y() );
1854 mZ.append( pt.
z() );
1858 mM.append( pt.
m() );
1865 double sqrDist = std::numeric_limits<double>::max();
1866 double leftOfDist = std::numeric_limits<double>::max();
1868 double prevLeftOfX = 0.0;
1869 double prevLeftOfY = 0.0;
1870 double testDist = 0;
1871 double segmentPtX, segmentPtY;
1876 int size = mX.size();
1877 if ( size == 0 || size == 1 )
1882 for (
int i = 1; i < size; ++i )
1884 double prevX = mX.at( i - 1 );
1885 double prevY = mY.at( i - 1 );
1886 double currentX = mX.at( i );
1887 double currentY = mY.at( i );
1889 if ( testDist < sqrDist )
1892 segmentPt.
setX( segmentPtX );
1893 segmentPt.
setY( segmentPtY );
1894 vertexAfter.
part = 0;
1895 vertexAfter.
ring = 0;
1906 if (
qgsDoubleNear( testDist, leftOfDist ) && left != prevLeftOf && prevLeftOf != 0 )
1918 prevLeftOf = *leftOf;
1919 leftOfDist = testDist;
1920 prevLeftOfX = prevX;
1921 prevLeftOfY = prevY;
1923 else if ( testDist < leftOfDist )
1926 leftOfDist = testDist;
1958 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
1960 double totalLineLength = 0.0;
1961 double prevX = mX.at( 0 );
1962 double prevY = mY.at( 0 );
1968 double currentX = mX.at( i );
1969 double currentY = mY.at( i );
1970 double segmentLength = std::sqrt( std::pow( currentX - prevX, 2.0 ) +
1971 std::pow( currentY - prevY, 2.0 ) );
1985 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
1987 return QgsPoint( sumX / totalLineLength, sumY / totalLineLength );
2006 const int maxIndex = mX.size();
2013 const double *x = mX.constData();
2014 const double *y = mY.constData();
2015 double prevX = *x++;
2016 double prevY = *y++;
2017 for (
int i = 1; i < maxIndex; ++i )
2019 mSummedUpArea += prevX * ( *y - prevY ) - prevY * ( *x - prevX );
2029void QgsLineString::importVerticesFromWkb(
const QgsConstWkbPtr &wkb )
2035 mX.resize( nVertices );
2036 mY.resize( nVertices );
2037 hasZ ? mZ.resize( nVertices ) : mZ.clear();
2038 hasM ? mM.resize( nVertices ) : mM.clear();
2039 double *x = mX.data();
2040 double *y = mY.data();
2041 double *m = hasM ? mM.data() :
nullptr;
2042 double *z = hasZ ? mZ.data() :
nullptr;
2043 for (
int i = 0; i < nVertices; ++i )
2076 if ( mX.count() < 2 )
2086 double previousX = mX.at(
numPoints() - 2 );
2087 double previousY = mY.at(
numPoints() - 2 );
2088 double currentX = mX.at( 0 );
2089 double currentY = mY.at( 0 );
2090 double afterX = mX.at( 1 );
2091 double afterY = mY.at( 1 );
2094 else if ( vertex.
vertex == 0 )
2107 double previousX = mX.at( vertex.
vertex - 1 );
2108 double previousY = mY.at( vertex.
vertex - 1 );
2109 double currentX = mX.at( vertex.
vertex );
2110 double currentY = mY.at( vertex.
vertex );
2111 double afterX = mX.at( vertex.
vertex + 1 );
2112 double afterY = mY.at( vertex.
vertex + 1 );
2119 if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 1 )
2122 double dx = mX.at( startVertex.
vertex + 1 ) - mX.at( startVertex.
vertex );
2123 double dy = mY.at( startVertex.
vertex + 1 ) - mY.at( startVertex.
vertex );
2124 return std::sqrt( dx * dx + dy * dy );
2149 mZ.reserve( nPoints );
2150 for (
int i = 0; i < nPoints; ++i )
2180 mM.reserve( nPoints );
2181 for (
int i = 0; i < nPoints; ++i )
2212 std::swap( mX, mY );
2226 addZValue( std::numeric_limits<double>::quiet_NaN() );
2243 int size = mX.size();
2245 double *srcX = mX.data();
2246 double *srcY = mY.data();
2247 double *srcM = hasM ? mM.data() :
nullptr;
2248 double *srcZ = hasZ ? mZ.data() :
nullptr;
2251 for (
int i = 0; i < size; ++i )
2255 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2256 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
2284 int size = mX.size();
2286 double *srcX = mX.data();
2287 double *srcY = mY.data();
2288 double *srcM = hasM ? mM.data() :
nullptr;
2289 double *srcZ = hasZ ? mZ.data() :
nullptr;
2291 double *destX = srcX;
2292 double *destY = srcY;
2293 double *destM = srcM;
2294 double *destZ = srcZ;
2296 int filteredPoints = 0;
2297 for (
int i = 0; i < size; ++i )
2301 double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
2302 double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
2304 if ( filter(
QgsPoint( x, y, z, m ) ) )
2316 mX.resize( filteredPoints );
2317 mY.resize( filteredPoints );
2319 mZ.resize( filteredPoints );
2321 mM.resize( filteredPoints );
2330 int size = mX.size();
2332 double *srcX = mX.data();
2333 double *srcY = mY.data();
2334 double *srcM = hasM ? mM.data() :
nullptr;
2335 double *srcZ = hasZ ? mZ.data() :
nullptr;
2337 for (
int i = 0; i < size; ++i )
2341 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2342 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
2358 std::unique_ptr< QgsLineString > cloned(
clone() );
2362 return cloned.release();
2365 if (
isEmpty() || ( nbpoints < 2 ) )
2367 return cloned.release();
2370 const double range = end - start;
2371 double lineLength =
length();
2372 double lengthSoFar = 0.0;
2375 double *mOut = cloned->mM.data();
2377 for (
int i = 1; i < nbpoints ; ++i )
2380 if ( lineLength > 0.0 )
2381 *mOut++ = start + range * lengthSoFar / lineLength;
2382 else if ( lineLength == 0.0 && nbpoints > 1 )
2383 *mOut++ = start + range * i / ( nbpoints - 1 );
2388 return cloned.release();
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
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 void pointOnLineWithDistance(double x1, double y1, double x2, double y2, double distance, double &x, double &y, double *z1=nullptr, double *z2=nullptr, double *z=nullptr, double *m1=nullptr, double *m2=nullptr, double *m=nullptr)
Calculates the point a specified distance from (x1, y1) toward a second point (x2,...
static double distance2D(double x1, double y1, double x2, double y2)
Returns the 2D distance between (x1, y1) and (x2, y2).
static double lineAngle(double x1, double y1, double x2, double y2)
Calculates the direction of line joining two points in radians, clockwise from the north direction.
static double averageAngle(double x1, double y1, double x2, double y2, double x3, double y3)
Calculates the average angle (in radians) between the two linear segments from (x1,...
static double sqrDistToLine(double ptX, double ptY, double x1, double y1, double x2, double y2, double &minDistX, double &minDistY, double epsilon)
Returns the squared distance between a point and a line.
static int leftOfLine(const double x, const double y, const double x1, const double y1, const double x2, const double y2)
Returns a value < 0 if the point (x, y) is left of the line from (x1, y1) -> (x2, y2).
static json pointsToJson(const QgsPointSequence &points, int precision)
Returns coordinates as json object.
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure, QgsAbstractGeometry::WkbFlags flags)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
static QPair< Qgis::WkbType, QString > wktReadBlock(const QString &wkt)
Parses a WKT block of the format "TYPE( contents )" and returns a pair of geometry type to contents (...
static QgsPointSequence pointsFromWKT(const QString &wktCoordinateList, bool is3D, bool isMeasure)
Returns a list of points contained in a WKT string.
static QDomElement pointsToGML2(const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY)
Returns a gml::coordinates DOM element.
static QDomElement pointsToGML3(const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, bool is3D, QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY)
Returns a gml::posList DOM element.
static QString pointsToWKT(const QgsPointSequence &points, int precision, bool is3D, bool isMeasure)
Returns a WKT coordinate list.
Represents a single 2D line segment, consisting of a 2D start and end vertex only.
Line string geometry type, with support for z-dimension and m-values.
double segmentLength(QgsVertexId startVertex) const override
Returns the length of the segment of the geometry which begins at startVertex.
bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
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 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.
QgsLineString * measuredLine(double start, double end) const
Re-write the measure ordinate (or add one, if it isn't already there) interpolating the measure betwe...
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
QgsPoint endPoint() const override
Returns the end point of the curve.
void setYAt(int index, double y)
Sets the y-coordinate of the specified node in the line string.
QDomElement asGml2(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML2 representation of the geometry.
QgsLineString * reversed() const override
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
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.