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 );
128 auto result = std::make_unique< QgsCircularString >();
130 return result.release();
135 const QgsCircularString *otherLine = qgsgeometry_cast<const QgsCircularString *>( other );
139 const int size = mX.size();
140 const int otherSize = otherLine->mX.size();
141 if ( size > otherSize )
145 else if ( size < otherSize )
152 else if ( !
is3D() && otherLine->
is3D() )
154 const bool considerZ =
is3D();
162 for (
int i = 0; i < size; i++ )
164 const double x = mX[i];
165 const double otherX = otherLine->mX[i];
170 else if ( x > otherX )
175 const double y = mY[i];
176 const double otherY = otherLine->mY[i];
181 else if ( y > otherY )
188 const double z = mZ[i];
189 const double otherZ = otherLine->mZ[i];
195 else if ( z > otherZ )
203 const double m = mM[i];
204 const double otherM = otherLine->mM[i];
210 else if ( m > otherM )
221 return QStringLiteral(
"CircularString" );
248 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
251 double zMin = std::numeric_limits<double>::quiet_NaN();
252 double zMax = std::numeric_limits<double>::quiet_NaN();
255 zMin = *std::min_element( mZ.begin() + i, mZ.begin() + i + 3 );
256 zMax = *std::max_element( mZ.begin() + i, mZ.begin() + i + 3 );
260 bbox =
QgsBox3D( box2d, zMin, zMax );
268 if ( nPoints > 0 && nPoints % 2 == 0 )
270 double z = std::numeric_limits<double>::quiet_NaN();
281 z = mZ[ nPoints - 1 ];
283 bbox.
combineWith( mX[ nPoints - 1 ], mY[ nPoints - 1 ], z );
290 const int size = mX.size();
291 if ( index < 1 || index >= size - 1 )
294 const bool useZ =
is3D();
297 QVector<double> newX( size );
298 QVector<double> newY( size );
299 QVector<double> newZ( useZ ? size : 0 );
300 QVector<double> newM( useM ? size : 0 );
301 auto it = std::copy( mX.constBegin() + index, mX.constEnd() - 1, newX.begin() );
302 it = std::copy( mX.constBegin(), mX.constBegin() + index, it );
303 *it = *newX.constBegin();
304 mX = std::move( newX );
306 it = std::copy( mY.constBegin() + index, mY.constEnd() - 1, newY.begin() );
307 it = std::copy( mY.constBegin(), mY.constBegin() + index, it );
308 *it = *newY.constBegin();
309 mY = std::move( newY );
312 it = std::copy( mZ.constBegin() + index, mZ.constEnd() - 1, newZ.begin() );
313 it = std::copy( mZ.constBegin(), mZ.constBegin() + index, it );
314 *it = *newZ.constBegin();
315 mZ = std::move( newZ );
319 it = std::copy( mM.constBegin() + index, mM.constEnd() - 1, newM.begin() );
320 it = std::copy( mM.constBegin(), mM.constBegin() + index, it );
321 *it = *newM.constBegin();
322 mM = std::move( newM );
328 double centerX, centerY, radius;
337 bbox.combineExtentWith( pt3.
x(), pt3.
y() );
339 QgsPointSequence compassPoints = compassPointsOnSegment( p1Angle, p2Angle, p3Angle, centerX, centerY, radius );
340 QgsPointSequence::const_iterator cpIt = compassPoints.constBegin();
341 for ( ; cpIt != compassPoints.constEnd(); ++cpIt )
343 bbox.combineExtentWith( cpIt->x(), cpIt->y() );
348QgsPointSequence QgsCircularString::compassPointsOnSegment(
double p1Angle,
double p2Angle,
double p3Angle,
double centerX,
double centerY,
double radius )
352 QgsPoint nPoint( centerX, centerY + radius );
353 QgsPoint ePoint( centerX + radius, centerY );
354 QgsPoint sPoint( centerX, centerY - radius );
355 QgsPoint wPoint( centerX - radius, centerY );
357 if ( p3Angle >= p1Angle )
359 if ( p2Angle > p1Angle && p2Angle < p3Angle )
361 if ( p1Angle <= 90 && p3Angle >= 90 )
363 pointList.append( nPoint );
365 if ( p1Angle <= 180 && p3Angle >= 180 )
367 pointList.append( wPoint );
369 if ( p1Angle <= 270 && p3Angle >= 270 )
371 pointList.append( sPoint );
376 pointList.append( ePoint );
377 if ( p1Angle >= 90 || p3Angle <= 90 )
379 pointList.append( nPoint );
381 if ( p1Angle >= 180 || p3Angle <= 180 )
383 pointList.append( wPoint );
385 if ( p1Angle >= 270 || p3Angle <= 270 )
387 pointList.append( sPoint );
393 if ( p2Angle < p1Angle && p2Angle > p3Angle )
395 if ( p1Angle >= 270 && p3Angle <= 270 )
397 pointList.append( sPoint );
399 if ( p1Angle >= 180 && p3Angle <= 180 )
401 pointList.append( wPoint );
403 if ( p1Angle >= 90 && p3Angle <= 90 )
405 pointList.append( nPoint );
410 pointList.append( ePoint );
411 if ( p1Angle <= 270 || p3Angle >= 270 )
413 pointList.append( sPoint );
415 if ( p1Angle <= 180 || p3Angle >= 180 )
417 pointList.append( wPoint );
419 if ( p1Angle <= 90 || p3Angle >= 90 )
421 pointList.append( nPoint );
442 const bool hasZ =
is3D();
446 mX.resize( nVertices );
447 mY.resize( nVertices );
449 mZ.resize( nVertices );
453 mM.resize( nVertices );
456 for (
int i = 0; i < nVertices; ++i )
483 parts.second =
parts.second.remove(
'(' ).remove(
')' );
484 QString secondWithoutParentheses =
parts.second;
485 secondWithoutParentheses = secondWithoutParentheses.simplified().remove(
' ' );
486 if ( (
parts.second.compare( QLatin1String(
"EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
487 secondWithoutParentheses.isEmpty() )
500 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
511 wkb << static_cast<quint32>(
wkbType() );
523 wkt += QLatin1String(
"EMPTY" );
536 std::unique_ptr< QgsLineString > line(
curveToLine() );
537 QDomElement gml = line->asGml2( doc,
precision, ns, axisOrder );
546 QDomElement elemCurve = doc.createElementNS( ns, QStringLiteral(
"Curve" ) );
551 QDomElement elemSegments = doc.createElementNS( ns, QStringLiteral(
"segments" ) );
552 QDomElement elemArcString = doc.createElementNS( ns, QStringLiteral(
"ArcString" ) );
554 elemSegments.appendChild( elemArcString );
555 elemCurve.appendChild( elemSegments );
563 std::unique_ptr< QgsLineString > line(
curveToLine() );
576 error = QObject::tr(
"CircularString has less than 3 points and is not empty." );
587 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
618 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
633 bool res =
snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM,
634 result->mX, result->mY, result->mZ, result->mM,
false );
636 return result.release();
643 std::unique_ptr< QgsLineString > line(
curveToLine() );
644 return line->simplifyByDistance( tolerance );
649 if ( mX.count() <= 3 )
652 double prevX = mX.at( 0 );
653 double prevY = mY.at( 0 );
655 bool useZ = hasZ && useZValues;
656 double prevZ = useZ ? mZ.at( 0 ) : 0;
658 int remaining = mX.count();
661 while ( i + 1 < remaining )
663 double currentCurveX = mX.at( i );
664 double currentCurveY = mY.at( i );
665 double currentX = mX.at( i + 1 );
666 double currentY = mY.at( i + 1 );
667 double currentZ = useZ ? mZ.at( i + 1 ) : 0;
700 return std::min( mX.size(), mY.size() );
705 const int size = mX.size();
709 const double *x = mX.constData();
710 const double *y = mY.constData();
711 const bool useZ =
is3D();
713 const double *z = useZ ? mZ.constData() :
nullptr;
714 const double *m = useM ? mM.constData() :
nullptr;
716 for (
int i = 0; i < size; i += 2 )
745 if ( i < 0 || std::min( mX.size(), mY.size() ) <= i )
750 double x = mX.at( i );
751 double y = mY.at( i );
782 if ( index >= 0 && index < mX.size() )
783 return mX.at( index );
790 if ( index >= 0 && index < mY.size() )
791 return mY.at( index );
798 if ( index >= 0 && index < mZ.size() )
799 return mZ.at( index );
806 if ( index >= 0 && index < mM.size() )
807 return mM.at( index );
819 int size = mX.size();
821 double *srcX = mX.data();
822 double *srcY = mY.data();
823 double *srcM = hasM ? mM.data() :
nullptr;
824 double *srcZ = hasZ ? mZ.data() :
nullptr;
827 for (
int i = 0; i < size; ++i )
831 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
832 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
860 int size = mX.size();
862 double *srcX = mX.data();
863 double *srcY = mY.data();
864 double *srcM = hasM ? mM.data() :
nullptr;
865 double *srcZ = hasZ ? mZ.data() :
nullptr;
867 double *destX = srcX;
868 double *destY = srcY;
869 double *destM = srcM;
870 double *destZ = srcZ;
872 int filteredPoints = 0;
873 for (
int i = 0; i < size; ++i )
877 double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
878 double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
880 if ( filter(
QgsPoint( x, y, z, m ) ) )
892 mX.resize( filteredPoints );
893 mY.resize( filteredPoints );
895 mZ.resize( filteredPoints );
897 mM.resize( filteredPoints );
906 int size = mX.size();
908 double *srcX = mX.data();
909 double *srcY = mY.data();
910 double *srcM = hasM ? mM.data() :
nullptr;
911 double *srcZ = hasZ ? mZ.data() :
nullptr;
913 for (
int i = 0; i < size; ++i )
917 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
918 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
932 const bool useZ =
is3D();
935 const int size = mX.size();
937 return std::make_tuple( std::make_unique< QgsCircularString >(), std::make_unique< QgsCircularString >() );
939 index = std::clamp( index, 0, size - 1 );
941 const int part1Size = index + 1;
942 QVector< double > x1( part1Size );
943 QVector< double > y1( part1Size );
944 QVector< double > z1( useZ ? part1Size : 0 );
945 QVector< double > m1( useM ? part1Size : 0 );
947 const double *sourceX = mX.constData();
948 const double *sourceY = mY.constData();
949 const double *sourceZ = useZ ? mZ.constData() :
nullptr;
950 const double *sourceM = useM ? mM.constData() :
nullptr;
952 double *destX = x1.data();
953 double *destY = y1.data();
954 double *destZ = useZ ? z1.data() :
nullptr;
955 double *destM = useM ? m1.data() :
nullptr;
957 std::copy( sourceX, sourceX + part1Size, destX );
958 std::copy( sourceY, sourceY + part1Size, destY );
960 std::copy( sourceZ, sourceZ + part1Size, destZ );
962 std::copy( sourceM, sourceM + part1Size, destM );
964 const int part2Size = size - index;
966 return std::make_tuple( std::make_unique< QgsCircularString >( x1, y1, z1, m1 ), std::make_unique< QgsCircularString >() );
968 QVector< double > x2( part2Size );
969 QVector< double > y2( part2Size );
970 QVector< double > z2( useZ ? part2Size : 0 );
971 QVector< double > m2( useM ? part2Size : 0 );
974 destZ = useZ ? z2.data() :
nullptr;
975 destM = useM ? m2.data() :
nullptr;
976 std::copy( sourceX + index, sourceX + size, destX );
977 std::copy( sourceY + index, sourceY + size, destY );
979 std::copy( sourceZ + index, sourceZ + size, destZ );
981 std::copy( sourceM + index, sourceM + size, destM );
984 return std::make_tuple( std::make_unique< QgsCircularString >(), std::make_unique< QgsCircularString >( x2, y2, z2, m2 ) );
986 return std::make_tuple( std::make_unique< QgsCircularString >( x1, y1, z1, m1 ), std::make_unique< QgsCircularString >( x2, y2, z2, m2 ) );
993 for (
int i = 0; i < nPts; ++i )
995 pts.push_back(
pointN( i ) );
1015 bool hasZ = firstPt.
is3D();
1020 mX.resize(
points.size() );
1021 mY.resize(
points.size() );
1024 mZ.resize(
points.size() );
1032 mM.resize(
points.size() );
1039 for (
int i = 0; i <
points.size(); ++i )
1045 double z =
points.at( i ).z();
1046 mZ[i] = std::isnan( z ) ? 0 : z;
1050 double m =
points.at( i ).m();
1051 mM[i] = std::isnan( m ) ? 0 : m;
1058 if ( !line || line->
isEmpty() )
1101 mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
1114 mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
1132 double *zArray = mZ.data();
1136 bool useDummyZ = !hasZ || !transformZ;
1139 zArray =
new double[nPoints];
1140 for (
int i = 0; i < nPoints; ++i )
1159 for (
int i = 0; i < nPoints; ++i )
1162 t.map( mX.at( i ), mY.at( i ), &x, &y );
1167 mZ[i] = mZ.at( i ) * zScale + zTranslate;
1171 mM[i] = mM.at( i ) * mScale + mTranslate;
1176void arcTo( QPainterPath &path, QPointF pt1, QPointF pt2, QPointF pt3 )
1178 double centerX, centerY, radius;
1180 radius, centerX, centerY );
1185 double diameter = 2 * radius;
1186 path.arcTo( centerX - radius, centerY - radius, diameter, diameter, -p1Angle, -sweepAngle );
1197 if ( path.isEmpty() || path.currentPosition() != QPointF( mX[0], mY[0] ) )
1199 path.moveTo( QPointF( mX[0], mY[0] ) );
1202 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
1204 arcTo( path, QPointF( mX[i], mY[i] ), QPointF( mX[i + 1], mY[i + 1] ), QPointF( mX[i + 2], mY[i + 2] ) );
1208 if ( nPoints % 2 == 0 )
1210 path.lineTo( mX[ nPoints - 1 ], mY[ nPoints - 1 ] );
1221 if ( position.
vertex >= mX.size() || position.
vertex < 1 )
1226 mX.insert( position.
vertex, vertex.
x() );
1227 mY.insert( position.
vertex, vertex.
y() );
1230 mZ.insert( position.
vertex, vertex.
z() );
1234 mM.insert( position.
vertex, vertex.
m() );
1237 bool vertexNrEven = ( position.
vertex % 2 == 0 );
1252 if ( position.
vertex < 0 || position.
vertex >= mX.size() )
1257 mX[position.
vertex] = newPos.
x();
1258 mY[position.
vertex] = newPos.
y();
1261 mZ[position.
vertex] = newPos.
z();
1265 mM[position.
vertex] = newPos.
m();
1274 if ( nVertices < 4 )
1279 if ( position.
vertex < 0 || position.
vertex > ( nVertices - 1 ) )
1284 if ( position.
vertex < ( nVertices - 2 ) )
1317 double minDist = std::numeric_limits<double>::max();
1320 int minDistLeftOf = 0;
1322 double currentDist = 0.0;
1325 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
1327 currentDist = closestPointOnArc( mX[i], mY[i], mX[i + 1], mY[i + 1], mX[i + 2], mY[i + 2], pt, segmentPt, vertexAfter, leftOf, epsilon );
1328 if ( currentDist < minDist )
1330 minDist = currentDist;
1331 minDistSegmentPoint = segmentPt;
1335 minDistLeftOf = *leftOf;
1340 if ( minDist == std::numeric_limits<double>::max() )
1343 segmentPt = minDistSegmentPoint;
1344 vertexAfter = minDistVertexAfter;
1345 vertexAfter.
part = 0;
1346 vertexAfter.
ring = 0;
1349 *leftOf =
qgsDoubleNear( minDist, 0.0 ) ? 0 : minDistLeftOf;
1375 for (
int i = 0; i < maxIndex; i += 2 )
1378 QgsPoint p2( mX[i + 1], mY[i + 1] );
1379 QgsPoint p3( mX[i + 2], mY[i + 2] );
1389 mSummedUpArea += 0.5 * ( mX[i] * mY[i + 2] - mY[i] * mX[i + 2] );
1392 double midPointX = ( p1.
x() + p3.
x() ) / 2.0;
1393 double midPointY = ( p1.
y() + p3.
y() ) / 2.0;
1395 double radius, centerX, centerY;
1399 double r2 = radius * radius;
1410 double cov = 0.5 - d * std::sqrt( r2 - d * d ) / ( M_PI * r2 ) - M_1_PI * std::asin( d / radius );
1411 double circleChordArea = 0;
1412 if ( circlePointLeftOfLine == centerPointLeftOfLine )
1414 circleChordArea = M_PI * r2 * ( 1 - cov );
1418 circleChordArea = M_PI * r2 * cov;
1421 if ( !circlePointLeftOfLine )
1440double QgsCircularString::closestPointOnArc(
double x1,
double y1,
double x2,
double y2,
double x3,
double y3,
1443 double radius, centerX, centerY;
1468 segmentPt = ( distPtPt1 <= distPtPt3 ) ? pt1 : pt3;
1469 vertexAfter.
vertex = ( distPtPt1 <= distPtPt3 ) ? 1 : 2;
1476 segmentPt.
setX( pt.
x() );
1477 segmentPt.
setY( pt.
y() );
1483 double sqrDistancePointToCenter = pt.
distanceSquared( centerX, centerY );
1484 *
leftOf = clockwise ? ( sqrDistancePointToCenter > radius * radius ? -1 : 1 )
1485 : ( sqrDistancePointToCenter < radius * radius ? -1 : 1 );
1491void QgsCircularString::insertVertexBetween(
int after,
int before,
int pointOnCircle )
1493 double xAfter = mX.at( after );
1494 double yAfter = mY.at( after );
1495 double xBefore = mX.at( before );
1496 double yBefore = mY.at( before );
1497 double xOnCircle = mX.at( pointOnCircle );
1498 double yOnCircle = mY.at( pointOnCircle );
1500 double radius, centerX, centerY;
1503 double x = ( xAfter + xBefore ) / 2.0;
1504 double y = ( yAfter + yBefore ) / 2.0;
1507 mX.insert( before, newVertex.
x() );
1508 mY.insert( before, newVertex.
y() );
1512 mZ.insert( before, ( mZ[after] + mZ[before] ) / 2.0 );
1516 mM.insert( before, ( mM[after] + mM[before] ) / 2.0 );
1529 int before = vId.
vertex - 1;
1531 int after = vId.
vertex + 1;
1533 if ( vId.
vertex % 2 != 0 )
1563 int vertex1 = vId.
vertex - 2;
1564 int vertex2 = vId.
vertex - 1;
1565 int vertex3 = vId.
vertex;
1567 QgsPoint( mX[vertex1], mY[vertex1] ),
QgsPoint( mX[vertex2], mY[vertex2] ),
QgsPoint( mX[vertex3], mY[vertex3] ) );
1568 int vertex4 = vId.
vertex + 1;
1569 int vertex5 = vId.
vertex + 2;
1571 QgsPoint( mX[vertex3], mY[vertex3] ),
QgsPoint( mX[vertex4], mY[vertex4] ),
QgsPoint( mX[vertex5], mY[vertex5] ) );
1580 if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 2 )
1583 if ( startVertex.
vertex % 2 == 1 )
1586 double x1 = mX.at( startVertex.
vertex );
1587 double y1 = mY.at( startVertex.
vertex );
1588 double x2 = mX.at( startVertex.
vertex + 1 );
1589 double y2 = mY.at( startVertex.
vertex + 1 );
1590 double x3 = mX.at( startVertex.
vertex + 2 );
1591 double y3 = mY.at( startVertex.
vertex + 2 );
1598 std::reverse( copy->mX.begin(), copy->mX.end() );
1599 std::reverse( copy->mY.begin(), copy->mY.end() );
1602 std::reverse( copy->mZ.begin(), copy->mZ.end() );
1606 std::reverse( copy->mM.begin(), copy->mM.end() );
1618 double distanceTraversed = 0;
1620 if ( totalPoints == 0 )
1629 const double *x = mX.constData();
1630 const double *y = mY.constData();
1631 const double *z =
is3D() ? mZ.constData() :
nullptr;
1632 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1634 double prevX = *x++;
1635 double prevY = *y++;
1636 double prevZ = z ? *z++ : 0.0;
1637 double prevM = m ? *m++ : 0.0;
1641 return new QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1644 for (
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
1653 double z2 = z ? *z++ : 0.0;
1654 double m2 = m ? *m++ : 0.0;
1658 double z3 = z ? *z++ : 0.0;
1659 double m3 = m ? *m++ : 0.0;
1665 const double distanceToPoint = std::min( distance - distanceTraversed,
segmentLength );
1667 QgsPoint( pointType, x2, y2, z2, m2 ),
1668 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToPoint ) );
1684 if ( startDistance < 0 && endDistance < 0 )
1687 endDistance = std::max( startDistance, endDistance );
1690 if ( totalPoints == 0 )
1693 QVector< QgsPoint > substringPoints;
1694 substringPoints.reserve( totalPoints );
1702 const double *x = mX.constData();
1703 const double *y = mY.constData();
1704 const double *z =
is3D() ? mZ.constData() :
nullptr;
1705 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1707 double distanceTraversed = 0;
1708 double prevX = *x++;
1709 double prevY = *y++;
1710 double prevZ = z ? *z++ : 0.0;
1711 double prevM = m ? *m++ : 0.0;
1712 bool foundStart =
false;
1714 if ( startDistance < 0 )
1717 for (
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
1726 double z2 = z ? *z++ : 0.0;
1727 double m2 = m ? *m++ : 0.0;
1731 double z3 = z ? *z++ : 0.0;
1732 double m3 = m ? *m++ : 0.0;
1734 bool addedSegmentEnd =
false;
1736 if ( distanceTraversed <= startDistance && startDistance < distanceTraversed +
segmentLength )
1739 const double distanceToStart = startDistance - distanceTraversed;
1741 QgsPoint( pointType, x2, y2, z2, m2 ),
1742 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToStart );
1745 const bool endPointOnSegment = distanceTraversed +
segmentLength > endDistance;
1746 if ( endPointOnSegment )
1748 const double distanceToEnd = endDistance - distanceTraversed;
1749 const double midPointDistance = ( distanceToEnd - distanceToStart ) * 0.5 + distanceToStart;
1752 QgsPoint( pointType, x2, y2, z2, m2 ),
1753 QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
1755 QgsPoint( pointType, x2, y2, z2, m2 ),
1756 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
1757 addedSegmentEnd =
true;
1761 const double midPointDistance = (
segmentLength - distanceToStart ) * 0.5 + distanceToStart;
1764 QgsPoint( pointType, x2, y2, z2, m2 ),
1765 QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
1766 <<
QgsPoint( pointType, x3, y3, z3, m3 );
1767 addedSegmentEnd =
true;
1771 if ( !addedSegmentEnd && foundStart && ( distanceTraversed +
segmentLength > endDistance ) )
1774 const double distanceToEnd = endDistance - distanceTraversed;
1777 QgsPoint( pointType, x2, y2, z2, m2 ),
1778 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd / 2.0 )
1781 QgsPoint( pointType, x2, y2, z2, m2 ),
1782 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
1784 else if ( !addedSegmentEnd && foundStart )
1786 substringPoints <<
QgsPoint( pointType, x2, y2, z2, m2 )
1787 <<
QgsPoint( pointType, x3, y3, z3, m3 );
1795 if ( distanceTraversed >= endDistance )
1800 if ( !foundStart &&
qgsDoubleNear( distanceTraversed, startDistance ) )
1802 substringPoints <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1803 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1804 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1807 std::unique_ptr< QgsCircularString > result = std::make_unique< QgsCircularString >();
1808 result->setPoints( substringPoints );
1809 return result.release();
1822 mZ.reserve( nPoints );
1823 for (
int i = 0; i < nPoints; ++i )
1840 mM.reserve( nPoints );
1841 for (
int i = 0; i < nPoints; ++i )
1874 std::swap( mX, mY );
QFlags< GeometryValidityFlag > GeometryValidityFlags
Geometry validity flags.
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
Indicates the direction (forward or inverse) of a transform.
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.
QFlags< WkbFlag > WkbFlags
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.
QgsCircularString * snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0, bool removeRedundantPoints=false) const override
Makes a new geometry with all the points or vertices snapped to the closest point of the grid.
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 * 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.
QgsAbstractGeometry * simplifyByDistance(double tolerance) const override
Simplifies the geometry by applying the Douglas Peucker simplification by distance algorithm.
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
Returns a WKB representation of the geometry.
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
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
bool mHasCachedSummedUpArea
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 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, bool removeRedundantPoints) const
Helper function for QgsCurve subclasses to snap to grids.
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 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 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 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 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 bool circleAngleBetween(double angle, double angle1, double angle2, bool clockwise)
Returns true if, in a circle, angle is between angle1 and angle2.
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 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 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 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 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.
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 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 Q_DECL_DEPRECATED double sqrDistance2D(double x1, double y1, double x2, double y2)
Returns the squared 2D distance between (x1, y1) and (x2, y2).
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...
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.
double distanceSquared(double x, double y) const
Returns the Cartesian 2D squared distance between this point a specified x, y 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.