32#include <QPainterPath> 
   34#include <nlohmann/json.hpp> 
   44  bool hasZ = p1.
is3D();
 
 
   77  int pointCount = std::min( x.size(), y.size() );
 
   78  if ( x.size() == pointCount )
 
   84    mX = x.mid( 0, pointCount );
 
   86  if ( y.size() == pointCount )
 
   92    mY = y.mid( 0, pointCount );
 
   94  if ( !z.isEmpty() && z.count() >= pointCount )
 
   97    if ( z.size() == pointCount )
 
  103      mZ = z.mid( 0, pointCount );
 
  106  if ( !m.isEmpty() && m.count() >= pointCount )
 
  109    if ( m.size() == pointCount )
 
  115      mM = m.mid( 0, pointCount );
 
 
  135  if ( mX.count() != otherLine->mX.count() )
 
  138  for ( 
int i = 0; i < mX.count(); ++i )
 
 
  156  auto result = std::make_unique< QgsCircularString >();
 
  158  return result.release();
 
 
  163  const QgsCircularString *otherLine = qgsgeometry_cast<const QgsCircularString *>( other );
 
  167  const int size = mX.size();
 
  168  const int otherSize = otherLine->mX.size();
 
  169  if ( size > otherSize )
 
  173  else if ( size < otherSize )
 
  180  else if ( !
is3D() && otherLine->
is3D() )
 
  182  const bool considerZ = 
is3D();
 
  190  for ( 
int i = 0; i < size; i++ )
 
  192    const double x = mX[i];
 
  193    const double otherX = otherLine->mX[i];
 
  198    else if ( x > otherX )
 
  203    const double y = mY[i];
 
  204    const double otherY = otherLine->mY[i];
 
  209    else if ( y > otherY )
 
  216      const double z = mZ[i];
 
  217      const double otherZ = otherLine->mZ[i];
 
  223      else if ( z > otherZ )
 
  231      const double m = mM[i];
 
  232      const double otherM = otherLine->mM[i];
 
  238      else if ( m > otherM )
 
 
  249  return QStringLiteral( 
"CircularString" );
 
 
  276  for ( 
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
 
  279    double zMin = std::numeric_limits<double>::quiet_NaN();
 
  280    double zMax = std::numeric_limits<double>::quiet_NaN();
 
  283      zMin = *std::min_element( mZ.begin() + i, mZ.begin() + i + 3 );
 
  284      zMax = *std::max_element( mZ.begin() + i, mZ.begin() + i + 3 );
 
  288      bbox = 
QgsBox3D( box2d, zMin, zMax );
 
  296  if ( nPoints > 0 && nPoints % 2 == 0 )
 
  298    double z = std::numeric_limits<double>::quiet_NaN();
 
  309      z = mZ[ nPoints - 1 ];
 
  311    bbox.
combineWith( mX[ nPoints - 1 ], mY[ nPoints - 1 ], z );
 
 
  318  const int size = mX.size();
 
  319  if ( index < 1 || index >= size - 1 )
 
  322  const bool useZ = 
is3D();
 
  325  QVector<double> newX( size );
 
  326  QVector<double> newY( size );
 
  327  QVector<double> newZ( useZ ? size : 0 );
 
  328  QVector<double> newM( useM ? size : 0 );
 
  329  auto it = std::copy( mX.constBegin() + index, mX.constEnd() - 1, newX.begin() );
 
  330  it = std::copy( mX.constBegin(), mX.constBegin() + index, it );
 
  331  *it = *newX.constBegin();
 
  332  mX = std::move( newX );
 
  334  it = std::copy( mY.constBegin() + index, mY.constEnd() - 1, newY.begin() );
 
  335  it = std::copy( mY.constBegin(), mY.constBegin() + index, it );
 
  336  *it = *newY.constBegin();
 
  337  mY = std::move( newY );
 
  340    it = std::copy( mZ.constBegin() + index, mZ.constEnd() - 1, newZ.begin() );
 
  341    it = std::copy( mZ.constBegin(), mZ.constBegin() + index, it );
 
  342    *it = *newZ.constBegin();
 
  343    mZ = std::move( newZ );
 
  347    it = std::copy( mM.constBegin() + index, mM.constEnd() - 1, newM.begin() );
 
  348    it = std::copy( mM.constBegin(), mM.constBegin() + index, it );
 
  349    *it = *newM.constBegin();
 
  350    mM = std::move( newM );
 
 
  356  double centerX, centerY, radius;
 
  365  bbox.combineExtentWith( pt3.
x(), pt3.
y() );
 
  367  QgsPointSequence compassPoints = compassPointsOnSegment( p1Angle, p2Angle, p3Angle, centerX, centerY, radius );
 
  368  QgsPointSequence::const_iterator cpIt = compassPoints.constBegin();
 
  369  for ( ; cpIt != compassPoints.constEnd(); ++cpIt )
 
  371    bbox.combineExtentWith( cpIt->x(), cpIt->y() );
 
  376QgsPointSequence QgsCircularString::compassPointsOnSegment( 
double p1Angle, 
double p2Angle, 
double p3Angle, 
double centerX, 
double centerY, 
double radius )
 
  380  QgsPoint nPoint( centerX, centerY + radius );
 
  381  QgsPoint ePoint( centerX + radius, centerY );
 
  382  QgsPoint sPoint( centerX, centerY - radius );
 
  383  QgsPoint wPoint( centerX - radius, centerY );
 
  385  if ( p3Angle >= p1Angle )
 
  387    if ( p2Angle > p1Angle && p2Angle < p3Angle )
 
  389      if ( p1Angle <= 90 && p3Angle >= 90 )
 
  391        pointList.append( nPoint );
 
  393      if ( p1Angle <= 180 && p3Angle >= 180 )
 
  395        pointList.append( wPoint );
 
  397      if ( p1Angle <= 270 && p3Angle >= 270 )
 
  399        pointList.append( sPoint );
 
  404      pointList.append( ePoint );
 
  405      if ( p1Angle >= 90 || p3Angle <= 90 )
 
  407        pointList.append( nPoint );
 
  409      if ( p1Angle >= 180 || p3Angle <= 180 )
 
  411        pointList.append( wPoint );
 
  413      if ( p1Angle >= 270 || p3Angle <= 270 )
 
  415        pointList.append( sPoint );
 
  421    if ( p2Angle < p1Angle && p2Angle > p3Angle )
 
  423      if ( p1Angle >= 270 && p3Angle <= 270 )
 
  425        pointList.append( sPoint );
 
  427      if ( p1Angle >= 180 && p3Angle <= 180 )
 
  429        pointList.append( wPoint );
 
  431      if ( p1Angle >= 90 && p3Angle <= 90 )
 
  433        pointList.append( nPoint );
 
  438      pointList.append( ePoint );
 
  439      if ( p1Angle <= 270 || p3Angle >= 270 )
 
  441        pointList.append( sPoint );
 
  443      if ( p1Angle <= 180 || p3Angle >= 180 )
 
  445        pointList.append( wPoint );
 
  447      if ( p1Angle <= 90 || p3Angle >= 90 )
 
  449        pointList.append( nPoint );
 
  470  const bool hasZ = 
is3D();
 
  474  mX.resize( nVertices );
 
  475  mY.resize( nVertices );
 
  477    mZ.resize( nVertices );
 
  481    mM.resize( nVertices );
 
  484  for ( 
int i = 0; i < nVertices; ++i )
 
 
  511  parts.second = 
parts.second.remove( 
'(' ).remove( 
')' );
 
  512  QString secondWithoutParentheses = 
parts.second;
 
  513  secondWithoutParentheses = secondWithoutParentheses.simplified().remove( 
' ' );
 
  514  if ( ( 
parts.second.compare( QLatin1String( 
"EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
 
  515       secondWithoutParentheses.isEmpty() )
 
 
  528  int binarySize = 
sizeof( char ) + 
sizeof( quint32 ) + 
sizeof( quint32 );
 
 
  539  wkb << static_cast<quint32>( 
wkbType() );
 
 
  551    wkt += QLatin1String( 
"EMPTY" );
 
 
  564  std::unique_ptr< QgsLineString > line( 
curveToLine() );
 
  565  QDomElement gml = line->asGml2( doc, 
precision, ns, axisOrder );
 
 
  574  QDomElement elemCurve = doc.createElementNS( ns, QStringLiteral( 
"Curve" ) );
 
  579  QDomElement elemSegments = doc.createElementNS( ns, QStringLiteral( 
"segments" ) );
 
  580  QDomElement elemArcString = doc.createElementNS( ns, QStringLiteral( 
"ArcString" ) );
 
  582  elemSegments.appendChild( elemArcString );
 
  583  elemCurve.appendChild( elemSegments );
 
 
  591  std::unique_ptr< QgsLineString > line( 
curveToLine() );
 
 
  604    error = QObject::tr( 
"CircularString has less than 3 points and is not empty." );
 
 
  615  for ( 
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
 
 
  646  for ( 
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
 
 
  660  bool res = 
snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM,
 
  661                                result->mX, result->mY, result->mZ, result->mM );
 
  663    return result.release();
 
 
  670  if ( mX.count() <= 3 )
 
  673  double prevX = mX.at( 0 );
 
  674  double prevY = mY.at( 0 );
 
  676  bool useZ = hasZ && useZValues;
 
  677  double prevZ = useZ ? mZ.at( 0 ) : 0;
 
  679  int remaining = mX.count();
 
  682  while ( i + 1 < remaining )
 
  684    double currentCurveX = mX.at( i );
 
  685    double currentCurveY = mY.at( i );
 
  686    double currentX = mX.at( i + 1 );
 
  687    double currentY = mY.at( i + 1 );
 
  688    double currentZ = useZ ? mZ.at( i + 1 ) : 0;
 
 
  721  return std::min( mX.size(), mY.size() );
 
 
  726  const int size = mX.size();
 
  730  const double *x = mX.constData();
 
  731  const double *y = mY.constData();
 
  732  const bool useZ = 
is3D();
 
  734  const double *z = useZ ? mZ.constData() : 
nullptr;
 
  735  const double *m = useM ? mM.constData() : 
nullptr;
 
  737  for ( 
int i = 0; i < size; i += 2 )
 
 
  766  if ( i < 0 || std::min( mX.size(), mY.size() ) <= i )
 
  771  double x = mX.at( i );
 
  772  double y = mY.at( i );
 
 
  803  if ( index >= 0 && index < mX.size() )
 
  804    return mX.at( index );
 
 
  811  if ( index >= 0 && index < mY.size() )
 
  812    return mY.at( index );
 
 
  819  if ( index >= 0 && index < mZ.size() )
 
  820    return mZ.at( index );
 
 
  827  if ( index >= 0 && index < mM.size() )
 
  828    return mM.at( index );
 
 
  840  int size = mX.size();
 
  842  double *srcX = mX.data();
 
  843  double *srcY = mY.data();
 
  844  double *srcM = hasM ? mM.data() : 
nullptr;
 
  845  double *srcZ = hasZ ? mZ.data() : 
nullptr;
 
  848  for ( 
int i = 0; i < size; ++i )
 
  852    double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
 
  853    double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
 
 
  881  int size = mX.size();
 
  883  double *srcX = mX.data(); 
 
  884  double *srcY = mY.data(); 
 
  885  double *srcM = hasM ? mM.data() : 
nullptr; 
 
  886  double *srcZ = hasZ ? mZ.data() : 
nullptr; 
 
  888  double *destX = srcX;
 
  889  double *destY = srcY;
 
  890  double *destM = srcM;
 
  891  double *destZ = srcZ;
 
  893  int filteredPoints = 0;
 
  894  for ( 
int i = 0; i < size; ++i )
 
  898    double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
 
  899    double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
 
  901    if ( filter( 
QgsPoint( x, y, z, m ) ) )
 
  913  mX.resize( filteredPoints );
 
  914  mY.resize( filteredPoints );
 
  916    mZ.resize( filteredPoints );
 
  918    mM.resize( filteredPoints );
 
 
  927  int size = mX.size();
 
  929  double *srcX = mX.data();
 
  930  double *srcY = mY.data();
 
  931  double *srcM = hasM ? mM.data() : 
nullptr;
 
  932  double *srcZ = hasZ ? mZ.data() : 
nullptr;
 
  934  for ( 
int i = 0; i < size; ++i )
 
  938    double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
 
  939    double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
 
 
  953  const bool useZ = 
is3D();
 
  956  const int size = mX.size();
 
  958    return std::make_tuple( std::make_unique< QgsCircularString >(), std::make_unique< QgsCircularString >() );
 
  960  index = std::clamp( index, 0, size - 1 );
 
  962  const int part1Size = index + 1;
 
  963  QVector< double > x1( part1Size );
 
  964  QVector< double > y1( part1Size );
 
  965  QVector< double > z1( useZ ? part1Size : 0 );
 
  966  QVector< double > m1( useM ? part1Size : 0 );
 
  968  const double *sourceX = mX.constData();
 
  969  const double *sourceY = mY.constData();
 
  970  const double *sourceZ = useZ ? mZ.constData() : 
nullptr;
 
  971  const double *sourceM = useM ? mM.constData() : 
nullptr;
 
  973  double *destX = x1.data();
 
  974  double *destY = y1.data();
 
  975  double *destZ = useZ ? z1.data() : 
nullptr;
 
  976  double *destM = useM ? m1.data() : 
nullptr;
 
  978  std::copy( sourceX, sourceX + part1Size, destX );
 
  979  std::copy( sourceY, sourceY + part1Size, destY );
 
  981    std::copy( sourceZ, sourceZ + part1Size, destZ );
 
  983    std::copy( sourceM, sourceM + part1Size, destM );
 
  985  const int part2Size = size - index;
 
  987    return std::make_tuple( std::make_unique< QgsCircularString >( x1, y1, z1, m1 ), std::make_unique< QgsCircularString >() );
 
  989  QVector< double > x2( part2Size );
 
  990  QVector< double > y2( part2Size );
 
  991  QVector< double > z2( useZ ? part2Size : 0 );
 
  992  QVector< double > m2( useM ? part2Size : 0 );
 
  995  destZ = useZ ? z2.data() : 
nullptr;
 
  996  destM = useM ? m2.data() : 
nullptr;
 
  997  std::copy( sourceX + index, sourceX + size, destX );
 
  998  std::copy( sourceY + index, sourceY + size, destY );
 
 1000    std::copy( sourceZ + index, sourceZ + size, destZ );
 
 1002    std::copy( sourceM + index, sourceM + size, destM );
 
 1004  if ( part1Size < 2 )
 
 1005    return std::make_tuple( std::make_unique< QgsCircularString >(), std::make_unique< QgsCircularString >( x2, y2, z2, m2 ) );
 
 1007    return std::make_tuple( std::make_unique< QgsCircularString >( x1, y1, z1, m1 ), std::make_unique< QgsCircularString >( x2, y2, z2, m2 ) );
 
 
 1014  for ( 
int i = 0; i < nPts; ++i )
 
 1016    pts.push_back( 
pointN( i ) );
 
 
 1036  bool hasZ = firstPt.
is3D();
 
 1041  mX.resize( 
points.size() );
 
 1042  mY.resize( 
points.size() );
 
 1045    mZ.resize( 
points.size() );
 
 1053    mM.resize( 
points.size() );
 
 1060  for ( 
int i = 0; i < 
points.size(); ++i )
 
 1066      double z = 
points.at( i ).z();
 
 1067      mZ[i] = std::isnan( z ) ? 0 : z;
 
 1071      double m = 
points.at( i ).m();
 
 1072      mM[i] = std::isnan( m ) ? 0 : m;
 
 
 1079  if ( !line || line->
isEmpty() )
 
 1122      mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
 
 1135      mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
 
 
 1153  double *zArray = mZ.data();
 
 1157  bool useDummyZ = !hasZ || !transformZ;
 
 1160    zArray = 
new double[nPoints];
 
 1161    for ( 
int i = 0; i < nPoints; ++i )
 
 
 1180  for ( 
int i = 0; i < nPoints; ++i )
 
 1183    t.map( mX.at( i ), mY.at( i ), &x, &y );
 
 1188      mZ[i] = mZ.at( i ) * zScale + zTranslate;
 
 1192      mM[i] = mM.at( i ) * mScale + mTranslate;
 
 
 1197void arcTo( QPainterPath &path, QPointF pt1, QPointF pt2, QPointF pt3 )
 
 1199  double centerX, centerY, radius;
 
 1201                                        radius, centerX, centerY );
 
 1206  double diameter = 2 * radius;
 
 1207  path.arcTo( centerX - radius, centerY - radius, diameter, diameter, -p1Angle, -sweepAngle );
 
 
 1218  if ( path.isEmpty() || path.currentPosition() != QPointF( mX[0], mY[0] ) )
 
 1220    path.moveTo( QPointF( mX[0], mY[0] ) );
 
 1223  for ( 
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
 
 1225    arcTo( path, QPointF( mX[i], mY[i] ), QPointF( mX[i + 1], mY[i + 1] ), QPointF( mX[i + 2], mY[i + 2] ) );
 
 1229  if ( nPoints % 2 == 0 )
 
 1231    path.lineTo( mX[ nPoints - 1 ], mY[ nPoints - 1 ] );
 
 
 1242  if ( position.
vertex >= mX.size() || position.
vertex < 1 )
 
 1247  mX.insert( position.
vertex, vertex.
x() );
 
 1248  mY.insert( position.
vertex, vertex.
y() );
 
 1251    mZ.insert( position.
vertex, vertex.
z() );
 
 1255    mM.insert( position.
vertex, vertex.
m() );
 
 1258  bool vertexNrEven = ( position.
vertex % 2 == 0 );
 
 
 1273  if ( position.
vertex < 0 || position.
vertex >= mX.size() )
 
 1278  mX[position.
vertex] = newPos.
x();
 
 1279  mY[position.
vertex] = newPos.
y();
 
 1282    mZ[position.
vertex] = newPos.
z();
 
 1286    mM[position.
vertex] = newPos.
m();
 
 
 1295  if ( nVertices < 4 ) 
 
 1300  if ( position.
vertex < 0 || position.
vertex > ( nVertices - 1 ) )
 
 1305  if ( position.
vertex < ( nVertices - 2 ) )
 
 
 1338  double minDist = std::numeric_limits<double>::max();
 
 1341  int minDistLeftOf = 0;
 
 1343  double currentDist = 0.0;
 
 1346  for ( 
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
 
 1348    currentDist = closestPointOnArc( mX[i], mY[i], mX[i + 1], mY[i + 1], mX[i + 2], mY[i + 2], pt, segmentPt, vertexAfter, leftOf, epsilon );
 
 1349    if ( currentDist < minDist )
 
 1351      minDist = currentDist;
 
 1352      minDistSegmentPoint = segmentPt;
 
 1356        minDistLeftOf = *leftOf;
 
 1361  if ( minDist == std::numeric_limits<double>::max() )
 
 1364  segmentPt = minDistSegmentPoint;
 
 1365  vertexAfter = minDistVertexAfter;
 
 1366  vertexAfter.
part = 0;
 
 1367  vertexAfter.
ring = 0;
 
 1370    *leftOf = 
qgsDoubleNear( minDist, 0.0 ) ? 0 : minDistLeftOf;
 
 
 1396  for ( 
int i = 0; i < maxIndex; i += 2 )
 
 1399    QgsPoint p2( mX[i + 1], mY[i + 1] );
 
 1400    QgsPoint p3( mX[i + 2], mY[i + 2] );
 
 1410    mSummedUpArea += 0.5 * ( mX[i] * mY[i + 2] - mY[i] * mX[i + 2] );
 
 1413    double midPointX = ( p1.
x() + p3.
x() ) / 2.0;
 
 1414    double midPointY = ( p1.
y() + p3.
y() ) / 2.0;
 
 1416    double radius, centerX, centerY;
 
 1420    double r2 = radius * radius;
 
 1431    double cov = 0.5 - d * std::sqrt( r2 - d * d ) / ( M_PI * r2 ) - M_1_PI * std::asin( d / radius );
 
 1432    double circleChordArea = 0;
 
 1433    if ( circlePointLeftOfLine == centerPointLeftOfLine )
 
 1435      circleChordArea = M_PI * r2 * ( 1 - cov );
 
 1439      circleChordArea = M_PI * r2 * cov;
 
 1442    if ( !circlePointLeftOfLine )
 
 
 1461double QgsCircularString::closestPointOnArc( 
double x1, 
double y1, 
double x2, 
double y2, 
double x3, 
double y3,
 
 1464  double radius, centerX, centerY;
 
 1489    segmentPt = ( distPtPt1 <= distPtPt3 ) ? pt1 : pt3;
 
 1490    vertexAfter.
vertex = ( distPtPt1 <= distPtPt3 ) ? 1 : 2;
 
 1497    segmentPt.
setX( pt.
x() );
 
 1498    segmentPt.
setY( pt.
y() );
 
 1504    double sqrDistancePointToCenter = ( pt.
x() - centerX ) * ( pt.
x() - centerX ) + ( pt.
y() - centerY ) * ( pt.
y() - centerY );
 
 1505    *
leftOf = clockwise ? ( sqrDistancePointToCenter > radius * radius ? -1 : 1 )
 
 1506              : ( sqrDistancePointToCenter < radius * radius ? -1 : 1 );
 
 1512void QgsCircularString::insertVertexBetween( 
int after, 
int before, 
int pointOnCircle )
 
 1514  double xAfter = mX.at( after );
 
 1515  double yAfter = mY.at( after );
 
 1516  double xBefore = mX.at( before );
 
 1517  double yBefore = mY.at( before );
 
 1518  double xOnCircle = mX.at( pointOnCircle );
 
 1519  double yOnCircle = mY.at( pointOnCircle );
 
 1521  double radius, centerX, centerY;
 
 1524  double x = ( xAfter + xBefore ) / 2.0;
 
 1525  double y = ( yAfter + yBefore ) / 2.0;
 
 1528  mX.insert( before, newVertex.
x() );
 
 1529  mY.insert( before, newVertex.
y() );
 
 1533    mZ.insert( before, ( mZ[after] + mZ[before] ) / 2.0 );
 
 1537    mM.insert( before, ( mM[after] + mM[before] ) / 2.0 );
 
 1550  int before = vId.
vertex - 1;
 
 1552  int after = vId.
vertex + 1;
 
 1554  if ( vId.
vertex % 2 != 0 ) 
 
 1584      int vertex1 = vId.
vertex - 2;
 
 1585      int vertex2 = vId.
vertex - 1;
 
 1586      int vertex3 = vId.
vertex;
 
 1588                      QgsPoint( mX[vertex1], mY[vertex1] ), 
QgsPoint( mX[vertex2], mY[vertex2] ), 
QgsPoint( mX[vertex3], mY[vertex3] ) );
 
 1589      int vertex4 = vId.
vertex + 1;
 
 1590      int vertex5 = vId.
vertex + 2;
 
 1592                      QgsPoint( mX[vertex3], mY[vertex3] ), 
QgsPoint( mX[vertex4], mY[vertex4] ), 
QgsPoint( mX[vertex5], mY[vertex5] ) );
 
 
 1601  if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 2 )
 
 1604  if ( startVertex.
vertex % 2 == 1 )
 
 1607  double x1 = mX.at( startVertex.
vertex );
 
 1608  double y1 = mY.at( startVertex.
vertex );
 
 1609  double x2 = mX.at( startVertex.
vertex + 1 );
 
 1610  double y2 = mY.at( startVertex.
vertex + 1 );
 
 1611  double x3 = mX.at( startVertex.
vertex + 2 );
 
 1612  double y3 = mY.at( startVertex.
vertex + 2 );
 
 
 1619  std::reverse( copy->mX.begin(), copy->mX.end() );
 
 1620  std::reverse( copy->mY.begin(), copy->mY.end() );
 
 1623    std::reverse( copy->mZ.begin(), copy->mZ.end() );
 
 1627    std::reverse( copy->mM.begin(), copy->mM.end() );
 
 
 1637  double distanceTraversed = 0;
 
 1639  if ( totalPoints == 0 )
 
 1648  const double *x = mX.constData();
 
 1649  const double *y = mY.constData();
 
 1650  const double *z = 
is3D() ? mZ.constData() : 
nullptr;
 
 1651  const double *m = 
isMeasure() ? mM.constData() : 
nullptr;
 
 1653  double prevX = *x++;
 
 1654  double prevY = *y++;
 
 1655  double prevZ = z ? *z++ : 0.0;
 
 1656  double prevM = m ? *m++ : 0.0;
 
 1660    return new QgsPoint( pointType, prevX, prevY, prevZ, prevM );
 
 1663  for ( 
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
 
 1672    double z2 = z ? *z++ : 0.0;
 
 1673    double m2 = m ? *m++ : 0.0;
 
 1677    double z3 = z ? *z++ : 0.0;
 
 1678    double m3 = m ? *m++ : 0.0;
 
 1684      const double distanceToPoint = std::min( distance - distanceTraversed, 
segmentLength );
 
 1686                           QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1687                           QgsPoint( pointType, x3, y3, z3, m3 ), distanceToPoint ) );
 
 
 1703  if ( startDistance < 0 && endDistance < 0 )
 
 1706  endDistance = std::max( startDistance, endDistance );
 
 1709  if ( totalPoints == 0 )
 
 1712  QVector< QgsPoint > substringPoints;
 
 1713  substringPoints.reserve( totalPoints );
 
 1721  const double *x = mX.constData();
 
 1722  const double *y = mY.constData();
 
 1723  const double *z = 
is3D() ? mZ.constData() : 
nullptr;
 
 1724  const double *m = 
isMeasure() ? mM.constData() : 
nullptr;
 
 1726  double distanceTraversed = 0;
 
 1727  double prevX = *x++;
 
 1728  double prevY = *y++;
 
 1729  double prevZ = z ? *z++ : 0.0;
 
 1730  double prevM = m ? *m++ : 0.0;
 
 1731  bool foundStart = 
false;
 
 1733  if ( startDistance < 0 )
 
 1736  for ( 
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
 
 1745    double z2 = z ? *z++ : 0.0;
 
 1746    double m2 = m ? *m++ : 0.0;
 
 1750    double z3 = z ? *z++ : 0.0;
 
 1751    double m3 = m ? *m++ : 0.0;
 
 1753    bool addedSegmentEnd = 
false;
 
 1755    if ( distanceTraversed <= startDistance && startDistance < distanceTraversed + 
segmentLength )
 
 1758      const double distanceToStart = startDistance - distanceTraversed;
 
 1760                                  QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1761                                  QgsPoint( pointType, x3, y3, z3, m3 ), distanceToStart );
 
 1764      const bool endPointOnSegment = distanceTraversed + 
segmentLength > endDistance;
 
 1765      if ( endPointOnSegment )
 
 1767        const double distanceToEnd = endDistance - distanceTraversed;
 
 1768        const double midPointDistance = ( distanceToEnd - distanceToStart ) * 0.5 + distanceToStart;
 
 1771                            QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1772                            QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
 
 1774                            QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1775                            QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
 
 1776        addedSegmentEnd = 
true;
 
 1780        const double midPointDistance = ( 
segmentLength - distanceToStart ) * 0.5 + distanceToStart;
 
 1783                            QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1784                            QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
 
 1785                        << 
QgsPoint( pointType, x3, y3, z3, m3 );
 
 1786        addedSegmentEnd = 
true;
 
 1790    if ( !addedSegmentEnd && foundStart && ( distanceTraversed + 
segmentLength > endDistance ) )
 
 1793      const double distanceToEnd = endDistance - distanceTraversed;
 
 1796                      QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1797                      QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd / 2.0 )
 
 1800                          QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1801                          QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
 
 1803    else if ( !addedSegmentEnd && foundStart )
 
 1805      substringPoints << 
QgsPoint( pointType, x2, y2, z2, m2 )
 
 1806                      << 
QgsPoint( pointType, x3, y3, z3, m3 );
 
 1814    if ( distanceTraversed >= endDistance )
 
 1819  if ( !foundStart && 
qgsDoubleNear( distanceTraversed, startDistance ) )
 
 1821    substringPoints << 
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
 
 1822                    << 
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
 
 1823                    << 
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
 
 1826  std::unique_ptr< QgsCircularString > result = std::make_unique< QgsCircularString >();
 
 1827  result->setPoints( substringPoints );
 
 1828  return result.release();
 
 
 1841  mZ.reserve( nPoints );
 
 1842  for ( 
int i = 0; i < nPoints; ++i )
 
 
 1859  mM.reserve( nPoints );
 
 1860  for ( 
int i = 0; i < nPoints; ++i )
 
 
 1893  std::swap( mX, mY );
 
 
VertexType
Types of vertex.
 
@ Curve
An intermediate point on a segment defining the curvature of the segment.
 
@ Segment
The actual start or end point of a segment.
 
WkbType
The WKB type describes the number of dimensions a geometry has.
 
@ CircularString
CircularString.
 
@ CircularStringZ
CircularStringZ.
 
TransformDirection
Flags for raster layer temporal capabilities.
 
Abstract base class for all geometries.
 
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
 
bool isMeasure() const
Returns true if the geometry contains m values.
 
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
 
AxisOrder
Axis order for GML generation.
 
QString wktTypeStr() const
Returns the WKT type string of the geometry.
 
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
 
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, Qgis::WkbType baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
 
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts of the geometry.
 
static endian_t endian()
Returns whether this machine uses big or little endian.
 
A 3-dimensional box composed of x, y, z coordinates.
 
void combineWith(const QgsBox3D &box)
Expands the bbox so that it covers both the original rectangle and the given rectangle.
 
Circular string geometry type.
 
bool equals(const QgsCurve &other) const override
Checks whether this curve exactly equals another curve.
 
double length() const override
Returns the planar, 2-dimensional length of the geometry.
 
QString geometryType() const override
Returns a unique string representing the geometry type.
 
void points(QgsPointSequence &pts) const override
Returns a list of points within the curve.
 
bool moveVertex(QgsVertexId position, const QgsPoint &newPos) override
Moves a vertex within the geometry.
 
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
 
QgsCircularString * snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0) const override
Makes a new geometry with all the points or vertices snapped to the closest point of the grid.
 
QgsCircularString * clone() const override
Clones the geometry by performing a deep copy.
 
QgsPoint endPoint() const override
Returns the end point of the curve.
 
void append(const QgsCircularString *string)
Appends the contents of another circular string to the end of this circular string.
 
bool fromWkb(QgsConstWkbPtr &wkb) override
Sets the geometry from a WKB string.
 
void draw(QPainter &p) const override
Draws the geometry using the specified QPainter.
 
QgsCircularString * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
 
double closestSegment(const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf=nullptr, double epsilon=4 *std::numeric_limits< double >::epsilon()) const override
Searches for the closest segment of the geometry to a given point.
 
void swapXy() override
Swaps the x and y coordinates from the geometry.
 
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
 
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
 
static QgsCircularString fromTwoPointsAndCenter(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint ¢er, bool useShortestArc=true)
Creates a circular string with a single arc representing the curve from p1 to p2 with the specified c...
 
void filterVertices(const std::function< bool(const QgsPoint &) > &filter) override
Filters the vertices from the geometry in place, removing any which do not return true for the filter...
 
double segmentLength(QgsVertexId startVertex) const override
Returns the length of the segment of the geometry which begins at startVertex.
 
bool removeDuplicateNodes(double epsilon=4 *std::numeric_limits< double >::epsilon(), bool useZValues=false) override
Removes duplicate nodes from the geometry, wherever removing the nodes does not result in a degenerat...
 
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
 
bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
 
void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) override
Transforms the geometry using a coordinate transform.
 
QDomElement asGml2(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML2 representation of the geometry.
 
void sumUpArea(double &sum) const override
Sums up the area of the curve by iterating over the vertices (shoelace formula).
 
QgsCircularString * reversed() const override
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
 
QgsBox3D calculateBoundingBox3D() const override
Calculates the minimal 3D bounding box for the geometry.
 
QgsPoint startPoint() const override
Returns the starting point of the curve.
 
bool pointAt(int node, QgsPoint &point, Qgis::VertexType &type) const override
Returns the point and vertex id of a point within the curve.
 
bool isEmpty() const override
Returns true if the geometry is empty.
 
int indexOf(const QgsPoint &point) const final
Returns the index of the first vertex matching the given point, or -1 if a matching vertex is not fou...
 
bool dropMValue() override
Drops any measure values which exist in the geometry.
 
int numPoints() const override
Returns the number of points in the curve.
 
void addToPainterPath(QPainterPath &path) const override
Adds a curve to a painter path.
 
int wkbSize(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns the length of the QByteArray returned by asWkb()
 
QgsCircularString * curveSubstring(double startDistance, double endDistance) const override
Returns a new curve representing a substring of this curve.
 
void drawAsPolygon(QPainter &p) const override
Draws the curve as a polygon on the specified QPainter.
 
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
 
int dimension() const override
Returns the inherent dimension of the geometry.
 
void setPoints(const QgsPointSequence &points)
Sets the circular string's points.
 
QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a new line string geometry corresponding to a segmentized approximation of the curve.
 
double vertexAngle(QgsVertexId vertex) const override
Returns approximate angle at a vertex.
 
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
 
QDomElement asGml3(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML3 representation of the geometry.
 
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
 
void clear() override
Clears the geometry, ie reset it to a null geometry.
 
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
 
bool hasCurvedSegments() const override
Returns true if the geometry contains curved segments.
 
void scroll(int firstVertexIndex) final
Scrolls the curve vertices so that they start with the vertex at the given index.
 
QgsPoint * interpolatePoint(double distance) const override
Returns an interpolated point on the curve at the specified distance.
 
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
 
double zAt(int index) const override
Returns the z-coordinate of the specified node in the line string.
 
bool insertVertex(QgsVertexId position, const QgsPoint &vertex) override
Inserts a vertex into the geometry.
 
QgsCircularString()
Constructs an empty circular string.
 
QgsPoint pointN(int i) const
Returns the point at index i within the circular string.
 
std::tuple< std::unique_ptr< QgsCurve >, std::unique_ptr< QgsCurve > > splitCurveAtVertex(int index) const final
Splits the curve at the specified vertex index, returning two curves which represent the portion of t...
 
double mAt(int index) const override
Returns the m-coordinate of the specified node in the line string.
 
int compareToSameClass(const QgsAbstractGeometry *other) const final
Compares to an other geometry of the same class, and returns a integer for sorting of the two geometr...
 
json asJsonObject(int precision=17) const override
Returns a json object representation of the geometry.
 
void transformVertices(const std::function< QgsPoint(const QgsPoint &) > &transform) override
Transforms the vertices from the geometry in place, applying the transform function to every vertex.
 
Qgis::WkbType readHeader() const
readHeader
 
Abstract base class for curved geometry type.
 
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
 
bool mHasCachedSummedUpArea
 
bool snapToGridPrivate(double hSpacing, double vSpacing, double dSpacing, double mSpacing, const QVector< double > &srcX, const QVector< double > &srcY, const QVector< double > &srcZ, const QVector< double > &srcM, QVector< double > &outX, QVector< double > &outY, QVector< double > &outZ, QVector< double > &outM) const
Helper function for QgsCurve subclasses to snap to grids.
 
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
 
Base class for feedback objects to be used for cancellation of something running in a worker thread.
 
bool isCanceled() const
Tells whether the operation has been canceled already.
 
static double sqrDistance2D(const QgsPoint &pt1, const QgsPoint &pt2)
Returns the squared 2D distance between two points.
 
static double circleTangentDirection(const QgsPoint &tangentPoint, const QgsPoint &cp1, const QgsPoint &cp2, const QgsPoint &cp3)
Calculates the direction angle of a circle tangent (clockwise from north in radians)
 
static QgsPoint pointOnLineWithDistance(const QgsPoint &startPoint, const QgsPoint &directionPoint, double distance)
Returns a point a specified distance toward a second point.
 
static bool angleOnCircle(double angle, double angle1, double angle2, double angle3)
Returns true if an angle is between angle1 and angle3 on a circle described by angle1,...
 
static bool circleClockwise(double angle1, double angle2, double angle3)
Returns true if the circle defined by three angles is ordered clockwise.
 
static double sweepAngle(double centerX, double centerY, double x1, double y1, double x2, double y2, double x3, double y3)
Calculates angle of a circular string part defined by pt1, pt2, pt3.
 
static double circleLength(double x1, double y1, double x2, double y2, double x3, double y3)
Length of a circular string segment defined by pt1, pt2, pt3.
 
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure, QgsAbstractGeometry::WkbFlags flags)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
 
static QPair< Qgis::WkbType, QString > wktReadBlock(const QString &wkt)
Parses a WKT block of the format "TYPE( contents )" and returns a pair of geometry type to contents (...
 
static QgsPoint interpolatePointOnArc(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double distance)
Interpolates a point on an arc defined by three points, pt1, pt2 and pt3.
 
static bool circleAngleBetween(double angle, double angle1, double angle2, bool clockwise)
Returns true if, in a circle, angle is between angle1 and angle2.
 
static double ccwAngle(double dy, double dx)
Returns the counter clockwise angle between a line with components dx, dy and the line with dx > 0 an...
 
static QgsPointSequence pointsFromWKT(const QString &wktCoordinateList, bool is3D, bool isMeasure)
Returns a list of points contained in a WKT string.
 
static void segmentizeArc(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3, QgsPointSequence &points, double tolerance=M_PI_2/90, QgsAbstractGeometry::SegmentationToleranceType toleranceType=QgsAbstractGeometry::MaximumAngle, bool hasZ=false, bool hasM=false)
Convert circular arc defined by p1, p2, p3 (p1/p3 being start resp.
 
static QDomElement pointsToGML3(const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, bool is3D, QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY)
Returns a gml::posList DOM element.
 
static QString pointsToWKT(const QgsPointSequence &points, int precision, bool is3D, bool isMeasure)
Returns a WKT coordinate list.
 
static QgsPoint segmentMidPointFromCenter(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint ¢er, bool useShortestArc=true)
Calculates the midpoint on the circle passing through p1 and p2, with the specified center coordinate...
 
static int leftOfLine(const double x, const double y, const double x1, const double y1, const double x2, const double y2)
Returns a value < 0 if the point (x, y) is left of the line from (x1, y1) -> (x2, y2).
 
static double averageAngle(double x1, double y1, double x2, double y2, double x3, double y3)
Calculates the average angle (in radians) between the two linear segments from (x1,...
 
static void circleCenterRadius(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double &radius, double ¢erX, double ¢erY)
Returns radius and center of the circle through pt1, pt2, pt3.
 
Line string geometry type, with support for z-dimension and m-values.
 
void setPoints(size_t size, const double *x, const double *y, const double *z=nullptr, const double *m=nullptr)
Resets the line string to match the specified point data.
 
Point geometry type, with support for z-dimension and m-values.
 
void setY(double y)
Sets the point's y-coordinate.
 
void setX(double x)
Sets the point's x-coordinate.
 
A rectangle specified with double values.
 
static Qgis::WkbType dropM(Qgis::WkbType type)
Drops the m dimension (if present) for a WKB type and returns the new type.
 
static Qgis::WkbType dropZ(Qgis::WkbType type)
Drops the z dimension (if present) for a WKB type and returns the new type.
 
static Qgis::WkbType addM(Qgis::WkbType type)
Adds the m dimension to a WKB type and returns the new type.
 
static Qgis::WkbType addZ(Qgis::WkbType type)
Adds the z dimension to a WKB type and returns the new type.
 
static bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
 
static bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
 
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
 
double ANALYSIS_EXPORT leftOf(const QgsPoint &thepoint, const QgsPoint *p1, const QgsPoint *p2)
Returns whether 'thepoint' is left or right of the line from 'p1' to 'p2'. Negative values mean left ...
 
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
 
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
 
QVector< QgsPoint > QgsPointSequence
 
void arcTo(QPainterPath &path, QPointF pt1, QPointF pt2, QPointF pt3)
 
Utility class for identifying a unique vertex within a geometry.