23#include <nlohmann/json.hpp>
33#include <QDomDocument>
38using namespace Qt::StringLiterals;
62 double *x =
mX.data();
63 double *y =
mY.data();
88QgsLineString::QgsLineString(
const QVector<double> &x,
const QVector<double> &y,
const QVector<double> &z,
const QVector<double> &m,
bool is25DType )
91 int pointCount = std::min( x.size(), y.size() );
92 if ( x.size() == pointCount )
98 mX = x.mid( 0, pointCount );
100 if ( y.size() == pointCount )
106 mY = y.mid( 0, pointCount );
108 if ( !z.isEmpty() && z.count() >= pointCount )
111 if ( z.size() == pointCount )
117 mZ = z.mid( 0, pointCount );
120 if ( !m.isEmpty() && m.count() >= pointCount )
123 if ( m.size() == pointCount )
129 mM = m.mid( 0, pointCount );
185 return std::make_unique< QgsLineString >();
187 QVector<double> x( segments + 1 );
188 QVector<double> y( segments + 1 );
192 const bool hasZ = start.
is3D() && controlPoint1.
is3D() && controlPoint2.
is3D() && end.
is3D();
195 z.resize( segments + 1 );
201 m.resize( segments + 1 );
204 double *
xData = x.data();
205 double *
yData = y.data();
206 double *
zData = z.data();
207 double *
mData = m.data();
209 const double step = 1.0 / segments;
211 for (
int i = 0; i <= segments; ++i )
213 const double t = i * step;
216 double iz = std::numeric_limits<double>::quiet_NaN();
217 double im = std::numeric_limits<double>::quiet_NaN();
253 return std::make_unique< QgsLineString >( x, y, z, m );
260 x.resize( polygon.count() );
261 y.resize( polygon.count() );
262 double *
xData = x.data();
263 double *
yData = y.data();
265 const QPointF *src = polygon.data();
266 for (
int i = 0; i < polygon.size(); ++i )
273 return std::make_unique< QgsLineString >( x, y );
289 const int size =
mX.size();
293 const double *x =
mX.constData();
294 const double *y =
mY.constData();
295 const bool useZ =
is3D();
297 const double *z = useZ ?
mZ.constData() :
nullptr;
298 const double *m = useM ?
mM.constData() :
nullptr;
300 for (
int i = 0; i < size; ++i )
319 error = QObject::tr(
"LineString has less than 2 points and is not empty." );
330 bool res =
snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing,
mX,
mY,
mZ,
mM, result->mX, result->mY, result->mZ, result->mM, removeRedundantPoints );
332 return result.release();
339 if (
mX.count() <= 2 )
342 double prevX =
mX.at( 0 );
343 double prevY =
mY.at( 0 );
345 bool useZ = hasZ && useZValues;
346 double prevZ = useZ ?
mZ.at( 0 ) : 0;
348 int remaining =
mX.count();
349 while ( i < remaining )
351 double currentX =
mX.at( i );
352 double currentY =
mY.at( i );
353 double currentZ = useZ ?
mZ.at( i ) : 0;
387 if (
is3D() && closed )
388 closed &=
qgsDoubleNear(
mZ.first(),
mZ.last() ) || ( std::isnan(
mZ.first() ) && std::isnan(
mZ.last() ) );
401 return mBoundingBox.toRectangle().intersects( rectangle );
403 const int nb =
mX.size();
413 || rectangle.
contains(
mX.at(
static_cast< int >( nb * 0.2 ) ),
mY.at(
static_cast< int >( nb * 0.2 ) ) )
414 || rectangle.
contains(
mX.at(
static_cast< int >( nb * 0.4 ) ),
mY.at(
static_cast< int >( nb * 0.4 ) ) )
415 || rectangle.
contains(
mX.at(
static_cast< int >( nb * 0.6 ) ),
mY.at(
static_cast< int >( nb * 0.6 ) ) )
416 || rectangle.
contains(
mX.at(
static_cast< int >( nb * 0.8 ) ),
mY.at(
static_cast< int >( nb * 0.8 ) ) )
417 || rectangle.
contains(
mX.at( nb - 1 ),
mY.at( nb - 1 ) ) )
426 double xmin = std::numeric_limits<double>::max();
427 double ymin = std::numeric_limits<double>::max();
428 double zmin = -std::numeric_limits<double>::max();
429 double xmax = -std::numeric_limits<double>::max();
430 double ymax = -std::numeric_limits<double>::max();
431 double zmax = -std::numeric_limits<double>::max();
433 const double *x =
mX.constData();
434 const double *y =
mY.constData();
435 const double *z =
is3D() ?
mZ.constData() :
nullptr;
436 bool foundPointInRectangle =
false;
437 for (
int i = 0; i < nb; ++i )
439 const double px = *x++;
440 xmin = std::min( xmin, px );
441 xmax = std::max( xmax, px );
442 const double py = *y++;
443 ymin = std::min( ymin, py );
444 ymax = std::max( ymax, py );
447 const double pz = *z++;
448 zmin = std::min( zmin, pz );
449 zmax = std::max( zmax, pz );
452 if ( !foundPointInRectangle && rectangle.
contains( px, py ) )
454 foundPointInRectangle =
true;
470 if ( foundPointInRectangle )
495 const int nb =
mX.size();
505 || 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 ) ) )
506 || 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 ) ) )
507 || 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 ) ) )
508 || 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 ) ) )
509 || box3d.
contains(
mX.at( nb - 1 ),
mY.at( nb - 1 ),
mZ.at( nb - 1 ) ) )
518 double xmin = std::numeric_limits<double>::max();
519 double ymin = std::numeric_limits<double>::max();
520 double zmin = std::numeric_limits<double>::max();
521 double xmax = -std::numeric_limits<double>::max();
522 double ymax = -std::numeric_limits<double>::max();
523 double zmax = -std::numeric_limits<double>::max();
525 const double *x =
mX.constData();
526 const double *y =
mY.constData();
527 const double *z =
mZ.constData();
528 bool foundPointInBox =
false;
529 for (
int i = 0; i < nb; ++i )
531 const double px = *x++;
532 xmin = std::min( xmin, px );
533 xmax = std::max( xmax, px );
534 const double py = *y++;
535 ymin = std::min( ymin, py );
536 ymax = std::max( ymax, py );
537 const double pz = *z++;
538 zmin = std::min( zmin, pz );
539 zmax = std::max( zmax, pz );
541 if ( !foundPointInBox && box3d.
contains( px, py, pz ) )
543 foundPointInBox =
true;
559 if ( foundPointInBox )
572 QVector< QgsVertexId > res;
573 if (
mX.count() <= 1 )
576 const double *x =
mX.constData();
577 const double *y =
mY.constData();
579 bool useZ = hasZ && useZValues;
580 const double *z = useZ ?
mZ.constData() :
nullptr;
584 double prevZ = z ? *z++ : 0;
587 for (
int i = 1; i <
mX.count(); ++i )
589 double currentX = *x++;
590 double currentY = *y++;
591 double currentZ = useZ ? *z++ : 0;
609 const int nb =
mX.size();
612 const double *x =
mX.constData();
613 const double *y =
mY.constData();
614 QPointF *dest =
points.data();
615 for (
int i = 0; i < nb; ++i )
617 *dest++ = QPointF( *x++, *y++ );
623void simplifySection(
int i,
int j,
const double *x,
const double *y, std::vector< bool > &usePoint,
const double distanceToleranceSquared,
const double epsilon )
630 double maxDistanceSquared = -1.0;
635 for (
int k = i + 1; k < j; k++ )
639 if ( distanceSquared > maxDistanceSquared )
641 maxDistanceSquared = distanceSquared;
645 if ( maxDistanceSquared <= distanceToleranceSquared )
647 for (
int k = i + 1; k < j; k++ )
654 simplifySection( i, maxIndex, x, y, usePoint, distanceToleranceSquared, epsilon );
655 simplifySection( maxIndex, j, x, y, usePoint, distanceToleranceSquared, epsilon );
668 const double distanceToleranceSquared = tolerance * tolerance;
669 const double *
xData =
mX.constData();
670 const double *
yData =
mY.constData();
671 const double *
zData =
mZ.constData();
672 const double *
mData =
mM.constData();
674 const int size =
mX.size();
676 std::vector< bool > usePoint( size,
true );
678 constexpr double epsilon = 4 * std::numeric_limits<double>::epsilon();
681 QVector< double > newX;
682 newX.reserve( size );
683 QVector< double > newY;
684 newY.reserve( size );
686 const bool hasZ =
is3D();
688 QVector< double > newZ;
690 newZ.reserve( size );
691 QVector< double > newM;
693 newM.reserve( size );
695 for (
int i = 0, n = size; i < n; ++i )
697 if ( usePoint[i] || i == n - 1 )
699 newX.append(
xData[i] );
700 newY.append(
yData[i] );
702 newZ.append(
zData[i] );
704 newM.append(
mData[i] );
708 const bool simplifyRing =
isRing();
709 const int newSize = newX.size();
710 if ( simplifyRing && newSize > 3 )
715 if ( distanceSquared <= distanceToleranceSquared )
718 newX.last() = newX.first();
720 newY.last() = newY.first();
724 newZ.last() = newZ.first();
729 newM.last() = newM.first();
744 auto result2D = std::minmax_element(
mX.begin(),
mX.end() );
745 const double xmin = *result2D.first;
746 const double xmax = *result2D.second;
747 result2D = std::minmax_element(
mY.begin(),
mY.end() );
748 const double ymin = *result2D.first;
749 const double ymax = *result2D.second;
751 double zmin = std::numeric_limits< double >::quiet_NaN();
752 double zmax = std::numeric_limits< double >::quiet_NaN();
756 auto resultZ = std::minmax_element(
mZ.begin(),
mZ.end() );
757 zmin = *resultZ.first;
758 zmax = *resultZ.second;
761 return QgsBox3D( xmin, ymin, zmin, xmax, ymax, zmax );
779 QDomElement elemLineString = doc.createElementNS( ns, u
"LineString"_s );
782 return elemLineString;
786 return elemLineString;
794 QDomElement elemLineString = doc.createElementNS( ns, u
"LineString"_s );
797 return elemLineString;
800 return elemLineString;
819 kml.append(
"<LinearRing>"_L1 );
823 kml.append(
"<LineString>"_L1 );
826 kml.append(
"<altitudeMode>"_L1 );
829 kml.append(
"absolute"_L1 );
833 kml.append(
"clampToGround"_L1 );
835 kml.append(
"</altitudeMode>"_L1 );
836 kml.append(
"<coordinates>"_L1 );
838 int nPoints =
mX.size();
839 for (
int i = 0; i < nPoints; ++i )
843 kml.append(
" "_L1 );
846 kml.append(
","_L1 );
850 kml.append(
","_L1 );
855 kml.append(
",0"_L1 );
858 kml.append(
"</coordinates>"_L1 );
861 kml.append(
"</LinearRing>"_L1 );
865 kml.append(
"</LineString>"_L1 );
879 const int size =
mX.size();
883 const double *x =
mX.constData();
884 const double *y =
mY.constData();
890 for (
int i = 1; i < size; ++i )
894 total += std::sqrt( dx * dx + dy * dy );
904 QVector< double > x1, y1, z1, m1;
905 QVector< double > x2, y2, z2, m2;
908 std::unique_ptr< QgsLineString > first;
909 if ( x1.isEmpty() || ( x1.size() < 2 && x2.size() >= 2 ) )
910 first = std::make_unique< QgsLineString >();
912 first = std::make_unique< QgsLineString >( x1, y1, z1, m1 );
914 std::unique_ptr< QgsLineString > second;
915 if ( x2.isEmpty() || x2.size() < 2 )
916 second = std::make_unique< QgsLineString >();
918 second = std::make_unique< QgsLineString >( x2, y2, z2, m2 );
920 return std::make_tuple( std::move( first ), std::move( second ) );
925 const double *allPointsX =
xData();
926 const double *allPointsY =
yData();
928 QVector<double> partX;
929 QVector<double> partY;
930 QSet<QgsPointXY> partPointSet;
932 QVector<QgsLineString *> disjointParts;
933 for (
size_t i = 0; i < allPointsCount; i++ )
935 const QgsPointXY point( *allPointsX++, *allPointsY++ );
936 if ( partPointSet.contains( point ) )
940 disjointParts.push_back(
new QgsLineString( partX, partY ) );
942 partX = { partX.last() };
943 partY = { partY.last() };
944 partPointSet = {
QgsPointXY( partX[0], partY[0] ) };
946 partX.push_back( point.
x() );
947 partY.push_back( point.
y() );
948 partPointSet.insert( point );
951 if ( partX.size() > 1 || disjointParts.size() == 0 )
952 disjointParts.push_back(
new QgsLineString( partX, partY ) );
954 return disjointParts;
962 const int size =
mX.size();
966 const double *x =
mX.constData();
967 const double *y =
mY.constData();
968 const double *z =
mZ.constData();
975 for (
int i = 1; i < size; ++i )
980 total += std::sqrt( dx * dx + dy * dy + dz * dz );
1002 Q_UNUSED( tolerance )
1003 Q_UNUSED( toleranceType )
1023 const bool hasZ =
static_cast< bool >( z );
1024 const bool hasM =
static_cast< bool >( m );
1045 double *destX =
mX.data();
1046 double *destY =
mY.data();
1047 double *destZ =
nullptr;
1057 double *destM =
nullptr;
1068 for (
size_t i = 0; i < size; ++i )
1095 const double distance,
const std::function<
bool(
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double,
double )> &visitPoint
1101 double distanceTraversed = 0;
1103 if ( totalPoints == 0 )
1106 const double *x =
mX.constData();
1107 const double *y =
mY.constData();
1108 const double *z =
is3D() ?
mZ.constData() :
nullptr;
1109 const double *m =
isMeasure() ?
mM.constData() :
nullptr;
1111 double prevX = *x++;
1112 double prevY = *y++;
1113 double prevZ = z ? *z++ : 0.0;
1114 double prevM = m ? *m++ : 0.0;
1118 visitPoint( prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM );
1122 double pZ = std::numeric_limits<double>::quiet_NaN();
1123 double pM = std::numeric_limits<double>::quiet_NaN();
1124 double nextPointDistance = distance;
1125 const double eps = 4 * nextPointDistance * std::numeric_limits<double>::epsilon();
1126 for (
int i = 1; i < totalPoints; ++i )
1128 double thisX = *x++;
1129 double thisY = *y++;
1130 double thisZ = z ? *z++ : 0.0;
1131 double thisM = m ? *m++ : 0.0;
1137 const double distanceToPoint = std::min( nextPointDistance - distanceTraversed,
segmentLength );
1140 pointOnLineWithDistance( prevX, prevY, thisX, thisY, distanceToPoint, pX, pY, z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &pZ :
nullptr, m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &pM :
nullptr );
1142 if ( !visitPoint( pX, pY, pZ, pM, prevX, prevY, prevZ, prevM, thisX, thisY, thisZ, thisM ) )
1145 nextPointDistance += distance;
1167 std::unique_ptr< QgsPoint > res;
1168 visitPointsByRegularDistance( distance, [&](
double x,
double y,
double z,
double m,
double,
double,
double,
double,
double,
double,
double,
double ) ->
bool {
1169 res = std::make_unique< QgsPoint >( pointType, x, y, z, m );
1172 return res.release();
1177 return lineLocatePointByMPrivate( m, x, y, z, distanceFromStart, use3DDistance,
false );
1180bool QgsLineString::lineLocatePointByMPrivate(
double m,
double &x,
double &y,
double &z,
double &distanceFromStart,
bool use3DDistance,
bool haveInterpolatedM )
const
1185 distanceFromStart = 0;
1187 if ( totalPoints == 0 )
1190 const double *
xData =
mX.constData();
1191 const double *
yData =
mY.constData();
1192 const double *
mData =
mM.constData();
1194 const double *
zData =
is3D() ?
mZ.constData() :
nullptr;
1195 use3DDistance &=
static_cast< bool >(
zData );
1197 double prevX = *
xData++;
1198 double prevY = *
yData++;
1200 double prevM = *
mData++;
1203 while ( i < totalPoints )
1205 double thisX = *
xData++;
1206 double thisY = *
yData++;
1208 double thisM = *
mData++;
1211 if ( std::isnan( thisM ) )
1213 if ( haveInterpolatedM )
1217 std::unique_ptr< QgsLineString > interpolatedM(
interpolateM( use3DDistance ) );
1218 return interpolatedM->lineLocatePointByMPrivate( m, x, y, z, distanceFromStart, use3DDistance,
true );
1230 double totalLengthOfSegmentsWithConstantM = 0;
1231 for (
int j = 0; j < ( totalPoints - i ); ++j )
1241 distanceFromStart += totalLengthOfSegmentsWithConstantM / 2;
1251 const double delta = ( m - prevM ) / ( thisM - prevM );
1256 z = prevZ + ( thisZ - prevZ ) * delta;
1257 distanceFromStart += distanceToPoint;
1274 if ( startDistance < 0 && endDistance < 0 )
1277 endDistance = std::max( startDistance, endDistance );
1280 if ( totalPoints == 0 )
1283 QVector< QgsPoint > substringPoints;
1284 substringPoints.reserve( totalPoints );
1292 const double *x =
mX.constData();
1293 const double *y =
mY.constData();
1294 const double *z =
is3D() ?
mZ.constData() :
nullptr;
1295 const double *m =
isMeasure() ?
mM.constData() :
nullptr;
1297 double distanceTraversed = 0;
1298 double prevX = *x++;
1299 double prevY = *y++;
1300 double prevZ = z ? *z++ : 0.0;
1301 double prevM = m ? *m++ : 0.0;
1302 bool foundStart =
false;
1304 if ( startDistance < 0 )
1307 for (
int i = 1; i < totalPoints; ++i )
1309 double thisX = *x++;
1310 double thisY = *y++;
1311 double thisZ = z ? *z++ : 0.0;
1312 double thisM = m ? *m++ : 0.0;
1316 if ( distanceTraversed <= startDistance && startDistance < distanceTraversed +
segmentLength )
1319 const double distanceToStart = startDistance - distanceTraversed;
1320 double startX, startY;
1324 pointOnLineWithDistance( prevX, prevY, thisX, thisY, distanceToStart, startX, startY, z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &startZ :
nullptr, m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &startM :
nullptr );
1325 substringPoints <<
QgsPoint( pointType, startX, startY, startZ, startM );
1328 if ( foundStart && ( distanceTraversed +
segmentLength > endDistance ) )
1331 const double distanceToEnd = endDistance - distanceTraversed;
1336 pointOnLineWithDistance( prevX, prevY, thisX, thisY, distanceToEnd, endX, endY, z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &endZ :
nullptr, m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &endM :
nullptr );
1337 substringPoints <<
QgsPoint( pointType, endX, endY, endZ, endM );
1339 else if ( foundStart )
1341 substringPoints <<
QgsPoint( pointType, thisX, thisY, thisZ, thisM );
1349 if ( distanceTraversed >= endDistance )
1354 if ( !foundStart &&
qgsDoubleNear( distanceTraversed, startDistance ) )
1356 substringPoints <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM ) <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1381 if ( path.isEmpty() || path.currentPosition() != QPointF(
mX.at( 0 ),
mY.at( 0 ) ) )
1383 path.moveTo(
mX.at( 0 ),
mY.at( 0 ) );
1386 for (
int i = 1; i < nPoints; ++i )
1388 path.lineTo(
mX.at( i ),
mY.at( i ) );
1401 return compoundCurve;
1406 if (
mX.size() < 2 ||
mY.size() < 2 )
1409 const bool extendStart = startDistance > 0;
1410 const bool extendEnd = endDistance > 0;
1412 constexpr double DEG_TO_RAD = M_PI / 180.0;
1417 double dx =
mX.at( 0 ) -
mX.at( 1 );
1418 double dy =
mY.at( 0 ) -
mY.at( 1 );
1419 const double currentLen = std::sqrt( std::pow( dx, 2 ) + std::pow( dy, 2 ) );
1420 if ( currentLen > 0 )
1425 const double startRad = startDeflection * DEG_TO_RAD;
1426 const double cosStart = std::cos( startRad );
1427 const double sinStart = std::sin( startRad );
1428 const double rotatedDx = dx * cosStart + dy * sinStart;
1429 const double rotatedDy = -dx * sinStart + dy * cosStart;
1431 const double newX =
mX.at( 0 ) + ( rotatedDx / currentLen ) * startDistance;
1432 const double newY =
mY.at( 0 ) + ( rotatedDy / currentLen ) * startDistance;
1434 mX.insert(
mX.begin(), newX );
1435 mY.insert(
mY.begin(), newY );
1439 mZ.insert(
mZ.begin(),
mZ.at( 0 ) );
1443 mM.insert(
mM.begin(),
mM.at( 0 ) );
1448 const double newLen = currentLen + startDistance;
1449 mX[0] =
mX.at( 1 ) + dx / currentLen * newLen;
1450 mY[0] =
mY.at( 1 ) + dy / currentLen * newLen;
1457 const qsizetype last =
mX.size() - 1;
1458 double dx =
mX.at( last ) -
mX.at( last - 1 );
1459 double dy =
mY.at( last ) -
mY.at( last - 1 );
1460 const double currentLen = std::sqrt( std::pow( dx, 2 ) + std::pow( dy, 2 ) );
1462 if ( currentLen > 0 )
1467 const double endRad = endDeflection * DEG_TO_RAD;
1468 const double cosEnd = std::cos( endRad );
1469 const double sinEnd = std::sin( endRad );
1470 const double rotatedDx = dx * cosEnd + dy * sinEnd;
1471 const double rotatedDy = -dx * sinEnd + dy * cosEnd;
1473 const double newX =
mX.at( last ) + ( rotatedDx / currentLen ) * endDistance;
1474 const double newY =
mY.at( last ) + ( rotatedDy / currentLen ) * endDistance;
1476 mX.push_back( newX );
1477 mY.push_back( newY );
1482 mZ.push_back(
mZ.at( last ) );
1486 mM.push_back(
mM.at( last ) );
1491 const double newLen = currentLen + endDistance;
1492 mX[last] =
mX.at( last - 1 ) + dx / currentLen * newLen;
1493 mY[last] =
mY.at( last - 1 ) + dy / currentLen * newLen;
1498 if ( extendStart || extendEnd )
1504 auto result = std::make_unique< QgsLineString >();
1506 return result.release();
1511 return u
"LineString"_s;
1532 mX.insert( position.
vertex, vertex.
x() );
1533 mY.insert( position.
vertex, vertex.
y() );
1536 mZ.insert( position.
vertex, vertex.
z() );
1540 mM.insert( position.
vertex, vertex.
m() );
1575 if ( positions.isEmpty() )
1580 QList<QgsVertexId>
vertices( positions.begin(), positions.end() );
1600 mX.remove( position.vertex );
1601 mY.remove( position.vertex );
1604 mZ.remove( position.vertex );
1608 mM.remove( position.vertex );
1629 mX.append( pt.
x() );
1630 mY.append( pt.
y() );
1633 mZ.append( pt.
z() );
1637 mM.append( pt.
m() );
1644 double sqrDist = std::numeric_limits<double>::max();
1645 double leftOfDist = std::numeric_limits<double>::max();
1647 double prevLeftOfX = 0.0;
1648 double prevLeftOfY = 0.0;
1649 double testDist = 0;
1650 double segmentPtX, segmentPtY;
1655 const int size =
mX.size();
1656 if ( size == 0 || size == 1 )
1662 const double *
xData =
mX.constData();
1663 const double *
yData =
mY.constData();
1664 for (
int i = 1; i < size; ++i )
1666 double prevX =
xData[i - 1];
1667 double prevY =
yData[i - 1];
1668 double currentX =
xData[i];
1669 double currentY =
yData[i];
1671 if ( testDist < sqrDist )
1674 segmentPt.
setX( segmentPtX );
1675 segmentPt.
setY( segmentPtY );
1676 vertexAfter.
part = 0;
1677 vertexAfter.
ring = 0;
1688 if (
qgsDoubleNear( testDist, leftOfDist ) && left != prevLeftOf && prevLeftOf != 0 )
1700 prevLeftOf = *leftOf;
1701 leftOfDist = testDist;
1702 prevLeftOfX = prevX;
1703 prevLeftOfY = prevY;
1705 else if ( testDist < leftOfDist )
1708 leftOfDist = testDist;
1742 double totalLineLength = 0.0;
1743 double prevX =
mX.at( 0 );
1744 double prevY =
mY.at( 0 );
1750 double currentX =
mX.at( i );
1751 double currentY =
mY.at( i );
1752 double segmentLength = std::sqrt( std::pow( currentX - prevX, 2.0 ) + std::pow( currentY - prevY, 2.0 ) );
1768 return QgsPoint( sumX / totalLineLength, sumY / totalLineLength );
1786 const int maxIndex =
mX.size();
1793 const double *x =
mX.constData();
1794 const double *y =
mY.constData();
1795 double prevX = *x++;
1796 double prevY = *y++;
1797 for (
int i = 1; i < maxIndex; ++i )
1799 mSummedUpArea += prevX * ( *y - prevY ) - prevY * ( *x - prevX );
1847 if ( planeNormal.
z() < 0 )
1849 planeNormal = -planeNormal;
1854 if ( planeNormal.
y() < 0 )
1855 planeNormal = -planeNormal;
1859 if ( planeNormal.
x() < 0 )
1860 planeNormal = -planeNormal;
1864 const double *x =
mX.constData();
1865 const double *y =
mY.constData();
1866 const double *z =
mZ.constData();
1868 double prevX = *x++;
1869 double prevY = *y++;
1870 double prevZ = *z++;
1872 double normalX = 0.0;
1873 double normalY = 0.0;
1874 double normalZ = 0.0;
1876 for (
unsigned int i = 1; i <
mX.size(); ++i )
1878 normalX += prevY * ( *z - prevZ ) - prevZ * ( *y - prevY );
1879 normalY += prevZ * ( *x - prevX ) - prevX * ( *z - prevZ );
1880 normalZ += prevX * ( *y - prevY ) - prevY * ( *x - prevX );
1887 mSummedUpArea3D = 0.5 * ( normalX * planeNormal.
x() + normalY * planeNormal.
y() + normalZ * planeNormal.
z() );
1910 if (
mX.count() < 2 )
1922 double currentX =
mX.at( 0 );
1923 double currentY =
mY.at( 0 );
1924 double afterX =
mX.at( 1 );
1925 double afterY =
mY.at( 1 );
1928 else if ( vertex.
vertex == 0 )
1941 double previousX =
mX.at( vertex.
vertex - 1 );
1942 double previousY =
mY.at( vertex.
vertex - 1 );
1943 double currentX =
mX.at( vertex.
vertex );
1944 double currentY =
mY.at( vertex.
vertex );
1945 double afterX =
mX.at( vertex.
vertex + 1 );
1946 double afterY =
mY.at( vertex.
vertex + 1 );
1953 if ( startVertex.
vertex < 0 || startVertex.
vertex >=
mX.count() - 1 )
1958 return std::sqrt( dx * dx + dy * dy );
1977 addZValue( std::numeric_limits<double>::quiet_NaN() );
1990 std::unique_ptr< QgsLineString > cloned(
clone() );
1997 if (
isEmpty() || ( nbpoints < 2 ) )
2002 const double range = end - start;
2003 double lineLength =
length();
2004 double lengthSoFar = 0.0;
2007 double *mOut = cloned->mM.data();
2009 for (
int i = 1; i < nbpoints; ++i )
2012 if ( lineLength > 0.0 )
2013 *mOut++ = start + range * lengthSoFar / lineLength;
2014 else if ( lineLength == 0.0 && nbpoints > 1 )
2015 *mOut++ = start + range * i / ( nbpoints - 1 );
2029 if ( totalPoints < 2 )
2030 return std::unique_ptr< QgsLineString >(
clone() );
2032 const double *
xData =
mX.constData();
2033 const double *
yData =
mY.constData();
2034 const double *
mData =
mM.constData();
2035 const double *
zData =
is3D() ?
mZ.constData() :
nullptr;
2036 use3DDistance &=
static_cast< bool >(
zData );
2038 QVector< double > xOut( totalPoints );
2039 QVector< double > yOut( totalPoints );
2040 QVector< double > mOut( totalPoints );
2041 QVector< double > zOut(
static_cast< bool >(
zData ) ? totalPoints : 0 );
2043 double *xOutData = xOut.data();
2044 double *yOutData = yOut.data();
2045 double *mOutData = mOut.data();
2046 double *zOutData =
static_cast< bool >(
zData ) ? zOut.data() :
nullptr;
2049 double currentSegmentLength = 0;
2050 double lastValidM = std::numeric_limits< double >::quiet_NaN();
2051 double prevX = *
xData;
2052 double prevY = *
yData;
2054 while ( i < totalPoints )
2056 double thisX = *
xData++;
2057 double thisY = *
yData++;
2059 double thisM = *
mData++;
2063 if ( !std::isnan( thisM ) )
2065 *xOutData++ = thisX;
2066 *yOutData++ = thisY;
2067 *mOutData++ = thisM;
2069 *zOutData++ = thisZ;
2076 double scanAheadM = thisM;
2077 while ( i + j + 1 < totalPoints && std::isnan( scanAheadM ) )
2079 scanAheadM =
mData[j];
2082 if ( std::isnan( scanAheadM ) )
2087 *xOutData++ = thisX;
2088 *yOutData++ = thisY;
2089 *mOutData++ = scanAheadM;
2091 *zOutData++ = thisZ;
2092 for ( ; i < j; ++i )
2096 *xOutData++ = thisX;
2097 *yOutData++ = thisY;
2098 *mOutData++ = scanAheadM;
2101 *zOutData++ = *
zData++;
2103 lastValidM = scanAheadM;
2109 double scanAheadX = thisX;
2110 double scanAheadY = thisY;
2111 double scanAheadZ = thisZ;
2112 double distanceToNextValidM = currentSegmentLength;
2113 std::vector< double > scanAheadSegmentLengths;
2114 scanAheadSegmentLengths.emplace_back( currentSegmentLength );
2116 double nextValidM = std::numeric_limits< double >::quiet_NaN();
2117 while ( i + j < totalPoints - 1 )
2119 double nextScanAheadX =
xData[j];
2120 double nextScanAheadY =
yData[j];
2121 double nextScanAheadZ =
zData ?
zData[j] : 0;
2122 double nextScanAheadM =
mData[j];
2123 const double scanAheadSegmentLength = use3DDistance ?
QgsGeometryUtilsBase::distance3D( scanAheadX, scanAheadY, scanAheadZ, nextScanAheadX, nextScanAheadY, nextScanAheadZ )
2125 scanAheadSegmentLengths.emplace_back( scanAheadSegmentLength );
2126 distanceToNextValidM += scanAheadSegmentLength;
2128 if ( !std::isnan( nextScanAheadM ) )
2130 nextValidM = nextScanAheadM;
2134 scanAheadX = nextScanAheadX;
2135 scanAheadY = nextScanAheadY;
2136 scanAheadZ = nextScanAheadZ;
2140 if ( std::isnan( nextValidM ) )
2143 *xOutData++ = thisX;
2144 *yOutData++ = thisY;
2145 *mOutData++ = lastValidM;
2147 *zOutData++ = thisZ;
2149 for ( ; i < totalPoints; ++i )
2151 *xOutData++ = *
xData++;
2152 *yOutData++ = *
yData++;
2153 *mOutData++ = lastValidM;
2155 *zOutData++ = *
zData++;
2162 const double delta = ( nextValidM - lastValidM ) / distanceToNextValidM;
2163 *xOutData++ = thisX;
2164 *yOutData++ = thisY;
2165 *mOutData++ = lastValidM + delta * scanAheadSegmentLengths[0];
2166 double totalScanAheadLength = scanAheadSegmentLengths[0];
2168 *zOutData++ = thisZ;
2169 for (
int k = 1; k <= j; ++i, ++k )
2173 *xOutData++ = thisX;
2174 *yOutData++ = thisY;
2175 totalScanAheadLength += scanAheadSegmentLengths[k];
2176 *mOutData++ = lastValidM + delta * totalScanAheadLength;
2179 *zOutData++ = *
zData++;
2181 lastValidM = nextValidM;
2190 return std::make_unique< QgsLineString >( xOut, yOut, zOut, mOut );
2196 if ( fromVertex.
part != 0 || fromVertex.
ring != 0 || toVertex.
part != 0 || toVertex.
ring != 0 )
2199 const int fromVertexNumber = fromVertex.
vertex;
2200 const int toVertexNumber = toVertex.
vertex;
2203 if ( fromVertexNumber > toVertexNumber )
2209 if ( fromVertexNumber < 0 || fromVertexNumber >= nPoints || toVertexNumber < 0 || toVertexNumber >= nPoints )
2212 if ( fromVertexNumber == toVertexNumber )
2215 const bool is3DGeometry =
is3D();
2216 const double *
xData =
mX.constData();
2217 const double *
yData =
mY.constData();
2218 const double *
zData = is3DGeometry ?
mZ.constData() :
nullptr;
2219 double totalDistance = 0.0;
2222 for (
int i = fromVertexNumber; i < toVertexNumber; ++i )
2233 totalDistance += std::sqrt( dx * dx + dy * dy + dz * dz );
2236 return totalDistance;
QFlags< GeometryValidityFlag > GeometryValidityFlags
Geometry validity flags.
VertexType
Types of vertex.
@ Segment
The actual start or end point of a segment.
GeoJsonProfile
GeoJson export Profile according to OGC Features and Geometries JSON - Part 1: Core https://docs....
WkbType
The WKB type describes the number of dimensions a geometry has.
@ LineString25D
LineString25D.
@ LineStringM
LineStringM.
@ LineStringZM
LineStringZM.
@ LineStringZ
LineStringZ.
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.
QgsVertexIterator vertices() const
Returns a read-only, Java-style iterator for traversal of vertices of all the geometry,...
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.
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.
A 3-dimensional box composed of x, y, z coordinates.
bool contains(const QgsBox3D &other) const
Returns true when box contains other box.
QgsRectangle toRectangle() const
Converts the box to a 2D rectangle.
Compound curve geometry type.
void addCurve(QgsCurve *c, bool extendPrevious=false)
Adds a curve to the geometry (takes ownership).
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 mHasCachedSummedUpArea3D
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 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, bool removeRedundantPoints) const
Helper function for QgsCurve subclasses to snap to grids.
QgsBox3D mBoundingBox
Cached bounding box.
bool hasVertex(QgsVertexId position) const override
Returns true if the geometry contains a vertex matching the given position.
Convenience functions for geometry utils.
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 distance3D(double x1, double y1, double z1, double x2, double y2, double z2)
Returns the 3D distance between (x1, y1, z1) and (x2, y2, z2).
static void interpolatePointOnCubicBezier(double p0x, double p0y, double p0z, double p0m, double p1x, double p1y, double p1z, double p1m, double p2x, double p2y, double p2z, double p2m, double p3x, double p3y, double p3z, double p3m, double t, bool hasZ, bool hasM, double &outX, double &outY, double &outZ, double &outM)
Evaluates a point on a cubic Bézier curve defined by four control points.
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 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 bool checkWeaklyFor3DPlane(const QgsAbstractGeometry *geom, QgsPoint &pt1, QgsPoint &pt2, QgsPoint &pt3, double epsilon=std::numeric_limits< double >::epsilon())
Checks if a 3D geometry has a plane defined by at least 3 non-collinear points.
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 json pointsToJson(const QgsPointSequence &points, int precision, Qgis::GeoJsonProfile profile)
Returns coordinates as json object.
Represents a single 2D line segment, consisting of a 2D start and end vertex only.
double segmentLength(QgsVertexId startVertex) const override
Returns the length of the segment of the geometry which begins at startVertex.
static std::unique_ptr< 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 pointAt(int node, QgsPoint &point, Qgis::VertexType &type) const override
Returns the point and vertex type of a point within the curve.
bool isClosed() const override
Returns true if the curve is closed.
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
QVector< QgsLineString * > splitToDisjointXYParts() const
Divides the linestring into parts that don't share any points or lines.
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.
static std::unique_ptr< QgsLineString > fromQPolygonF(const QPolygonF &polygon)
Returns a new linestring from a QPolygonF polygon input.
QgsLineString * simplifyByDistance(double tolerance) const override
Simplifies the geometry by applying the Douglas Peucker simplification by distance algorithm.
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.
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.
void extend(double startDistance, double endDistance, double startDeflection=0, double endDeflection=0)
Extends the line geometry by extrapolating out the start or end of the line by a specified distance.
void sumUpArea3D(double &sum) const override
Calculates the shoelace/triangle formula sum for the points in the linestring.
void drawAsPolygon(QPainter &p) const override
Draws the curve as a polygon on the specified QPainter.
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.
std::unique_ptr< QgsLineString > interpolateM(bool use3DDistance=true) const
Returns a copy of this line with all missing (NaN) m values interpolated from m values of surrounding...
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...
bool boundingBoxIntersects(const QgsRectangle &rectangle) const override
Returns true if the bounding box of this geometry intersects with a rectangle.
bool deleteVertices(const QSet< QgsVertexId > &positions) override
Deletes vertices within the geometry.
QString geometryType() const override
Returns a unique string representing the geometry type.
std::unique_ptr< 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...
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.
void close()
Closes the line string by appending the first point to the end of the line, if it is not already clos...
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.
QgsCompoundCurve * toCurveType() const override
Returns the geometry converted to the more generic curve type QgsCompoundCurve.
double distanceBetweenVertices(QgsVertexId fromVertex, QgsVertexId toVertex) const override
Returns the distance along the curve between two vertices.
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.
bool lineLocatePointByM(double m, double &x, double &y, double &z, double &distanceFromStart, bool use3DDistance=true) const
Attempts to locate a point on the linestring by m value.
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.
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.
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
Q_DECL_DEPRECATED QgsBox3D calculateBoundingBox3d() const
Calculates the minimal 3D bounding box for the geometry.
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.
QgsPoint * interpolatePoint(double distance) const override
Returns an interpolated point on the curve at the specified distance.
QgsLineString * snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0, bool removeRedundantPoints=false) const override
Makes a new geometry with all the points or vertices snapped to the closest point of the grid.
json asJsonObject(int precision=17, Qgis::GeoJsonProfile profile=Qgis::GeoJsonProfile::Legacy) const override
Returns a json object representation of the geometry with the given precision and profile.
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.
bool dropMValue() override
Drops any measure values which exist in the geometry.
int numPoints() const override
Returns the number of points in the curve.
bool isEmpty() const override
Returns true if the geometry is empty.
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the simple curve does not have m values.
void splitCurveAtVertexProtected(int index, QVector< double > &x1, QVector< double > &y1, QVector< double > &z1, QVector< double > &m1, QVector< double > &x2, QVector< double > &y2, QVector< double > &z2, QVector< double > &m2) const
Returns coordinate vectors for the split curves.
void points(QgsPointSequence &pts) const override
Returns a list of points within the curve.
void clear() override
Clears the geometry, ie reset it to a null geometry.
const double * yData() const
Returns a const pointer to the y vertex data.
QgsPoint startPoint() const override
Returns the starting point of the curve.
QgsPoint pointN(int i) const
Returns the specified point from inside the simple curve.
QgsSimpleCurve * reversed() const override
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
const double * xData() const
Returns a const pointer to the x vertex data.
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the simple curve does not have z values.
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
double y() const
Returns Y coordinate.
double z() const
Returns Z coordinate.
double x() const
Returns X coordinate.
void normalize()
Normalizes the current vector in place.
static QgsVector3D crossProduct(const QgsVector3D &v1, const QgsVector3D &v2)
Returns the cross product of two vectors.
static Qgis::WkbType zmType(Qgis::WkbType type, bool hasZ, bool hasM)
Returns the modified input geometry type according to hasZ / hasM.
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 Q_INVOKABLE bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
static Q_INVOKABLE bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
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
void simplifySection(int i, int j, const double *x, const double *y, std::vector< bool > &usePoint, const double distanceToleranceSquared, const double epsilon)
QLineF segment(int index, QRectF rect, double radius)
double distance2D(const QgsPolylineXY &coords)
Utility class for identifying a unique vertex within a geometry.