24#include <nlohmann/json.hpp>
40#include <QPainterPath>
43using namespace Qt::StringLiterals;
45using namespace nlohmann;
61 if ( !mControlPoints.isEmpty() )
63 const QgsPoint &firstPoint = mControlPoints.first();
64 if ( firstPoint.is3D() )
65 mWkbType = QgsWkbTypes::addZ( mWkbType );
66 if ( firstPoint.isMeasure() )
67 mWkbType = QgsWkbTypes::addM( mWkbType );
78 const int n = mControlPoints.size();
79 if ( n < 2 || mDegree < 1 )
82 if ( mDegree != n - 1 )
88 if ( mKnots.size() != n + mDegree + 1 )
91 for (
int i = 0; i <= mDegree; ++i )
96 for (
int i = n; i < mKnots.size(); ++i )
107 for (
const double w : mWeights )
122 const int n = mControlPoints.size();
123 return mDegree == 3 && n >= 4 && ( n - 1 ) % 3 == 0;
140static int findKnotSpan(
const int degree,
const double u,
const QVector<double> &knots,
const int nPoints )
143 if ( u >= knots[nPoints] )
147 if ( u <= knots[degree] )
153 int mid = ( low + high ) / 2;
155 while ( u < knots[mid] || u >= knots[mid + 1] )
157 if ( u < knots[mid] )
161 mid = ( low + high ) / 2;
171 const int n = mControlPoints.size();
185 return mControlPoints.first();
187 return mControlPoints.last();
189 const bool hasZ = !mControlPoints.
isEmpty() && mControlPoints.first().is3D();
190 const bool hasM = !mControlPoints.isEmpty() && mControlPoints.first().isMeasure();
193 const double u = mKnots[mDegree] + t * ( mKnots[n] - mKnots[mDegree] );
196 const int span = findKnotSpan( mDegree, u, mKnots, n );
201 std::vector<double> tempX( mDegree + 1 );
202 std::vector<double> tempY( mDegree + 1 );
203 std::vector<double> tempZ( mDegree + 1 );
204 std::vector<double> tempM( mDegree + 1 );
205 std::vector<double> tempW( mDegree + 1 );
208 for (
int j = 0; j <= mDegree; ++j )
210 const int cpIdx = span - mDegree + j;
211 const QgsPoint &cp = mControlPoints[cpIdx];
212 const double w = ( cpIdx < mWeights.size() ) ? mWeights[cpIdx] : 1.0;
215 tempX[j] = cp.
x() * w;
216 tempY[j] = cp.
y() * w;
217 tempZ[j] = hasZ ? cp.
z() * w : 0.0;
218 tempM[j] = hasM ? cp.
m() : 0.0;
223 for (
int k = 1; k <= mDegree; ++k )
225 for (
int j = mDegree; j >= k; --j )
227 const int knotIdx = span - mDegree + j;
228 const double denom = mKnots[knotIdx + mDegree - k + 1] - mKnots[knotIdx];
232 const double alpha = ( u - mKnots[knotIdx] ) / denom;
233 const double oneMinusAlpha = 1.0 - alpha;
236 tempX[j] = oneMinusAlpha * tempX[j - 1] + alpha * tempX[j];
237 tempY[j] = oneMinusAlpha * tempY[j - 1] + alpha * tempY[j];
239 tempZ[j] = oneMinusAlpha * tempZ[j - 1] + alpha * tempZ[j];
241 tempM[j] = oneMinusAlpha * tempM[j - 1] + alpha * tempM[j];
244 tempW[j] = oneMinusAlpha * tempW[j - 1] + alpha * tempW[j];
251 double x = tempX[mDegree];
252 double y = tempY[mDegree];
253 double z = tempZ[mDegree];
254 double m = tempM[mDegree];
255 const double w = tempW[mDegree];
272 return QgsPoint( x, y, std::numeric_limits<double>::quiet_NaN(), m );
279 if ( mControlPoints.size() < 2 )
288 if (
is3D() && closed )
289 closed &=
qgsDoubleNear( startPt.
z(), endPt.
z() ) || ( std::isnan( startPt.
z() ) && std::isnan( endPt.
z() ) );
296 if ( mControlPoints.size() < 2 )
308 Q_UNUSED( toleranceType );
312 const int steps = std::max( 2,
static_cast<int>( 2 * M_PI / tolerance ) );
315 for (
int i = 0; i <= steps; ++i )
317 const double t =
static_cast<double>( i ) / steps;
319 line->addVertex( pt );
327 std::unique_ptr<QgsLineString> line(
curveToLine() );
334 std::unique_ptr<QgsLineString> line(
curveToLine() );
336 line->drawAsPolygon( p );
341 std::unique_ptr<QgsLineString> line(
curveToLine() );
342 return line ? line->asQPolygonF() : QPolygonF();
361 if ( o->mDegree != mDegree )
366 if ( mControlPoints != o->mControlPoints )
369 if ( mWeights != o->mWeights )
372 if ( mKnots != o->mKnots )
380 for (
int i = 0; i < mControlPoints.size(); ++i )
382 if (
qgsDoubleNear( mControlPoints[i].distance( point ), 0.0 ) )
392 std::unique_ptr<QgsLineString> line(
curveToLine() );
397 return line->interpolatePoint( distance );
402 return mControlPoints.size();
407 if ( node < 0 || node >= mControlPoints.size() )
411 point = mControlPoints[node];
418 pts.reserve( pts.size() + mControlPoints.size() );
419 for (
const QgsPoint &p : mControlPoints )
428 std::reverse( rev->mControlPoints.begin(), rev->mControlPoints.end() );
429 std::reverse( rev->mWeights.begin(), rev->mWeights.end() );
432 if ( !rev->mKnots.isEmpty() )
434 const double maxKnot = rev->mKnots.last();
435 const double minKnot = rev->mKnots.first();
436 std::reverse( rev->mKnots.begin(), rev->mKnots.end() );
437 for (
double &knot : rev->mKnots )
439 knot = maxKnot + minKnot - knot;
449 if ( !
isClosed() || firstVertexIndex <= 0 || firstVertexIndex >= mControlPoints.size() )
455 std::rotate( mControlPoints.begin(), mControlPoints.begin() + firstVertexIndex, mControlPoints.end() );
456 std::rotate( mWeights.begin(), mWeights.begin() + firstVertexIndex, mWeights.end() );
459 if ( !mKnots.isEmpty() && firstVertexIndex < mKnots.size() )
461 const double delta = mKnots[firstVertexIndex] - mKnots[0];
462 std::rotate( mKnots.begin(), mKnots.begin() + firstVertexIndex, mKnots.end() );
464 for (
double &knot : mKnots )
473std::tuple<std::unique_ptr<QgsCurve>, std::unique_ptr<QgsCurve>>
476 std::unique_ptr<QgsLineString> line(
curveToLine() );
479 return std::make_tuple(
nullptr,
nullptr );
481 return line->splitCurveAtVertex( index );
492 std::unique_ptr<QgsLineString> line(
curveToLine() );
494 line->sumUpArea( sum );
499 std::unique_ptr<QgsLineString> line(
curveToLine() );
501 line->sumUpArea3D( sum );
506 if ( index < 0 || index >= mControlPoints.size() )
508 return mControlPoints[index].x();
513 if ( index < 0 || index >= mControlPoints.size() )
515 return mControlPoints[index].y();
520 if ( index < 0 || index >= mControlPoints.size() )
522 return mControlPoints[index].is3D() ? mControlPoints[index].z() : std::numeric_limits<double>::quiet_NaN();
527 if ( index < 0 || index >= mControlPoints.size() )
529 return mControlPoints[index].isMeasure() ? mControlPoints[index].m() : std::numeric_limits<double>::quiet_NaN();
540 for (
QgsPoint &p : mControlPoints )
542 p.addZValue( zValue );
556 for (
QgsPoint &p : mControlPoints )
558 p.addMValue( mValue );
569 for (
QgsPoint &p : mControlPoints )
571 p.setZ( std::numeric_limits<double>::quiet_NaN() );
584 for (
QgsPoint &p : mControlPoints )
586 p.setM( std::numeric_limits<double>::quiet_NaN() );
596 if ( position.
part != 0 || position.
ring != 0 )
600 const int idx = position.
vertex;
601 if ( idx < 0 || idx >= mControlPoints.size() )
605 mControlPoints.remove( idx );
606 if ( idx < mWeights.size() )
608 mWeights.remove( idx );
619 QVector<QgsPoint> newPts;
620 QVector<double> newWeights;
621 for (
int i = 0; i < mControlPoints.size(); ++i )
623 if ( filter( mControlPoints[i] ) )
625 newPts.append( mControlPoints[i] );
626 if ( i < mWeights.size() )
627 newWeights.append( mWeights[i] );
630 mControlPoints = newPts;
631 mWeights = newWeights;
640 Q_ASSERT( numControlPoints >
degree );
642 const int knotsSize = numControlPoints +
degree + 1;
643 QVector<double>
knots;
644 knots.reserve( knotsSize );
645 for (
int i = 0; i < knotsSize; ++i )
649 else if ( i >= numControlPoints )
652 knots.append(
static_cast<double>( i -
degree ) / ( numControlPoints -
degree ) );
670 const unsigned char headerEndianness = *
static_cast<const unsigned char *
>( wkb );
688 mDegree =
static_cast<int>(
degree );
691 quint32 numControlPoints;
692 wkb >> numControlPoints;
702 const int minBytesPerPoint = 18 + (
is3D ? 8 : 0 ) + (
isMeasure ? 8 : 0 );
703 if ( numControlPoints >
static_cast<quint32
>( wkb.
remaining() / minBytesPerPoint + 1 ) )
706 mControlPoints.clear();
708 mControlPoints.reserve( numControlPoints );
709 mWeights.reserve( numControlPoints );
712 for ( quint32 i = 0; i < numControlPoints; ++i )
715 char pointEndianness;
716 wkb >> pointEndianness;
720 if (
static_cast<unsigned char>( pointEndianness ) != headerEndianness )
724 double x, y, z = 0.0, m = 0.0;
737 if ( weightFlag == 1 )
750 point =
QgsPoint( x, y, std::numeric_limits<double>::quiet_NaN(), m );
754 mControlPoints.append( point );
755 mWeights.append(
weight );
763 const quint32 expectedKnots = numControlPoints +
degree + 1;
764 if ( numKnots != expectedKnots )
768 if ( numKnots *
sizeof(
double ) >
static_cast<quint32
>( wkb.
remaining() ) )
772 mKnots.reserve( numKnots );
775 for ( quint32 i = 0; i < numKnots; ++i )
779 mKnots.append( knot );
789 const QString geomTypeStr = wkt.split(
'(' )[0].trimmed().toUpper();
791 if ( !geomTypeStr.startsWith(
"NURBSCURVE"_L1 ) )
798 if ( geomTypeStr.contains(
"ZM"_L1 ) )
800 else if ( geomTypeStr.endsWith(
'Z' ) || geomTypeStr.endsWith(
" Z"_L1 ) )
802 else if ( geomTypeStr.endsWith(
'M' ) || geomTypeStr.endsWith(
" M"_L1 ) )
809 if (
parts.second.compare(
"EMPTY"_L1, Qt::CaseInsensitive ) == 0 ||
parts.second.isEmpty() )
815 if ( blocks.isEmpty() )
820 int degree = blocks[0].trimmed().toInt( &ok );
824 if ( blocks.size() < 2 )
828 QString pointsStr = blocks[1].trimmed();
831 if ( !pointsStr.startsWith(
'('_L1 ) || !pointsStr.endsWith(
')'_L1 ) )
834 pointsStr = pointsStr.mid( 1, pointsStr.length() - 2 ).trimmed();
837 QStringList pointsCoords = pointsStr.split(
',', Qt::SkipEmptyParts );
840 const thread_local QRegularExpression rx( u
"\\s+"_s );
842 for (
const QString &pointStr : pointsCoords )
844 QStringList coords = pointStr.trimmed().split( rx, Qt::SkipEmptyParts );
846 if ( coords.size() < 2 )
852 double x = coords[0].toDouble( &ok );
856 double y = coords[1].toDouble( &ok );
861 if ( coords.size() >= 3 )
866 double m = coords[2].toDouble( &ok );
869 point =
QgsPoint( x, y, std::numeric_limits<double>::quiet_NaN(), m );
874 double z = coords[2].toDouble( &ok );
882 double z = coords[2].toDouble( &ok );
885 double m = coords[3].toDouble( &ok );
890 else if (
isMeasure() && coords.size() >= 4 )
893 double z = coords[2].toDouble( &ok );
896 double m = coords[3].toDouble( &ok );
906 double z = coords[2].toDouble( &ok );
915 double z = coords[2].toDouble( &ok );
918 double m = coords[3].toDouble( &ok );
960 mWeights.append( 1.0 );
964 bool hasWeights =
false;
965 bool hasKnots =
false;
968 for (
int i = 2; i < blocks.size(); ++i )
970 QString block = blocks[i].trimmed();
972 if ( block.startsWith(
'('_L1 ) )
975 if ( !block.endsWith(
')'_L1 ) )
979 block = block.mid( 1, block.length() - 2 ).trimmed();
980 QStringList values = block.split(
',', Qt::SkipEmptyParts );
982 QVector<double> parsedValues;
983 for (
const QString &valueStr : values )
986 double value = valueStr.trimmed().toDouble( &ok );
989 parsedValues.append( value );
992 if ( !hasWeights && parsedValues.size() ==
controlPoints.size() )
995 mWeights = parsedValues;
998 else if ( !hasKnots )
1001 mKnots = parsedValues;
1033 if ( mDegree != o->mDegree || mControlPoints.size() != o->mControlPoints.size() || mWeights.size() != o->mWeights.size() || mKnots.size() != o->mKnots.size() )
1038 for (
int i = 0; i < mControlPoints.size(); ++i )
1040 if ( mControlPoints[i].distance( o->mControlPoints[i] ) >= epsilon )
1044 for (
int i = 0; i < mWeights.size(); ++i )
1046 if ( std::fabs( mWeights[i] - o->mWeights[i] ) > epsilon )
1050 for (
int i = 0; i < mKnots.size(); ++i )
1052 if ( std::fabs( mKnots[i] - o->mKnots[i] ) > epsilon )
1066 return u
"NurbsCurve"_s;
1086 if (
id.part != 0 ||
id.ring != 0 )
1090 const int idx =
id.vertex;
1091 if ( idx < 0 || idx >= mControlPoints.size() )
1095 return mControlPoints[idx];
1100 return ( part == 0 && ring == 0 ) ? mControlPoints.size() : 0;
1105 if (
id.part == 0 &&
id.ring == 0 )
1117 if ( mValidityComputed )
1120 error = u
"NURBS curve is invalid"_s;
1124 mValidityComputed =
true;
1129 error = u
"Degree must be >= 1"_s;
1133 const int n = mControlPoints.size();
1134 if ( n < mDegree + 1 )
1136 error = u
"Not enough control points for degree"_s;
1140 if ( mKnots.size() != n + mDegree + 1 )
1142 error = u
"Knot vector size is incorrect"_s;
1146 if ( mWeights.size() != n )
1148 error = u
"Weights vector size mismatch"_s;
1153 for (
int i = 1; i < mKnots.size(); ++i )
1155 if ( mKnots[i] < mKnots[i - 1] )
1157 error = u
"Knot vector values must be non-decreasing"_s;
1168 std::unique_ptr<QgsLineString> line(
curveToLine() );
1170 line->addToPainterPath( path );
1175 std::unique_ptr<QgsLineString> line(
curveToLine() );
1178 return line->curveSubstring( startDistance, endDistance );
1183 std::unique_ptr<QgsLineString> line(
curveToLine() );
1184 return line ? line->length() : 0.0;
1189 std::unique_ptr<QgsLineString> line(
curveToLine() );
1192 return line->segmentLength( startVertex );
1197 std::unique_ptr<QgsLineString> line(
curveToLine() );
1200 return line->distanceBetweenVertices( fromVertex, toVertex );
1206 for (
QgsPoint &pt : result->mControlPoints )
1209 pt.
setX( std::round( pt.
x() / hSpacing ) * hSpacing );
1211 pt.
setY( std::round( pt.
y() / vSpacing ) * vSpacing );
1212 if ( pt.
is3D() && dSpacing > 0 )
1213 pt.
setZ( std::round( pt.
z() / dSpacing ) * dSpacing );
1215 pt.
setM( std::round( pt.
m() / mSpacing ) * mSpacing );
1218 if ( removeRedundantPoints )
1219 result->removeDuplicateNodes();
1226 std::unique_ptr<QgsLineString> line(
curveToLine() );
1229 return line->simplifyByDistance( tolerance );
1234 if ( mControlPoints.size() < 2 )
1237 QVector<QgsPoint> newPoints;
1238 QVector<double> newWeights;
1240 newPoints.reserve( mControlPoints.size() );
1241 newWeights.reserve( mWeights.size() );
1243 newPoints.append( mControlPoints.first() );
1244 if ( !mWeights.isEmpty() )
1245 newWeights.append( mWeights.first() );
1247 for (
int i = 1; i < mControlPoints.size(); ++i )
1249 const double dist = ( useZValues && mControlPoints[i].is3D() && mControlPoints[i - 1].
is3D() )
1250 ? mControlPoints[i].distance3D( mControlPoints[i - 1] )
1251 : mControlPoints[i].distance( mControlPoints[i - 1] );
1253 if ( dist >= epsilon )
1255 newPoints.append( mControlPoints[i] );
1256 if ( i < mWeights.size() )
1257 newWeights.append( mWeights[i] );
1261 const bool changed = ( newPoints.size() != mControlPoints.size() );
1265 mControlPoints = newPoints;
1266 mWeights = newWeights;
1277 std::unique_ptr<QgsLineString> line(
curveToLine() );
1280 return line->vertexAngle( vertex );
1285 for (
QgsPoint &pt : mControlPoints )
1287 const double x = pt.x();
1296 Q_UNUSED( feedback );
1300 for (
QgsPoint &pt : mControlPoints )
1302 double x = pt.x(), y = pt.y(), z = pt.z(), m = pt.m();
1322 std::unique_ptr<QgsLineString> line(
curveToLine() );
1331 return line->closestSegment( pt, segmentPt, vertexAfter, leftOf, epsilon );
1336 for (
QgsPoint &pt : mControlPoints )
1340 double z = transformZ && pt.is3D() ? pt.z() : std::numeric_limits<double>::quiet_NaN();
1344 if ( transformZ && pt.is3D() )
1352 for (
QgsPoint &pt : mControlPoints )
1354 const QPointF p = t.map( QPointF( pt.x(), pt.y() ) );
1359 pt.setZ( pt.z() * zScale + zTranslate );
1360 if ( pt.isMeasure() )
1361 pt.setM( pt.m() * mScale + mTranslate );
1382 if ( mControlPoints.isEmpty() )
1388 for (
const QgsPoint &pt : mControlPoints )
1390 bbox.
combineWith( pt.x(), pt.y(), pt.is3D() ? pt.z() : std::numeric_limits<double>::quiet_NaN() );
1394 std::unique_ptr<QgsLineString> line(
curveToLine() );
1406 mValidityComputed =
false;
1412 if ( position.
part != 0 || position.
ring != 0 )
1415 const int idx = position.
vertex;
1416 if ( idx < 0 || idx >= mControlPoints.size() )
1419 mControlPoints[idx] = newPos;
1426 if ( position.
part != 0 || position.
ring != 0 )
1429 const int idx = position.
vertex;
1430 if ( idx < 0 || idx > mControlPoints.size() )
1433 mControlPoints.insert( idx, vertex );
1434 if ( idx <= mWeights.size() )
1435 mWeights.insert( idx, 1.0 );
1449 const int coordinateDimension = 2 + (
is3D ? 1 : 0 ) + (
isMeasure ? 1 : 0 );
1463 for (
int i = 0; i < mControlPoints.size(); ++i )
1469 size += coordinateDimension * 8;
1475 if ( i < mWeights.size() && std::fabs( mWeights[i] - 1.0 ) > 1e-10 )
1483 size += mKnots.size() * 8;
1490 QByteArray wkbArray;
1496 wkbPtr << static_cast<quint32>(
mWkbType );
1499 wkbPtr << static_cast<quint32>( mDegree );
1502 wkbPtr << static_cast<quint32>( mControlPoints.size() );
1508 for (
int i = 0; i < mControlPoints.size(); ++i )
1510 const QgsPoint &point = mControlPoints[i];
1516 wkbPtr << point.
x() << point.
y();
1519 wkbPtr << point.
z();
1521 wkbPtr << point.
m();
1524 const double weight = ( i < mWeights.size() ) ? mWeights[i] : 1.0;
1525 const bool hasCustomWeight = std::fabs(
weight - 1.0 ) > 1e-10;
1527 wkbPtr << static_cast<char>( hasCustomWeight ? 1 : 0 );
1529 if ( hasCustomWeight )
1536 wkbPtr << static_cast<quint32>( mKnots.size() );
1539 for (
const double knot : mKnots )
1560 wkt += QString::number( mDegree );
1564 for (
int i = 0; i < mControlPoints.size(); ++i )
1569 const QgsPoint &pt = mControlPoints[i];
1581 if ( !mWeights.isEmpty() )
1584 for (
int i = 0; i < mWeights.size(); ++i )
1594 if ( !mKnots.isEmpty() )
1597 for (
int i = 0; i < mKnots.size(); ++i )
1616 std::unique_ptr<QgsLineString> line(
curveToLine() );
1618 return QDomElement();
1619 return line->asGml2( doc, precision, ns, axisOrder );
1626 std::unique_ptr<QgsLineString> line(
curveToLine() );
1628 return QDomElement();
1629 return line->asGml3( doc, precision, ns, axisOrder );
1634 std::unique_ptr<QgsLineString> line(
curveToLine() );
1636 return json::object();
1637 return line->asJsonObject( precision );
1643 std::unique_ptr<QgsLineString> line(
curveToLine() );
1646 return line->asKml( precision );
1656 return mControlPoints.isEmpty();
1661 mControlPoints.clear();
1680 std::unique_ptr<QgsLineString> line(
curveToLine() );
1681 return line ? line->centroid() :
QgsPoint();
1690 if ( mDegree < otherCurve->mDegree )
1692 else if ( mDegree > otherCurve->mDegree )
1695 const int nThis = mControlPoints.size();
1696 const int nOther = otherCurve->mControlPoints.size();
1698 if ( nThis < nOther )
1700 else if ( nThis > nOther )
1703 for (
int i = 0; i < nThis; ++i )
1705 if ( mControlPoints[i].x() < otherCurve->mControlPoints[i].x() )
1707 if ( mControlPoints[i].x() > otherCurve->mControlPoints[i].x() )
1709 if ( mControlPoints[i].y() < otherCurve->mControlPoints[i].y() )
1711 if ( mControlPoints[i].y() > otherCurve->mControlPoints[i].y() )
1715 if ( mWeights.size() < otherCurve->mWeights.size() )
1717 else if ( mWeights.size() > otherCurve->mWeights.size() )
1720 for (
int i = 0; i < mWeights.size(); ++i )
1722 if ( mWeights[i] < otherCurve->mWeights[i] )
1724 else if ( mWeights[i] > otherCurve->mWeights[i] )
1728 if ( mKnots.size() < otherCurve->mKnots.size() )
1730 else if ( mKnots.size() > otherCurve->mKnots.size() )
1733 for (
int i = 0; i < mKnots.size(); ++i )
1735 if ( mKnots[i] < otherCurve->mKnots[i] )
1737 else if ( mKnots[i] > otherCurve->mKnots[i] )
1746 if ( index < 0 || index >= mWeights.size() )
1748 return mWeights[index];
1753 if ( index < 0 || index >= mWeights.size() )
1757 mWeights[index] =
weight;
QFlags< GeometryValidityFlag > GeometryValidityFlags
Geometry validity flags.
VertexType
Types of vertex.
@ ControlPoint
A NURBS control point (does not lie on the curve).
WkbType
The WKB type describes the number of dimensions a geometry has.
@ NurbsCurveM
NurbsCurveM.
@ NurbsCurveZ
NurbsCurveZ.
@ NurbsCurveZM
NurbsCurveZM.
TransformDirection
Indicates the direction (forward or inverse) of a transform.
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
bool isMeasure() const
Returns true if the geometry contains m values.
QFlags< WkbFlag > WkbFlags
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
AxisOrder
Axis order for GML generation.
virtual QString geometryType() const =0
Returns a unique string representing the geometry type.
QString wktTypeStr() const
Returns the WKT type string of the geometry.
QgsAbstractGeometry()=default
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.
QgsRectangle toRectangle() const
Converts the box to a 2D rectangle.
void combineWith(const QgsBox3D &box)
Expands the bbox so that it covers both the original rectangle and the given rectangle.
int remaining() const
remaining
Qgis::WkbType readHeader() const
readHeader
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
QgsBox3D mBoundingBox
Cached bounding box.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
static QStringList wktGetChildBlocks(const QString &wkt, const QString &defaultType=QString())
Parses a WKT string and returns of list of blocks contained in the WKT.
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 (...
Line string geometry type, with support for z-dimension and m-values.
std::tuple< std::unique_ptr< QgsCurve >, std::unique_ptr< QgsCurve > > splitCurveAtVertex(int index) const override
Splits the curve at the specified vertex index, returning two curves which represent the portion of t...
double segmentLength(QgsVertexId startVertex) const override
Returns the length of the segment of the geometry which begins at startVertex.
QgsPoint startPoint() const override
Returns the starting point of the curve.
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
QPolygonF asQPolygonF() const override
Returns a QPolygonF representing the points.
void addToPainterPath(QPainterPath &path) const override
Adds a curve to a painter path.
bool hasCurvedSegments() const override
Returns true if the geometry contains curved segments.
bool isRational() const
Returns true if this curve is rational (has non-uniform weights).
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
QgsNurbsCurve()
Constructor for an empty NURBS curve geometry.
QgsPoint endPoint() const override
Returns the end point of the curve.
int indexOf(const QgsPoint &point) const override
Returns the index of the first vertex matching the given point, or -1 if a matching vertex is not fou...
bool transform(QgsAbstractGeometryTransformer *transformer, QgsFeedback *feedback=nullptr) override
Transforms the vertices from the geometry in place, using the specified geometry transformer object.
QgsPoint centroid() const override
Returns the centroid of the geometry.
bool equals(const QgsCurve &other) const override
Checks whether this curve exactly equals another curve.
QgsCurve * curveSubstring(double startDistance, double endDistance) const override
Returns a new curve representing a substring of this curve.
int partCount() const override
Returns count of parts contained in the geometry.
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
bool fuzzyDistanceEqual(const QgsAbstractGeometry &other, double epsilon=1e-8) const override
Performs fuzzy distance comparison between this geometry and other using an epsilon.
QgsAbstractGeometry * simplifyByDistance(double tolerance) const override
Simplifies the geometry by applying the Douglas Peucker simplification by distance algorithm.
double zAt(int index) const override
Returns the z-coordinate of the specified node in the line string.
void sumUpArea(double &sum) const override
Sums up the area of the curve by iterating over the vertices (shoelace formula).
QString geometryType() const override
Returns a unique string representing the geometry type.
QString asKml(int precision=17) const override
Returns a KML representation of the 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.
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.
QVector< double > knots() const
Returns the knot vector of the NURBS curve.
void scroll(int firstVertexIndex) override
Scrolls the curve vertices so that they start with the vertex at the given index.
bool isEmpty() const override
Returns true if the geometry is empty.
bool isPolyBezier() const
Returns true if this curve represents a poly-Bézier curve.
void filterVertices(const std::function< bool(const QgsPoint &)> &filter) override
bool isBSpline() const
Returns true if this curve represents a B-spline (non-rational NURBS).
bool fromWkb(QgsConstWkbPtr &wkb) override
Sets the geometry from a WKB string.
int numPoints() const override
Returns the number of points in the curve.
void clear() override
Clears the geometry, ie reset it to a null geometry.
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
QgsBox3D calculateBoundingBox3D() const override
Calculates the minimal 3D bounding box for the geometry.
QgsBox3D boundingBox3D() const override
Returns the 3D bounding box for the geometry.
bool isClosed() const override
Returns true if the curve is closed.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
int wkbSize(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns the length of the QByteArray returned by asWkb().
QgsAbstractGeometry * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
bool moveVertex(QgsVertexId position, const QgsPoint &newPos) override
Moves a vertex within the geometry.
int vertexNumberFromVertexId(QgsVertexId id) const override
Returns the vertex number corresponding to a vertex id.
void swapXy() override
Swaps the x and y coordinates from the geometry.
void points(QgsPointSequence &pts) const override
Returns a list of points within the curve.
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.
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.
bool setWeight(int index, double weight)
Sets the weight at the specified control point index.
bool fuzzyEqual(const QgsAbstractGeometry &other, double epsilon=1e-8) const override
Performs fuzzy comparison between this geometry and other using an epsilon.
QgsCurve * reversed() const override
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
double mAt(int index) const override
Returns the m-coordinate of the specified node in the line string.
void drawAsPolygon(QPainter &p) const override
Draws the curve as a polygon on the specified QPainter.
bool boundingBoxIntersects(const QgsRectangle &rectangle) const override
Returns true if the bounding box of this geometry intersects with a rectangle.
double weight(int index) const
Returns the weight at the specified control point index.
void draw(QPainter &p) const override
Draws the geometry using the specified QPainter.
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns a WKB representation of the geometry.
bool pointAt(int node, QgsPoint &point, Qgis::VertexType &type) const override
Returns the point and vertex id of a point within the curve.
int degree() const
Returns the degree of the NURBS curve.
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.
void sumUpArea3D(double &sum) const override
Sums up the 3d area of the curve by iterating over the vertices (shoelace formula).
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 deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
static QVector< double > generateUniformKnots(int numControlPoints, int degree)
Generates a uniform clamped knot vector for a NURBS curve.
QVector< QgsPoint > controlPoints() const
Returns the control points of the NURBS curve.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
bool isBezier() const
Returns true if this curve represents a Bézier curve.
QgsRectangle boundingBox() const override
Returns the minimal bounding box for the geometry.
bool isClosed2D() const override
Returns true if the curve is closed.
QgsCurve * toCurveType() const override
Returns the geometry converted to the more generic curve type.
double vertexAngle(QgsVertexId vertex) const override
Returns approximate angle at a vertex.
bool insertVertex(QgsVertexId position, const QgsPoint &vertex) override
Inserts a vertex into the geometry.
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...
QgsPoint * interpolatePoint(double distance) const override
Returns an interpolated point on the curve at the specified distance.
double length() const override
Returns the planar, 2-dimensional length of the geometry.
QgsPoint evaluate(double t) const
Evaluates the NURBS curve at parameter t ∈ [0,1].
int dimension() const override
Returns the inherent dimension of the geometry.
QVector< double > weights() const
Returns the weight vector of the NURBS curve.
QgsAbstractGeometry * 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.
bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
QgsNurbsCurve * clone() const override
Clones the geometry by performing a deep copy.
QgsPoint vertexAt(QgsVertexId id) const override
Returns the point corresponding to a specified vertex id.
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
double distanceBetweenVertices(QgsVertexId fromVertex, QgsVertexId toVertex) const override
Returns the distance along the curve between two vertices.
int vertexCount(int part=0, int ring=0) const override
Returns the number of vertices of which this geometry is built.
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.
void setM(double m)
Sets the point's m-value.
bool isEmpty() const override
Returns true if the geometry is empty.
void setZ(double z)
Sets the point's z-coordinate.
A rectangle specified with double values.
bool intersects(const QgsRectangle &rect) const
Returns true when rectangle intersects with 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 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 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.
static Q_INVOKABLE bool isNurbsType(Qgis::WkbType type)
Returns true if the WKB type is a NURBS curve 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).
T qgsgeometry_cast(QgsAbstractGeometry *geom)
QVector< QgsPoint > QgsPointSequence
Utility class for identifying a unique vertex within a geometry.