30 #include <QJsonObject>
32 #include <QPainterPath>
34 #include <nlohmann/json.hpp>
44 bool hasZ = p1.
is3D();
77 int pointCount = std::min( x.size(), y.size() );
78 if ( x.size() == pointCount )
84 mX = x.mid( 0, pointCount );
86 if ( y.size() == pointCount )
92 mY = y.mid( 0, pointCount );
94 if ( !z.isEmpty() && z.count() >= pointCount )
97 if ( z.size() == pointCount )
103 mZ = z.mid( 0, pointCount );
106 if ( !m.isEmpty() && m.count() >= pointCount )
109 if ( m.size() == pointCount )
115 mM = m.mid( 0, pointCount );
135 if ( mX.count() != otherLine->mX.count() )
138 for (
int i = 0; i < mX.count(); ++i )
156 auto result = std::make_unique< QgsCircularString >();
158 return result.release();
163 const QgsCircularString *otherLine = qgsgeometry_cast<const QgsCircularString *>( other );
167 const int size = mX.size();
168 const int otherSize = otherLine->mX.size();
169 if ( size > otherSize )
173 else if ( size < otherSize )
180 else if ( !
is3D() && otherLine->
is3D() )
182 const bool considerZ =
is3D();
190 for (
int i = 0; i < size; i++ )
192 const double x = mX[i];
193 const double otherX = otherLine->mX[i];
198 else if ( x > otherX )
203 const double y = mY[i];
204 const double otherY = otherLine->mY[i];
209 else if ( y > otherY )
216 const double z = mZ[i];
217 const double otherZ = otherLine->mZ[i];
223 else if ( z > otherZ )
231 const double m = mM[i];
232 const double otherM = otherLine->mM[i];
238 else if ( m > otherM )
249 return QStringLiteral(
"CircularString" );
276 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
280 bbox = segmentBoundingBox(
QgsPoint( mX[i], mY[i] ),
QgsPoint( mX[i + 1], mY[i + 1] ),
QgsPoint( mX[i + 2], mY[i + 2] ) );
289 if ( nPoints > 0 && nPoints % 2 == 0 )
302 const int size = mX.size();
303 if ( index < 1 || index >= size - 1 )
306 const bool useZ =
is3D();
309 QVector<double> newX( size );
310 QVector<double> newY( size );
311 QVector<double> newZ( useZ ? size : 0 );
312 QVector<double> newM( useM ? size : 0 );
313 auto it = std::copy( mX.constBegin() + index, mX.constEnd() - 1, newX.begin() );
314 it = std::copy( mX.constBegin(), mX.constBegin() + index, it );
315 *it = *newX.constBegin();
316 mX = std::move( newX );
318 it = std::copy( mY.constBegin() + index, mY.constEnd() - 1, newY.begin() );
319 it = std::copy( mY.constBegin(), mY.constBegin() + index, it );
320 *it = *newY.constBegin();
321 mY = std::move( newY );
324 it = std::copy( mZ.constBegin() + index, mZ.constEnd() - 1, newZ.begin() );
325 it = std::copy( mZ.constBegin(), mZ.constBegin() + index, it );
326 *it = *newZ.constBegin();
327 mZ = std::move( newZ );
331 it = std::copy( mM.constBegin() + index, mM.constEnd() - 1, newM.begin() );
332 it = std::copy( mM.constBegin(), mM.constBegin() + index, it );
333 *it = *newM.constBegin();
334 mM = std::move( newM );
340 double centerX, centerY, radius;
349 bbox.combineExtentWith( pt3.
x(), pt3.
y() );
351 QgsPointSequence compassPoints = compassPointsOnSegment( p1Angle, p2Angle, p3Angle, centerX, centerY, radius );
352 QgsPointSequence::const_iterator cpIt = compassPoints.constBegin();
353 for ( ; cpIt != compassPoints.constEnd(); ++cpIt )
355 bbox.combineExtentWith( cpIt->x(), cpIt->y() );
360 QgsPointSequence QgsCircularString::compassPointsOnSegment(
double p1Angle,
double p2Angle,
double p3Angle,
double centerX,
double centerY,
double radius )
364 QgsPoint nPoint( centerX, centerY + radius );
365 QgsPoint ePoint( centerX + radius, centerY );
366 QgsPoint sPoint( centerX, centerY - radius );
367 QgsPoint wPoint( centerX - radius, centerY );
369 if ( p3Angle >= p1Angle )
371 if ( p2Angle > p1Angle && p2Angle < p3Angle )
373 if ( p1Angle <= 90 && p3Angle >= 90 )
375 pointList.append( nPoint );
377 if ( p1Angle <= 180 && p3Angle >= 180 )
379 pointList.append( wPoint );
381 if ( p1Angle <= 270 && p3Angle >= 270 )
383 pointList.append( sPoint );
388 pointList.append( ePoint );
389 if ( p1Angle >= 90 || p3Angle <= 90 )
391 pointList.append( nPoint );
393 if ( p1Angle >= 180 || p3Angle <= 180 )
395 pointList.append( wPoint );
397 if ( p1Angle >= 270 || p3Angle <= 270 )
399 pointList.append( sPoint );
405 if ( p2Angle < p1Angle && p2Angle > p3Angle )
407 if ( p1Angle >= 270 && p3Angle <= 270 )
409 pointList.append( sPoint );
411 if ( p1Angle >= 180 && p3Angle <= 180 )
413 pointList.append( wPoint );
415 if ( p1Angle >= 90 && p3Angle <= 90 )
417 pointList.append( nPoint );
422 pointList.append( ePoint );
423 if ( p1Angle <= 270 || p3Angle >= 270 )
425 pointList.append( sPoint );
427 if ( p1Angle <= 180 || p3Angle >= 180 )
429 pointList.append( wPoint );
431 if ( p1Angle <= 90 || p3Angle >= 90 )
433 pointList.append( nPoint );
458 mX.resize( nVertices );
459 mY.resize( nVertices );
460 hasZ ? mZ.resize( nVertices ) : mZ.clear();
461 hasM ? mM.resize( nVertices ) : mM.clear();
462 for (
int i = 0; i < nVertices; ++i )
489 parts.second =
parts.second.remove(
'(' ).remove(
')' );
490 QString secondWithoutParentheses =
parts.second;
491 secondWithoutParentheses = secondWithoutParentheses.simplified().remove(
' ' );
492 if ( (
parts.second.compare( QLatin1String(
"EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
493 secondWithoutParentheses.isEmpty() )
506 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
517 wkb << static_cast<quint32>(
wkbType() );
529 wkt += QLatin1String(
"EMPTY" );
542 std::unique_ptr< QgsLineString > line(
curveToLine() );
543 QDomElement gml = line->asGml2( doc,
precision, ns, axisOrder );
552 QDomElement elemCurve = doc.createElementNS( ns, QStringLiteral(
"Curve" ) );
557 QDomElement elemSegments = doc.createElementNS( ns, QStringLiteral(
"segments" ) );
558 QDomElement elemArcString = doc.createElementNS( ns, QStringLiteral(
"ArcString" ) );
560 elemSegments.appendChild( elemArcString );
561 elemCurve.appendChild( elemSegments );
569 std::unique_ptr< QgsLineString > line(
curveToLine() );
582 error = QObject::tr(
"CircularString has less than 3 points and is not empty." );
593 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
624 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
638 bool res =
snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM,
639 result->mX, result->mY, result->mZ, result->mM );
641 return result.release();
648 if ( mX.count() <= 3 )
651 double prevX = mX.at( 0 );
652 double prevY = mY.at( 0 );
654 bool useZ = hasZ && useZValues;
655 double prevZ = useZ ? mZ.at( 0 ) : 0;
657 int remaining = mX.count();
660 while ( i + 1 < remaining )
662 double currentCurveX = mX.at( i );
663 double currentCurveY = mY.at( i );
664 double currentX = mX.at( i + 1 );
665 double currentY = mY.at( i + 1 );
666 double currentZ = useZ ? mZ.at( i + 1 ) : 0;
699 return std::min( mX.size(), mY.size() );
704 const int size = mX.size();
708 const double *x = mX.constData();
709 const double *y = mY.constData();
710 const bool useZ =
is3D();
712 const double *z = useZ ? mZ.constData() :
nullptr;
713 const double *m = useM ? mM.constData() :
nullptr;
715 for (
int i = 0; i < size; i += 2 )
744 if ( i < 0 || std::min( mX.size(), mY.size() ) <= i )
749 double x = mX.at( i );
750 double y = mY.at( i );
781 if ( index >= 0 && index < mX.size() )
782 return mX.at( index );
789 if ( index >= 0 && index < mY.size() )
790 return mY.at( index );
802 int size = mX.size();
804 double *srcX = mX.data();
805 double *srcY = mY.data();
806 double *srcM = hasM ? mM.data() :
nullptr;
807 double *srcZ = hasZ ? mZ.data() :
nullptr;
810 for (
int i = 0; i < size; ++i )
814 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
815 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
843 int size = mX.size();
845 double *srcX = mX.data();
846 double *srcY = mY.data();
847 double *srcM = hasM ? mM.data() :
nullptr;
848 double *srcZ = hasZ ? mZ.data() :
nullptr;
850 double *destX = srcX;
851 double *destY = srcY;
852 double *destM = srcM;
853 double *destZ = srcZ;
855 int filteredPoints = 0;
856 for (
int i = 0; i < size; ++i )
860 double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
861 double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
863 if ( filter(
QgsPoint( x, y, z, m ) ) )
875 mX.resize( filteredPoints );
876 mY.resize( filteredPoints );
878 mZ.resize( filteredPoints );
880 mM.resize( filteredPoints );
889 int size = mX.size();
891 double *srcX = mX.data();
892 double *srcY = mY.data();
893 double *srcM = hasM ? mM.data() :
nullptr;
894 double *srcZ = hasZ ? mZ.data() :
nullptr;
896 for (
int i = 0; i < size; ++i )
900 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
901 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
915 const bool useZ =
is3D();
918 const int size = mX.size();
920 return std::make_tuple( std::make_unique< QgsCircularString >(), std::make_unique< QgsCircularString >() );
922 index = std::clamp( index, 0, size - 1 );
924 const int part1Size = index + 1;
925 QVector< double > x1( part1Size );
926 QVector< double > y1( part1Size );
927 QVector< double > z1( useZ ? part1Size : 0 );
928 QVector< double > m1( useM ? part1Size : 0 );
930 const double *sourceX = mX.constData();
931 const double *sourceY = mY.constData();
932 const double *sourceZ = useZ ? mZ.constData() :
nullptr;
933 const double *sourceM = useM ? mM.constData() :
nullptr;
935 double *destX = x1.data();
936 double *destY = y1.data();
937 double *destZ = useZ ? z1.data() :
nullptr;
938 double *destM = useM ? m1.data() :
nullptr;
940 std::copy( sourceX, sourceX + part1Size, destX );
941 std::copy( sourceY, sourceY + part1Size, destY );
943 std::copy( sourceZ, sourceZ + part1Size, destZ );
945 std::copy( sourceM, sourceM + part1Size, destM );
947 const int part2Size = size - index;
949 return std::make_tuple( std::make_unique< QgsCircularString >( x1, y1, z1, m1 ), std::make_unique< QgsCircularString >() );
951 QVector< double > x2( part2Size );
952 QVector< double > y2( part2Size );
953 QVector< double > z2( useZ ? part2Size : 0 );
954 QVector< double > m2( useM ? part2Size : 0 );
957 destZ = useZ ? z2.data() :
nullptr;
958 destM = useM ? m2.data() :
nullptr;
959 std::copy( sourceX + index, sourceX + size, destX );
960 std::copy( sourceY + index, sourceY + size, destY );
962 std::copy( sourceZ + index, sourceZ + size, destZ );
964 std::copy( sourceM + index, sourceM + size, destM );
967 return std::make_tuple( std::make_unique< QgsCircularString >(), std::make_unique< QgsCircularString >( x2, y2, z2, m2 ) );
969 return std::make_tuple( std::make_unique< QgsCircularString >( x1, y1, z1, m1 ), std::make_unique< QgsCircularString >( x2, y2, z2, m2 ) );
976 for (
int i = 0; i < nPts; ++i )
978 pts.push_back(
pointN( i ) );
998 bool hasZ = firstPt.
is3D();
1003 mX.resize(
points.size() );
1004 mY.resize(
points.size() );
1007 mZ.resize(
points.size() );
1015 mM.resize(
points.size() );
1022 for (
int i = 0; i <
points.size(); ++i )
1028 double z =
points.at( i ).z();
1029 mZ[i] = std::isnan( z ) ? 0 : z;
1033 double m =
points.at( i ).m();
1034 mM[i] = std::isnan( m ) ? 0 : m;
1041 if ( !line || line->
isEmpty() )
1084 mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
1097 mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
1115 double *zArray = mZ.data();
1119 bool useDummyZ = !hasZ || !transformZ;
1122 zArray =
new double[nPoints];
1123 for (
int i = 0; i < nPoints; ++i )
1142 for (
int i = 0; i < nPoints; ++i )
1145 t.map( mX.at( i ), mY.at( i ), &x, &y );
1150 mZ[i] = mZ.at( i ) * zScale + zTranslate;
1154 mM[i] = mM.at( i ) * mScale + mTranslate;
1159 void arcTo( QPainterPath &path, QPointF pt1, QPointF pt2, QPointF pt3 )
1161 double centerX, centerY, radius;
1163 radius, centerX, centerY );
1168 double diameter = 2 * radius;
1169 path.arcTo( centerX - radius, centerY - radius, diameter, diameter, -p1Angle, -sweepAngle );
1180 if ( path.isEmpty() || path.currentPosition() != QPointF( mX[0], mY[0] ) )
1182 path.moveTo( QPointF( mX[0], mY[0] ) );
1185 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
1187 arcTo( path, QPointF( mX[i], mY[i] ), QPointF( mX[i + 1], mY[i + 1] ), QPointF( mX[i + 2], mY[i + 2] ) );
1191 if ( nPoints % 2 == 0 )
1193 path.lineTo( mX[ nPoints - 1 ], mY[ nPoints - 1 ] );
1204 if ( position.
vertex >= mX.size() || position.
vertex < 1 )
1209 mX.insert( position.
vertex, vertex.
x() );
1210 mY.insert( position.
vertex, vertex.
y() );
1213 mZ.insert( position.
vertex, vertex.
z() );
1217 mM.insert( position.
vertex, vertex.
m() );
1220 bool vertexNrEven = ( position.
vertex % 2 == 0 );
1235 if ( position.
vertex < 0 || position.
vertex >= mX.size() )
1240 mX[position.
vertex] = newPos.
x();
1241 mY[position.
vertex] = newPos.
y();
1244 mZ[position.
vertex] = newPos.
z();
1248 mM[position.
vertex] = newPos.
m();
1257 if ( nVertices < 4 )
1262 if ( position.
vertex < 0 || position.
vertex > ( nVertices - 1 ) )
1267 if ( position.
vertex < ( nVertices - 2 ) )
1300 double minDist = std::numeric_limits<double>::max();
1303 int minDistLeftOf = 0;
1305 double currentDist = 0.0;
1308 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
1310 currentDist = closestPointOnArc( mX[i], mY[i], mX[i + 1], mY[i + 1], mX[i + 2], mY[i + 2], pt, segmentPt, vertexAfter,
leftOf, epsilon );
1311 if ( currentDist < minDist )
1313 minDist = currentDist;
1314 minDistSegmentPoint = segmentPt;
1323 if ( minDist == std::numeric_limits<double>::max() )
1326 segmentPt = minDistSegmentPoint;
1327 vertexAfter = minDistVertexAfter;
1328 vertexAfter.
part = 0;
1329 vertexAfter.
ring = 0;
1344 type = ( node % 2 == 0 ) ? Qgis::VertexType::Segment : Qgis::VertexType::Curve;
1352 for (
int i = 0; i < maxIndex; i += 2 )
1355 QgsPoint p2( mX[i + 1], mY[i + 1] );
1356 QgsPoint p3( mX[i + 2], mY[i + 2] );
1366 sum += 0.5 * ( mX[i] * mY[i + 2] - mY[i] * mX[i + 2] );
1369 double midPointX = ( p1.
x() + p3.
x() ) / 2.0;
1370 double midPointY = ( p1.
y() + p3.
y() ) / 2.0;
1372 double radius, centerX, centerY;
1376 double r2 = radius * radius;
1387 double cov = 0.5 - d * std::sqrt( r2 - d * d ) / ( M_PI * r2 ) - M_1_PI * std::asin( d / radius );
1388 double circleChordArea = 0;
1389 if ( circlePointLeftOfLine == centerPointLeftOfLine )
1391 circleChordArea = M_PI * r2 * ( 1 - cov );
1395 circleChordArea = M_PI * r2 * cov;
1398 if ( !circlePointLeftOfLine )
1400 sum += circleChordArea;
1404 sum -= circleChordArea;
1414 double QgsCircularString::closestPointOnArc(
double x1,
double y1,
double x2,
double y2,
double x3,
double y3,
1417 double radius, centerX, centerY;
1442 segmentPt = ( distPtPt1 <= distPtPt3 ) ? pt1 : pt3;
1443 vertexAfter.
vertex = ( distPtPt1 <= distPtPt3 ) ? 1 : 2;
1450 segmentPt.
setX( pt.
x() );
1451 segmentPt.
setY( pt.
y() );
1457 double sqrDistancePointToCenter = ( pt.
x() - centerX ) * ( pt.
x() - centerX ) + ( pt.
y() - centerY ) * ( pt.
y() - centerY );
1458 *
leftOf = clockwise ? ( sqrDistancePointToCenter > radius * radius ? -1 : 1 )
1459 : ( sqrDistancePointToCenter < radius * radius ? -1 : 1 );
1465 void QgsCircularString::insertVertexBetween(
int after,
int before,
int pointOnCircle )
1467 double xAfter = mX.at( after );
1468 double yAfter = mY.at( after );
1469 double xBefore = mX.at( before );
1470 double yBefore = mY.at( before );
1471 double xOnCircle = mX.at( pointOnCircle );
1472 double yOnCircle = mY.at( pointOnCircle );
1474 double radius, centerX, centerY;
1477 double x = ( xAfter + xBefore ) / 2.0;
1478 double y = ( yAfter + yBefore ) / 2.0;
1481 mX.insert( before, newVertex.
x() );
1482 mY.insert( before, newVertex.
y() );
1486 mZ.insert( before, ( mZ[after] + mZ[before] ) / 2.0 );
1490 mM.insert( before, ( mM[after] + mM[before] ) / 2.0 );
1503 int before = vId.
vertex - 1;
1505 int after = vId.
vertex + 1;
1507 if ( vId.
vertex % 2 != 0 )
1537 int vertex1 = vId.
vertex - 2;
1538 int vertex2 = vId.
vertex - 1;
1539 int vertex3 = vId.
vertex;
1541 QgsPoint( mX[vertex1], mY[vertex1] ),
QgsPoint( mX[vertex2], mY[vertex2] ),
QgsPoint( mX[vertex3], mY[vertex3] ) );
1542 int vertex4 = vId.
vertex + 1;
1543 int vertex5 = vId.
vertex + 2;
1545 QgsPoint( mX[vertex3], mY[vertex3] ),
QgsPoint( mX[vertex4], mY[vertex4] ),
QgsPoint( mX[vertex5], mY[vertex5] ) );
1554 if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 2 )
1557 if ( startVertex.
vertex % 2 == 1 )
1560 double x1 = mX.at( startVertex.
vertex );
1561 double y1 = mY.at( startVertex.
vertex );
1562 double x2 = mX.at( startVertex.
vertex + 1 );
1563 double y2 = mY.at( startVertex.
vertex + 1 );
1564 double x3 = mX.at( startVertex.
vertex + 2 );
1565 double y3 = mY.at( startVertex.
vertex + 2 );
1572 std::reverse( copy->mX.begin(), copy->mX.end() );
1573 std::reverse( copy->mY.begin(), copy->mY.end() );
1576 std::reverse( copy->mZ.begin(), copy->mZ.end() );
1580 std::reverse( copy->mM.begin(), copy->mM.end() );
1590 double distanceTraversed = 0;
1592 if ( totalPoints == 0 )
1601 const double *x = mX.constData();
1602 const double *y = mY.constData();
1603 const double *z =
is3D() ? mZ.constData() :
nullptr;
1604 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1606 double prevX = *x++;
1607 double prevY = *y++;
1608 double prevZ = z ? *z++ : 0.0;
1609 double prevM = m ? *m++ : 0.0;
1613 return new QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1616 for (
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
1625 double z2 = z ? *z++ : 0.0;
1626 double m2 = m ? *m++ : 0.0;
1630 double z3 = z ? *z++ : 0.0;
1631 double m3 = m ? *m++ : 0.0;
1637 const double distanceToPoint = std::min( distance - distanceTraversed,
segmentLength );
1639 QgsPoint( pointType, x2, y2, z2, m2 ),
1640 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToPoint ) );
1656 if ( startDistance < 0 && endDistance < 0 )
1659 endDistance = std::max( startDistance, endDistance );
1662 if ( totalPoints == 0 )
1665 QVector< QgsPoint > substringPoints;
1666 substringPoints.reserve( totalPoints );
1674 const double *x = mX.constData();
1675 const double *y = mY.constData();
1676 const double *z =
is3D() ? mZ.constData() :
nullptr;
1677 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1679 double distanceTraversed = 0;
1680 double prevX = *x++;
1681 double prevY = *y++;
1682 double prevZ = z ? *z++ : 0.0;
1683 double prevM = m ? *m++ : 0.0;
1684 bool foundStart =
false;
1686 if ( startDistance < 0 )
1689 for (
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
1698 double z2 = z ? *z++ : 0.0;
1699 double m2 = m ? *m++ : 0.0;
1703 double z3 = z ? *z++ : 0.0;
1704 double m3 = m ? *m++ : 0.0;
1706 bool addedSegmentEnd =
false;
1708 if ( distanceTraversed <= startDistance && startDistance < distanceTraversed +
segmentLength )
1711 const double distanceToStart = startDistance - distanceTraversed;
1713 QgsPoint( pointType, x2, y2, z2, m2 ),
1714 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToStart );
1717 const bool endPointOnSegment = distanceTraversed +
segmentLength > endDistance;
1718 if ( endPointOnSegment )
1720 const double distanceToEnd = endDistance - distanceTraversed;
1721 const double midPointDistance = ( distanceToEnd - distanceToStart ) * 0.5 + distanceToStart;
1724 QgsPoint( pointType, x2, y2, z2, m2 ),
1725 QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
1727 QgsPoint( pointType, x2, y2, z2, m2 ),
1728 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
1729 addedSegmentEnd =
true;
1733 const double midPointDistance = (
segmentLength - distanceToStart ) * 0.5 + distanceToStart;
1736 QgsPoint( pointType, x2, y2, z2, m2 ),
1737 QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
1738 <<
QgsPoint( pointType, x3, y3, z3, m3 );
1739 addedSegmentEnd =
true;
1743 if ( !addedSegmentEnd && foundStart && ( distanceTraversed +
segmentLength > endDistance ) )
1746 const double distanceToEnd = endDistance - distanceTraversed;
1749 QgsPoint( pointType, x2, y2, z2, m2 ),
1750 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd / 2.0 )
1753 QgsPoint( pointType, x2, y2, z2, m2 ),
1754 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
1756 else if ( !addedSegmentEnd && foundStart )
1758 substringPoints <<
QgsPoint( pointType, x2, y2, z2, m2 )
1759 <<
QgsPoint( pointType, x3, y3, z3, m3 );
1767 if ( distanceTraversed >= endDistance )
1772 if ( !foundStart &&
qgsDoubleNear( distanceTraversed, startDistance ) )
1774 substringPoints <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1775 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1776 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1779 std::unique_ptr< QgsCircularString > result = std::make_unique< QgsCircularString >();
1780 result->setPoints( substringPoints );
1781 return result.release();
1794 mZ.reserve( nPoints );
1795 for (
int i = 0; i < nPoints; ++i )
1812 mM.reserve( nPoints );
1813 for (
int i = 0; i < nPoints; ++i )
1846 std::swap( mX, mY );