30 #include <QJsonObject> 
   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() );
 
  360 QgsPointSequence 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;
 
 1167   if ( path.isEmpty() || path.currentPosition() != QPointF( mX[0], mY[0] ) )
 
 1169     path.moveTo( QPointF( mX[0], mY[0] ) );
 
 1172   for ( 
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
 
 1176     for ( 
int j = 1; j < pt.size(); ++j )
 
 1178       path.lineTo( pt.at( j ).x(), pt.at( j ).y() );
 
 1186   if ( nPoints % 2 == 0 )
 
 1188     path.lineTo( mX[ nPoints - 1 ], mY[ nPoints - 1 ] );
 
 1193 void QgsCircularString::arcTo( QPainterPath &path, QPointF pt1, QPointF pt2, QPointF pt3 )
 
 1195   double centerX, centerY, radius;
 
 1197                                         radius, centerX, centerY );
 
 1202   double diameter = 2 * radius;
 
 1203   path.arcTo( centerX - radius, centerY - radius, diameter, diameter, p1Angle, sweepAngle );
 
 1214   if ( position.
vertex >= mX.size() || position.
vertex < 1 )
 
 1219   mX.insert( position.
vertex, vertex.
x() );
 
 1220   mY.insert( position.
vertex, vertex.
y() );
 
 1223     mZ.insert( position.
vertex, vertex.
z() );
 
 1227     mM.insert( position.
vertex, vertex.
m() );
 
 1230   bool vertexNrEven = ( position.
vertex % 2 == 0 );
 
 1245   if ( position.
vertex < 0 || position.
vertex >= mX.size() )
 
 1250   mX[position.
vertex] = newPos.
x();
 
 1251   mY[position.
vertex] = newPos.
y();
 
 1254     mZ[position.
vertex] = newPos.
z();
 
 1258     mM[position.
vertex] = newPos.
m();
 
 1267   if ( nVertices < 4 ) 
 
 1272   if ( position.
vertex < 0 || position.
vertex > ( nVertices - 1 ) )
 
 1277   if ( position.
vertex < ( nVertices - 2 ) )
 
 1310   double minDist = std::numeric_limits<double>::max();
 
 1313   int minDistLeftOf = 0;
 
 1315   double currentDist = 0.0;
 
 1318   for ( 
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
 
 1320     currentDist = closestPointOnArc( mX[i], mY[i], mX[i + 1], mY[i + 1], mX[i + 2], mY[i + 2], pt, segmentPt, vertexAfter, 
leftOf, epsilon );
 
 1321     if ( currentDist < minDist )
 
 1323       minDist = currentDist;
 
 1324       minDistSegmentPoint = segmentPt;
 
 1333   if ( minDist == std::numeric_limits<double>::max() )
 
 1336   segmentPt = minDistSegmentPoint;
 
 1337   vertexAfter = minDistVertexAfter;
 
 1338   vertexAfter.
part = 0;
 
 1339   vertexAfter.
ring = 0;
 
 1362   for ( 
int i = 0; i < maxIndex; i += 2 )
 
 1365     QgsPoint p2( mX[i + 1], mY[i + 1] );
 
 1366     QgsPoint p3( mX[i + 2], mY[i + 2] );
 
 1376     sum += 0.5 * ( mX[i] * mY[i + 2] - mY[i] * mX[i + 2] );
 
 1379     double midPointX = ( p1.
x() + p3.
x() ) / 2.0;
 
 1380     double midPointY = ( p1.
y() + p3.
y() ) / 2.0;
 
 1382     double radius, centerX, centerY;
 
 1386     double r2 = radius * radius;
 
 1397     double cov = 0.5 - d * std::sqrt( r2 - d * d ) / ( M_PI * r2 ) - M_1_PI * std::asin( d / radius );
 
 1398     double circleChordArea = 0;
 
 1399     if ( circlePointLeftOfLine == centerPointLeftOfLine )
 
 1401       circleChordArea = M_PI * r2 * ( 1 - cov );
 
 1405       circleChordArea = M_PI * r2 * cov;
 
 1408     if ( !circlePointLeftOfLine )
 
 1410       sum += circleChordArea;
 
 1414       sum -= circleChordArea;
 
 1424 double QgsCircularString::closestPointOnArc( 
double x1, 
double y1, 
double x2, 
double y2, 
double x3, 
double y3,
 
 1427   double radius, centerX, centerY;
 
 1452     segmentPt = ( distPtPt1 <= distPtPt3 ) ? pt1 : pt3;
 
 1453     vertexAfter.
vertex = ( distPtPt1 <= distPtPt3 ) ? 1 : 2;
 
 1460     segmentPt.
setX( pt.
x() );
 
 1461     segmentPt.
setY( pt.
y() );
 
 1467     double sqrDistancePointToCenter = ( pt.
x() - centerX ) * ( pt.
x() - centerX ) + ( pt.
y() - centerY ) * ( pt.
y() - centerY );
 
 1468     *
leftOf = clockwise ? ( sqrDistancePointToCenter > radius * radius ? -1 : 1 )
 
 1469               : ( sqrDistancePointToCenter < radius * radius ? -1 : 1 );
 
 1475 void QgsCircularString::insertVertexBetween( 
int after, 
int before, 
int pointOnCircle )
 
 1477   double xAfter = mX.at( after );
 
 1478   double yAfter = mY.at( after );
 
 1479   double xBefore = mX.at( before );
 
 1480   double yBefore = mY.at( before );
 
 1481   double xOnCircle = mX.at( pointOnCircle );
 
 1482   double yOnCircle = mY.at( pointOnCircle );
 
 1484   double radius, centerX, centerY;
 
 1487   double x = ( xAfter + xBefore ) / 2.0;
 
 1488   double y = ( yAfter + yBefore ) / 2.0;
 
 1491   mX.insert( before, newVertex.
x() );
 
 1492   mY.insert( before, newVertex.
y() );
 
 1496     mZ.insert( before, ( mZ[after] + mZ[before] ) / 2.0 );
 
 1500     mM.insert( before, ( mM[after] + mM[before] ) / 2.0 );
 
 1513   int before = vId.
vertex - 1;
 
 1515   int after = vId.
vertex + 1;
 
 1517   if ( vId.
vertex % 2 != 0 ) 
 
 1547       int vertex1 = vId.
vertex - 2;
 
 1548       int vertex2 = vId.
vertex - 1;
 
 1549       int vertex3 = vId.
vertex;
 
 1551                       QgsPoint( mX[vertex1], mY[vertex1] ), 
QgsPoint( mX[vertex2], mY[vertex2] ), 
QgsPoint( mX[vertex3], mY[vertex3] ) );
 
 1552       int vertex4 = vId.
vertex + 1;
 
 1553       int vertex5 = vId.
vertex + 2;
 
 1555                       QgsPoint( mX[vertex3], mY[vertex3] ), 
QgsPoint( mX[vertex4], mY[vertex4] ), 
QgsPoint( mX[vertex5], mY[vertex5] ) );
 
 1564   if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 2 )
 
 1567   if ( startVertex.
vertex % 2 == 1 )
 
 1570   double x1 = mX.at( startVertex.
vertex );
 
 1571   double y1 = mY.at( startVertex.
vertex );
 
 1572   double x2 = mX.at( startVertex.
vertex + 1 );
 
 1573   double y2 = mY.at( startVertex.
vertex + 1 );
 
 1574   double x3 = mX.at( startVertex.
vertex + 2 );
 
 1575   double y3 = mY.at( startVertex.
vertex + 2 );
 
 1582   std::reverse( copy->mX.begin(), copy->mX.end() );
 
 1583   std::reverse( copy->mY.begin(), copy->mY.end() );
 
 1586     std::reverse( copy->mZ.begin(), copy->mZ.end() );
 
 1590     std::reverse( copy->mM.begin(), copy->mM.end() );
 
 1600   double distanceTraversed = 0;
 
 1602   if ( totalPoints == 0 )
 
 1611   const double *x = mX.constData();
 
 1612   const double *y = mY.constData();
 
 1613   const double *z = 
is3D() ? mZ.constData() : 
nullptr;
 
 1614   const double *m = 
isMeasure() ? mM.constData() : 
nullptr;
 
 1616   double prevX = *x++;
 
 1617   double prevY = *y++;
 
 1618   double prevZ = z ? *z++ : 0.0;
 
 1619   double prevM = m ? *m++ : 0.0;
 
 1623     return new QgsPoint( pointType, prevX, prevY, prevZ, prevM );
 
 1626   for ( 
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
 
 1635     double z2 = z ? *z++ : 0.0;
 
 1636     double m2 = m ? *m++ : 0.0;
 
 1640     double z3 = z ? *z++ : 0.0;
 
 1641     double m3 = m ? *m++ : 0.0;
 
 1647       const double distanceToPoint = std::min( distance - distanceTraversed, 
segmentLength );
 
 1649                            QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1650                            QgsPoint( pointType, x3, y3, z3, m3 ), distanceToPoint ) );
 
 1666   if ( startDistance < 0 && endDistance < 0 )
 
 1669   endDistance = std::max( startDistance, endDistance );
 
 1672   if ( totalPoints == 0 )
 
 1675   QVector< QgsPoint > substringPoints;
 
 1676   substringPoints.reserve( totalPoints );
 
 1684   const double *x = mX.constData();
 
 1685   const double *y = mY.constData();
 
 1686   const double *z = 
is3D() ? mZ.constData() : 
nullptr;
 
 1687   const double *m = 
isMeasure() ? mM.constData() : 
nullptr;
 
 1689   double distanceTraversed = 0;
 
 1690   double prevX = *x++;
 
 1691   double prevY = *y++;
 
 1692   double prevZ = z ? *z++ : 0.0;
 
 1693   double prevM = m ? *m++ : 0.0;
 
 1694   bool foundStart = 
false;
 
 1696   if ( startDistance < 0 )
 
 1699   for ( 
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
 
 1708     double z2 = z ? *z++ : 0.0;
 
 1709     double m2 = m ? *m++ : 0.0;
 
 1713     double z3 = z ? *z++ : 0.0;
 
 1714     double m3 = m ? *m++ : 0.0;
 
 1716     bool addedSegmentEnd = 
false;
 
 1718     if ( distanceTraversed <= startDistance && startDistance < distanceTraversed + 
segmentLength )
 
 1721       const double distanceToStart = startDistance - distanceTraversed;
 
 1723                                   QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1724                                   QgsPoint( pointType, x3, y3, z3, m3 ), distanceToStart );
 
 1727       const bool endPointOnSegment = distanceTraversed + 
segmentLength > endDistance;
 
 1728       if ( endPointOnSegment )
 
 1730         const double distanceToEnd = endDistance - distanceTraversed;
 
 1731         const double midPointDistance = ( distanceToEnd - distanceToStart ) * 0.5 + distanceToStart;
 
 1734                             QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1735                             QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
 
 1737                             QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1738                             QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
 
 1739         addedSegmentEnd = 
true;
 
 1743         const double midPointDistance = ( 
segmentLength - distanceToStart ) * 0.5 + distanceToStart;
 
 1746                             QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1747                             QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
 
 1748                         << 
QgsPoint( pointType, x3, y3, z3, m3 );
 
 1749         addedSegmentEnd = 
true;
 
 1753     if ( !addedSegmentEnd && foundStart && ( distanceTraversed + 
segmentLength > endDistance ) )
 
 1756       const double distanceToEnd = endDistance - distanceTraversed;
 
 1759                       QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1760                       QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd / 2.0 )
 
 1763                           QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1764                           QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
 
 1766     else if ( !addedSegmentEnd && foundStart )
 
 1768       substringPoints << 
QgsPoint( pointType, x2, y2, z2, m2 )
 
 1769                       << 
QgsPoint( pointType, x3, y3, z3, m3 );
 
 1777     if ( distanceTraversed >= endDistance )
 
 1782   if ( !foundStart && 
qgsDoubleNear( distanceTraversed, startDistance ) )
 
 1784     substringPoints << 
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
 
 1785                     << 
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
 
 1786                     << 
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
 
 1789   std::unique_ptr< QgsCircularString > result = std::make_unique< QgsCircularString >();
 
 1790   result->setPoints( substringPoints );
 
 1791   return result.release();
 
 1804   mZ.reserve( nPoints );
 
 1805   for ( 
int i = 0; i < nPoints; ++i )
 
 1822   mM.reserve( nPoints );
 
 1823   for ( 
int i = 0; i < nPoints; ++i )
 
 1856   std::swap( mX, mY );
 
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.
bool pointAt(int node, QgsPoint &point, QgsVertexId::VertexType &type) const override
Returns the point and vertex id of a point within the curve.
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.
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.
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 transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) override SIP_THROW(QgsCsException)
Transforms the geometry using a coordinate transform.
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 isValid(QString &error, int flags=0) const override
Checks validity of the geometry, and returns true if the geometry is valid.
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 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 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, int flags=0) 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(const QgsPointSequence &points)
Resets the line string to match the specified list of points.
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
Utility class for identifying a unique vertex within a geometry.
VertexType
Type of vertex.
@ SegmentVertex
The actual start or end point of a segment.
@ CurveVertex
An intermediate point on a segment defining the curvature of the segment.