32#include <QPainterPath> 
   34#include <nlohmann/json.hpp> 
   44  bool hasZ = p1.
is3D();
 
   77  int pointCount = std::min( x.size(), y.size() );
 
   78  if ( x.size() == pointCount )
 
   84    mX = x.mid( 0, pointCount );
 
   86  if ( y.size() == pointCount )
 
   92    mY = y.mid( 0, pointCount );
 
   94  if ( !z.isEmpty() && z.count() >= pointCount )
 
   97    if ( z.size() == pointCount )
 
  103      mZ = z.mid( 0, pointCount );
 
  106  if ( !m.isEmpty() && m.count() >= pointCount )
 
  109    if ( m.size() == pointCount )
 
  115      mM = m.mid( 0, pointCount );
 
  135  if ( mX.count() != otherLine->mX.count() )
 
  138  for ( 
int i = 0; i < mX.count(); ++i )
 
  156  auto result = std::make_unique< QgsCircularString >();
 
  158  return result.release();
 
  163  const QgsCircularString *otherLine = qgsgeometry_cast<const QgsCircularString *>( other );
 
  167  const int size = mX.size();
 
  168  const int otherSize = otherLine->mX.size();
 
  169  if ( size > otherSize )
 
  173  else if ( size < otherSize )
 
  180  else if ( !
is3D() && otherLine->
is3D() )
 
  182  const bool considerZ = 
is3D();
 
  190  for ( 
int i = 0; i < size; i++ )
 
  192    const double x = mX[i];
 
  193    const double otherX = otherLine->mX[i];
 
  198    else if ( x > otherX )
 
  203    const double y = mY[i];
 
  204    const double otherY = otherLine->mY[i];
 
  209    else if ( y > otherY )
 
  216      const double z = mZ[i];
 
  217      const double otherZ = otherLine->mZ[i];
 
  223      else if ( z > otherZ )
 
  231      const double m = mM[i];
 
  232      const double otherM = otherLine->mM[i];
 
  238      else if ( m > otherM )
 
  249  return QStringLiteral( 
"CircularString" );
 
  276  for ( 
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
 
  280      bbox = segmentBoundingBox( 
QgsPoint( mX[i], mY[i] ), 
QgsPoint( mX[i + 1], mY[i + 1] ), 
QgsPoint( mX[i + 2], mY[i + 2] ) );
 
  289  if ( nPoints > 0 && nPoints % 2 == 0 )
 
  302  const int size = mX.size();
 
  303  if ( index < 1 || index >= size - 1 )
 
  306  const bool useZ = 
is3D();
 
  309  QVector<double> newX( size );
 
  310  QVector<double> newY( size );
 
  311  QVector<double> newZ( useZ ? size : 0 );
 
  312  QVector<double> newM( useM ? size : 0 );
 
  313  auto it = std::copy( mX.constBegin() + index, mX.constEnd() - 1, newX.begin() );
 
  314  it = std::copy( mX.constBegin(), mX.constBegin() + index, it );
 
  315  *it = *newX.constBegin();
 
  316  mX = std::move( newX );
 
  318  it = std::copy( mY.constBegin() + index, mY.constEnd() - 1, newY.begin() );
 
  319  it = std::copy( mY.constBegin(), mY.constBegin() + index, it );
 
  320  *it = *newY.constBegin();
 
  321  mY = std::move( newY );
 
  324    it = std::copy( mZ.constBegin() + index, mZ.constEnd() - 1, newZ.begin() );
 
  325    it = std::copy( mZ.constBegin(), mZ.constBegin() + index, it );
 
  326    *it = *newZ.constBegin();
 
  327    mZ = std::move( newZ );
 
  331    it = std::copy( mM.constBegin() + index, mM.constEnd() - 1, newM.begin() );
 
  332    it = std::copy( mM.constBegin(), mM.constBegin() + index, it );
 
  333    *it = *newM.constBegin();
 
  334    mM = std::move( newM );
 
  340  double centerX, centerY, radius;
 
  349  bbox.combineExtentWith( pt3.
x(), pt3.
y() );
 
  351  QgsPointSequence compassPoints = compassPointsOnSegment( p1Angle, p2Angle, p3Angle, centerX, centerY, radius );
 
  352  QgsPointSequence::const_iterator cpIt = compassPoints.constBegin();
 
  353  for ( ; cpIt != compassPoints.constEnd(); ++cpIt )
 
  355    bbox.combineExtentWith( cpIt->x(), cpIt->y() );
 
  360QgsPointSequence QgsCircularString::compassPointsOnSegment( 
double p1Angle, 
double p2Angle, 
double p3Angle, 
double centerX, 
double centerY, 
double radius )
 
  364  QgsPoint nPoint( centerX, centerY + radius );
 
  365  QgsPoint ePoint( centerX + radius, centerY );
 
  366  QgsPoint sPoint( centerX, centerY - radius );
 
  367  QgsPoint wPoint( centerX - radius, centerY );
 
  369  if ( p3Angle >= p1Angle )
 
  371    if ( p2Angle > p1Angle && p2Angle < p3Angle )
 
  373      if ( p1Angle <= 90 && p3Angle >= 90 )
 
  375        pointList.append( nPoint );
 
  377      if ( p1Angle <= 180 && p3Angle >= 180 )
 
  379        pointList.append( wPoint );
 
  381      if ( p1Angle <= 270 && p3Angle >= 270 )
 
  383        pointList.append( sPoint );
 
  388      pointList.append( ePoint );
 
  389      if ( p1Angle >= 90 || p3Angle <= 90 )
 
  391        pointList.append( nPoint );
 
  393      if ( p1Angle >= 180 || p3Angle <= 180 )
 
  395        pointList.append( wPoint );
 
  397      if ( p1Angle >= 270 || p3Angle <= 270 )
 
  399        pointList.append( sPoint );
 
  405    if ( p2Angle < p1Angle && p2Angle > p3Angle )
 
  407      if ( p1Angle >= 270 && p3Angle <= 270 )
 
  409        pointList.append( sPoint );
 
  411      if ( p1Angle >= 180 && p3Angle <= 180 )
 
  413        pointList.append( wPoint );
 
  415      if ( p1Angle >= 90 && p3Angle <= 90 )
 
  417        pointList.append( nPoint );
 
  422      pointList.append( ePoint );
 
  423      if ( p1Angle <= 270 || p3Angle >= 270 )
 
  425        pointList.append( sPoint );
 
  427      if ( p1Angle <= 180 || p3Angle >= 180 )
 
  429        pointList.append( wPoint );
 
  431      if ( p1Angle <= 90 || p3Angle >= 90 )
 
  433        pointList.append( nPoint );
 
  458  mX.resize( nVertices );
 
  459  mY.resize( nVertices );
 
  460  hasZ ? mZ.resize( nVertices ) : mZ.clear();
 
  461  hasM ? mM.resize( nVertices ) : mM.clear();
 
  462  for ( 
int i = 0; i < nVertices; ++i )
 
  489  parts.second = 
parts.second.remove( 
'(' ).remove( 
')' );
 
  490  QString secondWithoutParentheses = 
parts.second;
 
  491  secondWithoutParentheses = secondWithoutParentheses.simplified().remove( 
' ' );
 
  492  if ( ( 
parts.second.compare( QLatin1String( 
"EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
 
  493       secondWithoutParentheses.isEmpty() )
 
  506  int binarySize = 
sizeof( char ) + 
sizeof( quint32 ) + 
sizeof( quint32 );
 
  517  wkb << static_cast<quint32>( 
wkbType() );
 
  529    wkt += QLatin1String( 
"EMPTY" );
 
  542  std::unique_ptr< QgsLineString > line( 
curveToLine() );
 
  543  QDomElement gml = line->asGml2( doc, 
precision, ns, axisOrder );
 
  552  QDomElement elemCurve = doc.createElementNS( ns, QStringLiteral( 
"Curve" ) );
 
  557  QDomElement elemSegments = doc.createElementNS( ns, QStringLiteral( 
"segments" ) );
 
  558  QDomElement elemArcString = doc.createElementNS( ns, QStringLiteral( 
"ArcString" ) );
 
  560  elemSegments.appendChild( elemArcString );
 
  561  elemCurve.appendChild( elemSegments );
 
  569  std::unique_ptr< QgsLineString > line( 
curveToLine() );
 
  582    error = QObject::tr( 
"CircularString has less than 3 points and is not empty." );
 
  593  for ( 
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
 
  624  for ( 
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
 
  638  bool res = 
snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM,
 
  639                                result->mX, result->mY, result->mZ, result->mM );
 
  641    return result.release();
 
  648  if ( mX.count() <= 3 )
 
  651  double prevX = mX.at( 0 );
 
  652  double prevY = mY.at( 0 );
 
  654  bool useZ = hasZ && useZValues;
 
  655  double prevZ = useZ ? mZ.at( 0 ) : 0;
 
  657  int remaining = mX.count();
 
  660  while ( i + 1 < remaining )
 
  662    double currentCurveX = mX.at( i );
 
  663    double currentCurveY = mY.at( i );
 
  664    double currentX = mX.at( i + 1 );
 
  665    double currentY = mY.at( i + 1 );
 
  666    double currentZ = useZ ? mZ.at( i + 1 ) : 0;
 
  699  return std::min( mX.size(), mY.size() );
 
  704  const int size = mX.size();
 
  708  const double *x = mX.constData();
 
  709  const double *y = mY.constData();
 
  710  const bool useZ = 
is3D();
 
  712  const double *z = useZ ? mZ.constData() : 
nullptr;
 
  713  const double *m = useM ? mM.constData() : 
nullptr;
 
  715  for ( 
int i = 0; i < size; i += 2 )
 
  744  if ( i < 0 || std::min( mX.size(), mY.size() ) <= i )
 
  749  double x = mX.at( i );
 
  750  double y = mY.at( i );
 
  781  if ( index >= 0 && index < mX.size() )
 
  782    return mX.at( index );
 
  789  if ( index >= 0 && index < mY.size() )
 
  790    return mY.at( index );
 
  802  int size = mX.size();
 
  804  double *srcX = mX.data();
 
  805  double *srcY = mY.data();
 
  806  double *srcM = hasM ? mM.data() : 
nullptr;
 
  807  double *srcZ = hasZ ? mZ.data() : 
nullptr;
 
  810  for ( 
int i = 0; i < size; ++i )
 
  814    double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
 
  815    double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
 
  843  int size = mX.size();
 
  845  double *srcX = mX.data(); 
 
  846  double *srcY = mY.data(); 
 
  847  double *srcM = hasM ? mM.data() : 
nullptr; 
 
  848  double *srcZ = hasZ ? mZ.data() : 
nullptr; 
 
  850  double *destX = srcX;
 
  851  double *destY = srcY;
 
  852  double *destM = srcM;
 
  853  double *destZ = srcZ;
 
  855  int filteredPoints = 0;
 
  856  for ( 
int i = 0; i < size; ++i )
 
  860    double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
 
  861    double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
 
  863    if ( filter( 
QgsPoint( x, y, z, m ) ) )
 
  875  mX.resize( filteredPoints );
 
  876  mY.resize( filteredPoints );
 
  878    mZ.resize( filteredPoints );
 
  880    mM.resize( filteredPoints );
 
  889  int size = mX.size();
 
  891  double *srcX = mX.data();
 
  892  double *srcY = mY.data();
 
  893  double *srcM = hasM ? mM.data() : 
nullptr;
 
  894  double *srcZ = hasZ ? mZ.data() : 
nullptr;
 
  896  for ( 
int i = 0; i < size; ++i )
 
  900    double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
 
  901    double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
 
  915  const bool useZ = 
is3D();
 
  918  const int size = mX.size();
 
  920    return std::make_tuple( std::make_unique< QgsCircularString >(), std::make_unique< QgsCircularString >() );
 
  922  index = std::clamp( index, 0, size - 1 );
 
  924  const int part1Size = index + 1;
 
  925  QVector< double > x1( part1Size );
 
  926  QVector< double > y1( part1Size );
 
  927  QVector< double > z1( useZ ? part1Size : 0 );
 
  928  QVector< double > m1( useM ? part1Size : 0 );
 
  930  const double *sourceX = mX.constData();
 
  931  const double *sourceY = mY.constData();
 
  932  const double *sourceZ = useZ ? mZ.constData() : 
nullptr;
 
  933  const double *sourceM = useM ? mM.constData() : 
nullptr;
 
  935  double *destX = x1.data();
 
  936  double *destY = y1.data();
 
  937  double *destZ = useZ ? z1.data() : 
nullptr;
 
  938  double *destM = useM ? m1.data() : 
nullptr;
 
  940  std::copy( sourceX, sourceX + part1Size, destX );
 
  941  std::copy( sourceY, sourceY + part1Size, destY );
 
  943    std::copy( sourceZ, sourceZ + part1Size, destZ );
 
  945    std::copy( sourceM, sourceM + part1Size, destM );
 
  947  const int part2Size = size - index;
 
  949    return std::make_tuple( std::make_unique< QgsCircularString >( x1, y1, z1, m1 ), std::make_unique< QgsCircularString >() );
 
  951  QVector< double > x2( part2Size );
 
  952  QVector< double > y2( part2Size );
 
  953  QVector< double > z2( useZ ? part2Size : 0 );
 
  954  QVector< double > m2( useM ? part2Size : 0 );
 
  957  destZ = useZ ? z2.data() : 
nullptr;
 
  958  destM = useM ? m2.data() : 
nullptr;
 
  959  std::copy( sourceX + index, sourceX + size, destX );
 
  960  std::copy( sourceY + index, sourceY + size, destY );
 
  962    std::copy( sourceZ + index, sourceZ + size, destZ );
 
  964    std::copy( sourceM + index, sourceM + size, destM );
 
  967    return std::make_tuple( std::make_unique< QgsCircularString >(), std::make_unique< QgsCircularString >( x2, y2, z2, m2 ) );
 
  969    return std::make_tuple( std::make_unique< QgsCircularString >( x1, y1, z1, m1 ), std::make_unique< QgsCircularString >( x2, y2, z2, m2 ) );
 
  976  for ( 
int i = 0; i < nPts; ++i )
 
  978    pts.push_back( 
pointN( i ) );
 
  998  bool hasZ = firstPt.
is3D();
 
 1003  mX.resize( 
points.size() );
 
 1004  mY.resize( 
points.size() );
 
 1007    mZ.resize( 
points.size() );
 
 1015    mM.resize( 
points.size() );
 
 1022  for ( 
int i = 0; i < 
points.size(); ++i )
 
 1028      double z = 
points.at( i ).z();
 
 1029      mZ[i] = std::isnan( z ) ? 0 : z;
 
 1033      double m = 
points.at( i ).m();
 
 1034      mM[i] = std::isnan( m ) ? 0 : m;
 
 1041  if ( !line || line->
isEmpty() )
 
 1084      mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
 
 1097      mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
 
 1115  double *zArray = mZ.data();
 
 1119  bool useDummyZ = !hasZ || !transformZ;
 
 1122    zArray = 
new double[nPoints];
 
 1123    for ( 
int i = 0; i < nPoints; ++i )
 
 1142  for ( 
int i = 0; i < nPoints; ++i )
 
 1145    t.map( mX.at( i ), mY.at( i ), &x, &y );
 
 1150      mZ[i] = mZ.at( i ) * zScale + zTranslate;
 
 1154      mM[i] = mM.at( i ) * mScale + mTranslate;
 
 1159void arcTo( QPainterPath &path, QPointF pt1, QPointF pt2, QPointF pt3 )
 
 1161  double centerX, centerY, radius;
 
 1163                                        radius, centerX, centerY );
 
 1168  double diameter = 2 * radius;
 
 1169  path.arcTo( centerX - radius, centerY - radius, diameter, diameter, -p1Angle, -sweepAngle );
 
 1180  if ( path.isEmpty() || path.currentPosition() != QPointF( mX[0], mY[0] ) )
 
 1182    path.moveTo( QPointF( mX[0], mY[0] ) );
 
 1185  for ( 
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
 
 1187    arcTo( path, QPointF( mX[i], mY[i] ), QPointF( mX[i + 1], mY[i + 1] ), QPointF( mX[i + 2], mY[i + 2] ) );
 
 1191  if ( nPoints % 2 == 0 )
 
 1193    path.lineTo( mX[ nPoints - 1 ], mY[ nPoints - 1 ] );
 
 1204  if ( position.
vertex >= mX.size() || position.
vertex < 1 )
 
 1209  mX.insert( position.
vertex, vertex.
x() );
 
 1210  mY.insert( position.
vertex, vertex.
y() );
 
 1213    mZ.insert( position.
vertex, vertex.
z() );
 
 1217    mM.insert( position.
vertex, vertex.
m() );
 
 1220  bool vertexNrEven = ( position.
vertex % 2 == 0 );
 
 1235  if ( position.
vertex < 0 || position.
vertex >= mX.size() )
 
 1240  mX[position.
vertex] = newPos.
x();
 
 1241  mY[position.
vertex] = newPos.
y();
 
 1244    mZ[position.
vertex] = newPos.
z();
 
 1248    mM[position.
vertex] = newPos.
m();
 
 1257  if ( nVertices < 4 ) 
 
 1262  if ( position.
vertex < 0 || position.
vertex > ( nVertices - 1 ) )
 
 1267  if ( position.
vertex < ( nVertices - 2 ) )
 
 1300  double minDist = std::numeric_limits<double>::max();
 
 1303  int minDistLeftOf = 0;
 
 1305  double currentDist = 0.0;
 
 1308  for ( 
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
 
 1310    currentDist = closestPointOnArc( mX[i], mY[i], mX[i + 1], mY[i + 1], mX[i + 2], mY[i + 2], pt, segmentPt, vertexAfter, 
leftOf, epsilon );
 
 1311    if ( currentDist < minDist )
 
 1313      minDist = currentDist;
 
 1314      minDistSegmentPoint = segmentPt;
 
 1323  if ( minDist == std::numeric_limits<double>::max() )
 
 1326  segmentPt = minDistSegmentPoint;
 
 1327  vertexAfter = minDistVertexAfter;
 
 1328  vertexAfter.
part = 0;
 
 1329  vertexAfter.
ring = 0;
 
 1344  type = ( node % 2 == 0 ) ? Qgis::VertexType::Segment : Qgis::VertexType::Curve;
 
 1358  for ( 
int i = 0; i < maxIndex; i += 2 )
 
 1361    QgsPoint p2( mX[i + 1], mY[i + 1] );
 
 1362    QgsPoint p3( mX[i + 2], mY[i + 2] );
 
 1372    mSummedUpArea += 0.5 * ( mX[i] * mY[i + 2] - mY[i] * mX[i + 2] );
 
 1375    double midPointX = ( p1.
x() + p3.
x() ) / 2.0;
 
 1376    double midPointY = ( p1.
y() + p3.
y() ) / 2.0;
 
 1378    double radius, centerX, centerY;
 
 1382    double r2 = radius * radius;
 
 1393    double cov = 0.5 - d * std::sqrt( r2 - d * d ) / ( M_PI * r2 ) - M_1_PI * std::asin( d / radius );
 
 1394    double circleChordArea = 0;
 
 1395    if ( circlePointLeftOfLine == centerPointLeftOfLine )
 
 1397      circleChordArea = M_PI * r2 * ( 1 - cov );
 
 1401      circleChordArea = M_PI * r2 * cov;
 
 1404    if ( !circlePointLeftOfLine )
 
 1423double QgsCircularString::closestPointOnArc( 
double x1, 
double y1, 
double x2, 
double y2, 
double x3, 
double y3,
 
 1426  double radius, centerX, centerY;
 
 1451    segmentPt = ( distPtPt1 <= distPtPt3 ) ? pt1 : pt3;
 
 1452    vertexAfter.
vertex = ( distPtPt1 <= distPtPt3 ) ? 1 : 2;
 
 1459    segmentPt.
setX( pt.
x() );
 
 1460    segmentPt.
setY( pt.
y() );
 
 1466    double sqrDistancePointToCenter = ( pt.
x() - centerX ) * ( pt.
x() - centerX ) + ( pt.
y() - centerY ) * ( pt.
y() - centerY );
 
 1467    *
leftOf = clockwise ? ( sqrDistancePointToCenter > radius * radius ? -1 : 1 )
 
 1468              : ( sqrDistancePointToCenter < radius * radius ? -1 : 1 );
 
 1474void QgsCircularString::insertVertexBetween( 
int after, 
int before, 
int pointOnCircle )
 
 1476  double xAfter = mX.at( after );
 
 1477  double yAfter = mY.at( after );
 
 1478  double xBefore = mX.at( before );
 
 1479  double yBefore = mY.at( before );
 
 1480  double xOnCircle = mX.at( pointOnCircle );
 
 1481  double yOnCircle = mY.at( pointOnCircle );
 
 1483  double radius, centerX, centerY;
 
 1486  double x = ( xAfter + xBefore ) / 2.0;
 
 1487  double y = ( yAfter + yBefore ) / 2.0;
 
 1490  mX.insert( before, newVertex.
x() );
 
 1491  mY.insert( before, newVertex.
y() );
 
 1495    mZ.insert( before, ( mZ[after] + mZ[before] ) / 2.0 );
 
 1499    mM.insert( before, ( mM[after] + mM[before] ) / 2.0 );
 
 1512  int before = vId.
vertex - 1;
 
 1514  int after = vId.
vertex + 1;
 
 1516  if ( vId.
vertex % 2 != 0 ) 
 
 1546      int vertex1 = vId.
vertex - 2;
 
 1547      int vertex2 = vId.
vertex - 1;
 
 1548      int vertex3 = vId.
vertex;
 
 1550                      QgsPoint( mX[vertex1], mY[vertex1] ), 
QgsPoint( mX[vertex2], mY[vertex2] ), 
QgsPoint( mX[vertex3], mY[vertex3] ) );
 
 1551      int vertex4 = vId.
vertex + 1;
 
 1552      int vertex5 = vId.
vertex + 2;
 
 1554                      QgsPoint( mX[vertex3], mY[vertex3] ), 
QgsPoint( mX[vertex4], mY[vertex4] ), 
QgsPoint( mX[vertex5], mY[vertex5] ) );
 
 1563  if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 2 )
 
 1566  if ( startVertex.
vertex % 2 == 1 )
 
 1569  double x1 = mX.at( startVertex.
vertex );
 
 1570  double y1 = mY.at( startVertex.
vertex );
 
 1571  double x2 = mX.at( startVertex.
vertex + 1 );
 
 1572  double y2 = mY.at( startVertex.
vertex + 1 );
 
 1573  double x3 = mX.at( startVertex.
vertex + 2 );
 
 1574  double y3 = mY.at( startVertex.
vertex + 2 );
 
 1581  std::reverse( copy->mX.begin(), copy->mX.end() );
 
 1582  std::reverse( copy->mY.begin(), copy->mY.end() );
 
 1585    std::reverse( copy->mZ.begin(), copy->mZ.end() );
 
 1589    std::reverse( copy->mM.begin(), copy->mM.end() );
 
 1599  double distanceTraversed = 0;
 
 1601  if ( totalPoints == 0 )
 
 1610  const double *x = mX.constData();
 
 1611  const double *y = mY.constData();
 
 1612  const double *z = 
is3D() ? mZ.constData() : 
nullptr;
 
 1613  const double *m = 
isMeasure() ? mM.constData() : 
nullptr;
 
 1615  double prevX = *x++;
 
 1616  double prevY = *y++;
 
 1617  double prevZ = z ? *z++ : 0.0;
 
 1618  double prevM = m ? *m++ : 0.0;
 
 1622    return new QgsPoint( pointType, prevX, prevY, prevZ, prevM );
 
 1625  for ( 
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
 
 1634    double z2 = z ? *z++ : 0.0;
 
 1635    double m2 = m ? *m++ : 0.0;
 
 1639    double z3 = z ? *z++ : 0.0;
 
 1640    double m3 = m ? *m++ : 0.0;
 
 1646      const double distanceToPoint = std::min( distance - distanceTraversed, 
segmentLength );
 
 1648                           QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1649                           QgsPoint( pointType, x3, y3, z3, m3 ), distanceToPoint ) );
 
 1665  if ( startDistance < 0 && endDistance < 0 )
 
 1668  endDistance = std::max( startDistance, endDistance );
 
 1671  if ( totalPoints == 0 )
 
 1674  QVector< QgsPoint > substringPoints;
 
 1675  substringPoints.reserve( totalPoints );
 
 1683  const double *x = mX.constData();
 
 1684  const double *y = mY.constData();
 
 1685  const double *z = 
is3D() ? mZ.constData() : 
nullptr;
 
 1686  const double *m = 
isMeasure() ? mM.constData() : 
nullptr;
 
 1688  double distanceTraversed = 0;
 
 1689  double prevX = *x++;
 
 1690  double prevY = *y++;
 
 1691  double prevZ = z ? *z++ : 0.0;
 
 1692  double prevM = m ? *m++ : 0.0;
 
 1693  bool foundStart = 
false;
 
 1695  if ( startDistance < 0 )
 
 1698  for ( 
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
 
 1707    double z2 = z ? *z++ : 0.0;
 
 1708    double m2 = m ? *m++ : 0.0;
 
 1712    double z3 = z ? *z++ : 0.0;
 
 1713    double m3 = m ? *m++ : 0.0;
 
 1715    bool addedSegmentEnd = 
false;
 
 1717    if ( distanceTraversed <= startDistance && startDistance < distanceTraversed + 
segmentLength )
 
 1720      const double distanceToStart = startDistance - distanceTraversed;
 
 1722                                  QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1723                                  QgsPoint( pointType, x3, y3, z3, m3 ), distanceToStart );
 
 1726      const bool endPointOnSegment = distanceTraversed + 
segmentLength > endDistance;
 
 1727      if ( endPointOnSegment )
 
 1729        const double distanceToEnd = endDistance - distanceTraversed;
 
 1730        const double midPointDistance = ( distanceToEnd - distanceToStart ) * 0.5 + distanceToStart;
 
 1733                            QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1734                            QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
 
 1736                            QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1737                            QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
 
 1738        addedSegmentEnd = 
true;
 
 1742        const double midPointDistance = ( 
segmentLength - distanceToStart ) * 0.5 + distanceToStart;
 
 1745                            QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1746                            QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
 
 1747                        << 
QgsPoint( pointType, x3, y3, z3, m3 );
 
 1748        addedSegmentEnd = 
true;
 
 1752    if ( !addedSegmentEnd && foundStart && ( distanceTraversed + 
segmentLength > endDistance ) )
 
 1755      const double distanceToEnd = endDistance - distanceTraversed;
 
 1758                      QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1759                      QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd / 2.0 )
 
 1762                          QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1763                          QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
 
 1765    else if ( !addedSegmentEnd && foundStart )
 
 1767      substringPoints << 
QgsPoint( pointType, x2, y2, z2, m2 )
 
 1768                      << 
QgsPoint( pointType, x3, y3, z3, m3 );
 
 1776    if ( distanceTraversed >= endDistance )
 
 1781  if ( !foundStart && 
qgsDoubleNear( distanceTraversed, startDistance ) )
 
 1783    substringPoints << 
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
 
 1784                    << 
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
 
 1785                    << 
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
 
 1788  std::unique_ptr< QgsCircularString > result = std::make_unique< QgsCircularString >();
 
 1789  result->setPoints( substringPoints );
 
 1790  return result.release();
 
 1803  mZ.reserve( nPoints );
 
 1804  for ( 
int i = 0; i < nPoints; ++i )
 
 1821  mM.reserve( nPoints );
 
 1822  for ( 
int i = 0; i < nPoints; ++i )
 
 1855  std::swap( mX, mY );
 
VertexType
Types of vertex.
 
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.
 
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
 
QgsWkbTypes::Type mWkbType
 
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.
 
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, QgsWkbTypes::Type baseGeomType)
Updates the geometry type based on whether sub geometries contain z or 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.
 
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.
 
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.
 
QgsWkbTypes::Type 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 QPair< QgsWkbTypes::Type, 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 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 void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
 
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 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 bool hasM(Type type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
 
Type
The WKB type describes the number of dimensions a geometry has.
 
static Type dropZ(Type type) SIP_HOLDGIL
Drops the z dimension (if present) for a WKB type and returns the new type.
 
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
 
static Type addZ(Type type) SIP_HOLDGIL
Adds the z dimension to a WKB type and returns the new type.
 
static bool hasZ(Type type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
 
static Type addM(Type type) SIP_HOLDGIL
Adds the m dimension to a WKB type and returns the new type.
 
static Type dropM(Type type) SIP_HOLDGIL
Drops the m dimension (if present) for a WKB type and returns the new 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.