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 QString secondWithoutParentheses =
parts.second;
183 secondWithoutParentheses = secondWithoutParentheses.remove(
'(' ).remove(
')' ).simplified().remove(
' ' );
184 if ( (
parts.second.compare( QLatin1String(
"EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
185 secondWithoutParentheses.isEmpty() )
188 QString defaultChildWkbType = QStringLiteral(
"LineString%1%2" ).arg(
is3D() ? QStringLiteral(
"Z" ) : QString(),
isMeasure() ? QStringLiteral(
"M" ) : QString() );
191 for (
const QString &childWkt : blocks )
204 if ( !mCurves.back()->fromWkt( childWkt ) )
215 for (
const QgsCurve *curve : qgis::as_const( mCurves ) )
217 hasZ = hasZ || curve->is3D();
218 hasM = hasM || curve->isMeasure();
232 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
233 for (
const QgsCurve *curve : mCurves )
235 binarySize += curve->wkbSize( flags );
246 wkb << static_cast<quint32>(
wkbType() );
247 wkb << static_cast<quint32>( mCurves.size() );
248 for (
const QgsCurve *curve : mCurves )
250 wkb << curve->asWkb( flags );
259 wkt += QLatin1String(
" EMPTY" );
262 wkt += QLatin1String(
" (" );
263 for (
const QgsCurve *curve : mCurves )
265 QString childWkt = curve->asWkt(
precision );
266 if ( qgsgeometry_cast<const QgsLineString *>( curve ) )
269 childWkt = childWkt.mid( childWkt.indexOf(
'(' ) );
271 wkt += childWkt +
',';
273 if ( wkt.endsWith(
',' ) )
285 std::unique_ptr< QgsLineString > line(
curveToLine() );
286 QDomElement gml = line->asGml2( doc,
precision, ns, axisOrder );
292 QDomElement compoundCurveElem = doc.createElementNS( ns, QStringLiteral(
"CompositeCurve" ) );
295 return compoundCurveElem;
297 for (
const QgsCurve *curve : mCurves )
299 QDomElement curveMemberElem = doc.createElementNS( ns, QStringLiteral(
"curveMember" ) );
300 QDomElement curveElem = curve->asGml3( doc,
precision, ns, axisOrder );
301 curveMemberElem.appendChild( curveElem );
302 compoundCurveElem.appendChild( curveMemberElem );
305 return compoundCurveElem;
311 std::unique_ptr< QgsLineString > line(
curveToLine() );
318 for (
const QgsCurve *curve : mCurves )
320 length += curve->length();
327 if ( mCurves.empty() )
331 return mCurves.at( 0 )->startPoint();
336 if ( mCurves.empty() )
340 return mCurves.at( mCurves.size() - 1 )->endPoint();
346 if ( mCurves.empty() )
351 mCurves[0]->points( pts );
352 for (
int i = 1; i < mCurves.size(); ++i )
355 mCurves[i]->points( pList );
370 for (
int i = 0; i <
nCurves; ++i )
372 nPoints += mCurves.at( i )->numPoints() - 1;
380 if ( mCurves.isEmpty() )
385 if ( !curve->isEmpty() )
394 std::unique_ptr< QgsLineString > currentLine;
395 for (
const QgsCurve *curve : mCurves )
397 currentLine.reset( curve->curveToLine( tolerance, toleranceType ) );
398 line->
append( currentLine.get() );
409 std::unique_ptr<QgsCurve> gridified(
static_cast< QgsCurve *
>( curve->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing ) ) );
412 result->mCurves.append( gridified.release() );
416 if ( result->mCurves.empty() )
419 return result.release();
425 const QVector< QgsCurve * > curves = mCurves;
431 if ( curve->numPoints() == 0 ||
qgsDoubleNear( curve->length(), 0.0, epsilon ) )
434 delete mCurves.takeAt( i );
442 curve->moveVertex(
QgsVertexId( -1, -1, 0 ), lastEnd );
453 if ( i < 0 || i >= mCurves.size() )
457 return mCurves.at( i );
464 if ( mCurves.empty() )
493 if ( i < 0 || i >= mCurves.size() )
498 delete mCurves.takeAt( i );
511 if ( !mCurves.isEmpty() )
513 lastCurve = mCurves.at( mCurves.size() - 1 );
520 mCurves.append( line );
537 for (
const QgsCurve *curve : mCurves )
545 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
547 curve->transform( ct, d, transformZ );
554 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
556 curve->transform( t, zTranslate, zScale, mTranslate, mScale );
564 for (
const QgsCurve *curve : mCurves )
566 curve->addToPainterPath( pp );
574 for (
const QgsCurve *curve : mCurves )
576 curve->addToPainterPath( pp );
583 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
584 if ( curveIds.empty() )
588 int curveId = curveIds.at( 0 ).first;
589 if ( curveId >= mCurves.size() )
594 bool success = mCurves.at( curveId )->insertVertex( curveIds.at( 0 ).second, vertex );
604 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
605 QVector< QPair<int, QgsVertexId> >::const_iterator idIt = curveIds.constBegin();
606 for ( ; idIt != curveIds.constEnd(); ++idIt )
608 mCurves.at( idIt->first )->moveVertex( idIt->second, newPos );
611 bool success = !curveIds.isEmpty();
621 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
622 if ( curveIds.size() == 1 )
624 if ( !mCurves.at( curveIds.at( 0 ).first )->deleteVertex( curveIds.at( 0 ).second ) )
629 if ( mCurves.at( curveIds.at( 0 ).first )->numPoints() == 0 )
634 else if ( curveIds.size() == 2 )
636 Q_ASSERT( curveIds.at( 1 ).first == curveIds.at( 0 ).first + 1 );
637 Q_ASSERT( curveIds.at( 0 ).second.vertex == mCurves.at( curveIds.at( 0 ).first )->numPoints() - 1 );
638 Q_ASSERT( curveIds.at( 1 ).second.vertex == 0 );
643 mCurves.at( curveIds.at( 1 ).first )->numPoints() > 3 )
647 mCurves.at( curveIds.at( 1 ).first ) ->pointAt( 2, intermediatePoint, type );
648 mCurves.at( curveIds.at( 0 ).first )->moveVertex(
649 QgsVertexId( 0, 0, mCurves.at( curveIds.at( 0 ).first )->numPoints() - 1 ), intermediatePoint );
651 else if ( !mCurves.at( curveIds.at( 0 ).first )->deleteVertex( curveIds.at( 0 ).second ) )
657 mCurves.at( curveIds.at( 0 ).first )->numPoints() > 0 &&
660 QgsPoint intermediatePoint = mCurves.at( curveIds.at( 0 ).first ) ->endPoint();
661 mCurves.at( curveIds.at( 1 ).first )->moveVertex(
QgsVertexId( 0, 0, 0 ), intermediatePoint );
663 else if ( !mCurves.at( curveIds.at( 1 ).first )->deleteVertex( curveIds.at( 1 ).second ) )
668 if ( mCurves.at( curveIds.at( 0 ).first )->numPoints() == 0 &&
669 mCurves.at( curveIds.at( 1 ).first )->numPoints() != 0 )
674 else if ( mCurves.at( curveIds.at( 0 ).first )->numPoints() != 0 &&
675 mCurves.at( curveIds.at( 1 ).first )->numPoints() == 0 )
677 mCurves.at( curveIds.at( 0 ).first )->moveVertex(
681 else if ( mCurves.at( curveIds.at( 0 ).first )->numPoints() == 0 &&
682 mCurves.at( curveIds.at( 1 ).first )->numPoints() == 0 )
689 mCurves.insert( curveIds.at( 0 ).first, line );
693 QgsPoint endPointOfFirst = mCurves.at( curveIds.at( 0 ).first ) ->endPoint();
694 QgsPoint startPointOfSecond = mCurves.at( curveIds.at( 1 ).first ) ->startPoint();
695 if ( endPointOfFirst != startPointOfSecond )
700 mCurves.insert( curveIds.at( 1 ).first, line );
705 bool success = !curveIds.isEmpty();
713 QVector< QPair<int, QgsVertexId> > QgsCompoundCurve::curveVertexId(
QgsVertexId id )
const
715 QVector< QPair<int, QgsVertexId> > curveIds;
717 int currentVertexIndex = 0;
718 for (
int i = 0; i < mCurves.size(); ++i )
720 int increment = mCurves.at( i )->numPoints() - 1;
721 if (
id.vertex >= currentVertexIndex &&
id.vertex <= currentVertexIndex + increment )
723 int curveVertexId =
id.vertex - currentVertexIndex;
727 vid.
vertex = curveVertexId;
728 curveIds.append( qMakePair( i, vid ) );
729 if ( curveVertexId == increment && i < ( mCurves.size() - 1 ) )
732 curveIds.append( qMakePair( i + 1, vid ) );
736 else if (
id.vertex >= currentVertexIndex &&
id.vertex == currentVertexIndex + increment + 1 && i == ( mCurves.size() - 1 ) )
738 int curveVertexId =
id.vertex - currentVertexIndex;
742 vid.
vertex = curveVertexId;
743 curveIds.append( qMakePair( i, vid ) );
746 currentVertexIndex += increment;
759 int currentVertexId = 0;
760 for (
int j = 0; j < mCurves.size(); ++j )
762 int nCurvePoints = mCurves.at( j )->numPoints();
763 if ( ( node - currentVertexId ) < nCurvePoints )
765 return ( mCurves.at( j )->pointAt( node - currentVertexId, point, type ) );
767 currentVertexId += ( nCurvePoints - 1 );
774 int currentVertexId = 0;
775 for (
int j = 0; j < mCurves.size(); ++j )
777 int nCurvePoints = mCurves.at( j )->numPoints();
778 if ( ( index - currentVertexId ) < nCurvePoints )
780 return mCurves.at( j )->xAt( index - currentVertexId );
782 currentVertexId += ( nCurvePoints - 1 );
789 int currentVertexId = 0;
790 for (
int j = 0; j < mCurves.size(); ++j )
792 int nCurvePoints = mCurves.at( j )->numPoints();
793 if ( ( index - currentVertexId ) < nCurvePoints )
795 return mCurves.at( j )->yAt( index - currentVertexId );
797 currentVertexId += ( nCurvePoints - 1 );
804 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
806 curve->filterVertices( filter );
813 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
822 for (
const QgsCurve *curve : mCurves )
824 curve->sumUpArea( sum );
839 for (
const QgsCurve *curve : mCurves )
841 if ( curve->hasCurvedSegments() )
851 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( vertex );
852 if ( curveIds.size() == 1 )
854 QgsCurve *curve = mCurves[curveIds.at( 0 ).first];
855 return curve->
vertexAngle( curveIds.at( 0 ).second );
857 else if ( curveIds.size() > 1 )
859 QgsCurve *curve1 = mCurves[curveIds.at( 0 ).first];
860 QgsCurve *curve2 = mCurves[curveIds.at( 1 ).first];
861 double angle1 = curve1->
vertexAngle( curveIds.at( 0 ).second );
862 double angle2 = curve2->
vertexAngle( curveIds.at( 1 ).second );
873 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( startVertex );
875 for (
auto it = curveIds.constBegin(); it != curveIds.constEnd(); ++it )
877 length += mCurves.at( it->first )->segmentLength( it->second );
885 for (
int i = mCurves.count() - 1; i >= 0; --i )
887 QgsCurve *reversedCurve = mCurves.at( i )->reversed();
898 double distanceTraversed = 0;
899 for (
const QgsCurve *curve : mCurves )
901 const double thisCurveLength = curve->
length();
902 if ( distanceTraversed + thisCurveLength > distance ||
qgsDoubleNear( distanceTraversed + thisCurveLength, distance ) )
905 const double distanceToPoint = std::min( distance - distanceTraversed, thisCurveLength );
908 return curve->interpolatePoint( distanceToPoint );
911 distanceTraversed += thisCurveLength;
919 if ( startDistance < 0 && endDistance < 0 )
922 endDistance = std::max( startDistance, endDistance );
923 std::unique_ptr< QgsCompoundCurve > substring = qgis::make_unique< QgsCompoundCurve >();
925 double distanceTraversed = 0;
926 for (
const QgsCurve *curve : mCurves )
928 const double thisCurveLength = curve->length();
929 if ( distanceTraversed + thisCurveLength < startDistance )
935 std::unique_ptr< QgsCurve > part( curve->curveSubstring( startDistance - distanceTraversed, endDistance - distanceTraversed ) );
937 substring->addCurve( part.release() );
940 distanceTraversed += thisCurveLength;
941 if ( distanceTraversed > endDistance )
945 return substring.release();
955 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
957 curve->addZValue( zValue );
970 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
972 curve->addMValue( mValue );
984 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
998 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
1000 curve->dropMValue();
1008 for (
QgsCurve *curve : qgis::as_const( mCurves ) )