27 #include <QJsonObject>
29 #include <QPainterPath>
31 #include <nlohmann/json.hpp>
45 const QgsCompoundCurve *otherCurve = qgsgeometry_cast< const QgsCompoundCurve * >( &other );
52 if ( mCurves.size() != otherCurve->mCurves.size() )
55 for (
int i = 0; i < mCurves.size(); ++i )
57 if ( *mCurves.at( i ) != *otherCurve->mCurves.at( i ) )
66 auto result = std::make_unique< QgsCompoundCurve >();
68 return result.release();
73 const QgsCompoundCurve *otherCurve = qgsgeometry_cast<const QgsCompoundCurve *>( other );
79 while ( i < mCurves.size() && j < otherCurve->mCurves.size() )
83 const int comparison = aGeom->
compareTo( bGeom );
84 if ( comparison != 0 )
91 if ( i < mCurves.size() )
95 if ( j < otherCurve->mCurves.size() )
104 return QStringLiteral(
"CompoundCurve" );
115 mCurves.reserve( curve.mCurves.size() );
116 for (
const QgsCurve *
c : curve.mCurves )
118 mCurves.append(
c->clone() );
124 if ( &curve !=
this )
128 for (
const QgsCurve *
c : curve.mCurves )
130 mCurves.append(
c->clone() );
144 qDeleteAll( mCurves );
151 if ( mCurves.empty() )
157 for (
int i = 1; i < mCurves.size(); ++i )
168 if ( index < 1 || index >= size - 1 )
174 if (
QgsCompoundCurve *curve2 = qgsgeometry_cast< QgsCompoundCurve *>( p2.get() ) )
177 mCurves = std::move( curve2->mCurves );
179 if (
QgsCompoundCurve *curve1 = qgsgeometry_cast< QgsCompoundCurve *>( p1.get() ) )
182 mCurves.append( curve1->mCurves );
183 curve1->mCurves.clear();
205 for (
int i = 0; i <
nCurves; ++i )
208 wkbPtr -= 1 +
sizeof( int );
221 currentCurve->
fromWkb( wkbPtr );
222 mCurves.append( currentCurve );
237 QString secondWithoutParentheses =
parts.second;
238 secondWithoutParentheses = secondWithoutParentheses.remove(
'(' ).remove(
')' ).simplified().remove(
' ' );
239 if ( (
parts.second.compare( QLatin1String(
"EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
240 secondWithoutParentheses.isEmpty() )
243 QString defaultChildWkbType = QStringLiteral(
"LineString%1%2" ).arg(
is3D() ? QStringLiteral(
"Z" ) : QString(),
isMeasure() ? QStringLiteral(
"M" ) : QString() );
246 for (
const QString &childWkt : blocks )
259 if ( !mCurves.back()->fromWkt( childWkt ) )
270 for (
const QgsCurve *curve : std::as_const( mCurves ) )
272 hasZ = hasZ || curve->is3D();
273 hasM = hasM || curve->isMeasure();
287 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
288 for (
const QgsCurve *curve : mCurves )
290 binarySize += curve->wkbSize( flags );
301 wkb << static_cast<quint32>(
wkbType() );
302 wkb << static_cast<quint32>( mCurves.size() );
303 for (
const QgsCurve *curve : mCurves )
305 wkb << curve->asWkb( flags );
314 wkt += QLatin1String(
" EMPTY" );
317 wkt += QLatin1String(
" (" );
318 for (
const QgsCurve *curve : mCurves )
320 QString childWkt = curve->asWkt(
precision );
321 if ( qgsgeometry_cast<const QgsLineString *>( curve ) )
324 childWkt = childWkt.mid( childWkt.indexOf(
'(' ) );
326 wkt += childWkt +
',';
328 if ( wkt.endsWith(
',' ) )
340 std::unique_ptr< QgsLineString > line(
curveToLine() );
341 QDomElement gml = line->asGml2( doc,
precision, ns, axisOrder );
347 QDomElement compoundCurveElem = doc.createElementNS( ns, QStringLiteral(
"CompositeCurve" ) );
350 return compoundCurveElem;
352 for (
const QgsCurve *curve : mCurves )
354 QDomElement curveMemberElem = doc.createElementNS( ns, QStringLiteral(
"curveMember" ) );
355 QDomElement curveElem = curve->asGml3( doc,
precision, ns, axisOrder );
356 curveMemberElem.appendChild( curveElem );
357 compoundCurveElem.appendChild( curveMemberElem );
360 return compoundCurveElem;
366 std::unique_ptr< QgsLineString > line(
curveToLine() );
373 for (
const QgsCurve *curve : mCurves )
375 length += curve->length();
382 if ( mCurves.empty() )
386 return mCurves.at( 0 )->startPoint();
391 if ( mCurves.empty() )
395 return mCurves.at( mCurves.size() - 1 )->endPoint();
401 if ( mCurves.empty() )
406 mCurves[0]->points( pts );
407 for (
int i = 1; i < mCurves.size(); ++i )
410 mCurves[i]->points( pList );
425 for (
int i = 0; i <
nCurves; ++i )
427 nPoints += mCurves.at( i )->numPoints() - 1;
435 if ( mCurves.isEmpty() )
440 if ( !curve->isEmpty() )
448 if ( mCurves.isEmpty() )
451 for (
int i = 0; i < mCurves.size() ; ++i )
453 if ( !mCurves[i]->
isValid( error, flags ) )
455 error = QObject::tr(
"Curve[%1]: %2" ).arg( i + 1 ).arg( error );
465 for (
const QgsCurve *curve : mCurves )
467 const int curveIndex = curve->indexOf( point );
468 if ( curveIndex >= 0 )
469 return curveStart + curveIndex;
472 curveStart += curve->numPoints() - 1;
480 std::unique_ptr< QgsLineString > currentLine;
481 for (
const QgsCurve *curve : mCurves )
483 currentLine.reset( curve->curveToLine( tolerance, toleranceType ) );
484 line->
append( currentLine.get() );
495 std::unique_ptr<QgsCurve> gridified(
static_cast< QgsCurve *
>( curve->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing ) ) );
498 result->mCurves.append( gridified.release() );
502 if ( result->mCurves.empty() )
505 return result.release();
511 const QVector< QgsCurve * > curves = mCurves;
517 if ( curve->numPoints() == 0 ||
qgsDoubleNear( curve->length(), 0.0, epsilon ) )
520 delete mCurves.takeAt( i );
528 curve->moveVertex(
QgsVertexId( -1, -1, 0 ), lastEnd );
539 if ( mCurves.empty() )
553 for (
const QgsCurve *curve : mCurves )
555 if ( curve->boundingBoxIntersects( rectangle ) )
568 if ( mCurves.size() == 1 )
569 return mCurves.at( 0 );
576 if ( i < 0 || i >= mCurves.size() )
580 return mCurves.at( i );
588 if ( mCurves.empty() )
610 QgsLineString *previousLineString = !mCurves.empty() ? qgsgeometry_cast< QgsLineString * >( mCurves.constLast() ) :
nullptr;
611 const QgsLineString *newLineString = qgsgeometry_cast< const QgsLineString * >(
c );
612 const bool canExtendPrevious = extendPrevious && previousLineString && newLineString;
613 if ( canExtendPrevious )
615 previousLineString->
append( newLineString );
630 if ( i < 0 || i >= mCurves.size() )
635 delete mCurves.takeAt( i );
648 if ( !mCurves.isEmpty() )
650 lastCurve = mCurves.at( mCurves.size() - 1 );
657 mCurves.append( line );
675 QVector< QgsCurve * > newCurves;
676 newCurves.reserve( mCurves.size() );
677 for (
QgsCurve *curve : std::as_const( mCurves ) )
679 if ( lastCurve && lastCurve->
wkbType() == curve->wkbType() )
681 if (
QgsLineString *ls = qgsgeometry_cast< QgsLineString * >( lastCurve ) )
683 ls->append( qgsgeometry_cast< QgsLineString * >( curve ) );
686 else if (
QgsCircularString *cs = qgsgeometry_cast< QgsCircularString * >( lastCurve ) )
688 cs->append( qgsgeometry_cast< QgsCircularString * >( curve ) );
703 for (
const QgsCurve *curve : mCurves )
711 for (
QgsCurve *curve : std::as_const( mCurves ) )
713 curve->transform( ct, d, transformZ );
720 for (
QgsCurve *curve : std::as_const( mCurves ) )
722 curve->transform( t, zTranslate, zScale, mTranslate, mScale );
731 for (
const QgsCurve *curve : mCurves )
733 if ( curve != mCurves.at( 0 ) && pp.currentPosition() != curve->startPoint().toQPointF() )
735 pp.lineTo( curve->startPoint().toQPointF() );
737 curve->addToPainterPath( pp );
745 for (
const QgsCurve *curve : mCurves )
747 if ( curve != mCurves.at( 0 ) && pp.currentPosition() != curve->startPoint().toQPointF() )
749 pp.lineTo( curve->startPoint().toQPointF() );
751 curve->addToPainterPath( pp );
758 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
759 if ( curveIds.empty() )
763 int curveId = curveIds.at( 0 ).first;
764 if ( curveId >= mCurves.size() )
769 bool success = mCurves.at( curveId )->insertVertex( curveIds.at( 0 ).second, vertex );
779 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
780 QVector< QPair<int, QgsVertexId> >::const_iterator idIt = curveIds.constBegin();
781 for ( ; idIt != curveIds.constEnd(); ++idIt )
783 mCurves.at( idIt->first )->moveVertex( idIt->second, newPos );
786 bool success = !curveIds.isEmpty();
796 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
797 if ( curveIds.size() == 1 )
799 if ( !mCurves.at( curveIds.at( 0 ).first )->deleteVertex( curveIds.at( 0 ).second ) )
804 if ( mCurves.at( curveIds.at( 0 ).first )->numPoints() == 0 )
809 else if ( curveIds.size() == 2 )
811 Q_ASSERT( curveIds.at( 1 ).first == curveIds.at( 0 ).first + 1 );
812 Q_ASSERT( curveIds.at( 0 ).second.vertex == mCurves.at( curveIds.at( 0 ).first )->numPoints() - 1 );
813 Q_ASSERT( curveIds.at( 1 ).second.vertex == 0 );
818 mCurves.at( curveIds.at( 1 ).first )->numPoints() > 3 )
822 mCurves.at( curveIds.at( 1 ).first ) ->pointAt( 2, intermediatePoint, type );
823 mCurves.at( curveIds.at( 0 ).first )->moveVertex(
824 QgsVertexId( 0, 0, mCurves.at( curveIds.at( 0 ).first )->numPoints() - 1 ), intermediatePoint );
826 else if ( !mCurves.at( curveIds.at( 0 ).first )->deleteVertex( curveIds.at( 0 ).second ) )
832 mCurves.at( curveIds.at( 0 ).first )->numPoints() > 0 &&
835 QgsPoint intermediatePoint = mCurves.at( curveIds.at( 0 ).first ) ->endPoint();
836 mCurves.at( curveIds.at( 1 ).first )->moveVertex(
QgsVertexId( 0, 0, 0 ), intermediatePoint );
838 else if ( !mCurves.at( curveIds.at( 1 ).first )->deleteVertex( curveIds.at( 1 ).second ) )
843 if ( mCurves.at( curveIds.at( 0 ).first )->numPoints() == 0 &&
844 mCurves.at( curveIds.at( 1 ).first )->numPoints() != 0 )
849 else if ( mCurves.at( curveIds.at( 0 ).first )->numPoints() != 0 &&
850 mCurves.at( curveIds.at( 1 ).first )->numPoints() == 0 )
852 mCurves.at( curveIds.at( 0 ).first )->moveVertex(
856 else if ( mCurves.at( curveIds.at( 0 ).first )->numPoints() == 0 &&
857 mCurves.at( curveIds.at( 1 ).first )->numPoints() == 0 )
864 mCurves.insert( curveIds.at( 0 ).first, line );
868 QgsPoint endPointOfFirst = mCurves.at( curveIds.at( 0 ).first ) ->endPoint();
869 QgsPoint startPointOfSecond = mCurves.at( curveIds.at( 1 ).first ) ->startPoint();
870 if ( endPointOfFirst != startPointOfSecond )
875 mCurves.insert( curveIds.at( 1 ).first, line );
880 bool success = !curveIds.isEmpty();
888 QVector< QPair<int, QgsVertexId> > QgsCompoundCurve::curveVertexId(
QgsVertexId id )
const
890 QVector< QPair<int, QgsVertexId> > curveIds;
892 int currentVertexIndex = 0;
893 for (
int i = 0; i < mCurves.size(); ++i )
895 int increment = mCurves.at( i )->numPoints() - 1;
896 if (
id.vertex >= currentVertexIndex &&
id.vertex <= currentVertexIndex + increment )
898 int curveVertexId =
id.vertex - currentVertexIndex;
902 vid.
vertex = curveVertexId;
903 curveIds.append( qMakePair( i, vid ) );
904 if ( curveVertexId == increment && i < ( mCurves.size() - 1 ) )
907 curveIds.append( qMakePair( i + 1, vid ) );
911 else if (
id.vertex >= currentVertexIndex &&
id.vertex == currentVertexIndex + increment + 1 && i == ( mCurves.size() - 1 ) )
913 int curveVertexId =
id.vertex - currentVertexIndex;
917 vid.
vertex = curveVertexId;
918 curveIds.append( qMakePair( i, vid ) );
921 currentVertexIndex += increment;
943 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
946 if ( curveIds.length() != 1 )
949 int curveId = curveIds[0].first;
957 if (
const QgsCircularString *circularString = qgsgeometry_cast<const QgsCircularString *>( curve ) )
962 if ( subVertexId.
vertex % 2 == 0 )
966 circularString->points(
points );
972 std::unique_ptr<QgsCircularString> curveA = std::make_unique<QgsCircularString>();
973 curveA->setPoints( partA );
974 std::unique_ptr<QgsLineString> curveB = std::make_unique<QgsLineString>();
975 curveB->setPoints( partB );
976 std::unique_ptr<QgsCircularString> curveC = std::make_unique<QgsCircularString>();
977 curveC->setPoints( partC );
981 mCurves.insert( curveId, curveC.release() );
982 mCurves.insert( curveId, curveB.release() );
983 if ( subVertexId.
vertex > 1 )
984 mCurves.insert( curveId, curveA.release() );
991 lineString->points(
points );
1006 mCurves.insert( curveId, curveC );
1007 mCurves.insert( curveId, curveB );
1008 if ( subVertexId.
vertex > 1 )
1009 mCurves.insert( curveId, curveA );
1027 int currentVertexId = 0;
1028 for (
int j = 0; j < mCurves.size(); ++j )
1030 int nCurvePoints = mCurves.at( j )->numPoints();
1031 if ( ( node - currentVertexId ) < nCurvePoints )
1033 return ( mCurves.at( j )->pointAt( node - currentVertexId, point, type ) );
1035 currentVertexId += ( nCurvePoints - 1 );
1042 int currentVertexId = 0;
1043 for (
int j = 0; j < mCurves.size(); ++j )
1045 int nCurvePoints = mCurves.at( j )->numPoints();
1046 if ( ( index - currentVertexId ) < nCurvePoints )
1048 return mCurves.at( j )->xAt( index - currentVertexId );
1050 currentVertexId += ( nCurvePoints - 1 );
1057 int currentVertexId = 0;
1058 for (
int j = 0; j < mCurves.size(); ++j )
1060 int nCurvePoints = mCurves.at( j )->numPoints();
1061 if ( ( index - currentVertexId ) < nCurvePoints )
1063 return mCurves.at( j )->yAt( index - currentVertexId );
1065 currentVertexId += ( nCurvePoints - 1 );
1073 for (
QgsCurve *curve : std::as_const( mCurves ) )
1075 if ( !curve->transform( transformer ) )
1093 for (
QgsCurve *curve : std::as_const( mCurves ) )
1095 curve->filterVertices( filter );
1102 for (
QgsCurve *curve : std::as_const( mCurves ) )
1111 if ( mCurves.empty() )
1112 return std::make_tuple( std::make_unique< QgsCompoundCurve >(), std::make_unique< QgsCompoundCurve >() );
1116 std::unique_ptr< QgsCompoundCurve > curve1 = std::make_unique< QgsCompoundCurve >();
1117 std::unique_ptr< QgsCompoundCurve > curve2;
1119 for (
const QgsCurve *curve : mCurves )
1121 const int curveSize = curve->numPoints();
1122 if ( !curve2 && index < curveStart + curveSize )
1125 auto [ p1, p2 ] = curve->splitCurveAtVertex( index - curveStart );
1126 if ( !p1->isEmpty() )
1127 curve1->addCurve( p1.release() );
1129 curve2 = std::make_unique< QgsCompoundCurve >();
1130 if ( !p2->isEmpty() )
1131 curve2->addCurve( p2.release() );
1136 curve2->addCurve( curve->clone() );
1138 curve1->addCurve( curve->clone() );
1143 curveStart += curve->numPoints() - 1;
1146 return std::make_tuple( std::move( curve1 ), curve2 ? std::move( curve2 ) : std::make_unique< QgsCompoundCurve >() );
1151 for (
const QgsCurve *curve : mCurves )
1153 curve->sumUpArea( sum );
1168 for (
const QgsCurve *curve : mCurves )
1170 if ( curve->hasCurvedSegments() )
1180 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( vertex );
1181 if ( curveIds.size() == 1 )
1183 QgsCurve *curve = mCurves[curveIds.at( 0 ).first];
1184 return curve->
vertexAngle( curveIds.at( 0 ).second );
1186 else if ( curveIds.size() > 1 )
1188 QgsCurve *curve1 = mCurves[curveIds.at( 0 ).first];
1189 QgsCurve *curve2 = mCurves[curveIds.at( 1 ).first];
1190 double angle1 = curve1->
vertexAngle( curveIds.at( 0 ).second );
1191 double angle2 = curve2->
vertexAngle( curveIds.at( 1 ).second );
1202 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( startVertex );
1204 for (
auto it = curveIds.constBegin(); it != curveIds.constEnd(); ++it )
1206 length += mCurves.at( it->first )->segmentLength( it->second );
1214 for (
int i = mCurves.count() - 1; i >= 0; --i )
1216 QgsCurve *reversedCurve = mCurves.at( i )->reversed();
1227 double distanceTraversed = 0;
1228 for (
const QgsCurve *curve : mCurves )
1230 const double thisCurveLength = curve->
length();
1231 if ( distanceTraversed + thisCurveLength > distance ||
qgsDoubleNear( distanceTraversed + thisCurveLength, distance ) )
1234 const double distanceToPoint = std::min( distance - distanceTraversed, thisCurveLength );
1237 return curve->interpolatePoint( distanceToPoint );
1240 distanceTraversed += thisCurveLength;
1248 if ( startDistance < 0 && endDistance < 0 )
1251 endDistance = std::max( startDistance, endDistance );
1252 std::unique_ptr< QgsCompoundCurve > substring = std::make_unique< QgsCompoundCurve >();
1254 double distanceTraversed = 0;
1255 for (
const QgsCurve *curve : mCurves )
1257 const double thisCurveLength = curve->length();
1258 if ( distanceTraversed + thisCurveLength < startDistance )
1264 std::unique_ptr< QgsCurve > part( curve->curveSubstring( startDistance - distanceTraversed, endDistance - distanceTraversed ) );
1266 substring->addCurve( part.release() );
1269 distanceTraversed += thisCurveLength;
1270 if ( distanceTraversed > endDistance )
1274 return substring.release();
1284 for (
QgsCurve *curve : std::as_const( mCurves ) )
1286 curve->addZValue( zValue );
1299 for (
QgsCurve *curve : std::as_const( mCurves ) )
1301 curve->addMValue( mValue );
1313 for (
QgsCurve *curve : std::as_const( mCurves ) )
1315 curve->dropZValue();
1327 for (
QgsCurve *curve : std::as_const( mCurves ) )
1329 curve->dropMValue();
1337 for (
QgsCurve *curve : std::as_const( mCurves ) )