30#include <QPainterPath>
32#include <nlohmann/json.hpp>
42 bool hasZ = p1.
is3D();
75 int pointCount = std::min( x.size(), y.size() );
76 if ( x.size() == pointCount )
82 mX = x.mid( 0, pointCount );
84 if ( y.size() == pointCount )
90 mY = y.mid( 0, pointCount );
92 if ( !z.isEmpty() && z.count() >= pointCount )
95 if ( z.size() == pointCount )
101 mZ = z.mid( 0, pointCount );
104 if ( !m.isEmpty() && m.count() >= pointCount )
107 if ( m.size() == pointCount )
113 mM = m.mid( 0, pointCount );
133 if ( mX.count() != otherLine->mX.count() )
136 for (
int i = 0; i < mX.count(); ++i )
154 auto result = std::make_unique< QgsCircularString >();
156 return result.release();
161 const QgsCircularString *otherLine = qgsgeometry_cast<const QgsCircularString *>( other );
165 const int size = mX.size();
166 const int otherSize = otherLine->mX.size();
167 if ( size > otherSize )
171 else if ( size < otherSize )
178 else if ( !
is3D() && otherLine->
is3D() )
180 const bool considerZ =
is3D();
188 for (
int i = 0; i < size; i++ )
190 const double x = mX[i];
191 const double otherX = otherLine->mX[i];
196 else if ( x > otherX )
201 const double y = mY[i];
202 const double otherY = otherLine->mY[i];
207 else if ( y > otherY )
214 const double z = mZ[i];
215 const double otherZ = otherLine->mZ[i];
221 else if ( z > otherZ )
229 const double m = mM[i];
230 const double otherM = otherLine->mM[i];
236 else if ( m > otherM )
247 return QStringLiteral(
"CircularString" );
274 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
278 bbox = segmentBoundingBox(
QgsPoint( mX[i], mY[i] ),
QgsPoint( mX[i + 1], mY[i + 1] ),
QgsPoint( mX[i + 2], mY[i + 2] ) );
287 if ( nPoints > 0 && nPoints % 2 == 0 )
300 const int size = mX.size();
301 if ( index < 1 || index >= size - 1 )
304 const bool useZ =
is3D();
307 QVector<double> newX( size );
308 QVector<double> newY( size );
309 QVector<double> newZ( useZ ? size : 0 );
310 QVector<double> newM( useM ? size : 0 );
311 auto it = std::copy( mX.constBegin() + index, mX.constEnd() - 1, newX.begin() );
312 it = std::copy( mX.constBegin(), mX.constBegin() + index, it );
313 *it = *newX.constBegin();
314 mX = std::move( newX );
316 it = std::copy( mY.constBegin() + index, mY.constEnd() - 1, newY.begin() );
317 it = std::copy( mY.constBegin(), mY.constBegin() + index, it );
318 *it = *newY.constBegin();
319 mY = std::move( newY );
322 it = std::copy( mZ.constBegin() + index, mZ.constEnd() - 1, newZ.begin() );
323 it = std::copy( mZ.constBegin(), mZ.constBegin() + index, it );
324 *it = *newZ.constBegin();
325 mZ = std::move( newZ );
329 it = std::copy( mM.constBegin() + index, mM.constEnd() - 1, newM.begin() );
330 it = std::copy( mM.constBegin(), mM.constBegin() + index, it );
331 *it = *newM.constBegin();
332 mM = std::move( newM );
338 double centerX, centerY, radius;
347 bbox.combineExtentWith( pt3.
x(), pt3.
y() );
349 QgsPointSequence compassPoints = compassPointsOnSegment( p1Angle, p2Angle, p3Angle, centerX, centerY, radius );
350 QgsPointSequence::const_iterator cpIt = compassPoints.constBegin();
351 for ( ; cpIt != compassPoints.constEnd(); ++cpIt )
353 bbox.combineExtentWith( cpIt->x(), cpIt->y() );
358QgsPointSequence QgsCircularString::compassPointsOnSegment(
double p1Angle,
double p2Angle,
double p3Angle,
double centerX,
double centerY,
double radius )
362 QgsPoint nPoint( centerX, centerY + radius );
363 QgsPoint ePoint( centerX + radius, centerY );
364 QgsPoint sPoint( centerX, centerY - radius );
365 QgsPoint wPoint( centerX - radius, centerY );
367 if ( p3Angle >= p1Angle )
369 if ( p2Angle > p1Angle && p2Angle < p3Angle )
371 if ( p1Angle <= 90 && p3Angle >= 90 )
373 pointList.append( nPoint );
375 if ( p1Angle <= 180 && p3Angle >= 180 )
377 pointList.append( wPoint );
379 if ( p1Angle <= 270 && p3Angle >= 270 )
381 pointList.append( sPoint );
386 pointList.append( ePoint );
387 if ( p1Angle >= 90 || p3Angle <= 90 )
389 pointList.append( nPoint );
391 if ( p1Angle >= 180 || p3Angle <= 180 )
393 pointList.append( wPoint );
395 if ( p1Angle >= 270 || p3Angle <= 270 )
397 pointList.append( sPoint );
403 if ( p2Angle < p1Angle && p2Angle > p3Angle )
405 if ( p1Angle >= 270 && p3Angle <= 270 )
407 pointList.append( sPoint );
409 if ( p1Angle >= 180 && p3Angle <= 180 )
411 pointList.append( wPoint );
413 if ( p1Angle >= 90 && p3Angle <= 90 )
415 pointList.append( nPoint );
420 pointList.append( ePoint );
421 if ( p1Angle <= 270 || p3Angle >= 270 )
423 pointList.append( sPoint );
425 if ( p1Angle <= 180 || p3Angle >= 180 )
427 pointList.append( wPoint );
429 if ( p1Angle <= 90 || p3Angle >= 90 )
431 pointList.append( nPoint );
452 const bool hasZ =
is3D();
456 mX.resize( nVertices );
457 mY.resize( nVertices );
459 mZ.resize( nVertices );
463 mM.resize( nVertices );
466 for (
int i = 0; i < nVertices; ++i )
493 parts.second =
parts.second.remove(
'(' ).remove(
')' );
494 QString secondWithoutParentheses =
parts.second;
495 secondWithoutParentheses = secondWithoutParentheses.simplified().remove(
' ' );
496 if ( (
parts.second.compare( QLatin1String(
"EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
497 secondWithoutParentheses.isEmpty() )
510 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
521 wkb << static_cast<quint32>(
wkbType() );
533 wkt += QLatin1String(
"EMPTY" );
546 std::unique_ptr< QgsLineString > line(
curveToLine() );
547 QDomElement gml = line->asGml2( doc,
precision, ns, axisOrder );
556 QDomElement elemCurve = doc.createElementNS( ns, QStringLiteral(
"Curve" ) );
561 QDomElement elemSegments = doc.createElementNS( ns, QStringLiteral(
"segments" ) );
562 QDomElement elemArcString = doc.createElementNS( ns, QStringLiteral(
"ArcString" ) );
564 elemSegments.appendChild( elemArcString );
565 elemCurve.appendChild( elemSegments );
573 std::unique_ptr< QgsLineString > line(
curveToLine() );
586 error = QObject::tr(
"CircularString has less than 3 points and is not empty." );
597 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
628 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
642 bool res =
snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM,
643 result->mX, result->mY, result->mZ, result->mM );
645 return result.release();
652 if ( mX.count() <= 3 )
655 double prevX = mX.at( 0 );
656 double prevY = mY.at( 0 );
658 bool useZ = hasZ && useZValues;
659 double prevZ = useZ ? mZ.at( 0 ) : 0;
661 int remaining = mX.count();
664 while ( i + 1 < remaining )
666 double currentCurveX = mX.at( i );
667 double currentCurveY = mY.at( i );
668 double currentX = mX.at( i + 1 );
669 double currentY = mY.at( i + 1 );
670 double currentZ = useZ ? mZ.at( i + 1 ) : 0;
703 return std::min( mX.size(), mY.size() );
708 const int size = mX.size();
712 const double *x = mX.constData();
713 const double *y = mY.constData();
714 const bool useZ =
is3D();
716 const double *z = useZ ? mZ.constData() :
nullptr;
717 const double *m = useM ? mM.constData() :
nullptr;
719 for (
int i = 0; i < size; i += 2 )
748 if ( i < 0 || std::min( mX.size(), mY.size() ) <= i )
753 double x = mX.at( i );
754 double y = mY.at( i );
785 if ( index >= 0 && index < mX.size() )
786 return mX.at( index );
793 if ( index >= 0 && index < mY.size() )
794 return mY.at( index );
801 if ( index >= 0 && index < mZ.size() )
802 return mZ.at( index );
809 if ( index >= 0 && index < mM.size() )
810 return mM.at( index );
822 int size = mX.size();
824 double *srcX = mX.data();
825 double *srcY = mY.data();
826 double *srcM = hasM ? mM.data() :
nullptr;
827 double *srcZ = hasZ ? mZ.data() :
nullptr;
830 for (
int i = 0; i < size; ++i )
834 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
835 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
863 int size = mX.size();
865 double *srcX = mX.data();
866 double *srcY = mY.data();
867 double *srcM = hasM ? mM.data() :
nullptr;
868 double *srcZ = hasZ ? mZ.data() :
nullptr;
870 double *destX = srcX;
871 double *destY = srcY;
872 double *destM = srcM;
873 double *destZ = srcZ;
875 int filteredPoints = 0;
876 for (
int i = 0; i < size; ++i )
880 double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
881 double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
883 if ( filter(
QgsPoint( x, y, z, m ) ) )
895 mX.resize( filteredPoints );
896 mY.resize( filteredPoints );
898 mZ.resize( filteredPoints );
900 mM.resize( filteredPoints );
909 int size = mX.size();
911 double *srcX = mX.data();
912 double *srcY = mY.data();
913 double *srcM = hasM ? mM.data() :
nullptr;
914 double *srcZ = hasZ ? mZ.data() :
nullptr;
916 for (
int i = 0; i < size; ++i )
920 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
921 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
935 const bool useZ =
is3D();
938 const int size = mX.size();
940 return std::make_tuple( std::make_unique< QgsCircularString >(), std::make_unique< QgsCircularString >() );
942 index = std::clamp( index, 0, size - 1 );
944 const int part1Size = index + 1;
945 QVector< double > x1( part1Size );
946 QVector< double > y1( part1Size );
947 QVector< double > z1( useZ ? part1Size : 0 );
948 QVector< double > m1( useM ? part1Size : 0 );
950 const double *sourceX = mX.constData();
951 const double *sourceY = mY.constData();
952 const double *sourceZ = useZ ? mZ.constData() :
nullptr;
953 const double *sourceM = useM ? mM.constData() :
nullptr;
955 double *destX = x1.data();
956 double *destY = y1.data();
957 double *destZ = useZ ? z1.data() :
nullptr;
958 double *destM = useM ? m1.data() :
nullptr;
960 std::copy( sourceX, sourceX + part1Size, destX );
961 std::copy( sourceY, sourceY + part1Size, destY );
963 std::copy( sourceZ, sourceZ + part1Size, destZ );
965 std::copy( sourceM, sourceM + part1Size, destM );
967 const int part2Size = size - index;
969 return std::make_tuple( std::make_unique< QgsCircularString >( x1, y1, z1, m1 ), std::make_unique< QgsCircularString >() );
971 QVector< double > x2( part2Size );
972 QVector< double > y2( part2Size );
973 QVector< double > z2( useZ ? part2Size : 0 );
974 QVector< double > m2( useM ? part2Size : 0 );
977 destZ = useZ ? z2.data() :
nullptr;
978 destM = useM ? m2.data() :
nullptr;
979 std::copy( sourceX + index, sourceX + size, destX );
980 std::copy( sourceY + index, sourceY + size, destY );
982 std::copy( sourceZ + index, sourceZ + size, destZ );
984 std::copy( sourceM + index, sourceM + size, destM );
987 return std::make_tuple( std::make_unique< QgsCircularString >(), std::make_unique< QgsCircularString >( x2, y2, z2, m2 ) );
989 return std::make_tuple( std::make_unique< QgsCircularString >( x1, y1, z1, m1 ), std::make_unique< QgsCircularString >( x2, y2, z2, m2 ) );
996 for (
int i = 0; i < nPts; ++i )
998 pts.push_back(
pointN( i ) );
1018 bool hasZ = firstPt.
is3D();
1023 mX.resize(
points.size() );
1024 mY.resize(
points.size() );
1027 mZ.resize(
points.size() );
1035 mM.resize(
points.size() );
1042 for (
int i = 0; i <
points.size(); ++i )
1048 double z =
points.at( i ).z();
1049 mZ[i] = std::isnan( z ) ? 0 : z;
1053 double m =
points.at( i ).m();
1054 mM[i] = std::isnan( m ) ? 0 : m;
1061 if ( !line || line->
isEmpty() )
1104 mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
1117 mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
1135 double *zArray = mZ.data();
1139 bool useDummyZ = !hasZ || !transformZ;
1142 zArray =
new double[nPoints];
1143 for (
int i = 0; i < nPoints; ++i )
1162 for (
int i = 0; i < nPoints; ++i )
1165 t.map( mX.at( i ), mY.at( i ), &x, &y );
1170 mZ[i] = mZ.at( i ) * zScale + zTranslate;
1174 mM[i] = mM.at( i ) * mScale + mTranslate;
1179void arcTo( QPainterPath &path, QPointF pt1, QPointF pt2, QPointF pt3 )
1181 double centerX, centerY, radius;
1183 radius, centerX, centerY );
1188 double diameter = 2 * radius;
1189 path.arcTo( centerX - radius, centerY - radius, diameter, diameter, -p1Angle, -sweepAngle );
1200 if ( path.isEmpty() || path.currentPosition() != QPointF( mX[0], mY[0] ) )
1202 path.moveTo( QPointF( mX[0], mY[0] ) );
1205 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
1207 arcTo( path, QPointF( mX[i], mY[i] ), QPointF( mX[i + 1], mY[i + 1] ), QPointF( mX[i + 2], mY[i + 2] ) );
1211 if ( nPoints % 2 == 0 )
1213 path.lineTo( mX[ nPoints - 1 ], mY[ nPoints - 1 ] );
1224 if ( position.
vertex >= mX.size() || position.
vertex < 1 )
1229 mX.insert( position.
vertex, vertex.
x() );
1230 mY.insert( position.
vertex, vertex.
y() );
1233 mZ.insert( position.
vertex, vertex.
z() );
1237 mM.insert( position.
vertex, vertex.
m() );
1240 bool vertexNrEven = ( position.
vertex % 2 == 0 );
1255 if ( position.
vertex < 0 || position.
vertex >= mX.size() )
1260 mX[position.
vertex] = newPos.
x();
1261 mY[position.
vertex] = newPos.
y();
1264 mZ[position.
vertex] = newPos.
z();
1268 mM[position.
vertex] = newPos.
m();
1277 if ( nVertices < 4 )
1282 if ( position.
vertex < 0 || position.
vertex > ( nVertices - 1 ) )
1287 if ( position.
vertex < ( nVertices - 2 ) )
1320 double minDist = std::numeric_limits<double>::max();
1323 int minDistLeftOf = 0;
1325 double currentDist = 0.0;
1328 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
1330 currentDist = closestPointOnArc( mX[i], mY[i], mX[i + 1], mY[i + 1], mX[i + 2], mY[i + 2], pt, segmentPt, vertexAfter,
leftOf, epsilon );
1331 if ( currentDist < minDist )
1333 minDist = currentDist;
1334 minDistSegmentPoint = segmentPt;
1343 if ( minDist == std::numeric_limits<double>::max() )
1346 segmentPt = minDistSegmentPoint;
1347 vertexAfter = minDistVertexAfter;
1348 vertexAfter.
part = 0;
1349 vertexAfter.
ring = 0;
1364 type = ( node % 2 == 0 ) ? Qgis::VertexType::Segment : Qgis::VertexType::Curve;
1378 for (
int i = 0; i < maxIndex; i += 2 )
1381 QgsPoint p2( mX[i + 1], mY[i + 1] );
1382 QgsPoint p3( mX[i + 2], mY[i + 2] );
1392 mSummedUpArea += 0.5 * ( mX[i] * mY[i + 2] - mY[i] * mX[i + 2] );
1395 double midPointX = ( p1.
x() + p3.
x() ) / 2.0;
1396 double midPointY = ( p1.
y() + p3.
y() ) / 2.0;
1398 double radius, centerX, centerY;
1402 double r2 = radius * radius;
1413 double cov = 0.5 - d * std::sqrt( r2 - d * d ) / ( M_PI * r2 ) - M_1_PI * std::asin( d / radius );
1414 double circleChordArea = 0;
1415 if ( circlePointLeftOfLine == centerPointLeftOfLine )
1417 circleChordArea = M_PI * r2 * ( 1 - cov );
1421 circleChordArea = M_PI * r2 * cov;
1424 if ( !circlePointLeftOfLine )
1443double QgsCircularString::closestPointOnArc(
double x1,
double y1,
double x2,
double y2,
double x3,
double y3,
1446 double radius, centerX, centerY;
1471 segmentPt = ( distPtPt1 <= distPtPt3 ) ? pt1 : pt3;
1472 vertexAfter.
vertex = ( distPtPt1 <= distPtPt3 ) ? 1 : 2;
1479 segmentPt.
setX( pt.
x() );
1480 segmentPt.
setY( pt.
y() );
1486 double sqrDistancePointToCenter = ( pt.
x() - centerX ) * ( pt.
x() - centerX ) + ( pt.
y() - centerY ) * ( pt.
y() - centerY );
1487 *
leftOf = clockwise ? ( sqrDistancePointToCenter > radius * radius ? -1 : 1 )
1488 : ( sqrDistancePointToCenter < radius * radius ? -1 : 1 );
1494void QgsCircularString::insertVertexBetween(
int after,
int before,
int pointOnCircle )
1496 double xAfter = mX.at( after );
1497 double yAfter = mY.at( after );
1498 double xBefore = mX.at( before );
1499 double yBefore = mY.at( before );
1500 double xOnCircle = mX.at( pointOnCircle );
1501 double yOnCircle = mY.at( pointOnCircle );
1503 double radius, centerX, centerY;
1506 double x = ( xAfter + xBefore ) / 2.0;
1507 double y = ( yAfter + yBefore ) / 2.0;
1510 mX.insert( before, newVertex.
x() );
1511 mY.insert( before, newVertex.
y() );
1515 mZ.insert( before, ( mZ[after] + mZ[before] ) / 2.0 );
1519 mM.insert( before, ( mM[after] + mM[before] ) / 2.0 );
1532 int before = vId.
vertex - 1;
1534 int after = vId.
vertex + 1;
1536 if ( vId.
vertex % 2 != 0 )
1566 int vertex1 = vId.
vertex - 2;
1567 int vertex2 = vId.
vertex - 1;
1568 int vertex3 = vId.
vertex;
1570 QgsPoint( mX[vertex1], mY[vertex1] ),
QgsPoint( mX[vertex2], mY[vertex2] ),
QgsPoint( mX[vertex3], mY[vertex3] ) );
1571 int vertex4 = vId.
vertex + 1;
1572 int vertex5 = vId.
vertex + 2;
1574 QgsPoint( mX[vertex3], mY[vertex3] ),
QgsPoint( mX[vertex4], mY[vertex4] ),
QgsPoint( mX[vertex5], mY[vertex5] ) );
1583 if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 2 )
1586 if ( startVertex.
vertex % 2 == 1 )
1589 double x1 = mX.at( startVertex.
vertex );
1590 double y1 = mY.at( startVertex.
vertex );
1591 double x2 = mX.at( startVertex.
vertex + 1 );
1592 double y2 = mY.at( startVertex.
vertex + 1 );
1593 double x3 = mX.at( startVertex.
vertex + 2 );
1594 double y3 = mY.at( startVertex.
vertex + 2 );
1601 std::reverse( copy->mX.begin(), copy->mX.end() );
1602 std::reverse( copy->mY.begin(), copy->mY.end() );
1605 std::reverse( copy->mZ.begin(), copy->mZ.end() );
1609 std::reverse( copy->mM.begin(), copy->mM.end() );
1619 double distanceTraversed = 0;
1621 if ( totalPoints == 0 )
1630 const double *x = mX.constData();
1631 const double *y = mY.constData();
1632 const double *z =
is3D() ? mZ.constData() :
nullptr;
1633 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1635 double prevX = *x++;
1636 double prevY = *y++;
1637 double prevZ = z ? *z++ : 0.0;
1638 double prevM = m ? *m++ : 0.0;
1642 return new QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1645 for (
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
1654 double z2 = z ? *z++ : 0.0;
1655 double m2 = m ? *m++ : 0.0;
1659 double z3 = z ? *z++ : 0.0;
1660 double m3 = m ? *m++ : 0.0;
1666 const double distanceToPoint = std::min( distance - distanceTraversed,
segmentLength );
1668 QgsPoint( pointType, x2, y2, z2, m2 ),
1669 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToPoint ) );
1685 if ( startDistance < 0 && endDistance < 0 )
1688 endDistance = std::max( startDistance, endDistance );
1691 if ( totalPoints == 0 )
1694 QVector< QgsPoint > substringPoints;
1695 substringPoints.reserve( totalPoints );
1703 const double *x = mX.constData();
1704 const double *y = mY.constData();
1705 const double *z =
is3D() ? mZ.constData() :
nullptr;
1706 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1708 double distanceTraversed = 0;
1709 double prevX = *x++;
1710 double prevY = *y++;
1711 double prevZ = z ? *z++ : 0.0;
1712 double prevM = m ? *m++ : 0.0;
1713 bool foundStart =
false;
1715 if ( startDistance < 0 )
1718 for (
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
1727 double z2 = z ? *z++ : 0.0;
1728 double m2 = m ? *m++ : 0.0;
1732 double z3 = z ? *z++ : 0.0;
1733 double m3 = m ? *m++ : 0.0;
1735 bool addedSegmentEnd =
false;
1737 if ( distanceTraversed <= startDistance && startDistance < distanceTraversed +
segmentLength )
1740 const double distanceToStart = startDistance - distanceTraversed;
1742 QgsPoint( pointType, x2, y2, z2, m2 ),
1743 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToStart );
1746 const bool endPointOnSegment = distanceTraversed +
segmentLength > endDistance;
1747 if ( endPointOnSegment )
1749 const double distanceToEnd = endDistance - distanceTraversed;
1750 const double midPointDistance = ( distanceToEnd - distanceToStart ) * 0.5 + distanceToStart;
1753 QgsPoint( pointType, x2, y2, z2, m2 ),
1754 QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
1756 QgsPoint( pointType, x2, y2, z2, m2 ),
1757 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
1758 addedSegmentEnd =
true;
1762 const double midPointDistance = (
segmentLength - distanceToStart ) * 0.5 + distanceToStart;
1765 QgsPoint( pointType, x2, y2, z2, m2 ),
1766 QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
1767 <<
QgsPoint( pointType, x3, y3, z3, m3 );
1768 addedSegmentEnd =
true;
1772 if ( !addedSegmentEnd && foundStart && ( distanceTraversed +
segmentLength > endDistance ) )
1775 const double distanceToEnd = endDistance - distanceTraversed;
1778 QgsPoint( pointType, x2, y2, z2, m2 ),
1779 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd / 2.0 )
1782 QgsPoint( pointType, x2, y2, z2, m2 ),
1783 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
1785 else if ( !addedSegmentEnd && foundStart )
1787 substringPoints <<
QgsPoint( pointType, x2, y2, z2, m2 )
1788 <<
QgsPoint( pointType, x3, y3, z3, m3 );
1796 if ( distanceTraversed >= endDistance )
1801 if ( !foundStart &&
qgsDoubleNear( distanceTraversed, startDistance ) )
1803 substringPoints <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1804 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1805 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1808 std::unique_ptr< QgsCircularString > result = std::make_unique< QgsCircularString >();
1809 result->setPoints( substringPoints );
1810 return result.release();
1823 mZ.reserve( nPoints );
1824 for (
int i = 0; i < nPoints; ++i )
1841 mM.reserve( nPoints );
1842 for (
int i = 0; i < nPoints; ++i )
1875 std::swap( mX, mY );
VertexType
Types of vertex.
WkbType
The WKB type describes the number of dimensions a geometry has.
@ CircularString
CircularString.
@ CircularStringZ
CircularStringZ.
TransformDirection
Flags for raster layer temporal capabilities.
Abstract base class for all geometries.
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
bool is3D() const SIP_HOLDGIL
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.
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, Qgis::WkbType baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
Qgis::WkbType wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts of the geometry.
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
static endian_t endian()
Returns whether this machine uses big or little endian.
Circular string geometry type.
bool equals(const QgsCurve &other) const override
Checks whether this curve exactly equals another curve.
double length() const override
Returns the planar, 2-dimensional length of the geometry.
QgsPoint pointN(int i) const SIP_HOLDGIL
Returns the point at index i within the circular string.
void points(QgsPointSequence &pts) const override
Returns a list of points within the curve.
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
int numPoints() const override SIP_HOLDGIL
Returns the number of points in the curve.
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.
QgsCircularString * snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0) const override
Makes a new geometry with all the points or vertices snapped to the closest point of the grid.
QgsCircularString * clone() const override
Clones the geometry by performing a deep copy.
QString geometryType() const override SIP_HOLDGIL
Returns a unique string representing the geometry type.
void append(const QgsCircularString *string)
Appends the contents of another circular string to the end of this circular string.
bool fromWkb(QgsConstWkbPtr &wkb) override
Sets the geometry from a WKB string.
int dimension() const override SIP_HOLDGIL
Returns the inherent dimension of the geometry.
void draw(QPainter &p) const override
Draws the geometry using the specified QPainter.
QgsCircularString * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
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.
void swapXy() override
Swaps the x and y coordinates from the geometry.
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
static QgsCircularString fromTwoPointsAndCenter(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint ¢er, bool useShortestArc=true)
Creates a circular string with a single arc representing the curve from p1 to p2 with the specified c...
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...
double segmentLength(QgsVertexId startVertex) const override
Returns the length of the segment of the geometry which begins at startVertex.
double xAt(int index) const override SIP_HOLDGIL
Returns the x-coordinate of the specified node in the line string.
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...
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
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.
void sumUpArea(double &sum) const override
Sums up the area of the curve by iterating over the vertices (shoelace formula).
QgsCircularString * reversed() const override
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
QgsRectangle calculateBoundingBox() const override
Default calculator for the minimal bounding box for the geometry.
bool pointAt(int node, QgsPoint &point, Qgis::VertexType &type) const override
Returns the point and vertex id of a point within the curve.
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...
bool dropMValue() override
Drops any measure values which exist in the geometry.
double yAt(int index) const override SIP_HOLDGIL
Returns the y-coordinate of the specified node in the line string.
void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) override SIP_THROW(QgsCsException)
Transforms the geometry using a coordinate transform.
QgsPoint endPoint() const override SIP_HOLDGIL
Returns the end point of the curve.
void addToPainterPath(QPainterPath &path) const override
Adds a curve to a painter path.
int wkbSize(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns the length of the QByteArray returned by asWkb()
QgsCircularString * curveSubstring(double startDistance, double endDistance) const override
Returns a new curve representing a substring of this curve.
double mAt(int index) const override SIP_HOLDGIL
Returns the m-coordinate of the specified node in the line string.
void drawAsPolygon(QPainter &p) const override
Draws the curve as a polygon on the specified QPainter.
void setPoints(const QgsPointSequence &points)
Sets the circular string's points.
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.
double vertexAngle(QgsVertexId vertex) const override
Returns approximate angle at a vertex.
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
double zAt(int index) const override SIP_HOLDGIL
Returns the z-coordinate of the specified node in the line string.
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.
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
void clear() override
Clears the geometry, ie reset it to a null geometry.
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
bool hasCurvedSegments() const override
Returns true if the geometry contains curved segments.
void scroll(int firstVertexIndex) final
Scrolls the curve vertices so that they start with the vertex at the given index.
QgsPoint * interpolatePoint(double distance) const override
Returns an interpolated point on the curve at the specified distance.
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
bool insertVertex(QgsVertexId position, const QgsPoint &vertex) override
Inserts a vertex into the geometry.
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...
QgsPoint startPoint() const override SIP_HOLDGIL
Returns the starting point of the curve.
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...
json asJsonObject(int precision=17) const override
Returns a json object representation of the geometry.
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.
QgsCircularString() SIP_HOLDGIL
Constructs an empty circular string.
Qgis::WkbType readHeader() const
readHeader
Abstract base class for curved geometry type.
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
bool mHasCachedSummedUpArea
bool snapToGridPrivate(double hSpacing, double vSpacing, double dSpacing, double mSpacing, const QVector< double > &srcX, const QVector< double > &srcY, const QVector< double > &srcZ, const QVector< double > &srcM, QVector< double > &outX, QVector< double > &outY, QVector< double > &outZ, QVector< double > &outM) const
Helper function for QgsCurve subclasses to snap to grids.
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
static double circleTangentDirection(const QgsPoint &tangentPoint, const QgsPoint &cp1, const QgsPoint &cp2, const QgsPoint &cp3) SIP_HOLDGIL
Calculates the direction angle of a circle tangent (clockwise from north in radians)
static double sqrDistance2D(const QgsPoint &pt1, const QgsPoint &pt2) SIP_HOLDGIL
Returns the squared 2D distance between two points.
static double ccwAngle(double dy, double dx) SIP_HOLDGIL
Returns the counter clockwise angle between a line with components dx, dy and the line with dx > 0 an...
static QgsPoint segmentMidPointFromCenter(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint ¢er, bool useShortestArc=true) SIP_HOLDGIL
Calculates the midpoint on the circle passing through p1 and p2, with the specified center coordinate...
static void circleCenterRadius(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double &radius, double ¢erX, double ¢erY) SIP_HOLDGIL
Returns radius and center of the circle through pt1, pt2, pt3.
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure, QgsAbstractGeometry::WkbFlags flags)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
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 averageAngle(double x1, double y1, double x2, double y2, double x3, double y3) SIP_HOLDGIL
Calculates the average angle (in radians) between the two linear segments from (x1,...
static bool angleOnCircle(double angle, double angle1, double angle2, double angle3) SIP_HOLDGIL
Returns true if an angle is between angle1 and angle3 on a circle described by angle1,...
static bool circleClockwise(double angle1, double angle2, double angle3) SIP_HOLDGIL
Returns true if the circle defined by three angles is ordered clockwise.
static double sweepAngle(double centerX, double centerY, double x1, double y1, double x2, double y2, double x3, double y3) SIP_HOLDGIL
Calculates angle of a circular string part defined by pt1, pt2, pt3.
static double circleLength(double x1, double y1, double x2, double y2, double x3, double y3) SIP_HOLDGIL
Length of a circular string segment defined by pt1, pt2, pt3.
static QgsPoint pointOnLineWithDistance(const QgsPoint &startPoint, const QgsPoint &directionPoint, double distance) SIP_HOLDGIL
Returns a point a specified distance toward a second point.
static QgsPointSequence pointsFromWKT(const QString &wktCoordinateList, bool is3D, bool isMeasure)
Returns a list of points contained in a WKT string.
static void segmentizeArc(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3, QgsPointSequence &points, double tolerance=M_PI_2/90, QgsAbstractGeometry::SegmentationToleranceType toleranceType=QgsAbstractGeometry::MaximumAngle, bool hasZ=false, bool hasM=false)
Convert circular arc defined by p1, p2, p3 (p1/p3 being start resp.
static bool circleAngleBetween(double angle, double angle1, double angle2, bool clockwise) SIP_HOLDGIL
Returns true if, in a circle, angle is between angle1 and angle2.
static QgsPoint interpolatePointOnArc(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double distance) SIP_HOLDGIL
Interpolates a point on an arc defined by three points, pt1, pt2 and pt3.
static QDomElement pointsToGML3(const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, bool is3D, QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY)
Returns a gml::posList DOM element.
static int leftOfLine(const double x, const double y, const double x1, const double y1, const double x2, const double y2) SIP_HOLDGIL
Returns a value < 0 if the point (x, y) is left of the line from (x1, y1) -> (x2, y2).
static QString pointsToWKT(const QgsPointSequence &points, int precision, bool is3D, bool isMeasure)
Returns a WKT coordinate list.
Line string geometry type, with support for z-dimension and m-values.
void setPoints(size_t size, const double *x, const double *y, const double *z=nullptr, const double *m=nullptr)
Resets the line string to match the specified point data.
Point geometry type, with support for z-dimension and m-values.
void setX(double x) SIP_HOLDGIL
Sets the point's x-coordinate.
void setY(double y) SIP_HOLDGIL
Sets the point's y-coordinate.
A rectangle specified with double values.
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
static Qgis::WkbType addZ(Qgis::WkbType type) SIP_HOLDGIL
Adds the z dimension to a WKB type and returns the new type.
static Qgis::WkbType addM(Qgis::WkbType type) SIP_HOLDGIL
Adds the m dimension to a WKB type and returns the new type.
static bool hasZ(Qgis::WkbType type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
static Qgis::WkbType dropZ(Qgis::WkbType type) SIP_HOLDGIL
Drops the z dimension (if present) for a WKB type and returns the new type.
static Qgis::WkbType dropM(Qgis::WkbType type) SIP_HOLDGIL
Drops the m dimension (if present) for a WKB type and returns the new type.
static bool hasM(Qgis::WkbType type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
static Qgis::WkbType flatType(Qgis::WkbType type) SIP_HOLDGIL
Returns the flat type for a WKB type.
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
double ANALYSIS_EXPORT leftOf(const QgsPoint &thepoint, const QgsPoint *p1, const QgsPoint *p2)
Returns whether 'thepoint' is left or right of the line from 'p1' to 'p2'. Negative values mean left ...
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
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QVector< QgsPoint > QgsPointSequence
void arcTo(QPainterPath &path, QPointF pt1, QPointF pt2, QPointF pt3)
Utility class for identifying a unique vertex within a geometry.