24#include <nlohmann/json.hpp>
40#include <QPainterPath>
42using namespace nlohmann;
58 if ( !mControlPoints.isEmpty() )
60 const QgsPoint &firstPoint = mControlPoints.first();
61 if ( firstPoint.is3D() )
62 mWkbType = QgsWkbTypes::addZ( mWkbType );
63 if ( firstPoint.isMeasure() )
64 mWkbType = QgsWkbTypes::addM( mWkbType );
75 const int n = mControlPoints.size();
76 if ( n < 2 || mDegree < 1 )
79 if ( mDegree != n - 1 )
85 if ( mKnots.size() != n + mDegree + 1 )
88 for (
int i = 0; i <= mDegree; ++i )
93 for (
int i = n; i < mKnots.size(); ++i )
104 for (
const double w : mWeights )
119 const int n = mControlPoints.size();
120 return mDegree == 3 && n >= 4 && ( n - 1 ) % 3 == 0;
137static int findKnotSpan(
const int degree,
const double u,
const QVector<double> &knots,
const int nPoints )
140 if ( u >= knots[nPoints] )
144 if ( u <= knots[degree] )
150 int mid = ( low + high ) / 2;
152 while ( u < knots[mid] || u >= knots[mid + 1] )
154 if ( u < knots[mid] )
158 mid = ( low + high ) / 2;
168 const int n = mControlPoints.size();
182 return mControlPoints.first();
184 return mControlPoints.last();
186 const bool hasZ = !mControlPoints.
isEmpty() && mControlPoints.first().is3D();
187 const bool hasM = !mControlPoints.isEmpty() && mControlPoints.first().isMeasure();
190 const double u = mKnots[mDegree] + t * ( mKnots[n] - mKnots[mDegree] );
193 const int span = findKnotSpan( mDegree, u, mKnots, n );
198 std::vector<double> tempX( mDegree + 1 );
199 std::vector<double> tempY( mDegree + 1 );
200 std::vector<double> tempZ( mDegree + 1 );
201 std::vector<double> tempM( mDegree + 1 );
202 std::vector<double> tempW( mDegree + 1 );
205 for (
int j = 0; j <= mDegree; ++j )
207 const int cpIdx = span - mDegree + j;
208 const QgsPoint &cp = mControlPoints[cpIdx];
209 const double w = ( cpIdx < mWeights.size() ) ? mWeights[cpIdx] : 1.0;
212 tempX[j] = cp.
x() * w;
213 tempY[j] = cp.
y() * w;
214 tempZ[j] = hasZ ? cp.
z() * w : 0.0;
215 tempM[j] = hasM ? cp.
m() : 0.0;
220 for (
int k = 1; k <= mDegree; ++k )
222 for (
int j = mDegree; j >= k; --j )
224 const int knotIdx = span - mDegree + j;
225 const double denom = mKnots[knotIdx + mDegree - k + 1] - mKnots[knotIdx];
229 const double alpha = ( u - mKnots[knotIdx] ) / denom;
230 const double oneMinusAlpha = 1.0 - alpha;
233 tempX[j] = oneMinusAlpha * tempX[j - 1] + alpha * tempX[j];
234 tempY[j] = oneMinusAlpha * tempY[j - 1] + alpha * tempY[j];
236 tempZ[j] = oneMinusAlpha * tempZ[j - 1] + alpha * tempZ[j];
238 tempM[j] = oneMinusAlpha * tempM[j - 1] + alpha * tempM[j];
241 tempW[j] = oneMinusAlpha * tempW[j - 1] + alpha * tempW[j];
248 double x = tempX[mDegree];
249 double y = tempY[mDegree];
250 double z = tempZ[mDegree];
251 double m = tempM[mDegree];
252 const double w = tempW[mDegree];
269 return QgsPoint( x, y, std::numeric_limits<double>::quiet_NaN(), m );
276 if ( mControlPoints.size() < 2 )
285 if (
is3D() && closed )
286 closed &=
qgsDoubleNear( startPt.
z(), endPt.
z() ) || ( std::isnan( startPt.
z() ) && std::isnan( endPt.
z() ) );
293 if ( mControlPoints.size() < 2 )
305 Q_UNUSED( toleranceType );
309 const int steps = std::max( 2,
static_cast<int>( 2 * M_PI / tolerance ) );
312 for (
int i = 0; i <= steps; ++i )
314 const double t =
static_cast<double>( i ) / steps;
316 line->addVertex( pt );
324 std::unique_ptr<QgsLineString> line(
curveToLine() );
331 std::unique_ptr<QgsLineString> line(
curveToLine() );
333 line->drawAsPolygon( p );
338 std::unique_ptr<QgsLineString> line(
curveToLine() );
339 return line ? line->asQPolygonF() : QPolygonF();
358 if ( o->mDegree != mDegree )
363 if ( mControlPoints != o->mControlPoints )
366 if ( mWeights != o->mWeights )
369 if ( mKnots != o->mKnots )
377 for (
int i = 0; i < mControlPoints.size(); ++i )
379 if (
qgsDoubleNear( mControlPoints[i].distance( point ), 0.0 ) )
389 std::unique_ptr<QgsLineString> line(
curveToLine() );
394 return line->interpolatePoint( distance );
399 return mControlPoints.size();
404 if ( node < 0 || node >= mControlPoints.size() )
408 point = mControlPoints[node];
415 pts.reserve( pts.size() + mControlPoints.size() );
416 for (
const QgsPoint &p : mControlPoints )
425 std::reverse( rev->mControlPoints.begin(), rev->mControlPoints.end() );
426 std::reverse( rev->mWeights.begin(), rev->mWeights.end() );
429 if ( !rev->mKnots.isEmpty() )
431 const double maxKnot = rev->mKnots.last();
432 const double minKnot = rev->mKnots.first();
433 std::reverse( rev->mKnots.begin(), rev->mKnots.end() );
434 for (
double &knot : rev->mKnots )
436 knot = maxKnot + minKnot - knot;
446 if ( !
isClosed() || firstVertexIndex <= 0 || firstVertexIndex >= mControlPoints.size() )
452 std::rotate( mControlPoints.begin(), mControlPoints.begin() + firstVertexIndex, mControlPoints.end() );
453 std::rotate( mWeights.begin(), mWeights.begin() + firstVertexIndex, mWeights.end() );
456 if ( !mKnots.isEmpty() && firstVertexIndex < mKnots.size() )
458 const double delta = mKnots[firstVertexIndex] - mKnots[0];
459 std::rotate( mKnots.begin(), mKnots.begin() + firstVertexIndex, mKnots.end() );
461 for (
double &knot : mKnots )
470std::tuple<std::unique_ptr<QgsCurve>, std::unique_ptr<QgsCurve>>
473 std::unique_ptr<QgsLineString> line(
curveToLine() );
476 return std::make_tuple(
nullptr,
nullptr );
478 return line->splitCurveAtVertex( index );
489 std::unique_ptr<QgsLineString> line(
curveToLine() );
491 line->sumUpArea( sum );
496 std::unique_ptr<QgsLineString> line(
curveToLine() );
498 line->sumUpArea3D( sum );
503 if ( index < 0 || index >= mControlPoints.size() )
505 return mControlPoints[index].x();
510 if ( index < 0 || index >= mControlPoints.size() )
512 return mControlPoints[index].y();
517 if ( index < 0 || index >= mControlPoints.size() )
519 return mControlPoints[index].is3D() ? mControlPoints[index].z() : std::numeric_limits<double>::quiet_NaN();
524 if ( index < 0 || index >= mControlPoints.size() )
526 return mControlPoints[index].isMeasure() ? mControlPoints[index].m() : std::numeric_limits<double>::quiet_NaN();
537 for (
QgsPoint &p : mControlPoints )
539 p.addZValue( zValue );
553 for (
QgsPoint &p : mControlPoints )
555 p.addMValue( mValue );
566 for (
QgsPoint &p : mControlPoints )
568 p.setZ( std::numeric_limits<double>::quiet_NaN() );
581 for (
QgsPoint &p : mControlPoints )
583 p.setM( std::numeric_limits<double>::quiet_NaN() );
593 if ( position.
part != 0 || position.
ring != 0 )
597 const int idx = position.
vertex;
598 if ( idx < 0 || idx >= mControlPoints.size() )
602 mControlPoints.remove( idx );
603 if ( idx < mWeights.size() )
605 mWeights.remove( idx );
608 generateUniformKnots();
616 QVector<QgsPoint> newPts;
617 QVector<double> newWeights;
618 for (
int i = 0; i < mControlPoints.size(); ++i )
620 if ( filter( mControlPoints[i] ) )
622 newPts.append( mControlPoints[i] );
623 if ( i < mWeights.size() )
624 newWeights.append( mWeights[i] );
627 mControlPoints = newPts;
628 mWeights = newWeights;
630 generateUniformKnots();
635void QgsNurbsCurve::generateUniformKnots()
637 const int n = mControlPoints.size();
638 const int knotsSize = n + mDegree + 1;
640 mKnots.reserve( knotsSize );
641 for (
int i = 0; i < knotsSize; ++i )
644 mKnots.append( 0.0 );
646 mKnots.append( 1.0 );
648 mKnots.append(
static_cast<double>( i - mDegree ) / ( n - mDegree ) );
660 const unsigned char headerEndianness = *
static_cast<const unsigned char *
>( wkb );
678 mDegree =
static_cast<int>(
degree );
681 quint32 numControlPoints;
682 wkb >> numControlPoints;
692 const int minBytesPerPoint = 18 + (
is3D ? 8 : 0 ) + (
isMeasure ? 8 : 0 );
693 if ( numControlPoints >
static_cast<quint32
>( wkb.
remaining() / minBytesPerPoint + 1 ) )
696 mControlPoints.clear();
698 mControlPoints.reserve( numControlPoints );
699 mWeights.reserve( numControlPoints );
702 for ( quint32 i = 0; i < numControlPoints; ++i )
705 char pointEndianness;
706 wkb >> pointEndianness;
710 if (
static_cast<unsigned char>( pointEndianness ) != headerEndianness )
714 double x, y, z = 0.0, m = 0.0;
727 if ( weightFlag == 1 )
740 point =
QgsPoint( x, y, std::numeric_limits<double>::quiet_NaN(), m );
744 mControlPoints.append( point );
745 mWeights.append(
weight );
753 const quint32 expectedKnots = numControlPoints +
degree + 1;
754 if ( numKnots != expectedKnots )
758 if ( numKnots *
sizeof(
double ) >
static_cast<quint32
>( wkb.
remaining() ) )
762 mKnots.reserve( numKnots );
765 for ( quint32 i = 0; i < numKnots; ++i )
769 mKnots.append( knot );
779 const QString geomTypeStr = wkt.split(
'(' )[0].trimmed().toUpper();
781 if ( !geomTypeStr.startsWith(
"NURBSCURVE"_L1 ) )
788 if ( geomTypeStr.contains(
"ZM"_L1 ) )
790 else if ( geomTypeStr.endsWith(
'Z' ) || geomTypeStr.endsWith(
" Z"_L1 ) )
792 else if ( geomTypeStr.endsWith(
'M' ) || geomTypeStr.endsWith(
" M"_L1 ) )
799 if (
parts.second.compare(
"EMPTY"_L1, Qt::CaseInsensitive ) == 0 ||
parts.second.isEmpty() )
805 if ( blocks.isEmpty() )
810 int degree = blocks[0].trimmed().toInt( &ok );
814 if ( blocks.size() < 2 )
818 QString pointsStr = blocks[1].trimmed();
821 if ( !pointsStr.startsWith(
'('_L1 ) || !pointsStr.endsWith(
')'_L1 ) )
824 pointsStr = pointsStr.mid( 1, pointsStr.length() - 2 ).trimmed();
827 QStringList pointsCoords = pointsStr.split(
',', Qt::SkipEmptyParts );
830 const thread_local QRegularExpression rx( u
"\\s+"_s );
832 for (
const QString &pointStr : pointsCoords )
834 QStringList coords = pointStr.trimmed().split( rx, Qt::SkipEmptyParts );
836 if ( coords.size() < 2 )
842 double x = coords[0].toDouble( &ok );
846 double y = coords[1].toDouble( &ok );
851 if ( coords.size() >= 3 )
856 double m = coords[2].toDouble( &ok );
859 point =
QgsPoint( x, y, std::numeric_limits<double>::quiet_NaN(), m );
864 double z = coords[2].toDouble( &ok );
872 double z = coords[2].toDouble( &ok );
875 double m = coords[3].toDouble( &ok );
880 else if (
isMeasure() && coords.size() >= 4 )
883 double z = coords[2].toDouble( &ok );
886 double m = coords[3].toDouble( &ok );
896 double z = coords[2].toDouble( &ok );
905 double z = coords[2].toDouble( &ok );
908 double m = coords[3].toDouble( &ok );
950 mWeights.append( 1.0 );
954 bool hasWeights =
false;
955 bool hasKnots =
false;
958 for (
int i = 2; i < blocks.size(); ++i )
960 QString block = blocks[i].trimmed();
962 if ( block.startsWith(
'('_L1 ) )
965 if ( !block.endsWith(
')'_L1 ) )
969 block = block.mid( 1, block.length() - 2 ).trimmed();
970 QStringList values = block.split(
',', Qt::SkipEmptyParts );
972 QVector<double> parsedValues;
973 for (
const QString &valueStr : values )
976 double value = valueStr.trimmed().toDouble( &ok );
979 parsedValues.append( value );
982 if ( !hasWeights && parsedValues.size() ==
controlPoints.size() )
985 mWeights = parsedValues;
988 else if ( !hasKnots )
991 mKnots = parsedValues;
1011 generateUniformKnots();
1023 if ( mDegree != o->mDegree || mControlPoints.size() != o->mControlPoints.size() || mWeights.size() != o->mWeights.size() || mKnots.size() != o->mKnots.size() )
1028 for (
int i = 0; i < mControlPoints.size(); ++i )
1030 if ( mControlPoints[i].distance( o->mControlPoints[i] ) >= epsilon )
1034 for (
int i = 0; i < mWeights.size(); ++i )
1036 if ( std::fabs( mWeights[i] - o->mWeights[i] ) > epsilon )
1040 for (
int i = 0; i < mKnots.size(); ++i )
1042 if ( std::fabs( mKnots[i] - o->mKnots[i] ) > epsilon )
1056 return u
"NurbsCurve"_s;
1076 if (
id.part != 0 ||
id.ring != 0 )
1080 const int idx =
id.vertex;
1081 if ( idx < 0 || idx >= mControlPoints.size() )
1085 return mControlPoints[idx];
1090 return ( part == 0 && ring == 0 ) ? mControlPoints.size() : 0;
1095 if (
id.part == 0 &&
id.ring == 0 )
1107 if ( mValidityComputed )
1110 error = u
"NURBS curve is invalid"_s;
1114 mValidityComputed =
true;
1119 error = u
"Degree must be >= 1"_s;
1123 const int n = mControlPoints.size();
1124 if ( n < mDegree + 1 )
1126 error = u
"Not enough control points for degree"_s;
1130 if ( mKnots.size() != n + mDegree + 1 )
1132 error = u
"Knot vector size is incorrect"_s;
1136 if ( mWeights.size() != n )
1138 error = u
"Weights vector size mismatch"_s;
1143 for (
int i = 1; i < mKnots.size(); ++i )
1145 if ( mKnots[i] < mKnots[i - 1] )
1147 error = u
"Knot vector values must be non-decreasing"_s;
1158 std::unique_ptr<QgsLineString> line(
curveToLine() );
1160 line->addToPainterPath( path );
1165 std::unique_ptr<QgsLineString> line(
curveToLine() );
1168 return line->curveSubstring( startDistance, endDistance );
1173 std::unique_ptr<QgsLineString> line(
curveToLine() );
1174 return line ? line->length() : 0.0;
1179 std::unique_ptr<QgsLineString> line(
curveToLine() );
1182 return line->segmentLength( startVertex );
1187 std::unique_ptr<QgsLineString> line(
curveToLine() );
1190 return line->distanceBetweenVertices( fromVertex, toVertex );
1196 for (
QgsPoint &pt : result->mControlPoints )
1199 pt.
setX( std::round( pt.
x() / hSpacing ) * hSpacing );
1201 pt.
setY( std::round( pt.
y() / vSpacing ) * vSpacing );
1202 if ( pt.
is3D() && dSpacing > 0 )
1203 pt.
setZ( std::round( pt.
z() / dSpacing ) * dSpacing );
1205 pt.
setM( std::round( pt.
m() / mSpacing ) * mSpacing );
1208 if ( removeRedundantPoints )
1209 result->removeDuplicateNodes();
1216 std::unique_ptr<QgsLineString> line(
curveToLine() );
1219 return line->simplifyByDistance( tolerance );
1224 if ( mControlPoints.size() < 2 )
1227 QVector<QgsPoint> newPoints;
1228 QVector<double> newWeights;
1230 newPoints.reserve( mControlPoints.size() );
1231 newWeights.reserve( mWeights.size() );
1233 newPoints.append( mControlPoints.first() );
1234 if ( !mWeights.isEmpty() )
1235 newWeights.append( mWeights.first() );
1237 for (
int i = 1; i < mControlPoints.size(); ++i )
1239 const double dist = ( useZValues && mControlPoints[i].is3D() && mControlPoints[i - 1].
is3D() )
1240 ? mControlPoints[i].distance3D( mControlPoints[i - 1] )
1241 : mControlPoints[i].distance( mControlPoints[i - 1] );
1243 if ( dist >= epsilon )
1245 newPoints.append( mControlPoints[i] );
1246 if ( i < mWeights.size() )
1247 newWeights.append( mWeights[i] );
1251 const bool changed = ( newPoints.size() != mControlPoints.size() );
1255 mControlPoints = newPoints;
1256 mWeights = newWeights;
1259 generateUniformKnots();
1267 std::unique_ptr<QgsLineString> line(
curveToLine() );
1270 return line->vertexAngle( vertex );
1275 for (
QgsPoint &pt : mControlPoints )
1277 const double x = pt.x();
1286 Q_UNUSED( feedback );
1290 for (
QgsPoint &pt : mControlPoints )
1292 double x = pt.x(), y = pt.y(), z = pt.z(), m = pt.m();
1312 std::unique_ptr<QgsLineString> line(
curveToLine() );
1321 return line->closestSegment( pt, segmentPt, vertexAfter, leftOf, epsilon );
1326 for (
QgsPoint &pt : mControlPoints )
1330 double z = transformZ && pt.is3D() ? pt.z() : std::numeric_limits<double>::quiet_NaN();
1334 if ( transformZ && pt.is3D() )
1342 for (
QgsPoint &pt : mControlPoints )
1344 const QPointF p = t.map( QPointF( pt.x(), pt.y() ) );
1349 pt.setZ( pt.z() * zScale + zTranslate );
1350 if ( pt.isMeasure() )
1351 pt.setM( pt.m() * mScale + mTranslate );
1372 if ( mControlPoints.isEmpty() )
1378 for (
const QgsPoint &pt : mControlPoints )
1380 bbox.
combineWith( pt.x(), pt.y(), pt.is3D() ? pt.z() : std::numeric_limits<double>::quiet_NaN() );
1384 std::unique_ptr<QgsLineString> line(
curveToLine() );
1396 mValidityComputed =
false;
1402 if ( position.
part != 0 || position.
ring != 0 )
1405 const int idx = position.
vertex;
1406 if ( idx < 0 || idx >= mControlPoints.size() )
1409 mControlPoints[idx] = newPos;
1416 if ( position.
part != 0 || position.
ring != 0 )
1419 const int idx = position.
vertex;
1420 if ( idx < 0 || idx > mControlPoints.size() )
1423 mControlPoints.insert( idx, vertex );
1424 if ( idx <= mWeights.size() )
1425 mWeights.insert( idx, 1.0 );
1427 generateUniformKnots();
1439 const int coordinateDimension = 2 + (
is3D ? 1 : 0 ) + (
isMeasure ? 1 : 0 );
1453 for (
int i = 0; i < mControlPoints.size(); ++i )
1459 size += coordinateDimension * 8;
1465 if ( i < mWeights.size() && std::fabs( mWeights[i] - 1.0 ) > 1e-10 )
1473 size += mKnots.size() * 8;
1480 QByteArray wkbArray;
1486 wkbPtr << static_cast<quint32>(
mWkbType );
1489 wkbPtr << static_cast<quint32>( mDegree );
1492 wkbPtr << static_cast<quint32>( mControlPoints.size() );
1498 for (
int i = 0; i < mControlPoints.size(); ++i )
1500 const QgsPoint &point = mControlPoints[i];
1506 wkbPtr << point.
x() << point.
y();
1509 wkbPtr << point.
z();
1511 wkbPtr << point.
m();
1514 const double weight = ( i < mWeights.size() ) ? mWeights[i] : 1.0;
1515 const bool hasCustomWeight = std::fabs(
weight - 1.0 ) > 1e-10;
1517 wkbPtr << static_cast<char>( hasCustomWeight ? 1 : 0 );
1519 if ( hasCustomWeight )
1526 wkbPtr << static_cast<quint32>( mKnots.size() );
1529 for (
const double knot : mKnots )
1550 wkt += QString::number( mDegree );
1554 for (
int i = 0; i < mControlPoints.size(); ++i )
1559 const QgsPoint &pt = mControlPoints[i];
1571 if ( !mWeights.isEmpty() )
1574 for (
int i = 0; i < mWeights.size(); ++i )
1584 if ( !mKnots.isEmpty() )
1587 for (
int i = 0; i < mKnots.size(); ++i )
1606 std::unique_ptr<QgsLineString> line(
curveToLine() );
1608 return QDomElement();
1609 return line->asGml2( doc, precision, ns, axisOrder );
1616 std::unique_ptr<QgsLineString> line(
curveToLine() );
1618 return QDomElement();
1619 return line->asGml3( doc, precision, ns, axisOrder );
1624 std::unique_ptr<QgsLineString> line(
curveToLine() );
1626 return json::object();
1627 return line->asJsonObject( precision );
1633 std::unique_ptr<QgsLineString> line(
curveToLine() );
1636 return line->asKml( precision );
1646 return mControlPoints.isEmpty();
1651 mControlPoints.clear();
1670 std::unique_ptr<QgsLineString> line(
curveToLine() );
1671 return line ? line->centroid() :
QgsPoint();
1680 if ( mDegree < otherCurve->mDegree )
1682 else if ( mDegree > otherCurve->mDegree )
1685 const int nThis = mControlPoints.size();
1686 const int nOther = otherCurve->mControlPoints.size();
1688 if ( nThis < nOther )
1690 else if ( nThis > nOther )
1693 for (
int i = 0; i < nThis; ++i )
1695 if ( mControlPoints[i].x() < otherCurve->mControlPoints[i].x() )
1697 if ( mControlPoints[i].x() > otherCurve->mControlPoints[i].x() )
1699 if ( mControlPoints[i].y() < otherCurve->mControlPoints[i].y() )
1701 if ( mControlPoints[i].y() > otherCurve->mControlPoints[i].y() )
1705 if ( mWeights.size() < otherCurve->mWeights.size() )
1707 else if ( mWeights.size() > otherCurve->mWeights.size() )
1710 for (
int i = 0; i < mWeights.size(); ++i )
1712 if ( mWeights[i] < otherCurve->mWeights[i] )
1714 else if ( mWeights[i] > otherCurve->mWeights[i] )
1718 if ( mKnots.size() < otherCurve->mKnots.size() )
1720 else if ( mKnots.size() > otherCurve->mKnots.size() )
1723 for (
int i = 0; i < mKnots.size(); ++i )
1725 if ( mKnots[i] < otherCurve->mKnots[i] )
1727 else if ( mKnots[i] > otherCurve->mKnots[i] )
1736 if ( index < 0 || index >= mWeights.size() )
1738 return mWeights[index];
1743 if ( index < 0 || index >= mWeights.size() )
1747 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.
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 Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
T qgsgeometry_cast(QgsAbstractGeometry *geom)
QVector< QgsPoint > QgsPointSequence
Utility class for identifying a unique vertex within a geometry.