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;
1159 void arcTo( QPainterPath &path, QPointF pt1, QPointF pt2, QPointF pt3 )
1161 double centerX, centerY, radius;
1163 radius, centerX, centerY );
1168 double diameter = 2 * radius;
1169 path.arcTo( centerX - radius, centerY - radius, diameter, diameter, -p1Angle, -sweepAngle );
1180 if ( path.isEmpty() || path.currentPosition() != QPointF( mX[0], mY[0] ) )
1182 path.moveTo( QPointF( mX[0], mY[0] ) );
1185 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
1187 arcTo( path, QPointF( mX[i], mY[i] ), QPointF( mX[i + 1], mY[i + 1] ), QPointF( mX[i + 2], mY[i + 2] ) );
1191 if ( nPoints % 2 == 0 )
1193 path.lineTo( mX[ nPoints - 1 ], mY[ nPoints - 1 ] );
1204 if ( position.
vertex >= mX.size() || position.
vertex < 1 )
1209 mX.insert( position.
vertex, vertex.
x() );
1210 mY.insert( position.
vertex, vertex.
y() );
1213 mZ.insert( position.
vertex, vertex.
z() );
1217 mM.insert( position.
vertex, vertex.
m() );
1220 bool vertexNrEven = ( position.
vertex % 2 == 0 );
1235 if ( position.
vertex < 0 || position.
vertex >= mX.size() )
1240 mX[position.
vertex] = newPos.
x();
1241 mY[position.
vertex] = newPos.
y();
1244 mZ[position.
vertex] = newPos.
z();
1248 mM[position.
vertex] = newPos.
m();
1257 if ( nVertices < 4 )
1262 if ( position.
vertex < 0 || position.
vertex > ( nVertices - 1 ) )
1267 if ( position.
vertex < ( nVertices - 2 ) )
1300 double minDist = std::numeric_limits<double>::max();
1303 int minDistLeftOf = 0;
1305 double currentDist = 0.0;
1308 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
1310 currentDist = closestPointOnArc( mX[i], mY[i], mX[i + 1], mY[i + 1], mX[i + 2], mY[i + 2], pt, segmentPt, vertexAfter,
leftOf, epsilon );
1311 if ( currentDist < minDist )
1313 minDist = currentDist;
1314 minDistSegmentPoint = segmentPt;
1323 if ( minDist == std::numeric_limits<double>::max() )
1326 segmentPt = minDistSegmentPoint;
1327 vertexAfter = minDistVertexAfter;
1328 vertexAfter.
part = 0;
1329 vertexAfter.
ring = 0;
1344 type = ( node % 2 == 0 ) ? Qgis::VertexType::Segment : Qgis::VertexType::Curve;
1352 for (
int i = 0; i < maxIndex; i += 2 )
1355 QgsPoint p2( mX[i + 1], mY[i + 1] );
1356 QgsPoint p3( mX[i + 2], mY[i + 2] );
1366 sum += 0.5 * ( mX[i] * mY[i + 2] - mY[i] * mX[i + 2] );
1369 double midPointX = ( p1.
x() + p3.
x() ) / 2.0;
1370 double midPointY = ( p1.
y() + p3.
y() ) / 2.0;
1372 double radius, centerX, centerY;
1376 double r2 = radius * radius;
1387 double cov = 0.5 - d * std::sqrt( r2 - d * d ) / ( M_PI * r2 ) - M_1_PI * std::asin( d / radius );
1388 double circleChordArea = 0;
1389 if ( circlePointLeftOfLine == centerPointLeftOfLine )
1391 circleChordArea = M_PI * r2 * ( 1 - cov );
1395 circleChordArea = M_PI * r2 * cov;
1398 if ( !circlePointLeftOfLine )
1400 sum += circleChordArea;
1404 sum -= circleChordArea;
1414 double QgsCircularString::closestPointOnArc(
double x1,
double y1,
double x2,
double y2,
double x3,
double y3,
1417 double radius, centerX, centerY;
1442 segmentPt = ( distPtPt1 <= distPtPt3 ) ? pt1 : pt3;
1443 vertexAfter.
vertex = ( distPtPt1 <= distPtPt3 ) ? 1 : 2;
1450 segmentPt.
setX( pt.
x() );
1451 segmentPt.
setY( pt.
y() );
1457 double sqrDistancePointToCenter = ( pt.
x() - centerX ) * ( pt.
x() - centerX ) + ( pt.
y() - centerY ) * ( pt.
y() - centerY );
1458 *
leftOf = clockwise ? ( sqrDistancePointToCenter > radius * radius ? -1 : 1 )
1459 : ( sqrDistancePointToCenter < radius * radius ? -1 : 1 );
1465 void QgsCircularString::insertVertexBetween(
int after,
int before,
int pointOnCircle )
1467 double xAfter = mX.at( after );
1468 double yAfter = mY.at( after );
1469 double xBefore = mX.at( before );
1470 double yBefore = mY.at( before );
1471 double xOnCircle = mX.at( pointOnCircle );
1472 double yOnCircle = mY.at( pointOnCircle );
1474 double radius, centerX, centerY;
1477 double x = ( xAfter + xBefore ) / 2.0;
1478 double y = ( yAfter + yBefore ) / 2.0;
1481 mX.insert( before, newVertex.
x() );
1482 mY.insert( before, newVertex.
y() );
1486 mZ.insert( before, ( mZ[after] + mZ[before] ) / 2.0 );
1490 mM.insert( before, ( mM[after] + mM[before] ) / 2.0 );
1503 int before = vId.
vertex - 1;
1505 int after = vId.
vertex + 1;
1507 if ( vId.
vertex % 2 != 0 )
1537 int vertex1 = vId.
vertex - 2;
1538 int vertex2 = vId.
vertex - 1;
1539 int vertex3 = vId.
vertex;
1541 QgsPoint( mX[vertex1], mY[vertex1] ),
QgsPoint( mX[vertex2], mY[vertex2] ),
QgsPoint( mX[vertex3], mY[vertex3] ) );
1542 int vertex4 = vId.
vertex + 1;
1543 int vertex5 = vId.
vertex + 2;
1545 QgsPoint( mX[vertex3], mY[vertex3] ),
QgsPoint( mX[vertex4], mY[vertex4] ),
QgsPoint( mX[vertex5], mY[vertex5] ) );
1554 if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 2 )
1557 if ( startVertex.
vertex % 2 == 1 )
1560 double x1 = mX.at( startVertex.
vertex );
1561 double y1 = mY.at( startVertex.
vertex );
1562 double x2 = mX.at( startVertex.
vertex + 1 );
1563 double y2 = mY.at( startVertex.
vertex + 1 );
1564 double x3 = mX.at( startVertex.
vertex + 2 );
1565 double y3 = mY.at( startVertex.
vertex + 2 );
1572 std::reverse( copy->mX.begin(), copy->mX.end() );
1573 std::reverse( copy->mY.begin(), copy->mY.end() );
1576 std::reverse( copy->mZ.begin(), copy->mZ.end() );
1580 std::reverse( copy->mM.begin(), copy->mM.end() );
1590 double distanceTraversed = 0;
1592 if ( totalPoints == 0 )
1601 const double *x = mX.constData();
1602 const double *y = mY.constData();
1603 const double *z =
is3D() ? mZ.constData() :
nullptr;
1604 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1606 double prevX = *x++;
1607 double prevY = *y++;
1608 double prevZ = z ? *z++ : 0.0;
1609 double prevM = m ? *m++ : 0.0;
1613 return new QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1616 for (
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
1625 double z2 = z ? *z++ : 0.0;
1626 double m2 = m ? *m++ : 0.0;
1630 double z3 = z ? *z++ : 0.0;
1631 double m3 = m ? *m++ : 0.0;
1637 const double distanceToPoint = std::min( distance - distanceTraversed,
segmentLength );
1639 QgsPoint( pointType, x2, y2, z2, m2 ),
1640 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToPoint ) );
1656 if ( startDistance < 0 && endDistance < 0 )
1659 endDistance = std::max( startDistance, endDistance );
1662 if ( totalPoints == 0 )
1665 QVector< QgsPoint > substringPoints;
1666 substringPoints.reserve( totalPoints );
1674 const double *x = mX.constData();
1675 const double *y = mY.constData();
1676 const double *z =
is3D() ? mZ.constData() :
nullptr;
1677 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1679 double distanceTraversed = 0;
1680 double prevX = *x++;
1681 double prevY = *y++;
1682 double prevZ = z ? *z++ : 0.0;
1683 double prevM = m ? *m++ : 0.0;
1684 bool foundStart =
false;
1686 if ( startDistance < 0 )
1689 for (
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
1698 double z2 = z ? *z++ : 0.0;
1699 double m2 = m ? *m++ : 0.0;
1703 double z3 = z ? *z++ : 0.0;
1704 double m3 = m ? *m++ : 0.0;
1706 bool addedSegmentEnd =
false;
1708 if ( distanceTraversed <= startDistance && startDistance < distanceTraversed +
segmentLength )
1711 const double distanceToStart = startDistance - distanceTraversed;
1713 QgsPoint( pointType, x2, y2, z2, m2 ),
1714 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToStart );
1717 const bool endPointOnSegment = distanceTraversed +
segmentLength > endDistance;
1718 if ( endPointOnSegment )
1720 const double distanceToEnd = endDistance - distanceTraversed;
1721 const double midPointDistance = ( distanceToEnd - distanceToStart ) * 0.5 + distanceToStart;
1724 QgsPoint( pointType, x2, y2, z2, m2 ),
1725 QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
1727 QgsPoint( pointType, x2, y2, z2, m2 ),
1728 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
1729 addedSegmentEnd =
true;
1733 const double midPointDistance = (
segmentLength - distanceToStart ) * 0.5 + distanceToStart;
1736 QgsPoint( pointType, x2, y2, z2, m2 ),
1737 QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
1738 <<
QgsPoint( pointType, x3, y3, z3, m3 );
1739 addedSegmentEnd =
true;
1743 if ( !addedSegmentEnd && foundStart && ( distanceTraversed +
segmentLength > endDistance ) )
1746 const double distanceToEnd = endDistance - distanceTraversed;
1749 QgsPoint( pointType, x2, y2, z2, m2 ),
1750 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd / 2.0 )
1753 QgsPoint( pointType, x2, y2, z2, m2 ),
1754 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
1756 else if ( !addedSegmentEnd && foundStart )
1758 substringPoints <<
QgsPoint( pointType, x2, y2, z2, m2 )
1759 <<
QgsPoint( pointType, x3, y3, z3, m3 );
1767 if ( distanceTraversed >= endDistance )
1772 if ( !foundStart &&
qgsDoubleNear( distanceTraversed, startDistance ) )
1774 substringPoints <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1775 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1776 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1779 std::unique_ptr< QgsCircularString > result = std::make_unique< QgsCircularString >();
1780 result->setPoints( substringPoints );
1781 return result.release();
1794 mZ.reserve( nPoints );
1795 for (
int i = 0; i < nPoints; ++i )
1812 mM.reserve( nPoints );
1813 for (
int i = 0; i < nPoints; ++i )
1846 std::swap( mX, mY );
VertexType
Types of vertex.
TransformDirection
Indicates the direction (forward or inverse) of a transform.
Abstract base class for all geometries.
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
AxisOrder
Axis order for GML generation.
QString wktTypeStr() const
Returns the WKT type string of the geometry.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
QgsWkbTypes::Type mWkbType
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts of the geometry.
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, QgsWkbTypes::Type baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
static endian_t endian()
Returns whether this machine uses big or little endian.
Circular string geometry type.
bool equals(const QgsCurve &other) const override
Checks whether this curve exactly equals another curve.
double length() const override
Returns the planar, 2-dimensional length of the geometry.
QgsPoint pointN(int i) const SIP_HOLDGIL
Returns the point at index i within the circular string.
void points(QgsPointSequence &pts) const override
Returns a list of points within the curve.
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
int numPoints() const override SIP_HOLDGIL
Returns the number of points in the curve.
bool moveVertex(QgsVertexId position, const QgsPoint &newPos) override
Moves a vertex within the geometry.
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
QgsCircularString * snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0) const override
Makes a new geometry with all the points or vertices snapped to the closest point of the grid.
QgsCircularString * clone() const override
Clones the geometry by performing a deep copy.
QString geometryType() const override SIP_HOLDGIL
Returns a unique string representing the geometry type.
void append(const QgsCircularString *string)
Appends the contents of another circular string to the end of this circular string.
bool fromWkb(QgsConstWkbPtr &wkb) override
Sets the geometry from a WKB string.
int dimension() const override SIP_HOLDGIL
Returns the inherent dimension of the geometry.
void draw(QPainter &p) const override
Draws the geometry using the specified QPainter.
QgsCircularString * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
double closestSegment(const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf=nullptr, double epsilon=4 *std::numeric_limits< double >::epsilon()) const override
Searches for the closest segment of the geometry to a given point.
void swapXy() override
Swaps the x and y coordinates from the geometry.
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
static QgsCircularString fromTwoPointsAndCenter(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint ¢er, bool useShortestArc=true)
Creates a circular string with a single arc representing the curve from p1 to p2 with the specified c...
void filterVertices(const std::function< bool(const QgsPoint &) > &filter) override
Filters the vertices from the geometry in place, removing any which do not return true for the filter...
double segmentLength(QgsVertexId startVertex) const override
Returns the length of the segment of the geometry which begins at startVertex.
double xAt(int index) const override SIP_HOLDGIL
Returns the x-coordinate of the specified node in the line string.
bool removeDuplicateNodes(double epsilon=4 *std::numeric_limits< double >::epsilon(), bool useZValues=false) override
Removes duplicate nodes from the geometry, wherever removing the nodes does not result in a degenerat...
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
QDomElement asGml2(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML2 representation of the geometry.
void sumUpArea(double &sum) const override
Sums up the area of the curve by iterating over the vertices (shoelace formula).
QgsCircularString * reversed() const override
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
QgsRectangle calculateBoundingBox() const override
Default calculator for the minimal bounding box for the geometry.
bool pointAt(int node, QgsPoint &point, Qgis::VertexType &type) const override
Returns the point and vertex id of a point within the curve.
int indexOf(const QgsPoint &point) const final
Returns the index of the first vertex matching the given point, or -1 if a matching vertex is not fou...
bool dropMValue() override
Drops any measure values which exist in the geometry.
double yAt(int index) const override SIP_HOLDGIL
Returns the y-coordinate of the specified node in the line string.
void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) override SIP_THROW(QgsCsException)
Transforms the geometry using a coordinate transform.
QgsPoint endPoint() const override SIP_HOLDGIL
Returns the end point of the curve.
void addToPainterPath(QPainterPath &path) const override
Adds a curve to a painter path.
int wkbSize(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns the length of the QByteArray returned by asWkb()
QgsCircularString * curveSubstring(double startDistance, double endDistance) const override
Returns a new curve representing a substring of this curve.
void drawAsPolygon(QPainter &p) const override
Draws the curve as a polygon on the specified QPainter.
void setPoints(const QgsPointSequence &points)
Sets the circular string's points.
QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a new line string geometry corresponding to a segmentized approximation of the curve.
double vertexAngle(QgsVertexId vertex) const override
Returns approximate angle at a vertex.
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
QDomElement asGml3(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML3 representation of the geometry.
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
void clear() override
Clears the geometry, ie reset it to a null geometry.
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
bool hasCurvedSegments() const override
Returns true if the geometry contains curved segments.
void scroll(int firstVertexIndex) final
Scrolls the curve vertices so that they start with the vertex at the given index.
QgsPoint * interpolatePoint(double distance) const override
Returns an interpolated point on the curve at the specified distance.
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
bool insertVertex(QgsVertexId position, const QgsPoint &vertex) override
Inserts a vertex into the geometry.
std::tuple< std::unique_ptr< QgsCurve >, std::unique_ptr< QgsCurve > > splitCurveAtVertex(int index) const final
Splits the curve at the specified vertex index, returning two curves which represent the portion of t...
QgsPoint startPoint() const override SIP_HOLDGIL
Returns the starting point of the curve.
int compareToSameClass(const QgsAbstractGeometry *other) const final
Compares to an other geometry of the same class, and returns a integer for sorting of the two geometr...
json asJsonObject(int precision=17) const override
Returns a json object representation of the geometry.
void transformVertices(const std::function< QgsPoint(const QgsPoint &) > &transform) override
Transforms the vertices from the geometry in place, applying the transform function to every vertex.
QgsCircularString() SIP_HOLDGIL
Constructs an empty circular string.
QgsWkbTypes::Type readHeader() const
readHeader
Abstract base class for curved geometry type.
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
bool snapToGridPrivate(double hSpacing, double vSpacing, double dSpacing, double mSpacing, const QVector< double > &srcX, const QVector< double > &srcY, const QVector< double > &srcZ, const QVector< double > &srcM, QVector< double > &outX, QVector< double > &outY, QVector< double > &outZ, QVector< double > &outM) const
Helper function for QgsCurve subclasses to snap to grids.
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
static QPair< QgsWkbTypes::Type, QString > wktReadBlock(const QString &wkt)
Parses a WKT block of the format "TYPE( contents )" and returns a pair of geometry type to contents (...
static double circleTangentDirection(const QgsPoint &tangentPoint, const QgsPoint &cp1, const QgsPoint &cp2, const QgsPoint &cp3) SIP_HOLDGIL
Calculates the direction angle of a circle tangent (clockwise from north in radians)
static double sqrDistance2D(const QgsPoint &pt1, const QgsPoint &pt2) SIP_HOLDGIL
Returns the squared 2D distance between two points.
static double ccwAngle(double dy, double dx) SIP_HOLDGIL
Returns the counter clockwise angle between a line with components dx, dy and the line with dx > 0 an...
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
static QgsPoint segmentMidPointFromCenter(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint ¢er, bool useShortestArc=true) SIP_HOLDGIL
Calculates the midpoint on the circle passing through p1 and p2, with the specified center coordinate...
static void circleCenterRadius(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double &radius, double ¢erX, double ¢erY) SIP_HOLDGIL
Returns radius and center of the circle through pt1, pt2, pt3.
static double averageAngle(double x1, double y1, double x2, double y2, double x3, double y3) SIP_HOLDGIL
Calculates the average angle (in radians) between the two linear segments from (x1,...
static bool angleOnCircle(double angle, double angle1, double angle2, double angle3) SIP_HOLDGIL
Returns true if an angle is between angle1 and angle3 on a circle described by angle1,...
static bool circleClockwise(double angle1, double angle2, double angle3) SIP_HOLDGIL
Returns true if the circle defined by three angles is ordered clockwise.
static double sweepAngle(double centerX, double centerY, double x1, double y1, double x2, double y2, double x3, double y3) SIP_HOLDGIL
Calculates angle of a circular string part defined by pt1, pt2, pt3.
static double circleLength(double x1, double y1, double x2, double y2, double x3, double y3) SIP_HOLDGIL
Length of a circular string segment defined by pt1, pt2, pt3.
static QgsPoint pointOnLineWithDistance(const QgsPoint &startPoint, const QgsPoint &directionPoint, double distance) SIP_HOLDGIL
Returns a point a specified distance toward a second point.
static QgsPointSequence pointsFromWKT(const QString &wktCoordinateList, bool is3D, bool isMeasure)
Returns a list of points contained in a WKT string.
static void segmentizeArc(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3, QgsPointSequence &points, double tolerance=M_PI_2/90, QgsAbstractGeometry::SegmentationToleranceType toleranceType=QgsAbstractGeometry::MaximumAngle, bool hasZ=false, bool hasM=false)
Convert circular arc defined by p1, p2, p3 (p1/p3 being start resp.
static bool circleAngleBetween(double angle, double angle1, double angle2, bool clockwise) SIP_HOLDGIL
Returns true if, in a circle, angle is between angle1 and angle2.
static QgsPoint interpolatePointOnArc(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double distance) SIP_HOLDGIL
Interpolates a point on an arc defined by three points, pt1, pt2 and pt3.
static QDomElement pointsToGML3(const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, bool is3D, QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY)
Returns a gml::posList DOM element.
static int leftOfLine(const double x, const double y, const double x1, const double y1, const double x2, const double y2) SIP_HOLDGIL
Returns a value < 0 if the point (x, y) is left of the line from (x1, y1) -> (x2, y2).
static QString pointsToWKT(const QgsPointSequence &points, int precision, bool is3D, bool isMeasure)
Returns a WKT coordinate list.
Line string geometry type, with support for z-dimension and m-values.
void setPoints(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
void arcTo(QPainterPath &path, QPointF pt1, QPointF pt2, QPointF pt3)
Utility class for identifying a unique vertex within a geometry.