28 #include <QJsonObject> 
   30 #include <QPainterPath> 
   32 #include <nlohmann/json.hpp> 
   42   bool hasZ = p1.
is3D();
 
   87   if ( mX.count() != otherLine->mX.count() )
 
   90   for ( 
int i = 0; i < mX.count(); ++i )
 
  108   auto result = qgis::make_unique< QgsCircularString >();
 
  110   return result.release();
 
  115   return QStringLiteral( 
"CircularString" );
 
  142   for ( 
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
 
  146       bbox = segmentBoundingBox( 
QgsPoint( mX[i], mY[i] ), 
QgsPoint( mX[i + 1], mY[i + 1] ), 
QgsPoint( mX[i + 2], mY[i + 2] ) );
 
  155   if ( nPoints > 0 && nPoints % 2 == 0 )
 
  168   double centerX, centerY, radius;
 
  177   bbox.combineExtentWith( pt3.
x(), pt3.
y() );
 
  179   QgsPointSequence compassPoints = compassPointsOnSegment( p1Angle, p2Angle, p3Angle, centerX, centerY, radius );
 
  180   QgsPointSequence::const_iterator cpIt = compassPoints.constBegin();
 
  181   for ( ; cpIt != compassPoints.constEnd(); ++cpIt )
 
  183     bbox.combineExtentWith( cpIt->x(), cpIt->y() );
 
  188 QgsPointSequence QgsCircularString::compassPointsOnSegment( 
double p1Angle, 
double p2Angle, 
double p3Angle, 
double centerX, 
double centerY, 
double radius )
 
  192   QgsPoint nPoint( centerX, centerY + radius );
 
  193   QgsPoint ePoint( centerX + radius, centerY );
 
  194   QgsPoint sPoint( centerX, centerY - radius );
 
  195   QgsPoint wPoint( centerX - radius, centerY );
 
  197   if ( p3Angle >= p1Angle )
 
  199     if ( p2Angle > p1Angle && p2Angle < p3Angle )
 
  201       if ( p1Angle <= 90 && p3Angle >= 90 )
 
  203         pointList.append( nPoint );
 
  205       if ( p1Angle <= 180 && p3Angle >= 180 )
 
  207         pointList.append( wPoint );
 
  209       if ( p1Angle <= 270 && p3Angle >= 270 )
 
  211         pointList.append( sPoint );
 
  216       pointList.append( ePoint );
 
  217       if ( p1Angle >= 90 || p3Angle <= 90 )
 
  219         pointList.append( nPoint );
 
  221       if ( p1Angle >= 180 || p3Angle <= 180 )
 
  223         pointList.append( wPoint );
 
  225       if ( p1Angle >= 270 || p3Angle <= 270 )
 
  227         pointList.append( sPoint );
 
  233     if ( p2Angle < p1Angle && p2Angle > p3Angle )
 
  235       if ( p1Angle >= 270 && p3Angle <= 270 )
 
  237         pointList.append( sPoint );
 
  239       if ( p1Angle >= 180 && p3Angle <= 180 )
 
  241         pointList.append( wPoint );
 
  243       if ( p1Angle >= 90 && p3Angle <= 90 )
 
  245         pointList.append( nPoint );
 
  250       pointList.append( ePoint );
 
  251       if ( p1Angle <= 270 || p3Angle >= 270 )
 
  253         pointList.append( sPoint );
 
  255       if ( p1Angle <= 180 || p3Angle >= 180 )
 
  257         pointList.append( wPoint );
 
  259       if ( p1Angle <= 90 || p3Angle >= 90 )
 
  261         pointList.append( nPoint );
 
  286   mX.resize( nVertices );
 
  287   mY.resize( nVertices );
 
  288   hasZ ? mZ.resize( nVertices ) : mZ.clear();
 
  289   hasM ? mM.resize( nVertices ) : mM.clear();
 
  290   for ( 
int i = 0; i < nVertices; ++i )
 
  317   parts.second = 
parts.second.remove( 
'(' ).remove( 
')' );
 
  318   QString secondWithoutParentheses = 
parts.second;
 
  319   secondWithoutParentheses = secondWithoutParentheses.simplified().remove( 
' ' );
 
  320   if ( ( 
parts.second.compare( QLatin1String( 
"EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
 
  321        secondWithoutParentheses.isEmpty() )
 
  334   int binarySize = 
sizeof( char ) + 
sizeof( quint32 ) + 
sizeof( quint32 );
 
  345   wkb << static_cast<quint32>( 
wkbType() );
 
  357     wkt += QLatin1String( 
"EMPTY" );
 
  370   std::unique_ptr< QgsLineString > line( 
curveToLine() );
 
  371   QDomElement gml = line->asGml2( doc, 
precision, ns, axisOrder );
 
  380   QDomElement elemCurve = doc.createElementNS( ns, QStringLiteral( 
"Curve" ) );
 
  385   QDomElement elemSegments = doc.createElementNS( ns, QStringLiteral( 
"segments" ) );
 
  386   QDomElement elemArcString = doc.createElementNS( ns, QStringLiteral( 
"ArcString" ) );
 
  388   elemSegments.appendChild( elemArcString );
 
  389   elemCurve.appendChild( elemSegments );
 
  397   std::unique_ptr< QgsLineString > line( 
curveToLine() );
 
  411   for ( 
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
 
  442   for ( 
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
 
  456   bool res = 
snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM,
 
  457                                 result->mX, result->mY, result->mZ, result->mM );
 
  459     return result.release();
 
  466   if ( mX.count() <= 3 )
 
  469   double prevX = mX.at( 0 );
 
  470   double prevY = mY.at( 0 );
 
  472   bool useZ = hasZ && useZValues;
 
  473   double prevZ = useZ ? mZ.at( 0 ) : 0;
 
  475   int remaining = mX.count();
 
  478   while ( i + 1 < remaining )
 
  480     double currentCurveX = mX.at( i );
 
  481     double currentCurveY = mY.at( i );
 
  482     double currentX = mX.at( i + 1 );
 
  483     double currentY = mY.at( i + 1 );
 
  484     double currentZ = useZ ? mZ.at( i + 1 ) : 0;
 
  517   return std::min( mX.size(), mY.size() );
 
  522   if ( i < 0 || std::min( mX.size(), mY.size() ) <= i )
 
  527   double x = mX.at( i );
 
  528   double y = mY.at( i );
 
  559   if ( index >= 0 && index < mX.size() )
 
  560     return mX.at( index );
 
  567   if ( index >= 0 && index < mY.size() )
 
  568     return mY.at( index );
 
  577   int size = mX.size();
 
  579   double *srcX = mX.data(); 
 
  580   double *srcY = mY.data(); 
 
  581   double *srcM = hasM ? mM.data() : 
nullptr; 
 
  582   double *srcZ = hasZ ? mZ.data() : 
nullptr; 
 
  584   double *destX = srcX;
 
  585   double *destY = srcY;
 
  586   double *destM = srcM;
 
  587   double *destZ = srcZ;
 
  589   int filteredPoints = 0;
 
  590   for ( 
int i = 0; i < size; ++i )
 
  594     double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
 
  595     double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
 
  597     if ( filter( 
QgsPoint( x, y, z, m ) ) )
 
  609   mX.resize( filteredPoints );
 
  610   mY.resize( filteredPoints );
 
  612     mZ.resize( filteredPoints );
 
  614     mM.resize( filteredPoints );
 
  623   int size = mX.size();
 
  625   double *srcX = mX.data();
 
  626   double *srcY = mY.data();
 
  627   double *srcM = hasM ? mM.data() : 
nullptr;
 
  628   double *srcZ = hasZ ? mZ.data() : 
nullptr;
 
  630   for ( 
int i = 0; i < size; ++i )
 
  634     double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
 
  635     double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
 
  651   for ( 
int i = 0; i < nPts; ++i )
 
  653     pts.push_back( 
pointN( i ) );
 
  673   bool hasZ = firstPt.
is3D();
 
  678   mX.resize( 
points.size() );
 
  679   mY.resize( 
points.size() );
 
  682     mZ.resize( 
points.size() );
 
  690     mM.resize( 
points.size() );
 
  697   for ( 
int i = 0; i < 
points.size(); ++i )
 
  703       double z = 
points.at( i ).z();
 
  704       mZ[i] = std::isnan( z ) ? 0 : z;
 
  708       double m = 
points.at( i ).m();
 
  709       mM[i] = std::isnan( m ) ? 0 : m;
 
  725   double *zArray = mZ.data();
 
  729   bool useDummyZ = !hasZ || !transformZ;
 
  732     zArray = 
new double[nPoints];
 
  733     for ( 
int i = 0; i < nPoints; ++i )
 
  752   for ( 
int i = 0; i < nPoints; ++i )
 
  755     t.map( mX.at( i ), mY.at( i ), &x, &y );
 
  760       mZ[i] = mZ.at( i ) * zScale + zTranslate;
 
  764       mM[i] = mM.at( i ) * mScale + mTranslate;
 
  777   if ( path.isEmpty() || path.currentPosition() != QPointF( mX[0], mY[0] ) )
 
  779     path.moveTo( QPointF( mX[0], mY[0] ) );
 
  782   for ( 
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
 
  786     for ( 
int j = 1; j < pt.size(); ++j )
 
  788       path.lineTo( pt.at( j ).x(), pt.at( j ).y() );
 
  796   if ( nPoints % 2 == 0 )
 
  798     path.lineTo( mX[ nPoints - 1 ], mY[ nPoints - 1 ] );
 
  803 void QgsCircularString::arcTo( QPainterPath &path, QPointF pt1, QPointF pt2, QPointF pt3 )
 
  805   double centerX, centerY, radius;
 
  807                                         radius, centerX, centerY );
 
  812   double diameter = 2 * radius;
 
  813   path.arcTo( centerX - radius, centerY - radius, diameter, diameter, p1Angle, sweepAngle );
 
  824   if ( position.
vertex >= mX.size() || position.
vertex < 1 )
 
  829   mX.insert( position.
vertex, vertex.
x() );
 
  830   mY.insert( position.
vertex, vertex.
y() );
 
  833     mZ.insert( position.
vertex, vertex.
z() );
 
  837     mM.insert( position.
vertex, vertex.
m() );
 
  840   bool vertexNrEven = ( position.
vertex % 2 == 0 );
 
  855   if ( position.
vertex < 0 || position.
vertex >= mX.size() )
 
  860   mX[position.
vertex] = newPos.
x();
 
  861   mY[position.
vertex] = newPos.
y();
 
  864     mZ[position.
vertex] = newPos.
z();
 
  868     mM[position.
vertex] = newPos.
m();
 
  882   if ( position.
vertex < 0 || position.
vertex > ( nVertices - 1 ) )
 
  887   if ( position.
vertex < ( nVertices - 2 ) )
 
  920   double minDist = std::numeric_limits<double>::max();
 
  923   int minDistLeftOf = 0;
 
  925   double currentDist = 0.0;
 
  928   for ( 
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
 
  930     currentDist = closestPointOnArc( mX[i], mY[i], mX[i + 1], mY[i + 1], mX[i + 2], mY[i + 2], pt, segmentPt, vertexAfter, 
leftOf, epsilon );
 
  931     if ( currentDist < minDist )
 
  933       minDist = currentDist;
 
  934       minDistSegmentPoint = segmentPt;
 
  943   if ( minDist == std::numeric_limits<double>::max() )
 
  946   segmentPt = minDistSegmentPoint;
 
  947   vertexAfter = minDistVertexAfter;
 
  948   vertexAfter.
part = 0;
 
  949   vertexAfter.
ring = 0;
 
  972   for ( 
int i = 0; i < maxIndex; i += 2 )
 
  975     QgsPoint p2( mX[i + 1], mY[i + 1] );
 
  976     QgsPoint p3( mX[i + 2], mY[i + 2] );
 
  986     sum += 0.5 * ( mX[i] * mY[i + 2] - mY[i] * mX[i + 2] );
 
  989     double midPointX = ( p1.
x() + p3.
x() ) / 2.0;
 
  990     double midPointY = ( p1.
y() + p3.
y() ) / 2.0;
 
  992     double radius, centerX, centerY;
 
  996     double r2 = radius * radius;
 
 1007     double cov = 0.5 - d * std::sqrt( r2 - d * d ) / ( M_PI * r2 ) - M_1_PI * std::asin( d / radius );
 
 1008     double circleChordArea = 0;
 
 1009     if ( circlePointLeftOfLine == centerPointLeftOfLine )
 
 1011       circleChordArea = M_PI * r2 * ( 1 - cov );
 
 1015       circleChordArea = M_PI * r2 * cov;
 
 1018     if ( !circlePointLeftOfLine )
 
 1020       sum += circleChordArea;
 
 1024       sum -= circleChordArea;
 
 1034 double QgsCircularString::closestPointOnArc( 
double x1, 
double y1, 
double x2, 
double y2, 
double x3, 
double y3,
 
 1037   double radius, centerX, centerY;
 
 1062     segmentPt = ( distPtPt1 <= distPtPt3 ) ? pt1 : pt3;
 
 1063     vertexAfter.
vertex = ( distPtPt1 <= distPtPt3 ) ? 1 : 2;
 
 1070     segmentPt.
setX( pt.
x() );
 
 1071     segmentPt.
setY( pt.
y() );
 
 1077     double sqrDistancePointToCenter = ( pt.
x() - centerX ) * ( pt.
x() - centerX ) + ( pt.
y() - centerY ) * ( pt.
y() - centerY );
 
 1078     *
leftOf = clockwise ? ( sqrDistancePointToCenter > radius * radius ? -1 : 1 )
 
 1079               : ( sqrDistancePointToCenter < radius * radius ? -1 : 1 );
 
 1085 void QgsCircularString::insertVertexBetween( 
int after, 
int before, 
int pointOnCircle )
 
 1087   double xAfter = mX.at( after );
 
 1088   double yAfter = mY.at( after );
 
 1089   double xBefore = mX.at( before );
 
 1090   double yBefore = mY.at( before );
 
 1091   double xOnCircle = mX.at( pointOnCircle );
 
 1092   double yOnCircle = mY.at( pointOnCircle );
 
 1094   double radius, centerX, centerY;
 
 1097   double x = ( xAfter + xBefore ) / 2.0;
 
 1098   double y = ( yAfter + yBefore ) / 2.0;
 
 1101   mX.insert( before, newVertex.
x() );
 
 1102   mY.insert( before, newVertex.
y() );
 
 1106     mZ.insert( before, ( mZ[after] + mZ[before] ) / 2.0 );
 
 1110     mM.insert( before, ( mM[after] + mM[before] ) / 2.0 );
 
 1123   int before = vId.
vertex - 1;
 
 1125   int after = vId.
vertex + 1;
 
 1127   if ( vId.
vertex % 2 != 0 ) 
 
 1157       int vertex1 = vId.
vertex - 2;
 
 1158       int vertex2 = vId.
vertex - 1;
 
 1159       int vertex3 = vId.
vertex;
 
 1161                       QgsPoint( mX[vertex1], mY[vertex1] ), 
QgsPoint( mX[vertex2], mY[vertex2] ), 
QgsPoint( mX[vertex3], mY[vertex3] ) );
 
 1162       int vertex4 = vId.
vertex + 1;
 
 1163       int vertex5 = vId.
vertex + 2;
 
 1165                       QgsPoint( mX[vertex3], mY[vertex3] ), 
QgsPoint( mX[vertex4], mY[vertex4] ), 
QgsPoint( mX[vertex5], mY[vertex5] ) );
 
 1174   if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 2 )
 
 1177   if ( startVertex.
vertex % 2 == 1 )
 
 1180   double x1 = mX.at( startVertex.
vertex );
 
 1181   double y1 = mY.at( startVertex.
vertex );
 
 1182   double x2 = mX.at( startVertex.
vertex + 1 );
 
 1183   double y2 = mY.at( startVertex.
vertex + 1 );
 
 1184   double x3 = mX.at( startVertex.
vertex + 2 );
 
 1185   double y3 = mY.at( startVertex.
vertex + 2 );
 
 1192   std::reverse( copy->mX.begin(), copy->mX.end() );
 
 1193   std::reverse( copy->mY.begin(), copy->mY.end() );
 
 1196     std::reverse( copy->mZ.begin(), copy->mZ.end() );
 
 1200     std::reverse( copy->mM.begin(), copy->mM.end() );
 
 1210   double distanceTraversed = 0;
 
 1212   if ( totalPoints == 0 )
 
 1221   const double *x = mX.constData();
 
 1222   const double *y = mY.constData();
 
 1223   const double *z = 
is3D() ? mZ.constData() : 
nullptr;
 
 1224   const double *m = 
isMeasure() ? mM.constData() : 
nullptr;
 
 1226   double prevX = *x++;
 
 1227   double prevY = *y++;
 
 1228   double prevZ = z ? *z++ : 0.0;
 
 1229   double prevM = m ? *m++ : 0.0;
 
 1233     return new QgsPoint( pointType, prevX, prevY, prevZ, prevM );
 
 1236   for ( 
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
 
 1245     double z2 = z ? *z++ : 0.0;
 
 1246     double m2 = m ? *m++ : 0.0;
 
 1250     double z3 = z ? *z++ : 0.0;
 
 1251     double m3 = m ? *m++ : 0.0;
 
 1257       const double distanceToPoint = std::min( distance - distanceTraversed, 
segmentLength );
 
 1259                            QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1260                            QgsPoint( pointType, x3, y3, z3, m3 ), distanceToPoint ) );
 
 1276   if ( startDistance < 0 && endDistance < 0 )
 
 1279   endDistance = std::max( startDistance, endDistance );
 
 1281   double distanceTraversed = 0;
 
 1283   if ( totalPoints == 0 )
 
 1286   QVector< QgsPoint > substringPoints;
 
 1294   const double *x = mX.constData();
 
 1295   const double *y = mY.constData();
 
 1296   const double *z = 
is3D() ? mZ.constData() : 
nullptr;
 
 1297   const double *m = 
isMeasure() ? mM.constData() : 
nullptr;
 
 1299   double prevX = *x++;
 
 1300   double prevY = *y++;
 
 1301   double prevZ = z ? *z++ : 0.0;
 
 1302   double prevM = m ? *m++ : 0.0;
 
 1303   bool foundStart = 
false;
 
 1305   if ( 
qgsDoubleNear( startDistance, 0.0 ) || startDistance < 0 )
 
 1307     substringPoints << 
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
 
 1311   substringPoints.reserve( totalPoints );
 
 1313   for ( 
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
 
 1322     double z2 = z ? *z++ : 0.0;
 
 1323     double m2 = m ? *m++ : 0.0;
 
 1327     double z3 = z ? *z++ : 0.0;
 
 1328     double m3 = m ? *m++ : 0.0;
 
 1330     bool addedSegmentEnd = 
false;
 
 1332     if ( distanceTraversed < startDistance && distanceTraversed + segmentLength > startDistance )
 
 1335       const double distanceToStart = startDistance - distanceTraversed;
 
 1337                                   QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1338                                   QgsPoint( pointType, x3, y3, z3, m3 ), distanceToStart );
 
 1341       const bool endPointOnSegment = distanceTraversed + 
segmentLength > endDistance;
 
 1342       if ( endPointOnSegment )
 
 1344         const double distanceToEnd = endDistance - distanceTraversed;
 
 1345         const double midPointDistance = ( distanceToEnd - distanceToStart ) * 0.5 + distanceToStart;
 
 1348                             QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1349                             QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
 
 1351                             QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1352                             QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
 
 1353         addedSegmentEnd = 
true;
 
 1357         const double midPointDistance = ( 
segmentLength - distanceToStart ) * 0.5 + distanceToStart;
 
 1360                             QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1361                             QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
 
 1362                         << 
QgsPoint( pointType, x3, y3, z3, m3 );
 
 1363         addedSegmentEnd = 
true;
 
 1367     if ( !addedSegmentEnd && foundStart && ( distanceTraversed + 
segmentLength > endDistance ) )
 
 1370       const double distanceToEnd = endDistance - distanceTraversed;
 
 1373                       QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1374                       QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd / 2.0 )
 
 1377                           QgsPoint( pointType, x2, y2, z2, m2 ),
 
 1378                           QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
 
 1380     else if ( !addedSegmentEnd && foundStart )
 
 1382       substringPoints << 
QgsPoint( pointType, x2, y2, z2, m2 )
 
 1383                       << 
QgsPoint( pointType, x3, y3, z3, m3 );
 
 1387     if ( distanceTraversed > endDistance )
 
 1396   std::unique_ptr< QgsCircularString > result = qgis::make_unique< QgsCircularString >();
 
 1397   result->setPoints( substringPoints );
 
 1398   return result.release();
 
 1411   mZ.reserve( nPoints );
 
 1412   for ( 
int i = 0; i < nPoints; ++i )
 
 1429   mM.reserve( nPoints );
 
 1430   for ( 
int i = 0; i < nPoints; ++i )
 
 1463   std::swap( mX, mY );