29 #include <nlohmann/json.hpp>
34 #include <QDomDocument>
35 #include <QJsonObject>
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() );
86 QgsLineString::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() );
180 static double cubicInterpolate(
double a,
double b,
181 double A,
double B,
double C,
double D )
183 return A * b * b * b + 3 * B * b * b * a + 3 * C * b * a * a + D * a * a * a;
192 x.resize( segments + 1 );
194 y.resize( segments + 1 );
196 double *
zData =
nullptr;
197 if ( start.
is3D() && end.
is3D() && controlPoint1.
is3D() && controlPoint2.
is3D() )
199 z.resize( segments + 1 );
203 double *
mData =
nullptr;
206 m.resize( segments + 1 );
210 double *
xData = x.data();
211 double *
yData = y.data();
212 const double step = 1.0 / segments;
215 for (
int i = 0; i < segments; i++, a += step, b -= step )
228 *
xData++ = cubicInterpolate( a, b, start.
x(), controlPoint1.
x(), controlPoint2.
x(), end.
x() );
229 *
yData++ = cubicInterpolate( a, b, start.
y(), controlPoint1.
y(), controlPoint2.
y(), end.
y() );
231 *
zData++ = cubicInterpolate( a, b, start.
z(), controlPoint1.
z(), controlPoint2.
z(), end.
z() );
233 *
mData++ = cubicInterpolate( a, b, start.
m(), controlPoint1.
m(), controlPoint2.
m(), end.
m() );
251 x.resize( polygon.count() );
252 y.resize( polygon.count() );
253 double *
xData = x.data();
254 double *
yData = y.data();
256 const QPointF *src = polygon.data();
257 for (
int i = 0 ; i < polygon.size(); ++ i )
269 const QgsLineString *otherLine = qgsgeometry_cast< const QgsLineString * >( &other );
276 if ( mX.count() != otherLine->mX.count() )
279 for (
int i = 0; i < mX.count(); ++i )
317 const int size = mX.size();
321 const double *x = mX.constData();
322 const double *y = mY.constData();
323 const bool useZ =
is3D();
325 const double *z = useZ ? mZ.constData() :
nullptr;
326 const double *m = useM ? mM.constData() :
nullptr;
328 for (
int i = 0; i < size; ++i )
350 error = QObject::tr(
"LineString has less than 2 points and is not empty." );
361 bool res =
snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM,
362 result->mX, result->mY, result->mZ, result->mM );
364 return result.release();
371 if ( mX.count() <= 2 )
374 double prevX = mX.at( 0 );
375 double prevY = mY.at( 0 );
377 bool useZ = hasZ && useZValues;
378 double prevZ = useZ ? mZ.at( 0 ) : 0;
380 int remaining = mX.count();
381 while ( i < remaining )
383 double currentX = mX.at( i );
384 double currentY = mY.at( i );
385 double currentZ = useZ ? mZ.at( i ) : 0;
422 if (
is3D() && closed )
423 closed &=
qgsDoubleNear( mZ.first(), mZ.last() ) || ( std::isnan( mZ.first() ) && std::isnan( mZ.last() ) );
436 const int nb = mX.size();
445 if ( rectangle.
contains( mX.at( 0 ), mY.at( 0 ) ) ||
446 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.2 ) ), mY.at(
static_cast< int >( nb * 0.2 ) ) ) ||
447 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.4 ) ), mY.at(
static_cast< int >( nb * 0.4 ) ) ) ||
448 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.6 ) ), mY.at(
static_cast< int >( nb * 0.6 ) ) ) ||
449 rectangle.
contains( mX.at(
static_cast< int >( nb * 0.8 ) ), mY.at(
static_cast< int >( nb * 0.8 ) ) ) ||
450 rectangle.
contains( mX.at( nb - 1 ), mY.at( nb - 1 ) ) )
459 double xmin = std::numeric_limits<double>::max();
460 double ymin = std::numeric_limits<double>::max();
461 double xmax = -std::numeric_limits<double>::max();
462 double ymax = -std::numeric_limits<double>::max();
464 const double *x = mX.constData();
465 const double *y = mY.constData();
466 bool foundPointInRectangle =
false;
467 for (
int i = 0; i < nb; ++i )
469 const double px = *x++;
470 xmin = std::min( xmin, px );
471 xmax = std::max( xmax, px );
472 const double py = *y++;
473 ymin = std::min( ymin, py );
474 ymax = std::max( ymax, py );
476 if ( !foundPointInRectangle && rectangle.
contains( px, py ) )
478 foundPointInRectangle =
true;
494 if ( foundPointInRectangle )
507 QVector< QgsVertexId > res;
508 if ( mX.count() <= 1 )
511 const double *x = mX.constData();
512 const double *y = mY.constData();
514 bool useZ = hasZ && useZValues;
515 const double *z = useZ ? mZ.constData() :
nullptr;
519 double prevZ = z ? *z++ : 0;
522 for (
int i = 1; i < mX.count(); ++i )
524 double currentX = *x++;
525 double currentY = *y++;
526 double currentZ = useZ ? *z++ : 0;
546 const int nb = mX.size();
549 const double *x = mX.constData();
550 const double *y = mY.constData();
551 QPointF *dest =
points.data();
552 for (
int i = 0; i < nb; ++i )
554 *dest++ = QPointF( *x++, *y++ );
572 importVerticesFromWkb( wkbPtr );
581 auto result = std::minmax_element( mX.begin(), mX.end() );
582 const double xmin = *result.first;
583 const double xmax = *result.second;
584 result = std::minmax_element( mY.begin(), mY.end() );
585 const double ymin = *result.first;
586 const double ymax = *result.second;
592 const int size = mX.size();
593 if ( index < 1 || index >= size - 1 )
596 const bool useZ =
is3D();
599 QVector<double> newX( size );
600 QVector<double> newY( size );
601 QVector<double> newZ( useZ ? size : 0 );
602 QVector<double> newM( useM ? size : 0 );
603 auto it = std::copy( mX.constBegin() + index, mX.constEnd() - 1, newX.begin() );
604 it = std::copy( mX.constBegin(), mX.constBegin() + index, it );
605 *it = *newX.constBegin();
606 mX = std::move( newX );
608 it = std::copy( mY.constBegin() + index, mY.constEnd() - 1, newY.begin() );
609 it = std::copy( mY.constBegin(), mY.constBegin() + index, it );
610 *it = *newY.constBegin();
611 mY = std::move( newY );
614 it = std::copy( mZ.constBegin() + index, mZ.constEnd() - 1, newZ.begin() );
615 it = std::copy( mZ.constBegin(), mZ.constBegin() + index, it );
616 *it = *newZ.constBegin();
617 mZ = std::move( newZ );
621 it = std::copy( mM.constBegin() + index, mM.constEnd() - 1, newM.begin() );
622 it = std::copy( mM.constBegin(), mM.constBegin() + index, it );
623 *it = *newM.constBegin();
624 mM = std::move( newM );
643 QString secondWithoutParentheses =
parts.second;
644 secondWithoutParentheses = secondWithoutParentheses.remove(
'(' ).remove(
')' ).simplified().remove(
' ' );
645 parts.second =
parts.second.remove(
'(' ).remove(
')' );
646 if ( (
parts.second.compare( QLatin1String(
"EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
647 secondWithoutParentheses.isEmpty() )
662 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
673 wkb << static_cast<quint32>(
wkbType() );
691 wkt += QLatin1String(
"EMPTY" );
706 QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral(
"LineString" ) );
709 return elemLineString;
713 return elemLineString;
721 QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral(
"LineString" ) );
724 return elemLineString;
727 return elemLineString;
736 {
"type",
"LineString" },
746 kml.append( QLatin1String(
"<LinearRing>" ) );
750 kml.append( QLatin1String(
"<LineString>" ) );
753 kml.append( QLatin1String(
"<altitudeMode>" ) );
756 kml.append( QLatin1String(
"absolute" ) );
760 kml.append( QLatin1String(
"clampToGround" ) );
762 kml.append( QLatin1String(
"</altitudeMode>" ) );
763 kml.append( QLatin1String(
"<coordinates>" ) );
765 int nPoints = mX.size();
766 for (
int i = 0; i < nPoints; ++i )
770 kml.append( QLatin1String(
" " ) );
773 kml.append( QLatin1String(
"," ) );
777 kml.append( QLatin1String(
"," ) );
782 kml.append( QLatin1String(
",0" ) );
785 kml.append( QLatin1String(
"</coordinates>" ) );
788 kml.append( QLatin1String(
"</LinearRing>" ) );
792 kml.append( QLatin1String(
"</LineString>" ) );
806 const int size = mX.size();
810 const double *x = mX.constData();
811 const double *y = mY.constData();
817 for (
int i = 1; i < size; ++i )
821 total += std::sqrt( dx * dx + dy * dy );
831 const bool useZ =
is3D();
834 const int size = mX.size();
836 return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >() );
838 index = std::clamp( index, 0, size - 1 );
840 const int part1Size = index + 1;
841 QVector< double > x1( part1Size );
842 QVector< double > y1( part1Size );
843 QVector< double > z1( useZ ? part1Size : 0 );
844 QVector< double > m1( useM ? part1Size : 0 );
846 const double *sourceX = mX.constData();
847 const double *sourceY = mY.constData();
848 const double *sourceZ = useZ ? mZ.constData() :
nullptr;
849 const double *sourceM = useM ? mM.constData() :
nullptr;
851 double *destX = x1.data();
852 double *destY = y1.data();
853 double *destZ = useZ ? z1.data() :
nullptr;
854 double *destM = useM ? m1.data() :
nullptr;
856 std::copy( sourceX, sourceX + part1Size, destX );
857 std::copy( sourceY, sourceY + part1Size, destY );
859 std::copy( sourceZ, sourceZ + part1Size, destZ );
861 std::copy( sourceM, sourceM + part1Size, destM );
863 const int part2Size = size - index;
865 return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >() );
867 QVector< double > x2( part2Size );
868 QVector< double > y2( part2Size );
869 QVector< double > z2( useZ ? part2Size : 0 );
870 QVector< double > m2( useM ? part2Size : 0 );
873 destZ = useZ ? z2.data() :
nullptr;
874 destM = useM ? m2.data() :
nullptr;
875 std::copy( sourceX + index, sourceX + size, destX );
876 std::copy( sourceY + index, sourceY + size, destY );
878 std::copy( sourceZ + index, sourceZ + size, destZ );
880 std::copy( sourceM + index, sourceM + size, destM );
883 return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
885 return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
893 const int size = mX.size();
897 const double *x = mX.constData();
898 const double *y = mY.constData();
899 const double *z = mZ.constData();
906 for (
int i = 1; i < size; ++i )
911 total += std::sqrt( dx * dx + dy * dy + dz * dz );
951 Q_UNUSED( tolerance )
952 Q_UNUSED( toleranceType )
968 if ( i < 0 || i >= mX.size() )
973 double x = mX.at( i );
974 double y = mY.at( i );
975 double z = std::numeric_limits<double>::quiet_NaN();
976 double m = std::numeric_limits<double>::quiet_NaN();
994 else if ( hasZ && hasM )
1017 if ( index >= 0 && index < mX.size() )
1018 return mX.at( index );
1025 if ( index >= 0 && index < mY.size() )
1026 return mY.at( index );
1033 if ( index >= 0 && index < mX.size() )
1040 if ( index >= 0 && index < mY.size() )
1055 pts.reserve( nPoints );
1056 for (
int i = 0; i < nPoints; ++i )
1058 pts.push_back(
pointN( i ) );
1074 bool hasZ = firstPt.
is3D();
1079 mX.resize(
points.size() );
1080 mY.resize(
points.size() );
1083 mZ.resize(
points.size() );
1091 mM.resize(
points.size() );
1098 for (
int i = 0; i <
points.size(); ++i )
1100 mX[i] =
points.at( i ).x();
1101 mY[i] =
points.at( i ).y();
1104 double z =
points.at( i ).z();
1105 mZ[i] = std::isnan( z ) ? 0 : z;
1109 double m =
points.at( i ).m();
1110 mM[i] = std::isnan( m ) ? 0 : m;
1163 mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
1176 mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
1186 std::reverse( copy->mX.begin(), copy->mX.end() );
1187 std::reverse( copy->mY.begin(), copy->mY.end() );
1190 std::reverse( copy->mZ.begin(), copy->mZ.end() );
1194 std::reverse( copy->mM.begin(), copy->mM.end() );
1199 void QgsLineString::visitPointsByRegularDistance(
const double distance,
const std::function<
bool (
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double )> &visitPoint )
const
1204 double distanceTraversed = 0;
1206 if ( totalPoints == 0 )
1209 const double *x = mX.constData();
1210 const double *y = mY.constData();
1211 const double *z =
is3D() ? mZ.constData() :
nullptr;
1212 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1214 double prevX = *x++;
1215 double prevY = *y++;
1216 double prevZ = z ? *z++ : 0.0;
1217 double prevM = m ? *m++ : 0.0;
1221 visitPoint( prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM );
1225 double pZ = std::numeric_limits<double>::quiet_NaN();
1226 double pM = std::numeric_limits<double>::quiet_NaN();
1227 double nextPointDistance = distance;
1228 for (
int i = 1; i < totalPoints; ++i )
1230 double thisX = *x++;
1231 double thisY = *y++;
1232 double thisZ = z ? *z++ : 0.0;
1233 double thisM = m ? *m++ : 0.0;
1235 const double segmentLength = std::sqrt( ( thisX - prevX ) * ( thisX - prevX ) + ( thisY - prevY ) * ( thisY - prevY ) );
1239 const double distanceToPoint = std::min( nextPointDistance - distanceTraversed,
segmentLength );
1242 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &pZ :
nullptr,
1243 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &pM :
nullptr );
1245 if ( !visitPoint( pX, pY, pZ, pM, prevX, prevY, prevZ, prevM, thisX, thisY, thisZ, thisM ) )
1248 nextPointDistance += distance;
1270 std::unique_ptr< QgsPoint > res;
1271 visitPointsByRegularDistance( distance, [ & ](
double x,
double y,
double z,
double m,
double,
double,
double,
double,
double,
double,
double,
double )->
bool
1273 res = std::make_unique< QgsPoint >( pointType, x, y, z, m );
1276 return res.release();
1281 if ( startDistance < 0 && endDistance < 0 )
1284 endDistance = std::max( startDistance, endDistance );
1287 if ( totalPoints == 0 )
1290 QVector< QgsPoint > substringPoints;
1291 substringPoints.reserve( totalPoints );
1299 const double *x = mX.constData();
1300 const double *y = mY.constData();
1301 const double *z =
is3D() ? mZ.constData() :
nullptr;
1302 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1304 double distanceTraversed = 0;
1305 double prevX = *x++;
1306 double prevY = *y++;
1307 double prevZ = z ? *z++ : 0.0;
1308 double prevM = m ? *m++ : 0.0;
1309 bool foundStart =
false;
1311 if ( startDistance < 0 )
1314 for (
int i = 1; i < totalPoints; ++i )
1316 double thisX = *x++;
1317 double thisY = *y++;
1318 double thisZ = z ? *z++ : 0.0;
1319 double thisM = m ? *m++ : 0.0;
1321 const double segmentLength = std::sqrt( ( thisX - prevX ) * ( thisX - prevX ) + ( thisY - prevY ) * ( thisY - prevY ) );
1323 if ( distanceTraversed <= startDistance && startDistance < distanceTraversed +
segmentLength )
1326 const double distanceToStart = startDistance - distanceTraversed;
1327 double startX, startY;
1331 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &startZ :
nullptr,
1332 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &startM :
nullptr );
1333 substringPoints <<
QgsPoint( pointType, startX, startY, startZ, startM );
1336 if ( foundStart && ( distanceTraversed +
segmentLength > endDistance ) )
1339 const double distanceToEnd = endDistance - distanceTraversed;
1344 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &endZ :
nullptr,
1345 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &endM :
nullptr );
1346 substringPoints <<
QgsPoint( pointType, endX, endY, endZ, endM );
1348 else if ( foundStart )
1350 substringPoints <<
QgsPoint( pointType, thisX, thisY, thisZ, thisM );
1358 if ( distanceTraversed >= endDistance )
1363 if ( !foundStart &&
qgsDoubleNear( distanceTraversed, startDistance ) )
1365 substringPoints <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1366 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1391 if ( path.isEmpty() || path.currentPosition() != QPointF( mX.at( 0 ), mY.at( 0 ) ) )
1393 path.moveTo( mX.at( 0 ), mY.at( 0 ) );
1396 for (
int i = 1; i < nPoints; ++i )
1398 path.lineTo( mX.at( i ), mY.at( i ) );
1411 return compoundCurve;
1416 if ( mX.size() < 2 || mY.size() < 2 )
1420 if ( startDistance > 0 )
1422 double currentLen = std::sqrt( std::pow( mX.at( 0 ) - mX.at( 1 ), 2 ) +
1423 std::pow( mY.at( 0 ) - mY.at( 1 ), 2 ) );
1424 double newLen = currentLen + startDistance;
1425 mX[ 0 ] = mX.at( 1 ) + ( mX.at( 0 ) - mX.at( 1 ) ) / currentLen * newLen;
1426 mY[ 0 ] = mY.at( 1 ) + ( mY.at( 0 ) - mY.at( 1 ) ) / currentLen * newLen;
1429 if ( endDistance > 0 )
1431 int last = mX.size() - 1;
1432 double currentLen = std::sqrt( std::pow( mX.at( last ) - mX.at( last - 1 ), 2 ) +
1433 std::pow( mY.at( last ) - mY.at( last - 1 ), 2 ) );
1434 double newLen = currentLen + endDistance;
1435 mX[ last ] = mX.at( last - 1 ) + ( mX.at( last ) - mX.at( last - 1 ) ) / currentLen * newLen;
1436 mY[ last ] = mY.at( last - 1 ) + ( mY.at( last ) - mY.at( last - 1 ) ) / currentLen * newLen;
1442 auto result = std::make_unique< QgsLineString >();
1444 return result.release();
1449 const QgsLineString *otherLine = qgsgeometry_cast<const QgsLineString *>( other );
1453 const int size = mX.size();
1454 const int otherSize = otherLine->mX.size();
1455 if ( size > otherSize )
1459 else if ( size < otherSize )
1464 if (
is3D() && !otherLine->
is3D() )
1466 else if ( !
is3D() && otherLine->
is3D() )
1468 const bool considerZ =
is3D();
1476 for (
int i = 0; i < size; i++ )
1478 const double x = mX[i];
1479 const double otherX = otherLine->mX[i];
1484 else if ( x > otherX )
1489 const double y = mY[i];
1490 const double otherY = otherLine->mY[i];
1495 else if ( y > otherY )
1502 const double z = mZ[i];
1503 const double otherZ = otherLine->mZ[i];
1509 else if ( z > otherZ )
1517 const double m = mM[i];
1518 const double otherM = otherLine->mM[i];
1524 else if ( m > otherM )
1535 return QStringLiteral(
"LineString" );
1551 double *zArray =
nullptr;
1557 std::unique_ptr< double[] > dummyZ;
1558 if ( !hasZ || !transformZ )
1560 dummyZ.reset(
new double[nPoints]() );
1561 zArray = dummyZ.get();
1576 double *x = mX.data();
1577 double *y = mY.data();
1578 double *z = hasZ ? mZ.data() :
nullptr;
1579 double *m = hasM ? mM.data() :
nullptr;
1580 for (
int i = 0; i < nPoints; ++i )
1583 t.map( *x, *y, &xOut, &yOut );
1588 *z = *z * zScale + zTranslate;
1593 *m = *m * mScale + mTranslate;
1608 if ( position.
vertex < 0 || position.
vertex > mX.size() )
1618 mX.insert( position.
vertex, vertex.
x() );
1619 mY.insert( position.
vertex, vertex.
y() );
1622 mZ.insert( position.
vertex, vertex.
z() );
1626 mM.insert( position.
vertex, vertex.
m() );
1634 if ( position.
vertex < 0 || position.
vertex >= mX.size() )
1638 mX[position.
vertex] = newPos.
x();
1639 mY[position.
vertex] = newPos.
y();
1642 mZ[position.
vertex] = newPos.
z();
1646 mM[position.
vertex] = newPos.
m();
1654 if ( position.
vertex >= mX.size() || position.
vertex < 0 )
1659 mX.remove( position.
vertex );
1660 mY.remove( position.
vertex );
1663 mZ.remove( position.
vertex );
1667 mM.remove( position.
vertex );
1692 mX.append( pt.
x() );
1693 mY.append( pt.
y() );
1696 mZ.append( pt.
z() );
1700 mM.append( pt.
m() );
1707 double sqrDist = std::numeric_limits<double>::max();
1708 double leftOfDist = std::numeric_limits<double>::max();
1710 double prevLeftOfX = 0.0;
1711 double prevLeftOfY = 0.0;
1712 double testDist = 0;
1713 double segmentPtX, segmentPtY;
1718 int size = mX.size();
1719 if ( size == 0 || size == 1 )
1724 for (
int i = 1; i < size; ++i )
1726 double prevX = mX.at( i - 1 );
1727 double prevY = mY.at( i - 1 );
1728 double currentX = mX.at( i );
1729 double currentY = mY.at( i );
1731 if ( testDist < sqrDist )
1734 segmentPt.
setX( segmentPtX );
1735 segmentPt.
setY( segmentPtY );
1736 vertexAfter.
part = 0;
1737 vertexAfter.
ring = 0;
1748 if (
qgsDoubleNear( testDist, leftOfDist ) && left != prevLeftOf && prevLeftOf != 0 )
1761 leftOfDist = testDist;
1762 prevLeftOfX = prevX;
1763 prevLeftOfY = prevY;
1765 else if ( testDist < leftOfDist )
1768 leftOfDist = testDist;
1789 type = Qgis::VertexType::Segment;
1800 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
1802 double totalLineLength = 0.0;
1803 double prevX = mX.at( 0 );
1804 double prevY = mY.at( 0 );
1810 double currentX = mX.at( i );
1811 double currentY = mY.at( i );
1812 double segmentLength = std::sqrt( std::pow( currentX - prevX, 2.0 ) +
1813 std::pow( currentY - prevY, 2.0 ) );
1825 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
1827 return QgsPoint( sumX / totalLineLength, sumY / totalLineLength );
1841 for (
int i = 0; i < maxIndex; ++i )
1843 sum += 0.5 * ( mX.at( i ) * mY.at( i + 1 ) - mY.at( i ) * mX.at( i + 1 ) );
1847 void QgsLineString::importVerticesFromWkb(
const QgsConstWkbPtr &wkb )
1853 mX.resize( nVertices );
1854 mY.resize( nVertices );
1855 hasZ ? mZ.resize( nVertices ) : mZ.clear();
1856 hasM ? mM.resize( nVertices ) : mM.clear();
1857 double *x = mX.data();
1858 double *y = mY.data();
1859 double *m = hasM ? mM.data() :
nullptr;
1860 double *z = hasZ ? mZ.data() :
nullptr;
1861 for (
int i = 0; i < nVertices; ++i )
1894 if ( mX.count() < 2 )
1904 double previousX = mX.at(
numPoints() - 2 );
1905 double previousY = mY.at(
numPoints() - 2 );
1906 double currentX = mX.at( 0 );
1907 double currentY = mY.at( 0 );
1908 double afterX = mX.at( 1 );
1909 double afterY = mY.at( 1 );
1912 else if ( vertex.
vertex == 0 )
1925 double previousX = mX.at( vertex.
vertex - 1 );
1926 double previousY = mY.at( vertex.
vertex - 1 );
1927 double currentX = mX.at( vertex.
vertex );
1928 double currentY = mY.at( vertex.
vertex );
1929 double afterX = mX.at( vertex.
vertex + 1 );
1930 double afterY = mY.at( vertex.
vertex + 1 );
1937 if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 1 )
1940 double dx = mX.at( startVertex.
vertex + 1 ) - mX.at( startVertex.
vertex );
1941 double dy = mY.at( startVertex.
vertex + 1 ) - mY.at( startVertex.
vertex );
1942 return std::sqrt( dx * dx + dy * dy );
1967 mZ.reserve( nPoints );
1968 for (
int i = 0; i < nPoints; ++i )
1998 mM.reserve( nPoints );
1999 for (
int i = 0; i < nPoints; ++i )
2030 std::swap( mX, mY );
2044 addZValue( std::numeric_limits<double>::quiet_NaN() );
2061 int size = mX.size();
2063 double *srcX = mX.data();
2064 double *srcY = mY.data();
2065 double *srcM = hasM ? mM.data() :
nullptr;
2066 double *srcZ = hasZ ? mZ.data() :
nullptr;
2069 for (
int i = 0; i < size; ++i )
2073 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2074 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
2102 int size = mX.size();
2104 double *srcX = mX.data();
2105 double *srcY = mY.data();
2106 double *srcM = hasM ? mM.data() :
nullptr;
2107 double *srcZ = hasZ ? mZ.data() :
nullptr;
2109 double *destX = srcX;
2110 double *destY = srcY;
2111 double *destM = srcM;
2112 double *destZ = srcZ;
2114 int filteredPoints = 0;
2115 for (
int i = 0; i < size; ++i )
2119 double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
2120 double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
2122 if ( filter(
QgsPoint( x, y, z, m ) ) )
2134 mX.resize( filteredPoints );
2135 mY.resize( filteredPoints );
2137 mZ.resize( filteredPoints );
2139 mM.resize( filteredPoints );
2148 int size = mX.size();
2150 double *srcX = mX.data();
2151 double *srcY = mY.data();
2152 double *srcM = hasM ? mM.data() :
nullptr;
2153 double *srcZ = hasZ ? mZ.data() :
nullptr;
2155 for (
int i = 0; i < size; ++i )
2159 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2160 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
VertexType
Types of vertex.
TransformDirection
Indicates the direction (forward or inverse) of a transform.
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.
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.
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.
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 * yData() const
Returns a const pointer to the y 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
Sums up the area of the curve by iterating over the vertices (shoelace formula).
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.
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()
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.
void setPoints(const QgsPointSequence &points)
Resets the line string to match the specified list of points.
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the linestring does not have m values.
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.
bool insertVertex(QgsVertexId position, const QgsPoint &vertex) override
Inserts a vertex into the geometry.
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.
const double * xData() const
Returns a const pointer to the x vertex data.
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the linestring does not have z values.
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.
bool intersects(const QgsRectangle &rect) const SIP_HOLDGIL
Returns true when rectangle intersects with other 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.