21#include <nlohmann/json.hpp>
33#include <QPainterPath>
36using namespace Qt::StringLiterals;
50 auto result = std::make_unique< QgsCompoundCurve >();
52 return result.release();
63 while ( i < mCurves.size() && j < otherCurve->mCurves.size() )
67 const int comparison = aGeom->
compareTo( bGeom );
68 if ( comparison != 0 )
75 if ( i < mCurves.size() )
79 if ( j < otherCurve->mCurves.size() )
88 return u
"CompoundCurve"_s;
100 mCurves.reserve( curve.mCurves.size() );
101 for (
const QgsCurve *
c : curve.mCurves )
103 mCurves.append( c->clone() );
110 if ( &curve !=
this )
113 for (
const QgsCurve *
c : curve.mCurves )
115 mCurves.append(
c->clone() );
129 qDeleteAll( mCurves );
136 if ( mCurves.empty() )
141 QgsBox3D bbox = mCurves.at( 0 )->boundingBox3D();
142 for (
int i = 1; i < mCurves.size(); ++i )
144 QgsBox3D curveBox = mCurves.at( i )->boundingBox3D();
153 if ( index < 1 || index >= size - 1 )
162 mCurves = std::move( curve2->mCurves );
167 mCurves.append( curve1->mCurves );
168 curve1->mCurves.clear();
190 for (
int i = 0; i <
nCurves; ++i )
193 wkbPtr -= 1 +
sizeof( int );
206 currentCurve->
fromWkb( wkbPtr );
207 mCurves.append( currentCurve );
222 QString secondWithoutParentheses =
parts.second;
223 secondWithoutParentheses = secondWithoutParentheses.remove(
'(' ).remove(
')' ).simplified().remove(
' ' );
224 if ( (
parts.second.compare(
"EMPTY"_L1, Qt::CaseInsensitive ) == 0 ) || secondWithoutParentheses.isEmpty() )
227 QString defaultChildWkbType = u
"LineString%1%2"_s.arg(
is3D() ? u
"Z"_s : QString(),
isMeasure() ? u
"M"_s : QString() );
230 for (
const QString &childWkt : blocks )
243 if ( !mCurves.back()->fromWkt( childWkt ) )
254 for (
const QgsCurve *curve : std::as_const( mCurves ) )
256 hasZ = hasZ || curve->is3D();
257 hasM = hasM || curve->isMeasure();
271 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
272 for (
const QgsCurve *curve : mCurves )
274 binarySize += curve->wkbSize( flags );
285 wkb << static_cast<quint32>(
wkbType() );
286 wkb << static_cast<quint32>( mCurves.size() );
287 for (
const QgsCurve *curve : mCurves )
289 wkb << curve->asWkb( flags );
302 for (
const QgsCurve *curve : mCurves )
304 QString childWkt = curve->asWkt( precision );
308 childWkt = childWkt.mid( childWkt.indexOf(
'(' ) );
310 wkt += childWkt +
',';
312 if ( wkt.endsWith(
',' ) )
324 std::unique_ptr< QgsLineString > line(
curveToLine() );
325 QDomElement gml = line->asGml2( doc, precision, ns, axisOrder );
331 QDomElement compoundCurveElem = doc.createElementNS( ns, u
"CompositeCurve"_s );
334 return compoundCurveElem;
336 for (
const QgsCurve *curve : mCurves )
338 QDomElement curveMemberElem = doc.createElementNS( ns, u
"curveMember"_s );
339 QDomElement curveElem = curve->asGml3( doc, precision, ns, axisOrder );
340 curveMemberElem.appendChild( curveElem );
341 compoundCurveElem.appendChild( curveMemberElem );
344 return compoundCurveElem;
354 std::unique_ptr< QgsLineString > line(
curveToLine() );
355 return line->asJsonObject( precision );
360 json geometries = json::array();
361 for (
const QgsCurve *curve : mCurves )
363 geometries.push_back( curve->asJsonObject( precision, profile ) );
365 return { {
"type",
"CompoundCurve" }, {
"geometries", geometries } };
374 for (
const QgsCurve *curve : mCurves )
376 length += curve->length();
383 if ( mCurves.empty() )
387 return mCurves.at( 0 )->startPoint();
392 if ( mCurves.empty() )
396 return mCurves.at( mCurves.size() - 1 )->endPoint();
402 if ( mCurves.empty() )
407 mCurves[0]->points( pts );
408 for (
int i = 1; i < mCurves.size(); ++i )
411 mCurves[i]->points( pList );
426 for (
int i = 0; i <
nCurves; ++i )
428 nPoints += mCurves.at( i )->numPoints() - 1;
436 if ( mCurves.isEmpty() )
441 if ( !curve->isEmpty() )
449 if ( mCurves.isEmpty() )
452 for (
int i = 0; i < mCurves.size(); ++i )
454 if ( !mCurves[i]->
isValid( error, flags ) )
456 error = QObject::tr(
"Curve[%1]: %2" ).arg( i + 1 ).arg( error );
466 for (
const QgsCurve *curve : mCurves )
468 const int curveIndex = curve->indexOf( point );
469 if ( curveIndex >= 0 )
470 return curveStart + curveIndex;
473 curveStart += curve->numPoints() - 1;
486 std::unique_ptr< QgsLineString > currentLine;
487 for (
const QgsCurve *curve : mCurves )
489 currentLine.reset( curve->curveToLine( tolerance, toleranceType ) );
490 line->
append( currentLine.get() );
501 std::unique_ptr<QgsCurve> gridified(
static_cast< QgsCurve *
>( curve->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing, removeRedundantPoints ) ) );
504 result->mCurves.append( gridified.release() );
508 if ( result->mCurves.empty() )
511 return result.release();
516 std::unique_ptr< QgsLineString > line(
curveToLine() );
517 return line->simplifyByDistance( tolerance );
523 const QVector< QgsCurve * > curves = mCurves;
528 result = curve->removeDuplicateNodes( epsilon, useZValues ) || result;
529 if ( curve->numPoints() == 0 ||
qgsDoubleNear( curve->length(), 0.0, epsilon ) )
532 delete mCurves.takeAt( i );
540 curve->moveVertex(
QgsVertexId( -1, -1, 0 ), lastEnd );
551 if ( mCurves.empty() )
565 for (
const QgsCurve *curve : mCurves )
567 if ( curve->boundingBoxIntersects( box3d ) )
580 if ( mCurves.size() == 1 )
581 return mCurves.at( 0 );
588 if ( i < 0 || i >= mCurves.size() )
592 return mCurves.at( i );
600 if ( mCurves.empty() )
624 const bool canExtendPrevious = extendPrevious && previousLineString && newLineString;
625 if ( canExtendPrevious )
627 previousLineString->
append( newLineString );
642 if ( i < 0 || i >= mCurves.size() )
647 delete mCurves.takeAt( i );
660 if ( !mCurves.isEmpty() )
662 lastCurve = mCurves.at( mCurves.size() - 1 );
669 mCurves.append( line );
687 QVector< QgsCurve * > newCurves;
688 newCurves.reserve( mCurves.size() );
689 for (
QgsCurve *curve : std::as_const( mCurves ) )
691 if ( lastCurve && lastCurve->
wkbType() == curve->wkbType() )
715 for (
const QgsCurve *curve : mCurves )
723 for (
QgsCurve *curve : std::as_const( mCurves ) )
725 curve->transform( ct, d, transformZ );
732 for (
QgsCurve *curve : std::as_const( mCurves ) )
734 curve->transform( t, zTranslate, zScale, mTranslate, mScale );
743 for (
const QgsCurve *curve : mCurves )
745 if ( curve != mCurves.at( 0 ) && pp.currentPosition() != curve->startPoint().toQPointF() )
747 pp.lineTo( curve->startPoint().toQPointF() );
749 curve->addToPainterPath( pp );
757 for (
const QgsCurve *curve : mCurves )
759 if ( curve != mCurves.at( 0 ) && pp.currentPosition() != curve->startPoint().toQPointF() )
761 pp.lineTo( curve->startPoint().toQPointF() );
763 curve->addToPainterPath( pp );
770 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
771 if ( curveIds.empty() )
775 int curveId = curveIds.at( 0 ).first;
776 if ( curveId >= mCurves.size() )
781 bool success = mCurves.at( curveId )->insertVertex( curveIds.at( 0 ).second, vertex );
791 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
792 QVector< QPair<int, QgsVertexId> >::const_iterator idIt = curveIds.constBegin();
793 for ( ; idIt != curveIds.constEnd(); ++idIt )
795 mCurves.at( idIt->first )->moveVertex( idIt->second, newPos );
798 bool success = !curveIds.isEmpty();
809 QMap<int, QList<QgsVertexId >> curveVertices;
817 const QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
819 if ( curveIds.isEmpty() )
822 const int firstCurveId = curveIds.at( 0 ).first;
823 const QgsVertexId firstCurveVertex = curveIds.at( 0 ).second;
824 curveVertices[firstCurveId].append( firstCurveVertex );
825 if ( curveIds.size() == 2 )
827 const int secondCurveId = curveIds.at( 1 ).first;
828 const QgsVertexId secondCurveVertex = curveIds.at( 1 ).second;
829 curveVertices[secondCurveId].append( secondCurveVertex );
833 QVector< QgsPoint > survivingPoints;
835 auto appendSurvivingPoints = [&survivingPoints,
this](
const QgsPoint &point,
const int curveId ) {
837 pts.reserve( 1 + survivingPoints.size() );
840 for (
size_t i = survivingPoints.size(); i-- > 0; )
841 pts << survivingPoints[i];
843 auto newLineString = std::make_unique<QgsLineString>();
844 newLineString->setPoints( pts );
845 mCurves.insert( curveId, newLineString.release() );
847 survivingPoints.clear();
851 QMapIterator<int, QList<QgsVertexId >> curveVerticesIt( curveVertices );
852 curveVerticesIt.toBack();
853 int previousCurveId = -1;
854 while ( curveVerticesIt.hasPrevious() )
856 curveVerticesIt.previous();
857 const int curveId = curveVerticesIt.key();
860 if ( previousCurveId - 1 > curveId && !survivingPoints.isEmpty() )
862 QgsCurve *curve = mCurves.at( previousCurveId - 1 );
863 appendSurvivingPoints( curve->
endPoint(), previousCurveId );
866 QgsCurve *curve = mCurves.at( curveId );
867 QList<QgsVertexId>
vertices = curveVerticesIt.value();
873 if ( circularString )
877 QList<QgsVertexId> circularVerticesToDelete;
878 circularVerticesToDelete.reserve(
vertices.size() );
881 for (
size_t i =
vertices.size(); i-- > 0; )
886 if ( curveVertexId.vertex % 2 == 1 )
890 if ( !circularVerticesToDelete.isEmpty() )
892 if ( curveVertexId.vertex == circularVerticesToDelete.last().vertex - 1 )
894 circularVerticesToDelete.append( curveVertexId );
898 else if ( i != 0 && curveVertexId.vertex - 1 ==
vertices.at( i - 1 ).vertex )
900 circularVerticesToDelete.append( curveVertexId );
907 if ( !circularVerticesToDelete.isEmpty() )
909 if ( !curve->
deleteVertices( QSet<QgsVertexId>( circularVerticesToDelete.begin(), circularVerticesToDelete.end() ) ) )
915 circularVerticesToDelete.clear();
923 if ( curveVertexId.vertex <
points.length() - 2 )
925 auto curveC = std::make_unique<QgsCircularString>();
926 curveC->setPoints(
points.mid( curveVertexId.vertex + 1 ) );
927 mCurves.insert( curveId, curveC.release() );
931 auto curveB = std::make_unique<QgsLineString>();
932 curveB->setPoints( partB );
933 mCurves.insert( curveId, curveB.release() );
934 curve = mCurves.at( curveId );
936 if ( curveVertexId.vertex > 1 )
938 auto curveA = std::make_unique<QgsCircularString>();
939 curveA->setPoints(
points.mid( 0, curveVertexId.vertex ) );
940 mCurves.insert( curveId, curveA.release() );
942 curve = mCurves.at( curveId );
949 circularVerticesToDelete.append( curveVertexId );
953 if ( !circularVerticesToDelete.isEmpty() )
960 if ( curveId > 0 && circularVerticesToDelete.last().vertex == 0 && circularVerticesToDelete.first().vertex != curve->
numPoints() - 1 )
964 else if ( curveId == 0 && circularVerticesToDelete.first().vertex == curve->
numPoints() - 1 && circularVerticesToDelete.last().vertex != 0 )
968 if ( !curve->
deleteVertices( QSet<QgsVertexId>( circularVerticesToDelete.begin(), circularVerticesToDelete.end() ) ) )
979 if ( !survivingPoint.
isEmpty() )
981 survivingPoints.emplace_back( survivingPoint );
984 else if ( survivingPoints.size() != 0 )
986 appendSurvivingPoints( curve->
endPoint(), curveId + 1 );
989 previousCurveId = curveId;
999 int remainingIdx = 0;
1002 if ( v.vertex != remainingIdx )
1008 previousCurveId = curveId;
1022 else if ( survivingPoints.size() != 0 )
1024 appendSurvivingPoints( curve->
endPoint(), curveId + 1 );
1027 previousCurveId = curveId;
1031 if ( survivingPoints.size() != 0 )
1033 if ( previousCurveId > 0 )
1038 const QgsCurve *curve = mCurves.at( previousCurveId - 1 );
1039 appendSurvivingPoints( curve->
endPoint(), previousCurveId );
1047 if ( mCurves.size() != 0 )
1054 if ( survivingPoints[0] == curve->
startPoint() )
1056 survivingPoints.removeAt( 0 );
1058 for (
int i = 0; i < survivingPoints.size(); ++i )
1064 for (
int i = survivingPoints.size() - 1; i >= 0; --i )
1065 pts << survivingPoints[i];
1068 auto newLineString = std::make_unique<QgsLineString>();
1069 newLineString->setPoints( pts );
1070 mCurves.insert( 0, newLineString.release() );
1073 else if ( survivingPoints.size() >= 2 )
1076 for (
int i = survivingPoints.size() - 1; i >= 0; --i )
1077 pts << survivingPoints[i];
1080 auto newLineString = std::make_unique<QgsLineString>();
1081 newLineString->setPoints( pts );
1083 mCurves.insert( 0, newLineString.release() );
1088 if ( mCurves.isEmpty() )
1097 for (
size_t i = mCurves.size() - 1; i > 0; i-- )
1100 QgsCurve *previousCurve = mCurves.at( i - 1 );
1108 mCurves.insert( i, line );
1130QVector< QPair<int, QgsVertexId> > QgsCompoundCurve::curveVertexId(
QgsVertexId id )
const
1132 QVector< QPair<int, QgsVertexId> > curveIds;
1134 int currentVertexIndex = 0;
1135 for (
int i = 0; i < mCurves.size(); ++i )
1137 int increment = mCurves.at( i )->numPoints() - 1;
1138 if (
id.vertex >= currentVertexIndex &&
id.vertex <= currentVertexIndex + increment )
1140 int curveVertexId =
id.vertex - currentVertexIndex;
1144 vid.
vertex = curveVertexId;
1145 curveIds.append( qMakePair( i, vid ) );
1146 if ( curveVertexId == increment && i < ( mCurves.size() - 1 ) )
1149 curveIds.append( qMakePair( i + 1, vid ) );
1153 else if (
id.vertex >= currentVertexIndex &&
id.vertex == currentVertexIndex + increment + 1 && i == ( mCurves.size() - 1 ) )
1155 int curveVertexId =
id.vertex - currentVertexIndex;
1159 vid.
vertex = curveVertexId;
1160 curveIds.append( qMakePair( i, vid ) );
1163 currentVertexIndex += increment;
1184 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
1187 if ( curveIds.length() != 1 )
1190 int curveId = curveIds[0].first;
1192 QgsCurve *curve = mCurves[curveId];
1203 if ( subVertexId.
vertex % 2 == 0 )
1207 circularString->points(
points );
1213 auto curveA = std::make_unique<QgsCircularString>();
1214 curveA->setPoints( partA );
1215 auto curveB = std::make_unique<QgsLineString>();
1216 curveB->setPoints( partB );
1217 auto curveC = std::make_unique<QgsCircularString>();
1218 curveC->setPoints( partC );
1222 mCurves.insert( curveId, curveC.release() );
1223 mCurves.insert( curveId, curveB.release() );
1224 if ( subVertexId.
vertex > 1 )
1225 mCurves.insert( curveId, curveA.release() );
1232 lineString->points(
points );
1238 auto curveA = std::make_unique<QgsLineString>();
1239 curveA->setPoints( partA );
1240 auto curveB = std::make_unique<QgsCircularString>();
1241 curveB->setPoints( partB );
1242 auto curveC = std::make_unique<QgsLineString>();
1243 curveC->setPoints( partC );
1247 mCurves.insert( curveId, curveC.release() );
1248 mCurves.insert( curveId, curveB.release() );
1249 if ( subVertexId.
vertex > 1 )
1250 mCurves.insert( curveId, curveA.release() );
1268 int currentVertexId = 0;
1269 for (
int j = 0; j < mCurves.size(); ++j )
1271 int nCurvePoints = mCurves.at( j )->numPoints();
1272 if ( ( node - currentVertexId ) < nCurvePoints )
1274 return ( mCurves.at( j )->pointAt( node - currentVertexId, point, type ) );
1276 currentVertexId += ( nCurvePoints - 1 );
1283 int currentVertexId = 0;
1284 for (
int j = 0; j < mCurves.size(); ++j )
1286 int nCurvePoints = mCurves.at( j )->numPoints();
1287 if ( ( index - currentVertexId ) < nCurvePoints )
1289 return mCurves.at( j )->xAt( index - currentVertexId );
1291 currentVertexId += ( nCurvePoints - 1 );
1298 int currentVertexId = 0;
1299 for (
int j = 0; j < mCurves.size(); ++j )
1301 int nCurvePoints = mCurves.at( j )->numPoints();
1302 if ( ( index - currentVertexId ) < nCurvePoints )
1304 return mCurves.at( j )->yAt( index - currentVertexId );
1306 currentVertexId += ( nCurvePoints - 1 );
1313 int currentVertexId = 0;
1314 for (
int j = 0; j < mCurves.size(); ++j )
1316 int nCurvePoints = mCurves.at( j )->numPoints();
1317 if ( ( index - currentVertexId ) < nCurvePoints )
1319 return mCurves.at( j )->zAt( index - currentVertexId );
1321 currentVertexId += ( nCurvePoints - 1 );
1328 int currentVertexId = 0;
1329 for (
int j = 0; j < mCurves.size(); ++j )
1331 int nCurvePoints = mCurves.at( j )->numPoints();
1332 if ( ( index - currentVertexId ) < nCurvePoints )
1334 return mCurves.at( j )->mAt( index - currentVertexId );
1336 currentVertexId += ( nCurvePoints - 1 );
1344 for (
QgsCurve *curve : std::as_const( mCurves ) )
1346 if ( !curve->transform( transformer ) )
1364 for (
QgsCurve *curve : std::as_const( mCurves ) )
1366 curve->filterVertices( filter );
1373 for (
QgsCurve *curve : std::as_const( mCurves ) )
1382 if ( mCurves.empty() )
1383 return std::make_tuple( std::make_unique< QgsCompoundCurve >(), std::make_unique< QgsCompoundCurve >() );
1387 auto curve1 = std::make_unique< QgsCompoundCurve >();
1388 std::unique_ptr< QgsCompoundCurve > curve2;
1390 for (
const QgsCurve *curve : mCurves )
1392 const int curveSize = curve->numPoints();
1393 if ( !curve2 && index < curveStart + curveSize )
1396 auto [p1, p2] = curve->splitCurveAtVertex( index - curveStart );
1397 if ( !p1->isEmpty() )
1398 curve1->addCurve( p1.release() );
1400 curve2 = std::make_unique< QgsCompoundCurve >();
1401 if ( !p2->isEmpty() )
1402 curve2->addCurve( p2.release() );
1407 curve2->addCurve( curve->clone() );
1409 curve1->addCurve( curve->clone() );
1414 curveStart += curve->numPoints() - 1;
1417 return std::make_tuple( std::move( curve1 ), curve2 ? std::move( curve2 ) : std::make_unique< QgsCompoundCurve >() );
1429 for (
const QgsCurve *curve : mCurves )
1446 for (
const QgsCurve *curve : mCurves )
1465 for (
const QgsCurve *curve : mCurves )
1467 if ( curve->hasCurvedSegments() )
1477 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( vertex );
1478 if ( curveIds.size() == 1 )
1480 QgsCurve *curve = mCurves[curveIds.at( 0 ).first];
1481 return curve->
vertexAngle( curveIds.at( 0 ).second );
1483 else if ( curveIds.size() > 1 )
1485 QgsCurve *curve1 = mCurves[curveIds.at( 0 ).first];
1486 QgsCurve *curve2 = mCurves[curveIds.at( 1 ).first];
1487 double angle1 = curve1->
vertexAngle( curveIds.at( 0 ).second );
1488 double angle2 = curve2->
vertexAngle( curveIds.at( 1 ).second );
1499 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( startVertex );
1501 for (
auto it = curveIds.constBegin(); it != curveIds.constEnd(); ++it )
1503 length += mCurves.at( it->first )->segmentLength( it->second );
1511 for (
int i = mCurves.count() - 1; i >= 0; --i )
1513 QgsCurve *reversedCurve = mCurves.at( i )->reversed();
1514 clone->addCurve( reversedCurve );
1524 double distanceTraversed = 0;
1525 for (
const QgsCurve *curve : mCurves )
1527 const double thisCurveLength = curve->length();
1528 if ( distanceTraversed + thisCurveLength > distance ||
qgsDoubleNear( distanceTraversed + thisCurveLength, distance ) )
1531 const double distanceToPoint = std::min( distance - distanceTraversed, thisCurveLength );
1534 return curve->interpolatePoint( distanceToPoint );
1537 distanceTraversed += thisCurveLength;
1545 if ( startDistance < 0 && endDistance < 0 )
1548 endDistance = std::max( startDistance, endDistance );
1549 auto substring = std::make_unique< QgsCompoundCurve >();
1551 double distanceTraversed = 0;
1552 for (
const QgsCurve *curve : mCurves )
1554 const double thisCurveLength = curve->length();
1555 if ( distanceTraversed + thisCurveLength < startDistance )
1561 std::unique_ptr< QgsCurve > part( curve->curveSubstring( startDistance - distanceTraversed, endDistance - distanceTraversed ) );
1563 substring->addCurve( part.release() );
1566 distanceTraversed += thisCurveLength;
1567 if ( distanceTraversed > endDistance )
1571 return substring.release();
1581 for (
QgsCurve *curve : std::as_const( mCurves ) )
1583 curve->addZValue( zValue );
1596 for (
QgsCurve *curve : std::as_const( mCurves ) )
1598 curve->addMValue( mValue );
1610 for (
QgsCurve *curve : std::as_const( mCurves ) )
1612 curve->dropZValue();
1624 for (
QgsCurve *curve : std::as_const( mCurves ) )
1626 curve->dropMValue();
1634 for (
QgsCurve *curve : std::as_const( mCurves ) )
1650 if ( fromVertex.
part != 0 || fromVertex.
ring != 0 || toVertex.
part != 0 || toVertex.
ring != 0 )
1653 const int fromVertexNumber = fromVertex.
vertex;
1654 const int toVertexNumber = toVertex.
vertex;
1657 if ( fromVertexNumber < 0 || fromVertexNumber >= totalVertices || toVertexNumber < 0 || toVertexNumber >= totalVertices )
1660 if ( fromVertexNumber == toVertexNumber )
1663 double totalDistance = 0.0;
1666 int currentVertexId = 0;
1667 int fromCurve = -1, toCurve = -1;
1668 int fromCurveVertex = -1, toCurveVertex = -1;
1671 for (
int j = 0; j < mCurves.size(); ++j )
1673 int nCurvePoints = mCurves.at( j )->numPoints();
1676 if ( fromCurve == -1 && fromVertexNumber >= currentVertexId && fromVertexNumber < currentVertexId + nCurvePoints )
1679 fromCurveVertex = fromVertexNumber - currentVertexId;
1683 if ( toCurve == -1 && toVertexNumber >= currentVertexId && toVertexNumber < currentVertexId + nCurvePoints )
1686 toCurveVertex = toVertexNumber - currentVertexId;
1690 currentVertexId += ( nCurvePoints - 1 );
1693 if ( fromCurve == -1 || toCurve == -1 )
1696 if ( fromCurve == toCurve )
1701 return mCurves.at( fromCurve )->distanceBetweenVertices( fromId, toId );
1708 if ( fromCurveVertex < mCurves.at( fromCurve )->numPoints() - 1 )
1711 QgsVertexId endId( 0, 0, mCurves.at( fromCurve )->numPoints() - 1 );
1712 totalDistance += mCurves.at( fromCurve )->distanceBetweenVertices( fromId, endId );
1716 for (
int j = fromCurve + 1; j < toCurve; ++j )
1718 totalDistance += mCurves.at( j )->length();
1722 if ( toCurveVertex > 0 )
1726 totalDistance += mCurves.at( toCurve )->distanceBetweenVertices( startId, toId );
1730 return totalDistance;
QFlags< GeometryValidityFlag > GeometryValidityFlags
Geometry validity flags.
VertexType
Types of vertex.
GeoJsonProfile
GeoJson export Profile according to OGC Features and Geometries JSON - Part 1: Core https://docs....
@ Legacy
Legacy GeoJson profile used in QGIS prior to 4.2, which included some non-standard extensions and dev...
@ Rfc7946
GeoJson profile compliant with RFC7946 standard "http://www.opengis.net/def/profile/OGC/0/rfc7946".
@ JsonFg
GeoJson profile from OGC Features and Geometries JSON Part 1: core "http://www.opengis....
@ JsonFgPlus
GeoJson profile from OGC Features and Geometries JSON Part 1: core "http://www.opengis....
WkbType
The WKB type describes the number of dimensions a geometry has.
@ CompoundCurve
CompoundCurve.
@ CircularString
CircularString.
TransformDirection
Indicates the direction (forward or inverse) of a transform.
virtual bool fromWkb(QgsConstWkbPtr &wkb)=0
Sets the geometry from a WKB string.
virtual bool moveVertex(QgsVertexId position, const QgsPoint &newPos)=0
Moves a vertex within the geometry.
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
virtual double vertexAngle(QgsVertexId vertex) const =0
Returns approximate angle at a vertex.
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.
QFlags< WkbFlag > WkbFlags
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
AxisOrder
Axis order for GML generation.
QString wktTypeStr() const
Returns the WKT type string of the geometry.
virtual bool deleteVertices(const QSet< QgsVertexId > &positions)=0
Deletes vertices within the geometry.
QgsAbstractGeometry & operator=(const QgsAbstractGeometry &geom)
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
virtual bool insertVertex(QgsVertexId position, const QgsPoint &vertex)=0
Inserts a vertex into the geometry.
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, Qgis::WkbType baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
virtual bool boundingBoxIntersects(const QgsRectangle &rectangle) const
Returns true if the bounding box of this geometry intersects with a rectangle.
virtual int compareTo(const QgsAbstractGeometry *other) const
Comparator for sorting of 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.
void combineWith(const QgsBox3D &box)
Expands the bbox so that it covers both the original rectangle and the given rectangle.
Circular string geometry type.
bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
void draw(QPainter &p) const override
Draws the geometry using the specified QPainter.
void sumUpArea(double &sum) const override
Sums up the area of the curve by iterating over the vertices (shoelace formula).
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 insertVertex(QgsVertexId position, const QgsPoint &vertex) override
Inserts a vertex into the geometry.
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...
QgsAbstractGeometry * simplifyByDistance(double tolerance) const override
Simplifies the geometry by applying the Douglas Peucker simplification by distance algorithm.
int compareToSameClass(const QgsAbstractGeometry *other) const final
Compares to an other geometry of the same class, and returns a integer for sorting of the two geometr...
bool fromWkb(QgsConstWkbPtr &wkb) override
Sets the geometry from a WKB string.
QgsCompoundCurve * reversed() const override
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
void condenseCurves()
Condenses the curves in this geometry by combining adjacent linestrings a to a single continuous line...
void close()
Appends first point if not already closed.
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
void drawAsPolygon(QPainter &p) const override
Draws the curve as a polygon on the specified QPainter.
int dimension() const override
Returns the inherent dimension of the geometry.
void filterVertices(const std::function< bool(const QgsPoint &) > &filter) override
Filters the vertices from the geometry in place, removing any which do not return true for the filter...
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...
bool boundingBoxIntersects(const QgsBox3D &box3d) const override
Returns true if the bounding box of this geometry intersects with a box3d.
QString geometryType() const override
Returns a unique string representing the geometry type.
double mAt(int index) const override
Returns the m-coordinate of the specified node in the line string.
double distanceBetweenVertices(QgsVertexId fromVertex, QgsVertexId toVertex) const override
Returns the distance along the curve between two vertices.
bool isEmpty() const override
Returns true if the geometry is empty.
double vertexAngle(QgsVertexId vertex) const override
Returns approximate angle at a vertex.
double segmentLength(QgsVertexId startVertex) const override
Returns the length of the segment of the geometry which begins at startVertex.
bool isSimpleCurve() const override
This method returns true for classes that can be cast to the QgsSimpleCurve class.
void transformVertices(const std::function< QgsPoint(const QgsPoint &) > &transform) override
Transforms the vertices from the geometry in place, applying the transform function to every vertex.
int nCurves() const
Returns the number of curves in the geometry.
bool toggleCircularAtVertex(QgsVertexId position)
Converts the vertex at the given position from/to circular.
QgsBox3D calculateBoundingBox3D() const override
Calculates the minimal 3D bounding box for the geometry.
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.
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
const QgsAbstractGeometry * simplifiedTypeRef() const override
Returns a reference to the simplest lossless representation of this geometry, e.g.
int wkbSize(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns the length of the QByteArray returned by asWkb().
bool deleteVertices(const QSet< QgsVertexId > &positions) override
Deletes vertices within the geometry.
void sumUpArea3D(double &sum) const override
Sums up the 3d area of the curve by iterating over the vertices (shoelace formula).
void swapXy() override
Swaps the x and y coordinates from the geometry.
void removeCurve(int i)
Removes a curve from the geometry.
void addCurve(QgsCurve *c, bool extendPrevious=false)
Adds a curve to the geometry (takes ownership).
bool moveVertex(QgsVertexId position, const QgsPoint &newPos) override
Moves 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.
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.
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
bool dropMValue() override
Drops any measure values which exist in the geometry.
QgsCompoundCurve & operator=(const QgsCompoundCurve &curve)
QgsCompoundCurve * clone() const override
Clones the geometry by performing a deep copy.
const QgsCurve * curveAt(int i) const
Returns the curve at the specified index.
void points(QgsPointSequence &pts) const override
Returns a list of points within the curve.
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
~QgsCompoundCurve() override
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns a WKB representation of the geometry.
void clear() override
Clears the geometry, ie reset it to a null geometry.
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...
void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) override
Transforms the geometry using a coordinate transform.
bool hasCurvedSegments() const override
Returns true if the geometry contains curved segments.
QgsCompoundCurve * curveSubstring(double startDistance, double endDistance) const override
Returns a new curve representing a substring of this curve.
void scroll(int firstVertexIndex) final
Scrolls the curve vertices so that they start with the vertex at the given index.
double length() const override
Returns the planar, 2-dimensional length of the geometry.
void addToPainterPath(QPainterPath &path) const override
Adds a curve to a painter path.
QgsPoint * interpolatePoint(double distance) const override
Returns an interpolated point on the curve at the specified distance.
QgsCompoundCurve * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
bool pointAt(int node, QgsPoint &point, Qgis::VertexType &type) const override
Returns the point and vertex type of a point within the curve.
QgsPoint startPoint() const override
Returns the starting point of the curve.
QgsCompoundCurve * 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.
QgsPoint endPoint() const override
Returns the end point of the curve.
int numPoints() const override
Returns the number of points in the curve.
double zAt(int index) const override
Returns the z-coordinate of the specified node in the line string.
void addVertex(const QgsPoint &pt)
Adds a vertex to the end of the geometry.
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
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.
Qgis::WkbType readHeader() const
readHeader
virtual int numPoints() const =0
Returns the number of points in the curve.
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
bool mHasCachedSummedUpArea
bool mHasCachedSummedUpArea3D
virtual bool isClosed() const
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.
QgsPoint vertexAt(QgsVertexId id) const override
Returns the point corresponding to a specified vertex id.
QgsBox3D mBoundingBox
Cached bounding box.
virtual QgsPoint startPoint() const =0
Returns the starting point of the curve.
bool hasVertex(QgsVertexId position) const override
Returns true if the geometry contains a vertex matching the given position.
virtual QgsPoint endPoint() const =0
Returns the end point of the curve.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const
Tells whether the operation has been canceled already.
static 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 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 (...
static double closestSegmentFromComponents(T &container, ComponentType ctype, const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf, double epsilon)
Line string geometry type, with support for z-dimension and m-values.
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.
Point geometry type, with support for z-dimension and m-values.
QgsPoint vertexAt(QgsVertexId) const override
Returns the point corresponding to a specified vertex id.
bool isEmpty() const override
Returns true if the geometry is empty.
void points(QgsPointSequence &pts) const override
Returns a list of points within the curve.
void append(const QgsSimpleCurve *curve)
Appends the contents of another simple curve to the end of this simple curve.
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.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
#define BUILTIN_UNREACHABLE
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.