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 );
456 mX.resize( nVertices );
457 mY.resize( nVertices );
458 hasZ ? mZ.resize( nVertices ) : mZ.clear();
459 hasM ? mM.resize( nVertices ) : mM.clear();
460 for (
int i = 0; i < nVertices; ++i )
487 parts.second =
parts.second.remove(
'(' ).remove(
')' );
488 QString secondWithoutParentheses =
parts.second;
489 secondWithoutParentheses = secondWithoutParentheses.simplified().remove(
' ' );
490 if ( (
parts.second.compare( QLatin1String(
"EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
491 secondWithoutParentheses.isEmpty() )
504 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
515 wkb << static_cast<quint32>(
wkbType() );
527 wkt += QLatin1String(
"EMPTY" );
540 std::unique_ptr< QgsLineString > line(
curveToLine() );
541 QDomElement gml = line->asGml2( doc,
precision, ns, axisOrder );
550 QDomElement elemCurve = doc.createElementNS( ns, QStringLiteral(
"Curve" ) );
555 QDomElement elemSegments = doc.createElementNS( ns, QStringLiteral(
"segments" ) );
556 QDomElement elemArcString = doc.createElementNS( ns, QStringLiteral(
"ArcString" ) );
558 elemSegments.appendChild( elemArcString );
559 elemCurve.appendChild( elemSegments );
567 std::unique_ptr< QgsLineString > line(
curveToLine() );
580 error = QObject::tr(
"CircularString has less than 3 points and is not empty." );
591 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
622 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
636 bool res =
snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM,
637 result->mX, result->mY, result->mZ, result->mM );
639 return result.release();
646 if ( mX.count() <= 3 )
649 double prevX = mX.at( 0 );
650 double prevY = mY.at( 0 );
652 bool useZ = hasZ && useZValues;
653 double prevZ = useZ ? mZ.at( 0 ) : 0;
655 int remaining = mX.count();
658 while ( i + 1 < remaining )
660 double currentCurveX = mX.at( i );
661 double currentCurveY = mY.at( i );
662 double currentX = mX.at( i + 1 );
663 double currentY = mY.at( i + 1 );
664 double currentZ = useZ ? mZ.at( i + 1 ) : 0;
697 return std::min( mX.size(), mY.size() );
702 const int size = mX.size();
706 const double *x = mX.constData();
707 const double *y = mY.constData();
708 const bool useZ =
is3D();
710 const double *z = useZ ? mZ.constData() :
nullptr;
711 const double *m = useM ? mM.constData() :
nullptr;
713 for (
int i = 0; i < size; i += 2 )
742 if ( i < 0 || std::min( mX.size(), mY.size() ) <= i )
747 double x = mX.at( i );
748 double y = mY.at( i );
779 if ( index >= 0 && index < mX.size() )
780 return mX.at( index );
787 if ( index >= 0 && index < mY.size() )
788 return mY.at( index );
795 if ( index >= 0 && index < mZ.size() )
796 return mZ.at( index );
803 if ( index >= 0 && index < mM.size() )
804 return mM.at( index );
816 int size = mX.size();
818 double *srcX = mX.data();
819 double *srcY = mY.data();
820 double *srcM = hasM ? mM.data() :
nullptr;
821 double *srcZ = hasZ ? mZ.data() :
nullptr;
824 for (
int i = 0; i < size; ++i )
828 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
829 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
857 int size = mX.size();
859 double *srcX = mX.data();
860 double *srcY = mY.data();
861 double *srcM = hasM ? mM.data() :
nullptr;
862 double *srcZ = hasZ ? mZ.data() :
nullptr;
864 double *destX = srcX;
865 double *destY = srcY;
866 double *destM = srcM;
867 double *destZ = srcZ;
869 int filteredPoints = 0;
870 for (
int i = 0; i < size; ++i )
874 double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
875 double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
877 if ( filter(
QgsPoint( x, y, z, m ) ) )
889 mX.resize( filteredPoints );
890 mY.resize( filteredPoints );
892 mZ.resize( filteredPoints );
894 mM.resize( filteredPoints );
903 int size = mX.size();
905 double *srcX = mX.data();
906 double *srcY = mY.data();
907 double *srcM = hasM ? mM.data() :
nullptr;
908 double *srcZ = hasZ ? mZ.data() :
nullptr;
910 for (
int i = 0; i < size; ++i )
914 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
915 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
929 const bool useZ =
is3D();
932 const int size = mX.size();
934 return std::make_tuple( std::make_unique< QgsCircularString >(), std::make_unique< QgsCircularString >() );
936 index = std::clamp( index, 0, size - 1 );
938 const int part1Size = index + 1;
939 QVector< double > x1( part1Size );
940 QVector< double > y1( part1Size );
941 QVector< double > z1( useZ ? part1Size : 0 );
942 QVector< double > m1( useM ? part1Size : 0 );
944 const double *sourceX = mX.constData();
945 const double *sourceY = mY.constData();
946 const double *sourceZ = useZ ? mZ.constData() :
nullptr;
947 const double *sourceM = useM ? mM.constData() :
nullptr;
949 double *destX = x1.data();
950 double *destY = y1.data();
951 double *destZ = useZ ? z1.data() :
nullptr;
952 double *destM = useM ? m1.data() :
nullptr;
954 std::copy( sourceX, sourceX + part1Size, destX );
955 std::copy( sourceY, sourceY + part1Size, destY );
957 std::copy( sourceZ, sourceZ + part1Size, destZ );
959 std::copy( sourceM, sourceM + part1Size, destM );
961 const int part2Size = size - index;
963 return std::make_tuple( std::make_unique< QgsCircularString >( x1, y1, z1, m1 ), std::make_unique< QgsCircularString >() );
965 QVector< double > x2( part2Size );
966 QVector< double > y2( part2Size );
967 QVector< double > z2( useZ ? part2Size : 0 );
968 QVector< double > m2( useM ? part2Size : 0 );
971 destZ = useZ ? z2.data() :
nullptr;
972 destM = useM ? m2.data() :
nullptr;
973 std::copy( sourceX + index, sourceX + size, destX );
974 std::copy( sourceY + index, sourceY + size, destY );
976 std::copy( sourceZ + index, sourceZ + size, destZ );
978 std::copy( sourceM + index, sourceM + size, destM );
981 return std::make_tuple( std::make_unique< QgsCircularString >(), std::make_unique< QgsCircularString >( x2, y2, z2, m2 ) );
983 return std::make_tuple( std::make_unique< QgsCircularString >( x1, y1, z1, m1 ), std::make_unique< QgsCircularString >( x2, y2, z2, m2 ) );
990 for (
int i = 0; i < nPts; ++i )
992 pts.push_back(
pointN( i ) );
1012 bool hasZ = firstPt.
is3D();
1017 mX.resize(
points.size() );
1018 mY.resize(
points.size() );
1021 mZ.resize(
points.size() );
1029 mM.resize(
points.size() );
1036 for (
int i = 0; i <
points.size(); ++i )
1042 double z =
points.at( i ).z();
1043 mZ[i] = std::isnan( z ) ? 0 : z;
1047 double m =
points.at( i ).m();
1048 mM[i] = std::isnan( m ) ? 0 : m;
1055 if ( !line || line->
isEmpty() )
1098 mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
1111 mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
1129 double *zArray = mZ.data();
1133 bool useDummyZ = !hasZ || !transformZ;
1136 zArray =
new double[nPoints];
1137 for (
int i = 0; i < nPoints; ++i )
1156 for (
int i = 0; i < nPoints; ++i )
1159 t.map( mX.at( i ), mY.at( i ), &x, &y );
1164 mZ[i] = mZ.at( i ) * zScale + zTranslate;
1168 mM[i] = mM.at( i ) * mScale + mTranslate;
1173void arcTo( QPainterPath &path, QPointF pt1, QPointF pt2, QPointF pt3 )
1175 double centerX, centerY, radius;
1177 radius, centerX, centerY );
1182 double diameter = 2 * radius;
1183 path.arcTo( centerX - radius, centerY - radius, diameter, diameter, -p1Angle, -sweepAngle );
1194 if ( path.isEmpty() || path.currentPosition() != QPointF( mX[0], mY[0] ) )
1196 path.moveTo( QPointF( mX[0], mY[0] ) );
1199 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
1201 arcTo( path, QPointF( mX[i], mY[i] ), QPointF( mX[i + 1], mY[i + 1] ), QPointF( mX[i + 2], mY[i + 2] ) );
1205 if ( nPoints % 2 == 0 )
1207 path.lineTo( mX[ nPoints - 1 ], mY[ nPoints - 1 ] );
1218 if ( position.
vertex >= mX.size() || position.
vertex < 1 )
1223 mX.insert( position.
vertex, vertex.
x() );
1224 mY.insert( position.
vertex, vertex.
y() );
1227 mZ.insert( position.
vertex, vertex.
z() );
1231 mM.insert( position.
vertex, vertex.
m() );
1234 bool vertexNrEven = ( position.
vertex % 2 == 0 );
1249 if ( position.
vertex < 0 || position.
vertex >= mX.size() )
1254 mX[position.
vertex] = newPos.
x();
1255 mY[position.
vertex] = newPos.
y();
1258 mZ[position.
vertex] = newPos.
z();
1262 mM[position.
vertex] = newPos.
m();
1271 if ( nVertices < 4 )
1276 if ( position.
vertex < 0 || position.
vertex > ( nVertices - 1 ) )
1281 if ( position.
vertex < ( nVertices - 2 ) )
1314 double minDist = std::numeric_limits<double>::max();
1317 int minDistLeftOf = 0;
1319 double currentDist = 0.0;
1322 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
1324 currentDist = closestPointOnArc( mX[i], mY[i], mX[i + 1], mY[i + 1], mX[i + 2], mY[i + 2], pt, segmentPt, vertexAfter,
leftOf, epsilon );
1325 if ( currentDist < minDist )
1327 minDist = currentDist;
1328 minDistSegmentPoint = segmentPt;
1337 if ( minDist == std::numeric_limits<double>::max() )
1340 segmentPt = minDistSegmentPoint;
1341 vertexAfter = minDistVertexAfter;
1342 vertexAfter.
part = 0;
1343 vertexAfter.
ring = 0;
1358 type = ( node % 2 == 0 ) ? Qgis::VertexType::Segment : Qgis::VertexType::Curve;
1372 for (
int i = 0; i < maxIndex; i += 2 )
1375 QgsPoint p2( mX[i + 1], mY[i + 1] );
1376 QgsPoint p3( mX[i + 2], mY[i + 2] );
1386 mSummedUpArea += 0.5 * ( mX[i] * mY[i + 2] - mY[i] * mX[i + 2] );
1389 double midPointX = ( p1.
x() + p3.
x() ) / 2.0;
1390 double midPointY = ( p1.
y() + p3.
y() ) / 2.0;
1392 double radius, centerX, centerY;
1396 double r2 = radius * radius;
1407 double cov = 0.5 - d * std::sqrt( r2 - d * d ) / ( M_PI * r2 ) - M_1_PI * std::asin( d / radius );
1408 double circleChordArea = 0;
1409 if ( circlePointLeftOfLine == centerPointLeftOfLine )
1411 circleChordArea = M_PI * r2 * ( 1 - cov );
1415 circleChordArea = M_PI * r2 * cov;
1418 if ( !circlePointLeftOfLine )
1437double QgsCircularString::closestPointOnArc(
double x1,
double y1,
double x2,
double y2,
double x3,
double y3,
1440 double radius, centerX, centerY;
1465 segmentPt = ( distPtPt1 <= distPtPt3 ) ? pt1 : pt3;
1466 vertexAfter.
vertex = ( distPtPt1 <= distPtPt3 ) ? 1 : 2;
1473 segmentPt.
setX( pt.
x() );
1474 segmentPt.
setY( pt.
y() );
1480 double sqrDistancePointToCenter = ( pt.
x() - centerX ) * ( pt.
x() - centerX ) + ( pt.
y() - centerY ) * ( pt.
y() - centerY );
1481 *
leftOf = clockwise ? ( sqrDistancePointToCenter > radius * radius ? -1 : 1 )
1482 : ( sqrDistancePointToCenter < radius * radius ? -1 : 1 );
1488void QgsCircularString::insertVertexBetween(
int after,
int before,
int pointOnCircle )
1490 double xAfter = mX.at( after );
1491 double yAfter = mY.at( after );
1492 double xBefore = mX.at( before );
1493 double yBefore = mY.at( before );
1494 double xOnCircle = mX.at( pointOnCircle );
1495 double yOnCircle = mY.at( pointOnCircle );
1497 double radius, centerX, centerY;
1500 double x = ( xAfter + xBefore ) / 2.0;
1501 double y = ( yAfter + yBefore ) / 2.0;
1504 mX.insert( before, newVertex.
x() );
1505 mY.insert( before, newVertex.
y() );
1509 mZ.insert( before, ( mZ[after] + mZ[before] ) / 2.0 );
1513 mM.insert( before, ( mM[after] + mM[before] ) / 2.0 );
1526 int before = vId.
vertex - 1;
1528 int after = vId.
vertex + 1;
1530 if ( vId.
vertex % 2 != 0 )
1560 int vertex1 = vId.
vertex - 2;
1561 int vertex2 = vId.
vertex - 1;
1562 int vertex3 = vId.
vertex;
1564 QgsPoint( mX[vertex1], mY[vertex1] ),
QgsPoint( mX[vertex2], mY[vertex2] ),
QgsPoint( mX[vertex3], mY[vertex3] ) );
1565 int vertex4 = vId.
vertex + 1;
1566 int vertex5 = vId.
vertex + 2;
1568 QgsPoint( mX[vertex3], mY[vertex3] ),
QgsPoint( mX[vertex4], mY[vertex4] ),
QgsPoint( mX[vertex5], mY[vertex5] ) );
1577 if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 2 )
1580 if ( startVertex.
vertex % 2 == 1 )
1583 double x1 = mX.at( startVertex.
vertex );
1584 double y1 = mY.at( startVertex.
vertex );
1585 double x2 = mX.at( startVertex.
vertex + 1 );
1586 double y2 = mY.at( startVertex.
vertex + 1 );
1587 double x3 = mX.at( startVertex.
vertex + 2 );
1588 double y3 = mY.at( startVertex.
vertex + 2 );
1595 std::reverse( copy->mX.begin(), copy->mX.end() );
1596 std::reverse( copy->mY.begin(), copy->mY.end() );
1599 std::reverse( copy->mZ.begin(), copy->mZ.end() );
1603 std::reverse( copy->mM.begin(), copy->mM.end() );
1613 double distanceTraversed = 0;
1615 if ( totalPoints == 0 )
1624 const double *x = mX.constData();
1625 const double *y = mY.constData();
1626 const double *z =
is3D() ? mZ.constData() :
nullptr;
1627 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1629 double prevX = *x++;
1630 double prevY = *y++;
1631 double prevZ = z ? *z++ : 0.0;
1632 double prevM = m ? *m++ : 0.0;
1636 return new QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1639 for (
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
1648 double z2 = z ? *z++ : 0.0;
1649 double m2 = m ? *m++ : 0.0;
1653 double z3 = z ? *z++ : 0.0;
1654 double m3 = m ? *m++ : 0.0;
1660 const double distanceToPoint = std::min( distance - distanceTraversed,
segmentLength );
1662 QgsPoint( pointType, x2, y2, z2, m2 ),
1663 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToPoint ) );
1679 if ( startDistance < 0 && endDistance < 0 )
1682 endDistance = std::max( startDistance, endDistance );
1685 if ( totalPoints == 0 )
1688 QVector< QgsPoint > substringPoints;
1689 substringPoints.reserve( totalPoints );
1697 const double *x = mX.constData();
1698 const double *y = mY.constData();
1699 const double *z =
is3D() ? mZ.constData() :
nullptr;
1700 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1702 double distanceTraversed = 0;
1703 double prevX = *x++;
1704 double prevY = *y++;
1705 double prevZ = z ? *z++ : 0.0;
1706 double prevM = m ? *m++ : 0.0;
1707 bool foundStart =
false;
1709 if ( startDistance < 0 )
1712 for (
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
1721 double z2 = z ? *z++ : 0.0;
1722 double m2 = m ? *m++ : 0.0;
1726 double z3 = z ? *z++ : 0.0;
1727 double m3 = m ? *m++ : 0.0;
1729 bool addedSegmentEnd =
false;
1731 if ( distanceTraversed <= startDistance && startDistance < distanceTraversed +
segmentLength )
1734 const double distanceToStart = startDistance - distanceTraversed;
1736 QgsPoint( pointType, x2, y2, z2, m2 ),
1737 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToStart );
1740 const bool endPointOnSegment = distanceTraversed +
segmentLength > endDistance;
1741 if ( endPointOnSegment )
1743 const double distanceToEnd = endDistance - distanceTraversed;
1744 const double midPointDistance = ( distanceToEnd - distanceToStart ) * 0.5 + distanceToStart;
1747 QgsPoint( pointType, x2, y2, z2, m2 ),
1748 QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
1750 QgsPoint( pointType, x2, y2, z2, m2 ),
1751 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
1752 addedSegmentEnd =
true;
1756 const double midPointDistance = (
segmentLength - distanceToStart ) * 0.5 + distanceToStart;
1759 QgsPoint( pointType, x2, y2, z2, m2 ),
1760 QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
1761 <<
QgsPoint( pointType, x3, y3, z3, m3 );
1762 addedSegmentEnd =
true;
1766 if ( !addedSegmentEnd && foundStart && ( distanceTraversed +
segmentLength > endDistance ) )
1769 const double distanceToEnd = endDistance - distanceTraversed;
1772 QgsPoint( pointType, x2, y2, z2, m2 ),
1773 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd / 2.0 )
1776 QgsPoint( pointType, x2, y2, z2, m2 ),
1777 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
1779 else if ( !addedSegmentEnd && foundStart )
1781 substringPoints <<
QgsPoint( pointType, x2, y2, z2, m2 )
1782 <<
QgsPoint( pointType, x3, y3, z3, m3 );
1790 if ( distanceTraversed >= endDistance )
1795 if ( !foundStart &&
qgsDoubleNear( distanceTraversed, startDistance ) )
1797 substringPoints <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1798 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1799 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1802 std::unique_ptr< QgsCircularString > result = std::make_unique< QgsCircularString >();
1803 result->setPoints( substringPoints );
1804 return result.release();
1817 mZ.reserve( nPoints );
1818 for (
int i = 0; i < nPoints; ++i )
1835 mM.reserve( nPoints );
1836 for (
int i = 0; i < nPoints; ++i )
1869 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.