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() );
 
 
 1616  double distanceTraversed = 0;
 
 1618  if ( totalPoints == 0 )
 
 1627  const double *x = mX.constData();
 
 1628  const double *y = mY.constData();
 
 1629  const double *z = 
is3D() ? mZ.constData() : 
nullptr;
 
 1630  const double *m = 
isMeasure() ? mM.constData() : 
nullptr;
 
 1632  double prevX = *x++;
 
 1633  double prevY = *y++;
 
 1634  double prevZ = z ? *z++ : 0.0;
 
 1635  double prevM = m ? *m++ : 0.0;
 
 1639    return new QgsPoint( pointType, prevX, prevY, prevZ, prevM );
 
 1642  for ( 
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
 
 1651    double z2 = z ? *z++ : 0.0;
 
 1652    double m2 = m ? *m++ : 0.0;
 
 1656    double z3 = z ? *z++ : 0.0;
 
 1657    double m3 = m ? *m++ : 0.0;
 
 1663      const double distanceToPoint = std::min( distance - distanceTraversed, 
segmentLength );
 
 1665                           QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1666                           QgsPoint( pointType, x3, y3, z3, m3 ), distanceToPoint ) );
 
 
 1682  if ( startDistance < 0 && endDistance < 0 )
 
 1685  endDistance = std::max( startDistance, endDistance );
 
 1688  if ( totalPoints == 0 )
 
 1691  QVector< QgsPoint > substringPoints;
 
 1692  substringPoints.reserve( totalPoints );
 
 1700  const double *x = mX.constData();
 
 1701  const double *y = mY.constData();
 
 1702  const double *z = 
is3D() ? mZ.constData() : 
nullptr;
 
 1703  const double *m = 
isMeasure() ? mM.constData() : 
nullptr;
 
 1705  double distanceTraversed = 0;
 
 1706  double prevX = *x++;
 
 1707  double prevY = *y++;
 
 1708  double prevZ = z ? *z++ : 0.0;
 
 1709  double prevM = m ? *m++ : 0.0;
 
 1710  bool foundStart = 
false;
 
 1712  if ( startDistance < 0 )
 
 1715  for ( 
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
 
 1724    double z2 = z ? *z++ : 0.0;
 
 1725    double m2 = m ? *m++ : 0.0;
 
 1729    double z3 = z ? *z++ : 0.0;
 
 1730    double m3 = m ? *m++ : 0.0;
 
 1732    bool addedSegmentEnd = 
false;
 
 1734    if ( distanceTraversed <= startDistance && startDistance < distanceTraversed + 
segmentLength )
 
 1737      const double distanceToStart = startDistance - distanceTraversed;
 
 1739                                  QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1740                                  QgsPoint( pointType, x3, y3, z3, m3 ), distanceToStart );
 
 1743      const bool endPointOnSegment = distanceTraversed + 
segmentLength > endDistance;
 
 1744      if ( endPointOnSegment )
 
 1746        const double distanceToEnd = endDistance - distanceTraversed;
 
 1747        const double midPointDistance = ( distanceToEnd - distanceToStart ) * 0.5 + distanceToStart;
 
 1750                            QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1751                            QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
 
 1753                            QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1754                            QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
 
 1755        addedSegmentEnd = 
true;
 
 1759        const double midPointDistance = ( 
segmentLength - distanceToStart ) * 0.5 + distanceToStart;
 
 1762                            QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1763                            QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
 
 1764                        << 
QgsPoint( pointType, x3, y3, z3, m3 );
 
 1765        addedSegmentEnd = 
true;
 
 1769    if ( !addedSegmentEnd && foundStart && ( distanceTraversed + 
segmentLength > endDistance ) )
 
 1772      const double distanceToEnd = endDistance - distanceTraversed;
 
 1775                      QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1776                      QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd / 2.0 )
 
 1779                          QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1780                          QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
 
 1782    else if ( !addedSegmentEnd && foundStart )
 
 1784      substringPoints << 
QgsPoint( pointType, x2, y2, z2, m2 )
 
 1785                      << 
QgsPoint( pointType, x3, y3, z3, m3 );
 
 1793    if ( distanceTraversed >= endDistance )
 
 1798  if ( !foundStart && 
qgsDoubleNear( distanceTraversed, startDistance ) )
 
 1800    substringPoints << 
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
 
 1801                    << 
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
 
 1802                    << 
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
 
 1805  std::unique_ptr< QgsCircularString > result = std::make_unique< QgsCircularString >();
 
 1806  result->setPoints( substringPoints );
 
 1807  return result.release();
 
 
 1820  mZ.reserve( nPoints );
 
 1821  for ( 
int i = 0; i < nPoints; ++i )
 
 
 1838  mM.reserve( nPoints );
 
 1839  for ( 
int i = 0; i < nPoints; ++i )
 
 
 1872  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.