25 #include <QJsonObject>
27 #include <QPainterPath>
29 #include <nlohmann/json.hpp>
43 const QgsCompoundCurve *otherCurve = qgsgeometry_cast< const QgsCompoundCurve * >( &other );
50 if ( mCurves.size() != otherCurve->mCurves.size() )
53 for (
int i = 0; i < mCurves.size(); ++i )
55 if ( *mCurves.at( i ) != *otherCurve->mCurves.at( i ) )
64 auto result = qgis::make_unique< QgsCompoundCurve >();
66 return result.release();
71 return QStringLiteral(
"CompoundCurve" );
82 mCurves.reserve( curve.mCurves.size() );
85 mCurves.append(
c->clone() );
97 mCurves.append(
c->clone() );
111 qDeleteAll( mCurves );
118 if ( mCurves.empty() )
124 for (
int i = 1; i < mCurves.size(); ++i )
150 for (
int i = 0; i <
nCurves; ++i )
153 wkbPtr -= 1 +
sizeof( int );
166 currentCurve->
fromWkb( wkbPtr );
167 mCurves.append( currentCurve );
182 if (
parts.second.compare( QLatin1String(
"EMPTY" ), Qt::CaseInsensitive ) == 0 )
185 QString defaultChildWkbType = QStringLiteral(
"LineString%1%2" ).arg(
is3D() ? QStringLiteral(
"Z" ) : QString(),
isMeasure() ? QStringLiteral(
"M" ) : QString() );
188 for (
const QString &childWkt : blocks )
201 if ( !mCurves.back()->fromWkt( childWkt ) )
212 for (
const QgsCurve *curve : qgis::as_const( mCurves ) )
214 hasZ = hasZ || curve->is3D();
215 hasM = hasM || curve->isMeasure();
229 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
230 QVector<QByteArray> wkbForCurves;
231 wkbForCurves.reserve( mCurves.size() );
232 for (
const QgsCurve *curve : mCurves )
234 QByteArray wkbForCurve = curve->asWkb( flags );
235 binarySize += wkbForCurve.length();
236 wkbForCurves << wkbForCurve;
240 wkbArray.resize( binarySize );
243 wkb << static_cast<quint32>(
wkbType() );
244 wkb << static_cast<quint32>( mCurves.size() );
245 for (
const QByteArray &wkbForCurve : qgis::as_const( wkbForCurves ) )
256 wkt += QStringLiteral(
" EMPTY" );
259 wkt += QLatin1String(
" (" );
260 for (
const QgsCurve *curve : mCurves )
262 QString childWkt = curve->asWkt(
precision );
263 if ( qgsgeometry_cast<const QgsLineString *>( curve ) )
266 childWkt = childWkt.mid( childWkt.indexOf(
'(' ) );
268 wkt += childWkt +
',';
270 if ( wkt.endsWith(
',' ) )
282 std::unique_ptr< QgsLineString > line(
curveToLine() );
283 QDomElement gml = line->asGml2( doc,
precision, ns, axisOrder );
289 QDomElement compoundCurveElem = doc.createElementNS( ns, QStringLiteral(
"CompositeCurve" ) );
292 return compoundCurveElem;
294 for (
const QgsCurve *curve : mCurves )
296 QDomElement curveMemberElem = doc.createElementNS( ns, QStringLiteral(
"curveMember" ) );
297 QDomElement curveElem = curve->asGml3( doc,
precision, ns, axisOrder );
298 curveMemberElem.appendChild( curveElem );
299 compoundCurveElem.appendChild( curveMemberElem );
302 return compoundCurveElem;
308 std::unique_ptr< QgsLineString > line(
curveToLine() );
315 for (
const QgsCurve *curve : mCurves )
317 length += curve->length();
324 if ( mCurves.empty() )
328 return mCurves.at( 0 )->startPoint();
333 if ( mCurves.empty() )
337 return mCurves.at( mCurves.size() - 1 )->endPoint();
343 if ( mCurves.empty() )
348 mCurves[0]->points( pts );
349 for (
int i = 1; i < mCurves.size(); ++i )
352 mCurves[i]->points( pList );
367 for (
int i = 0; i <
nCurves; ++i )
369 nPoints += mCurves.at( i )->numPoints() - 1;
377 if ( mCurves.isEmpty() )
382 if ( !curve->isEmpty() )
391 std::unique_ptr< QgsLineString > currentLine;
392 for (
const QgsCurve *curve : mCurves )
394 currentLine.reset( curve->curveToLine( tolerance, toleranceType ) );
395 line->
append( currentLine.get() );
406 std::unique_ptr<QgsCurve> gridified(
static_cast< QgsCurve *
>( curve->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing ) ) );
409 result->mCurves.append( gridified.release() );
413 if ( result->mCurves.empty() )
416 return result.release();
422 const QVector< QgsCurve * > curves = mCurves;
428 if ( curve->numPoints() == 0 ||
qgsDoubleNear( curve->length(), 0.0, epsilon ) )
431 delete mCurves.takeAt( i );
439 curve->moveVertex(
QgsVertexId( -1, -1, 0 ), lastEnd );
450 if ( i < 0 || i >= mCurves.size() )
454 return mCurves.at( i );
461 if ( mCurves.empty() )
490 if ( i < 0 || i >= mCurves.size() )
495 delete mCurves.takeAt( i );
508 if ( !mCurves.isEmpty() )
510 lastCurve = mCurves.at( mCurves.size() - 1 );
517 mCurves.append( line );
534 for (
const QgsCurve *curve : mCurves )
542 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
544 curve->transform( ct, d, transformZ );
551 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
553 curve->transform( t, zTranslate, zScale, mTranslate, mScale );
561 for (
const QgsCurve *curve : mCurves )
563 curve->addToPainterPath( pp );
571 for (
const QgsCurve *curve : mCurves )
573 curve->addToPainterPath( pp );
580 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
581 if ( curveIds.empty() )
585 int curveId = curveIds.at( 0 ).first;
586 if ( curveId >= mCurves.size() )
591 bool success = mCurves.at( curveId )->insertVertex( curveIds.at( 0 ).second, vertex );
601 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
602 QVector< QPair<int, QgsVertexId> >::const_iterator idIt = curveIds.constBegin();
603 for ( ; idIt != curveIds.constEnd(); ++idIt )
605 mCurves.at( idIt->first )->moveVertex( idIt->second, newPos );
608 bool success = !curveIds.isEmpty();
618 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
619 if ( curveIds.size() == 1 )
621 if ( !mCurves.at( curveIds.at( 0 ).first )->deleteVertex( curveIds.at( 0 ).second ) )
626 if ( mCurves.at( curveIds.at( 0 ).first )->numPoints() == 0 )
631 else if ( curveIds.size() == 2 )
633 Q_ASSERT( curveIds.at( 1 ).first == curveIds.at( 0 ).first + 1 );
634 Q_ASSERT( curveIds.at( 0 ).second.vertex == mCurves.at( curveIds.at( 0 ).first )->numPoints() - 1 );
635 Q_ASSERT( curveIds.at( 1 ).second.vertex == 0 );
640 mCurves.at( curveIds.at( 1 ).first )->numPoints() > 3 )
644 mCurves.at( curveIds.at( 1 ).first ) ->pointAt( 2, intermediatePoint, type );
645 mCurves.at( curveIds.at( 0 ).first )->moveVertex(
646 QgsVertexId( 0, 0, mCurves.at( curveIds.at( 0 ).first )->numPoints() - 1 ), intermediatePoint );
648 else if ( !mCurves.at( curveIds.at( 0 ).first )->deleteVertex( curveIds.at( 0 ).second ) )
654 mCurves.at( curveIds.at( 0 ).first )->numPoints() > 0 &&
657 QgsPoint intermediatePoint = mCurves.at( curveIds.at( 0 ).first ) ->endPoint();
658 mCurves.at( curveIds.at( 1 ).first )->moveVertex(
QgsVertexId( 0, 0, 0 ), intermediatePoint );
660 else if ( !mCurves.at( curveIds.at( 1 ).first )->deleteVertex( curveIds.at( 1 ).second ) )
665 if ( mCurves.at( curveIds.at( 0 ).first )->numPoints() == 0 &&
666 mCurves.at( curveIds.at( 1 ).first )->numPoints() != 0 )
671 else if ( mCurves.at( curveIds.at( 0 ).first )->numPoints() != 0 &&
672 mCurves.at( curveIds.at( 1 ).first )->numPoints() == 0 )
674 mCurves.at( curveIds.at( 0 ).first )->moveVertex(
678 else if ( mCurves.at( curveIds.at( 0 ).first )->numPoints() == 0 &&
679 mCurves.at( curveIds.at( 1 ).first )->numPoints() == 0 )
686 mCurves.insert( curveIds.at( 0 ).first, line );
690 QgsPoint endPointOfFirst = mCurves.at( curveIds.at( 0 ).first ) ->endPoint();
691 QgsPoint startPointOfSecond = mCurves.at( curveIds.at( 1 ).first ) ->startPoint();
692 if ( endPointOfFirst != startPointOfSecond )
697 mCurves.insert( curveIds.at( 1 ).first, line );
702 bool success = !curveIds.isEmpty();
710 QVector< QPair<int, QgsVertexId> > QgsCompoundCurve::curveVertexId(
QgsVertexId id )
const
712 QVector< QPair<int, QgsVertexId> > curveIds;
714 int currentVertexIndex = 0;
715 for (
int i = 0; i < mCurves.size(); ++i )
717 int increment = mCurves.at( i )->numPoints() - 1;
718 if (
id.vertex >= currentVertexIndex &&
id.vertex <= currentVertexIndex + increment )
720 int curveVertexId =
id.vertex - currentVertexIndex;
724 vid.
vertex = curveVertexId;
725 curveIds.append( qMakePair( i, vid ) );
726 if ( curveVertexId == increment && i < ( mCurves.size() - 1 ) )
729 curveIds.append( qMakePair( i + 1, vid ) );
733 else if (
id.vertex >= currentVertexIndex &&
id.vertex == currentVertexIndex + increment + 1 && i == ( mCurves.size() - 1 ) )
735 int curveVertexId =
id.vertex - currentVertexIndex;
739 vid.
vertex = curveVertexId;
740 curveIds.append( qMakePair( i, vid ) );
743 currentVertexIndex += increment;
756 int currentVertexId = 0;
757 for (
int j = 0; j < mCurves.size(); ++j )
759 int nCurvePoints = mCurves.at( j )->numPoints();
760 if ( ( node - currentVertexId ) < nCurvePoints )
762 return ( mCurves.at( j )->pointAt( node - currentVertexId, point, type ) );
764 currentVertexId += ( nCurvePoints - 1 );
771 int currentVertexId = 0;
772 for (
int j = 0; j < mCurves.size(); ++j )
774 int nCurvePoints = mCurves.at( j )->numPoints();
775 if ( ( index - currentVertexId ) < nCurvePoints )
777 return mCurves.at( j )->xAt( index - currentVertexId );
779 currentVertexId += ( nCurvePoints - 1 );
786 int currentVertexId = 0;
787 for (
int j = 0; j < mCurves.size(); ++j )
789 int nCurvePoints = mCurves.at( j )->numPoints();
790 if ( ( index - currentVertexId ) < nCurvePoints )
792 return mCurves.at( j )->yAt( index - currentVertexId );
794 currentVertexId += ( nCurvePoints - 1 );
801 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
803 curve->filterVertices( filter );
810 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
819 for (
const QgsCurve *curve : mCurves )
821 curve->sumUpArea( sum );
836 for (
const QgsCurve *curve : mCurves )
838 if ( curve->hasCurvedSegments() )
848 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( vertex );
849 if ( curveIds.size() == 1 )
851 QgsCurve *curve = mCurves[curveIds.at( 0 ).first];
852 return curve->
vertexAngle( curveIds.at( 0 ).second );
854 else if ( curveIds.size() > 1 )
856 QgsCurve *curve1 = mCurves[curveIds.at( 0 ).first];
857 QgsCurve *curve2 = mCurves[curveIds.at( 1 ).first];
858 double angle1 = curve1->
vertexAngle( curveIds.at( 0 ).second );
859 double angle2 = curve2->
vertexAngle( curveIds.at( 1 ).second );
870 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( startVertex );
872 for (
auto it = curveIds.constBegin(); it != curveIds.constEnd(); ++it )
874 length += mCurves.at( it->first )->segmentLength( it->second );
882 for (
int i = mCurves.count() - 1; i >= 0; --i )
884 QgsCurve *reversedCurve = mCurves.at( i )->reversed();
895 double distanceTraversed = 0;
896 for (
const QgsCurve *curve : mCurves )
898 const double thisCurveLength = curve->
length();
899 if ( distanceTraversed + thisCurveLength > distance ||
qgsDoubleNear( distanceTraversed + thisCurveLength, distance ) )
902 const double distanceToPoint = std::min( distance - distanceTraversed, thisCurveLength );
905 return curve->interpolatePoint( distanceToPoint );
908 distanceTraversed += thisCurveLength;
916 if ( startDistance < 0 && endDistance < 0 )
919 endDistance = std::max( startDistance, endDistance );
920 std::unique_ptr< QgsCompoundCurve > substring = qgis::make_unique< QgsCompoundCurve >();
922 double distanceTraversed = 0;
923 for (
const QgsCurve *curve : mCurves )
925 const double thisCurveLength = curve->length();
926 if ( distanceTraversed + thisCurveLength < startDistance )
932 std::unique_ptr< QgsCurve > part( curve->curveSubstring( startDistance - distanceTraversed, endDistance - distanceTraversed ) );
934 substring->addCurve( part.release() );
937 distanceTraversed += thisCurveLength;
938 if ( distanceTraversed > endDistance )
942 return substring.release();
952 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
954 curve->addZValue( zValue );
967 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
969 curve->addMValue( mValue );
981 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
995 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
1005 for (
QgsCurve *curve : qgis::as_const( mCurves ) )