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 )
279 double zMin = std::numeric_limits<double>::quiet_NaN();
280 double zMax = std::numeric_limits<double>::quiet_NaN();
283 zMin = *std::min_element( mZ.begin() + i, mZ.begin() + i + 3 );
284 zMax = *std::max_element( mZ.begin() + i, mZ.begin() + i + 3 );
288 bbox =
QgsBox3D( box2d, zMin, zMax );
296 if ( nPoints > 0 && nPoints % 2 == 0 )
298 double z = std::numeric_limits<double>::quiet_NaN();
309 z = mZ[ nPoints - 1 ];
311 bbox.
combineWith( mX[ nPoints - 1 ], mY[ nPoints - 1 ], z );
318 const int size = mX.size();
319 if ( index < 1 || index >= size - 1 )
322 const bool useZ =
is3D();
325 QVector<double> newX( size );
326 QVector<double> newY( size );
327 QVector<double> newZ( useZ ? size : 0 );
328 QVector<double> newM( useM ? size : 0 );
329 auto it = std::copy( mX.constBegin() + index, mX.constEnd() - 1, newX.begin() );
330 it = std::copy( mX.constBegin(), mX.constBegin() + index, it );
331 *it = *newX.constBegin();
332 mX = std::move( newX );
334 it = std::copy( mY.constBegin() + index, mY.constEnd() - 1, newY.begin() );
335 it = std::copy( mY.constBegin(), mY.constBegin() + index, it );
336 *it = *newY.constBegin();
337 mY = std::move( newY );
340 it = std::copy( mZ.constBegin() + index, mZ.constEnd() - 1, newZ.begin() );
341 it = std::copy( mZ.constBegin(), mZ.constBegin() + index, it );
342 *it = *newZ.constBegin();
343 mZ = std::move( newZ );
347 it = std::copy( mM.constBegin() + index, mM.constEnd() - 1, newM.begin() );
348 it = std::copy( mM.constBegin(), mM.constBegin() + index, it );
349 *it = *newM.constBegin();
350 mM = std::move( newM );
356 double centerX, centerY, radius;
365 bbox.combineExtentWith( pt3.
x(), pt3.
y() );
367 QgsPointSequence compassPoints = compassPointsOnSegment( p1Angle, p2Angle, p3Angle, centerX, centerY, radius );
368 QgsPointSequence::const_iterator cpIt = compassPoints.constBegin();
369 for ( ; cpIt != compassPoints.constEnd(); ++cpIt )
371 bbox.combineExtentWith( cpIt->x(), cpIt->y() );
376QgsPointSequence QgsCircularString::compassPointsOnSegment(
double p1Angle,
double p2Angle,
double p3Angle,
double centerX,
double centerY,
double radius )
380 QgsPoint nPoint( centerX, centerY + radius );
381 QgsPoint ePoint( centerX + radius, centerY );
382 QgsPoint sPoint( centerX, centerY - radius );
383 QgsPoint wPoint( centerX - radius, centerY );
385 if ( p3Angle >= p1Angle )
387 if ( p2Angle > p1Angle && p2Angle < p3Angle )
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 );
404 pointList.append( ePoint );
405 if ( p1Angle >= 90 || p3Angle <= 90 )
407 pointList.append( nPoint );
409 if ( p1Angle >= 180 || p3Angle <= 180 )
411 pointList.append( wPoint );
413 if ( p1Angle >= 270 || p3Angle <= 270 )
415 pointList.append( sPoint );
421 if ( p2Angle < p1Angle && p2Angle > p3Angle )
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 );
438 pointList.append( ePoint );
439 if ( p1Angle <= 270 || p3Angle >= 270 )
441 pointList.append( sPoint );
443 if ( p1Angle <= 180 || p3Angle >= 180 )
445 pointList.append( wPoint );
447 if ( p1Angle <= 90 || p3Angle >= 90 )
449 pointList.append( nPoint );
470 const bool hasZ =
is3D();
474 mX.resize( nVertices );
475 mY.resize( nVertices );
477 mZ.resize( nVertices );
481 mM.resize( nVertices );
484 for (
int i = 0; i < nVertices; ++i )
511 parts.second =
parts.second.remove(
'(' ).remove(
')' );
512 QString secondWithoutParentheses =
parts.second;
513 secondWithoutParentheses = secondWithoutParentheses.simplified().remove(
' ' );
514 if ( (
parts.second.compare( QLatin1String(
"EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
515 secondWithoutParentheses.isEmpty() )
528 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
539 wkb << static_cast<quint32>(
wkbType() );
551 wkt += QLatin1String(
"EMPTY" );
564 std::unique_ptr< QgsLineString > line(
curveToLine() );
565 QDomElement gml = line->asGml2( doc,
precision, ns, axisOrder );
574 QDomElement elemCurve = doc.createElementNS( ns, QStringLiteral(
"Curve" ) );
579 QDomElement elemSegments = doc.createElementNS( ns, QStringLiteral(
"segments" ) );
580 QDomElement elemArcString = doc.createElementNS( ns, QStringLiteral(
"ArcString" ) );
582 elemSegments.appendChild( elemArcString );
583 elemCurve.appendChild( elemSegments );
591 std::unique_ptr< QgsLineString > line(
curveToLine() );
604 error = QObject::tr(
"CircularString has less than 3 points and is not empty." );
615 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
646 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
660 bool res =
snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM,
661 result->mX, result->mY, result->mZ, result->mM );
663 return result.release();
670 if ( mX.count() <= 3 )
673 double prevX = mX.at( 0 );
674 double prevY = mY.at( 0 );
676 bool useZ = hasZ && useZValues;
677 double prevZ = useZ ? mZ.at( 0 ) : 0;
679 int remaining = mX.count();
682 while ( i + 1 < remaining )
684 double currentCurveX = mX.at( i );
685 double currentCurveY = mY.at( i );
686 double currentX = mX.at( i + 1 );
687 double currentY = mY.at( i + 1 );
688 double currentZ = useZ ? mZ.at( i + 1 ) : 0;
721 return std::min( mX.size(), mY.size() );
726 const int size = mX.size();
730 const double *x = mX.constData();
731 const double *y = mY.constData();
732 const bool useZ =
is3D();
734 const double *z = useZ ? mZ.constData() :
nullptr;
735 const double *m = useM ? mM.constData() :
nullptr;
737 for (
int i = 0; i < size; i += 2 )
766 if ( i < 0 || std::min( mX.size(), mY.size() ) <= i )
771 double x = mX.at( i );
772 double y = mY.at( i );
803 if ( index >= 0 && index < mX.size() )
804 return mX.at( index );
811 if ( index >= 0 && index < mY.size() )
812 return mY.at( index );
819 if ( index >= 0 && index < mZ.size() )
820 return mZ.at( index );
827 if ( index >= 0 && index < mM.size() )
828 return mM.at( index );
840 int size = mX.size();
842 double *srcX = mX.data();
843 double *srcY = mY.data();
844 double *srcM = hasM ? mM.data() :
nullptr;
845 double *srcZ = hasZ ? mZ.data() :
nullptr;
848 for (
int i = 0; i < size; ++i )
852 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
853 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
881 int size = mX.size();
883 double *srcX = mX.data();
884 double *srcY = mY.data();
885 double *srcM = hasM ? mM.data() :
nullptr;
886 double *srcZ = hasZ ? mZ.data() :
nullptr;
888 double *destX = srcX;
889 double *destY = srcY;
890 double *destM = srcM;
891 double *destZ = srcZ;
893 int filteredPoints = 0;
894 for (
int i = 0; i < size; ++i )
898 double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
899 double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
901 if ( filter(
QgsPoint( x, y, z, m ) ) )
913 mX.resize( filteredPoints );
914 mY.resize( filteredPoints );
916 mZ.resize( filteredPoints );
918 mM.resize( filteredPoints );
927 int size = mX.size();
929 double *srcX = mX.data();
930 double *srcY = mY.data();
931 double *srcM = hasM ? mM.data() :
nullptr;
932 double *srcZ = hasZ ? mZ.data() :
nullptr;
934 for (
int i = 0; i < size; ++i )
938 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
939 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
953 const bool useZ =
is3D();
956 const int size = mX.size();
958 return std::make_tuple( std::make_unique< QgsCircularString >(), std::make_unique< QgsCircularString >() );
960 index = std::clamp( index, 0, size - 1 );
962 const int part1Size = index + 1;
963 QVector< double > x1( part1Size );
964 QVector< double > y1( part1Size );
965 QVector< double > z1( useZ ? part1Size : 0 );
966 QVector< double > m1( useM ? part1Size : 0 );
968 const double *sourceX = mX.constData();
969 const double *sourceY = mY.constData();
970 const double *sourceZ = useZ ? mZ.constData() :
nullptr;
971 const double *sourceM = useM ? mM.constData() :
nullptr;
973 double *destX = x1.data();
974 double *destY = y1.data();
975 double *destZ = useZ ? z1.data() :
nullptr;
976 double *destM = useM ? m1.data() :
nullptr;
978 std::copy( sourceX, sourceX + part1Size, destX );
979 std::copy( sourceY, sourceY + part1Size, destY );
981 std::copy( sourceZ, sourceZ + part1Size, destZ );
983 std::copy( sourceM, sourceM + part1Size, destM );
985 const int part2Size = size - index;
987 return std::make_tuple( std::make_unique< QgsCircularString >( x1, y1, z1, m1 ), std::make_unique< QgsCircularString >() );
989 QVector< double > x2( part2Size );
990 QVector< double > y2( part2Size );
991 QVector< double > z2( useZ ? part2Size : 0 );
992 QVector< double > m2( useM ? part2Size : 0 );
995 destZ = useZ ? z2.data() :
nullptr;
996 destM = useM ? m2.data() :
nullptr;
997 std::copy( sourceX + index, sourceX + size, destX );
998 std::copy( sourceY + index, sourceY + size, destY );
1000 std::copy( sourceZ + index, sourceZ + size, destZ );
1002 std::copy( sourceM + index, sourceM + size, destM );
1004 if ( part1Size < 2 )
1005 return std::make_tuple( std::make_unique< QgsCircularString >(), std::make_unique< QgsCircularString >( x2, y2, z2, m2 ) );
1007 return std::make_tuple( std::make_unique< QgsCircularString >( x1, y1, z1, m1 ), std::make_unique< QgsCircularString >( x2, y2, z2, m2 ) );
1014 for (
int i = 0; i < nPts; ++i )
1016 pts.push_back(
pointN( i ) );
1036 bool hasZ = firstPt.
is3D();
1041 mX.resize(
points.size() );
1042 mY.resize(
points.size() );
1045 mZ.resize(
points.size() );
1053 mM.resize(
points.size() );
1060 for (
int i = 0; i <
points.size(); ++i )
1066 double z =
points.at( i ).z();
1067 mZ[i] = std::isnan( z ) ? 0 : z;
1071 double m =
points.at( i ).m();
1072 mM[i] = std::isnan( m ) ? 0 : m;
1079 if ( !line || line->
isEmpty() )
1122 mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
1135 mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
1153 double *zArray = mZ.data();
1157 bool useDummyZ = !hasZ || !transformZ;
1160 zArray =
new double[nPoints];
1161 for (
int i = 0; i < nPoints; ++i )
1180 for (
int i = 0; i < nPoints; ++i )
1183 t.map( mX.at( i ), mY.at( i ), &x, &y );
1188 mZ[i] = mZ.at( i ) * zScale + zTranslate;
1192 mM[i] = mM.at( i ) * mScale + mTranslate;
1197void arcTo( QPainterPath &path, QPointF pt1, QPointF pt2, QPointF pt3 )
1199 double centerX, centerY, radius;
1201 radius, centerX, centerY );
1206 double diameter = 2 * radius;
1207 path.arcTo( centerX - radius, centerY - radius, diameter, diameter, -p1Angle, -sweepAngle );
1218 if ( path.isEmpty() || path.currentPosition() != QPointF( mX[0], mY[0] ) )
1220 path.moveTo( QPointF( mX[0], mY[0] ) );
1223 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
1225 arcTo( path, QPointF( mX[i], mY[i] ), QPointF( mX[i + 1], mY[i + 1] ), QPointF( mX[i + 2], mY[i + 2] ) );
1229 if ( nPoints % 2 == 0 )
1231 path.lineTo( mX[ nPoints - 1 ], mY[ nPoints - 1 ] );
1242 if ( position.
vertex >= mX.size() || position.
vertex < 1 )
1247 mX.insert( position.
vertex, vertex.
x() );
1248 mY.insert( position.
vertex, vertex.
y() );
1251 mZ.insert( position.
vertex, vertex.
z() );
1255 mM.insert( position.
vertex, vertex.
m() );
1258 bool vertexNrEven = ( position.
vertex % 2 == 0 );
1273 if ( position.
vertex < 0 || position.
vertex >= mX.size() )
1278 mX[position.
vertex] = newPos.
x();
1279 mY[position.
vertex] = newPos.
y();
1282 mZ[position.
vertex] = newPos.
z();
1286 mM[position.
vertex] = newPos.
m();
1295 if ( nVertices < 4 )
1300 if ( position.
vertex < 0 || position.
vertex > ( nVertices - 1 ) )
1305 if ( position.
vertex < ( nVertices - 2 ) )
1338 double minDist = std::numeric_limits<double>::max();
1341 int minDistLeftOf = 0;
1343 double currentDist = 0.0;
1346 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
1348 currentDist = closestPointOnArc( mX[i], mY[i], mX[i + 1], mY[i + 1], mX[i + 2], mY[i + 2], pt, segmentPt, vertexAfter, leftOf, epsilon );
1349 if ( currentDist < minDist )
1351 minDist = currentDist;
1352 minDistSegmentPoint = segmentPt;
1356 minDistLeftOf = *leftOf;
1361 if ( minDist == std::numeric_limits<double>::max() )
1364 segmentPt = minDistSegmentPoint;
1365 vertexAfter = minDistVertexAfter;
1366 vertexAfter.
part = 0;
1367 vertexAfter.
ring = 0;
1370 *leftOf =
qgsDoubleNear( minDist, 0.0 ) ? 0 : minDistLeftOf;
1396 for (
int i = 0; i < maxIndex; i += 2 )
1399 QgsPoint p2( mX[i + 1], mY[i + 1] );
1400 QgsPoint p3( mX[i + 2], mY[i + 2] );
1410 mSummedUpArea += 0.5 * ( mX[i] * mY[i + 2] - mY[i] * mX[i + 2] );
1413 double midPointX = ( p1.
x() + p3.
x() ) / 2.0;
1414 double midPointY = ( p1.
y() + p3.
y() ) / 2.0;
1416 double radius, centerX, centerY;
1420 double r2 = radius * radius;
1431 double cov = 0.5 - d * std::sqrt( r2 - d * d ) / ( M_PI * r2 ) - M_1_PI * std::asin( d / radius );
1432 double circleChordArea = 0;
1433 if ( circlePointLeftOfLine == centerPointLeftOfLine )
1435 circleChordArea = M_PI * r2 * ( 1 - cov );
1439 circleChordArea = M_PI * r2 * cov;
1442 if ( !circlePointLeftOfLine )
1461double QgsCircularString::closestPointOnArc(
double x1,
double y1,
double x2,
double y2,
double x3,
double y3,
1464 double radius, centerX, centerY;
1489 segmentPt = ( distPtPt1 <= distPtPt3 ) ? pt1 : pt3;
1490 vertexAfter.
vertex = ( distPtPt1 <= distPtPt3 ) ? 1 : 2;
1497 segmentPt.
setX( pt.
x() );
1498 segmentPt.
setY( pt.
y() );
1504 double sqrDistancePointToCenter = ( pt.
x() - centerX ) * ( pt.
x() - centerX ) + ( pt.
y() - centerY ) * ( pt.
y() - centerY );
1505 *
leftOf = clockwise ? ( sqrDistancePointToCenter > radius * radius ? -1 : 1 )
1506 : ( sqrDistancePointToCenter < radius * radius ? -1 : 1 );
1512void QgsCircularString::insertVertexBetween(
int after,
int before,
int pointOnCircle )
1514 double xAfter = mX.at( after );
1515 double yAfter = mY.at( after );
1516 double xBefore = mX.at( before );
1517 double yBefore = mY.at( before );
1518 double xOnCircle = mX.at( pointOnCircle );
1519 double yOnCircle = mY.at( pointOnCircle );
1521 double radius, centerX, centerY;
1524 double x = ( xAfter + xBefore ) / 2.0;
1525 double y = ( yAfter + yBefore ) / 2.0;
1528 mX.insert( before, newVertex.
x() );
1529 mY.insert( before, newVertex.
y() );
1533 mZ.insert( before, ( mZ[after] + mZ[before] ) / 2.0 );
1537 mM.insert( before, ( mM[after] + mM[before] ) / 2.0 );
1550 int before = vId.
vertex - 1;
1552 int after = vId.
vertex + 1;
1554 if ( vId.
vertex % 2 != 0 )
1584 int vertex1 = vId.
vertex - 2;
1585 int vertex2 = vId.
vertex - 1;
1586 int vertex3 = vId.
vertex;
1588 QgsPoint( mX[vertex1], mY[vertex1] ),
QgsPoint( mX[vertex2], mY[vertex2] ),
QgsPoint( mX[vertex3], mY[vertex3] ) );
1589 int vertex4 = vId.
vertex + 1;
1590 int vertex5 = vId.
vertex + 2;
1592 QgsPoint( mX[vertex3], mY[vertex3] ),
QgsPoint( mX[vertex4], mY[vertex4] ),
QgsPoint( mX[vertex5], mY[vertex5] ) );
1601 if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 2 )
1604 if ( startVertex.
vertex % 2 == 1 )
1607 double x1 = mX.at( startVertex.
vertex );
1608 double y1 = mY.at( startVertex.
vertex );
1609 double x2 = mX.at( startVertex.
vertex + 1 );
1610 double y2 = mY.at( startVertex.
vertex + 1 );
1611 double x3 = mX.at( startVertex.
vertex + 2 );
1612 double y3 = mY.at( startVertex.
vertex + 2 );
1619 std::reverse( copy->mX.begin(), copy->mX.end() );
1620 std::reverse( copy->mY.begin(), copy->mY.end() );
1623 std::reverse( copy->mZ.begin(), copy->mZ.end() );
1627 std::reverse( copy->mM.begin(), copy->mM.end() );
1637 double distanceTraversed = 0;
1639 if ( totalPoints == 0 )
1648 const double *x = mX.constData();
1649 const double *y = mY.constData();
1650 const double *z =
is3D() ? mZ.constData() :
nullptr;
1651 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1653 double prevX = *x++;
1654 double prevY = *y++;
1655 double prevZ = z ? *z++ : 0.0;
1656 double prevM = m ? *m++ : 0.0;
1660 return new QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1663 for (
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
1672 double z2 = z ? *z++ : 0.0;
1673 double m2 = m ? *m++ : 0.0;
1677 double z3 = z ? *z++ : 0.0;
1678 double m3 = m ? *m++ : 0.0;
1684 const double distanceToPoint = std::min( distance - distanceTraversed,
segmentLength );
1686 QgsPoint( pointType, x2, y2, z2, m2 ),
1687 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToPoint ) );
1703 if ( startDistance < 0 && endDistance < 0 )
1706 endDistance = std::max( startDistance, endDistance );
1709 if ( totalPoints == 0 )
1712 QVector< QgsPoint > substringPoints;
1713 substringPoints.reserve( totalPoints );
1721 const double *x = mX.constData();
1722 const double *y = mY.constData();
1723 const double *z =
is3D() ? mZ.constData() :
nullptr;
1724 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1726 double distanceTraversed = 0;
1727 double prevX = *x++;
1728 double prevY = *y++;
1729 double prevZ = z ? *z++ : 0.0;
1730 double prevM = m ? *m++ : 0.0;
1731 bool foundStart =
false;
1733 if ( startDistance < 0 )
1736 for (
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
1745 double z2 = z ? *z++ : 0.0;
1746 double m2 = m ? *m++ : 0.0;
1750 double z3 = z ? *z++ : 0.0;
1751 double m3 = m ? *m++ : 0.0;
1753 bool addedSegmentEnd =
false;
1755 if ( distanceTraversed <= startDistance && startDistance < distanceTraversed +
segmentLength )
1758 const double distanceToStart = startDistance - distanceTraversed;
1760 QgsPoint( pointType, x2, y2, z2, m2 ),
1761 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToStart );
1764 const bool endPointOnSegment = distanceTraversed +
segmentLength > endDistance;
1765 if ( endPointOnSegment )
1767 const double distanceToEnd = endDistance - distanceTraversed;
1768 const double midPointDistance = ( distanceToEnd - distanceToStart ) * 0.5 + distanceToStart;
1771 QgsPoint( pointType, x2, y2, z2, m2 ),
1772 QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
1774 QgsPoint( pointType, x2, y2, z2, m2 ),
1775 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
1776 addedSegmentEnd =
true;
1780 const double midPointDistance = (
segmentLength - distanceToStart ) * 0.5 + distanceToStart;
1783 QgsPoint( pointType, x2, y2, z2, m2 ),
1784 QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
1785 <<
QgsPoint( pointType, x3, y3, z3, m3 );
1786 addedSegmentEnd =
true;
1790 if ( !addedSegmentEnd && foundStart && ( distanceTraversed +
segmentLength > endDistance ) )
1793 const double distanceToEnd = endDistance - distanceTraversed;
1796 QgsPoint( pointType, x2, y2, z2, m2 ),
1797 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd / 2.0 )
1800 QgsPoint( pointType, x2, y2, z2, m2 ),
1801 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
1803 else if ( !addedSegmentEnd && foundStart )
1805 substringPoints <<
QgsPoint( pointType, x2, y2, z2, m2 )
1806 <<
QgsPoint( pointType, x3, y3, z3, m3 );
1814 if ( distanceTraversed >= endDistance )
1819 if ( !foundStart &&
qgsDoubleNear( distanceTraversed, startDistance ) )
1821 substringPoints <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1822 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1823 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1826 std::unique_ptr< QgsCircularString > result = std::make_unique< QgsCircularString >();
1827 result->setPoints( substringPoints );
1828 return result.release();
1841 mZ.reserve( nPoints );
1842 for (
int i = 0; i < nPoints; ++i )
1859 mM.reserve( nPoints );
1860 for (
int i = 0; i < nPoints; ++i )
1893 std::swap( mX, mY );
VertexType
Types of vertex.
@ Curve
An intermediate point on a segment defining the curvature of the segment.
@ Segment
The actual start or end point of a segment.
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 isMeasure() const
Returns true if the geometry contains m values.
bool is3D() const
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.
Qgis::WkbType wkbType() const
Returns the WKB type 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.
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts of the geometry.
static endian_t endian()
Returns whether this machine uses big or little endian.
A 3-dimensional box composed of x, y, z coordinates.
void combineWith(const QgsBox3D &box)
Expands the bbox so that it covers both the original rectangle and the given rectangle.
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.
QString geometryType() const override
Returns a unique string representing the geometry type.
void points(QgsPointSequence &pts) const override
Returns a list of points within 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.
QgsPoint endPoint() const override
Returns the end point of the curve.
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.
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.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
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.
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.
void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) override
Transforms the geometry using a coordinate transform.
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.
QgsBox3D calculateBoundingBox3D() const override
Calculates the minimal 3D bounding box for the geometry.
QgsPoint startPoint() const override
Returns the starting point of the curve.
bool pointAt(int node, QgsPoint &point, Qgis::VertexType &type) const override
Returns the point and vertex id of a point within the curve.
bool isEmpty() const override
Returns true if the geometry is empty.
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.
int numPoints() const override
Returns the number of points in 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.
void drawAsPolygon(QPainter &p) const override
Draws the curve as a polygon on the specified QPainter.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
int dimension() const override
Returns the inherent dimension of the geometry.
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.
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.
double zAt(int index) const override
Returns the z-coordinate of the specified node in the line string.
bool insertVertex(QgsVertexId position, const QgsPoint &vertex) override
Inserts a vertex into the geometry.
QgsCircularString()
Constructs an empty circular string.
QgsPoint pointN(int i) const
Returns the point at index i within the circular string.
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...
double mAt(int index) const override
Returns the m-coordinate of the specified node in the line string.
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.
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
Tells whether the operation has been canceled already.
static double sqrDistance2D(const QgsPoint &pt1, const QgsPoint &pt2)
Returns the squared 2D distance between two points.
static double circleTangentDirection(const QgsPoint &tangentPoint, const QgsPoint &cp1, const QgsPoint &cp2, const QgsPoint &cp3)
Calculates the direction angle of a circle tangent (clockwise from north in radians)
static QgsPoint pointOnLineWithDistance(const QgsPoint &startPoint, const QgsPoint &directionPoint, double distance)
Returns a point a specified distance toward a second point.
static bool angleOnCircle(double angle, double angle1, double angle2, double angle3)
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)
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)
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)
Length of a circular string segment defined by 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 QgsPoint interpolatePointOnArc(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double distance)
Interpolates a point on an arc defined by three points, pt1, pt2 and pt3.
static bool circleAngleBetween(double angle, double angle1, double angle2, bool clockwise)
Returns true if, in a circle, angle is between angle1 and angle2.
static double ccwAngle(double dy, double dx)
Returns the counter clockwise angle between a line with components dx, dy and the line with dx > 0 an...
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 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 QString pointsToWKT(const QgsPointSequence &points, int precision, bool is3D, bool isMeasure)
Returns a WKT coordinate list.
static QgsPoint segmentMidPointFromCenter(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint ¢er, bool useShortestArc=true)
Calculates the midpoint on the circle passing through p1 and p2, with the specified center coordinate...
static int leftOfLine(const double x, const double y, const double x1, const double y1, const double x2, const double y2)
Returns a value < 0 if the point (x, y) is left of the line from (x1, y1) -> (x2, y2).
static double averageAngle(double x1, double y1, double x2, double y2, double x3, double y3)
Calculates the average angle (in radians) between the two linear segments from (x1,...
static void circleCenterRadius(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double &radius, double ¢erX, double ¢erY)
Returns radius and center of the circle through pt1, pt2, pt3.
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 setY(double y)
Sets the point's y-coordinate.
void setX(double x)
Sets the point's x-coordinate.
A rectangle specified with double values.
static Qgis::WkbType dropM(Qgis::WkbType type)
Drops the m dimension (if present) for a WKB type and returns the new type.
static Qgis::WkbType dropZ(Qgis::WkbType type)
Drops the z dimension (if present) for a WKB type and returns the new type.
static Qgis::WkbType addM(Qgis::WkbType type)
Adds the m dimension to a WKB type and returns the new type.
static Qgis::WkbType addZ(Qgis::WkbType type)
Adds the z dimension to a WKB type and returns the new type.
static bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
static bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
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.