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;
481 std::unique_ptr< QgsLineString > currentLine;
482 for (
const QgsCurve *curve : mCurves )
484 currentLine.reset( curve->curveToLine( tolerance, toleranceType ) );
485 line->
append( currentLine.get() );
496 std::unique_ptr<QgsCurve> gridified(
static_cast< QgsCurve *
>( curve->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing, removeRedundantPoints ) ) );
499 result->mCurves.append( gridified.release() );
503 if ( result->mCurves.empty() )
506 return result.release();
511 std::unique_ptr< QgsLineString > line(
curveToLine() );
512 return line->simplifyByDistance( tolerance );
518 const QVector< QgsCurve * > curves = mCurves;
523 result = curve->removeDuplicateNodes( epsilon, useZValues ) || result;
524 if ( curve->numPoints() == 0 ||
qgsDoubleNear( curve->length(), 0.0, epsilon ) )
527 delete mCurves.takeAt( i );
535 curve->moveVertex(
QgsVertexId( -1, -1, 0 ), lastEnd );
546 if ( mCurves.empty() )
560 for (
const QgsCurve *curve : mCurves )
562 if ( curve->boundingBoxIntersects( box3d ) )
575 if ( mCurves.size() == 1 )
576 return mCurves.at( 0 );
583 if ( i < 0 || i >= mCurves.size() )
587 return mCurves.at( i );
595 if ( mCurves.empty() )
619 const bool canExtendPrevious = extendPrevious && previousLineString && newLineString;
620 if ( canExtendPrevious )
622 previousLineString->
append( newLineString );
637 if ( i < 0 || i >= mCurves.size() )
642 delete mCurves.takeAt( i );
655 if ( !mCurves.isEmpty() )
657 lastCurve = mCurves.at( mCurves.size() - 1 );
664 mCurves.append( line );
682 QVector< QgsCurve * > newCurves;
683 newCurves.reserve( mCurves.size() );
684 for (
QgsCurve *curve : std::as_const( mCurves ) )
686 if ( lastCurve && lastCurve->
wkbType() == curve->wkbType() )
710 for (
const QgsCurve *curve : mCurves )
718 for (
QgsCurve *curve : std::as_const( mCurves ) )
720 curve->transform( ct, d, transformZ );
727 for (
QgsCurve *curve : std::as_const( mCurves ) )
729 curve->transform( t, zTranslate, zScale, mTranslate, mScale );
738 for (
const QgsCurve *curve : mCurves )
740 if ( curve != mCurves.at( 0 ) && pp.currentPosition() != curve->startPoint().toQPointF() )
742 pp.lineTo( curve->startPoint().toQPointF() );
744 curve->addToPainterPath( pp );
752 for (
const QgsCurve *curve : mCurves )
754 if ( curve != mCurves.at( 0 ) && pp.currentPosition() != curve->startPoint().toQPointF() )
756 pp.lineTo( curve->startPoint().toQPointF() );
758 curve->addToPainterPath( pp );
765 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
766 if ( curveIds.empty() )
770 int curveId = curveIds.at( 0 ).first;
771 if ( curveId >= mCurves.size() )
776 bool success = mCurves.at( curveId )->insertVertex( curveIds.at( 0 ).second, vertex );
786 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
787 QVector< QPair<int, QgsVertexId> >::const_iterator idIt = curveIds.constBegin();
788 for ( ; idIt != curveIds.constEnd(); ++idIt )
790 mCurves.at( idIt->first )->moveVertex( idIt->second, newPos );
793 bool success = !curveIds.isEmpty();
803 const QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
804 if ( curveIds.isEmpty() )
807 const int curveId = curveIds.at( 0 ).first;
808 QgsCurve *curve = mCurves.at( curveId );
809 const QgsVertexId subVertexId = curveIds.at( 0 ).second;
812 if ( curveIds.size() == 1 )
817 if ( circularString && subVertexId.
vertex % 2 == 1 )
827 auto curveC = std::make_unique<QgsCircularString>();
828 curveC->setPoints(
points.mid( subVertexId.
vertex + 1 ) );
829 mCurves.insert( curveId, curveC.release() );
833 auto curveB = std::make_unique<QgsLineString>();
834 curveB->setPoints( partB );
835 mCurves.insert( curveId, curveB.release() );
836 curve = mCurves.at( curveId );
838 if ( subVertexId.
vertex > 1 )
840 auto curveA = std::make_unique<QgsCircularString>();
841 curveA->setPoints(
points.mid( 0, subVertexId.
vertex ) );
842 mCurves.insert( curveId, curveA.release() );
857 else if ( curveIds.size() == 2 )
859 const int nextCurveId = curveIds.at( 1 ).first;
860 QgsCurve *nextCurve = mCurves.at( nextCurveId );
861 const QgsVertexId nextSubVertexId = curveIds.at( 1 ).second;
863 Q_ASSERT( nextCurveId == curveId + 1 );
865 Q_ASSERT( nextSubVertexId.
vertex == 0 );
895 mCurves.insert( curveId, line );
907 mCurves.insert( nextCurveId, line );
919 mCurves.insert( curveId, line );
927 if ( endPointOfFirst != startPointOfSecond )
932 mCurves.insert( nextCurveId, line );
938 bool success = !curveIds.isEmpty();
947 QMap<int, QList<QgsVertexId >> curveVertices;
955 const QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
957 if ( curveIds.isEmpty() )
960 const int firstCurveId = curveIds.at( 0 ).first;
961 const QgsVertexId firstCurveVertex = curveIds.at( 0 ).second;
962 curveVertices[firstCurveId].append( firstCurveVertex );
963 if ( curveIds.size() == 2 )
965 const int secondCurveId = curveIds.at( 1 ).first;
966 const QgsVertexId secondCurveVertex = curveIds.at( 1 ).second;
967 curveVertices[secondCurveId].append( secondCurveVertex );
971 QVector< QgsPoint > survivingPoints;
973 auto appendSurvivingPoints = [&survivingPoints,
this](
const QgsPoint &point,
const int curveId ) {
975 pts.reserve( 1 + survivingPoints.size() );
978 for (
size_t i = survivingPoints.size(); i-- > 0; )
979 pts << survivingPoints[i];
981 auto newLineString = std::make_unique<QgsLineString>();
982 newLineString->setPoints( pts );
983 mCurves.insert( curveId, newLineString.release() );
985 survivingPoints.clear();
989 QMapIterator<int, QList<QgsVertexId >> curveVerticesIt( curveVertices );
990 curveVerticesIt.toBack();
991 int previousCurveId = -1;
992 while ( curveVerticesIt.hasPrevious() )
994 curveVerticesIt.previous();
995 const int curveId = curveVerticesIt.key();
998 if ( previousCurveId - 1 > curveId && !survivingPoints.isEmpty() )
1000 QgsCurve *curve = mCurves.at( previousCurveId - 1 );
1001 appendSurvivingPoints( curve->
endPoint(), previousCurveId );
1004 QgsCurve *curve = mCurves.at( curveId );
1005 QList<QgsVertexId>
vertices = curveVerticesIt.value();
1011 if ( circularString )
1015 QList<QgsVertexId> circularVerticesToDelete;
1016 circularVerticesToDelete.reserve(
vertices.size() );
1019 for (
size_t i =
vertices.size(); i-- > 0; )
1024 if ( curveVertexId.vertex % 2 == 1 )
1028 if ( !circularVerticesToDelete.isEmpty() )
1030 if ( curveVertexId.vertex == circularVerticesToDelete.last().vertex - 1 )
1032 circularVerticesToDelete.append( curveVertexId );
1036 else if ( i != 0 && curveVertexId.vertex - 1 ==
vertices.at( i - 1 ).vertex )
1038 circularVerticesToDelete.append( curveVertexId );
1045 if ( !circularVerticesToDelete.isEmpty() )
1047 if ( !curve->
deleteVertices( QSet<QgsVertexId>( circularVerticesToDelete.begin(), circularVerticesToDelete.end() ) ) )
1053 circularVerticesToDelete.clear();
1061 if ( curveVertexId.vertex <
points.length() - 2 )
1063 auto curveC = std::make_unique<QgsCircularString>();
1064 curveC->setPoints(
points.mid( curveVertexId.vertex + 1 ) );
1065 mCurves.insert( curveId, curveC.release() );
1069 auto curveB = std::make_unique<QgsLineString>();
1070 curveB->setPoints( partB );
1071 mCurves.insert( curveId, curveB.release() );
1072 curve = mCurves.at( curveId );
1074 if ( curveVertexId.vertex > 1 )
1076 auto curveA = std::make_unique<QgsCircularString>();
1077 curveA->setPoints(
points.mid( 0, curveVertexId.vertex ) );
1078 mCurves.insert( curveId, curveA.release() );
1080 curve = mCurves.at( curveId );
1087 circularVerticesToDelete.append( curveVertexId );
1091 if ( !circularVerticesToDelete.isEmpty() )
1098 if ( curveId > 0 && circularVerticesToDelete.last().vertex == 0 && circularVerticesToDelete.first().vertex != curve->
numPoints() - 1 )
1100 survivingPoint = curve->
endPoint();
1102 else if ( curveId == 0 && circularVerticesToDelete.first().vertex == curve->
numPoints() - 1 && circularVerticesToDelete.last().vertex != 0 )
1106 if ( !curve->
deleteVertices( QSet<QgsVertexId>( circularVerticesToDelete.begin(), circularVerticesToDelete.end() ) ) )
1117 if ( !survivingPoint.
isEmpty() )
1119 survivingPoints.emplace_back( survivingPoint );
1122 else if ( survivingPoints.size() != 0 )
1124 appendSurvivingPoints( curve->
endPoint(), curveId + 1 );
1127 previousCurveId = curveId;
1137 int remainingIdx = 0;
1140 if ( v.vertex != remainingIdx )
1146 previousCurveId = curveId;
1160 else if ( survivingPoints.size() != 0 )
1162 appendSurvivingPoints( curve->
endPoint(), curveId + 1 );
1165 previousCurveId = curveId;
1169 if ( survivingPoints.size() != 0 )
1171 if ( previousCurveId > 0 )
1176 const QgsCurve *curve = mCurves.at( previousCurveId - 1 );
1177 appendSurvivingPoints( curve->
endPoint(), previousCurveId );
1186 if ( mCurves.size() != 0 )
1188 const QgsCurve *curve = mCurves.at( 0 );
1193 for (
int i = survivingPoints.size() - 1; i >= 0; --i )
1194 pts << survivingPoints[i];
1199 if ( pts.size() > 1 )
1201 auto newLineString = std::make_unique<QgsLineString>();
1202 newLineString->setPoints( pts );
1204 mCurves.insert( 0, newLineString.release() );
1209 if ( mCurves.isEmpty() )
1216 for (
size_t i = mCurves.size() - 1; i > 0; i-- )
1219 QgsCurve *previousCurve = mCurves.at( i - 1 );
1225 mCurves.insert( i, line );
1234QVector< QPair<int, QgsVertexId> > QgsCompoundCurve::curveVertexId(
QgsVertexId id )
const
1236 QVector< QPair<int, QgsVertexId> > curveIds;
1238 int currentVertexIndex = 0;
1239 for (
int i = 0; i < mCurves.size(); ++i )
1241 int increment = mCurves.at( i )->numPoints() - 1;
1242 if (
id.vertex >= currentVertexIndex &&
id.vertex <= currentVertexIndex + increment )
1244 int curveVertexId =
id.vertex - currentVertexIndex;
1248 vid.
vertex = curveVertexId;
1249 curveIds.append( qMakePair( i, vid ) );
1250 if ( curveVertexId == increment && i < ( mCurves.size() - 1 ) )
1253 curveIds.append( qMakePair( i + 1, vid ) );
1257 else if (
id.vertex >= currentVertexIndex &&
id.vertex == currentVertexIndex + increment + 1 && i == ( mCurves.size() - 1 ) )
1259 int curveVertexId =
id.vertex - currentVertexIndex;
1263 vid.
vertex = curveVertexId;
1264 curveIds.append( qMakePair( i, vid ) );
1267 currentVertexIndex += increment;
1288 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
1291 if ( curveIds.length() != 1 )
1294 int curveId = curveIds[0].first;
1296 QgsCurve *curve = mCurves[curveId];
1307 if ( subVertexId.
vertex % 2 == 0 )
1311 circularString->points(
points );
1317 auto curveA = std::make_unique<QgsCircularString>();
1318 curveA->setPoints( partA );
1319 auto curveB = std::make_unique<QgsLineString>();
1320 curveB->setPoints( partB );
1321 auto curveC = std::make_unique<QgsCircularString>();
1322 curveC->setPoints( partC );
1326 mCurves.insert( curveId, curveC.release() );
1327 mCurves.insert( curveId, curveB.release() );
1328 if ( subVertexId.
vertex > 1 )
1329 mCurves.insert( curveId, curveA.release() );
1336 lineString->points(
points );
1342 auto curveA = std::make_unique<QgsLineString>();
1343 curveA->setPoints( partA );
1344 auto curveB = std::make_unique<QgsCircularString>();
1345 curveB->setPoints( partB );
1346 auto curveC = std::make_unique<QgsLineString>();
1347 curveC->setPoints( partC );
1351 mCurves.insert( curveId, curveC.release() );
1352 mCurves.insert( curveId, curveB.release() );
1353 if ( subVertexId.
vertex > 1 )
1354 mCurves.insert( curveId, curveA.release() );
1372 int currentVertexId = 0;
1373 for (
int j = 0; j < mCurves.size(); ++j )
1375 int nCurvePoints = mCurves.at( j )->numPoints();
1376 if ( ( node - currentVertexId ) < nCurvePoints )
1378 return ( mCurves.at( j )->pointAt( node - currentVertexId, point, type ) );
1380 currentVertexId += ( nCurvePoints - 1 );
1387 int currentVertexId = 0;
1388 for (
int j = 0; j < mCurves.size(); ++j )
1390 int nCurvePoints = mCurves.at( j )->numPoints();
1391 if ( ( index - currentVertexId ) < nCurvePoints )
1393 return mCurves.at( j )->xAt( index - currentVertexId );
1395 currentVertexId += ( nCurvePoints - 1 );
1402 int currentVertexId = 0;
1403 for (
int j = 0; j < mCurves.size(); ++j )
1405 int nCurvePoints = mCurves.at( j )->numPoints();
1406 if ( ( index - currentVertexId ) < nCurvePoints )
1408 return mCurves.at( j )->yAt( index - currentVertexId );
1410 currentVertexId += ( nCurvePoints - 1 );
1417 int currentVertexId = 0;
1418 for (
int j = 0; j < mCurves.size(); ++j )
1420 int nCurvePoints = mCurves.at( j )->numPoints();
1421 if ( ( index - currentVertexId ) < nCurvePoints )
1423 return mCurves.at( j )->zAt( index - currentVertexId );
1425 currentVertexId += ( nCurvePoints - 1 );
1432 int currentVertexId = 0;
1433 for (
int j = 0; j < mCurves.size(); ++j )
1435 int nCurvePoints = mCurves.at( j )->numPoints();
1436 if ( ( index - currentVertexId ) < nCurvePoints )
1438 return mCurves.at( j )->mAt( index - currentVertexId );
1440 currentVertexId += ( nCurvePoints - 1 );
1448 for (
QgsCurve *curve : std::as_const( mCurves ) )
1450 if ( !curve->transform( transformer ) )
1468 for (
QgsCurve *curve : std::as_const( mCurves ) )
1470 curve->filterVertices( filter );
1477 for (
QgsCurve *curve : std::as_const( mCurves ) )
1486 if ( mCurves.empty() )
1487 return std::make_tuple( std::make_unique< QgsCompoundCurve >(), std::make_unique< QgsCompoundCurve >() );
1491 auto curve1 = std::make_unique< QgsCompoundCurve >();
1492 std::unique_ptr< QgsCompoundCurve > curve2;
1494 for (
const QgsCurve *curve : mCurves )
1496 const int curveSize = curve->numPoints();
1497 if ( !curve2 && index < curveStart + curveSize )
1500 auto [p1, p2] = curve->splitCurveAtVertex( index - curveStart );
1501 if ( !p1->isEmpty() )
1502 curve1->addCurve( p1.release() );
1504 curve2 = std::make_unique< QgsCompoundCurve >();
1505 if ( !p2->isEmpty() )
1506 curve2->addCurve( p2.release() );
1511 curve2->addCurve( curve->clone() );
1513 curve1->addCurve( curve->clone() );
1518 curveStart += curve->numPoints() - 1;
1521 return std::make_tuple( std::move( curve1 ), curve2 ? std::move( curve2 ) : std::make_unique< QgsCompoundCurve >() );
1533 for (
const QgsCurve *curve : mCurves )
1550 for (
const QgsCurve *curve : mCurves )
1569 for (
const QgsCurve *curve : mCurves )
1571 if ( curve->hasCurvedSegments() )
1581 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( vertex );
1582 if ( curveIds.size() == 1 )
1584 QgsCurve *curve = mCurves[curveIds.at( 0 ).first];
1585 return curve->
vertexAngle( curveIds.at( 0 ).second );
1587 else if ( curveIds.size() > 1 )
1589 QgsCurve *curve1 = mCurves[curveIds.at( 0 ).first];
1590 QgsCurve *curve2 = mCurves[curveIds.at( 1 ).first];
1591 double angle1 = curve1->
vertexAngle( curveIds.at( 0 ).second );
1592 double angle2 = curve2->
vertexAngle( curveIds.at( 1 ).second );
1603 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( startVertex );
1605 for (
auto it = curveIds.constBegin(); it != curveIds.constEnd(); ++it )
1607 length += mCurves.at( it->first )->segmentLength( it->second );
1615 for (
int i = mCurves.count() - 1; i >= 0; --i )
1617 QgsCurve *reversedCurve = mCurves.at( i )->reversed();
1618 clone->addCurve( reversedCurve );
1628 double distanceTraversed = 0;
1629 for (
const QgsCurve *curve : mCurves )
1631 const double thisCurveLength = curve->length();
1632 if ( distanceTraversed + thisCurveLength > distance ||
qgsDoubleNear( distanceTraversed + thisCurveLength, distance ) )
1635 const double distanceToPoint = std::min( distance - distanceTraversed, thisCurveLength );
1638 return curve->interpolatePoint( distanceToPoint );
1641 distanceTraversed += thisCurveLength;
1649 if ( startDistance < 0 && endDistance < 0 )
1652 endDistance = std::max( startDistance, endDistance );
1653 auto substring = std::make_unique< QgsCompoundCurve >();
1655 double distanceTraversed = 0;
1656 for (
const QgsCurve *curve : mCurves )
1658 const double thisCurveLength = curve->length();
1659 if ( distanceTraversed + thisCurveLength < startDistance )
1665 std::unique_ptr< QgsCurve > part( curve->curveSubstring( startDistance - distanceTraversed, endDistance - distanceTraversed ) );
1667 substring->addCurve( part.release() );
1670 distanceTraversed += thisCurveLength;
1671 if ( distanceTraversed > endDistance )
1675 return substring.release();
1685 for (
QgsCurve *curve : std::as_const( mCurves ) )
1687 curve->addZValue( zValue );
1700 for (
QgsCurve *curve : std::as_const( mCurves ) )
1702 curve->addMValue( mValue );
1714 for (
QgsCurve *curve : std::as_const( mCurves ) )
1716 curve->dropZValue();
1728 for (
QgsCurve *curve : std::as_const( mCurves ) )
1730 curve->dropMValue();
1738 for (
QgsCurve *curve : std::as_const( mCurves ) )
1754 if ( fromVertex.
part != 0 || fromVertex.
ring != 0 || toVertex.
part != 0 || toVertex.
ring != 0 )
1757 const int fromVertexNumber = fromVertex.
vertex;
1758 const int toVertexNumber = toVertex.
vertex;
1761 if ( fromVertexNumber < 0 || fromVertexNumber >= totalVertices || toVertexNumber < 0 || toVertexNumber >= totalVertices )
1764 if ( fromVertexNumber == toVertexNumber )
1767 double totalDistance = 0.0;
1770 int currentVertexId = 0;
1771 int fromCurve = -1, toCurve = -1;
1772 int fromCurveVertex = -1, toCurveVertex = -1;
1775 for (
int j = 0; j < mCurves.size(); ++j )
1777 int nCurvePoints = mCurves.at( j )->numPoints();
1780 if ( fromCurve == -1 && fromVertexNumber >= currentVertexId && fromVertexNumber < currentVertexId + nCurvePoints )
1783 fromCurveVertex = fromVertexNumber - currentVertexId;
1787 if ( toCurve == -1 && toVertexNumber >= currentVertexId && toVertexNumber < currentVertexId + nCurvePoints )
1790 toCurveVertex = toVertexNumber - currentVertexId;
1794 currentVertexId += ( nCurvePoints - 1 );
1797 if ( fromCurve == -1 || toCurve == -1 )
1800 if ( fromCurve == toCurve )
1805 return mCurves.at( fromCurve )->distanceBetweenVertices( fromId, toId );
1812 if ( fromCurveVertex < mCurves.at( fromCurve )->numPoints() - 1 )
1815 QgsVertexId endId( 0, 0, mCurves.at( fromCurve )->numPoints() - 1 );
1816 totalDistance += mCurves.at( fromCurve )->distanceBetweenVertices( fromId, endId );
1820 for (
int j = fromCurve + 1; j < toCurve; ++j )
1822 totalDistance += mCurves.at( j )->length();
1826 if ( toCurveVertex > 0 )
1830 totalDistance += mCurves.at( toCurve )->distanceBetweenVertices( startId, toId );
1834 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.
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.
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 bool deleteVertex(QgsVertexId position)=0
Deletes a vertex within the geometry.
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.
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.
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
double closestSegment(const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf=nullptr, double epsilon=4 *std::numeric_limits< double >::epsilon()) const override
Searches for the closest segment of the geometry to a given point.
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.