21#include <nlohmann/json.hpp>
38#include <QPainterPath>
48 bool hasZ = p1.
is3D();
81 int pointCount = std::min( x.size(), y.size() );
82 if ( x.size() == pointCount )
88 mX = x.mid( 0, pointCount );
90 if ( y.size() == pointCount )
96 mY = y.mid( 0, pointCount );
98 if ( !z.isEmpty() && z.count() >= pointCount )
101 if ( z.size() == pointCount )
107 mZ = z.mid( 0, pointCount );
110 if ( !m.isEmpty() && m.count() >= pointCount )
113 if ( m.size() == pointCount )
119 mM = m.mid( 0, pointCount );
132 auto result = std::make_unique< QgsCircularString >();
134 return result.release();
143 const int size = mX.size();
144 const int otherSize = otherLine->mX.size();
145 if ( size > otherSize )
149 else if ( size < otherSize )
156 else if ( !
is3D() && otherLine->
is3D() )
158 const bool considerZ =
is3D();
166 for (
int i = 0; i < size; i++ )
168 const double x = mX[i];
169 const double otherX = otherLine->mX[i];
174 else if ( x > otherX )
179 const double y = mY[i];
180 const double otherY = otherLine->mY[i];
185 else if ( y > otherY )
192 const double z = mZ[i];
193 const double otherZ = otherLine->mZ[i];
199 else if ( z > otherZ )
207 const double m = mM[i];
208 const double otherM = otherLine->mM[i];
214 else if ( m > otherM )
225 return u
"CircularString"_s;
252 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
255 double zMin = std::numeric_limits<double>::quiet_NaN();
256 double zMax = std::numeric_limits<double>::quiet_NaN();
259 zMin = *std::min_element( mZ.begin() + i, mZ.begin() + i + 3 );
260 zMax = *std::max_element( mZ.begin() + i, mZ.begin() + i + 3 );
264 bbox =
QgsBox3D( box2d, zMin, zMax );
272 if ( nPoints > 0 && nPoints % 2 == 0 )
274 double z = std::numeric_limits<double>::quiet_NaN();
285 z = mZ[ nPoints - 1 ];
287 bbox.
combineWith( mX[ nPoints - 1 ], mY[ nPoints - 1 ], z );
294 const int size = mX.size();
295 if ( index < 1 || index >= size - 1 )
298 const bool useZ =
is3D();
301 QVector<double> newX( size );
302 QVector<double> newY( size );
303 QVector<double> newZ( useZ ? size : 0 );
304 QVector<double> newM( useM ? size : 0 );
305 auto it = std::copy( mX.constBegin() + index, mX.constEnd() - 1, newX.begin() );
306 it = std::copy( mX.constBegin(), mX.constBegin() + index, it );
307 *it = *newX.constBegin();
308 mX = std::move( newX );
310 it = std::copy( mY.constBegin() + index, mY.constEnd() - 1, newY.begin() );
311 it = std::copy( mY.constBegin(), mY.constBegin() + index, it );
312 *it = *newY.constBegin();
313 mY = std::move( newY );
316 it = std::copy( mZ.constBegin() + index, mZ.constEnd() - 1, newZ.begin() );
317 it = std::copy( mZ.constBegin(), mZ.constBegin() + index, it );
318 *it = *newZ.constBegin();
319 mZ = std::move( newZ );
323 it = std::copy( mM.constBegin() + index, mM.constEnd() - 1, newM.begin() );
324 it = std::copy( mM.constBegin(), mM.constBegin() + index, it );
325 *it = *newM.constBegin();
326 mM = std::move( newM );
332 double centerX, centerY, radius;
341 bbox.combineExtentWith( pt3.
x(), pt3.
y() );
343 QgsPointSequence compassPoints = compassPointsOnSegment( p1Angle, p2Angle, p3Angle, centerX, centerY, radius );
344 QgsPointSequence::const_iterator cpIt = compassPoints.constBegin();
345 for ( ; cpIt != compassPoints.constEnd(); ++cpIt )
347 bbox.combineExtentWith( cpIt->x(), cpIt->y() );
352QgsPointSequence QgsCircularString::compassPointsOnSegment(
double p1Angle,
double p2Angle,
double p3Angle,
double centerX,
double centerY,
double radius )
356 QgsPoint nPoint( centerX, centerY + radius );
357 QgsPoint ePoint( centerX + radius, centerY );
358 QgsPoint sPoint( centerX, centerY - radius );
359 QgsPoint wPoint( centerX - radius, centerY );
361 if ( p3Angle >= p1Angle )
363 if ( p2Angle > p1Angle && p2Angle < p3Angle )
365 if ( p1Angle <= 90 && p3Angle >= 90 )
367 pointList.append( nPoint );
369 if ( p1Angle <= 180 && p3Angle >= 180 )
371 pointList.append( wPoint );
373 if ( p1Angle <= 270 && p3Angle >= 270 )
375 pointList.append( sPoint );
380 pointList.append( ePoint );
381 if ( p1Angle >= 90 || p3Angle <= 90 )
383 pointList.append( nPoint );
385 if ( p1Angle >= 180 || p3Angle <= 180 )
387 pointList.append( wPoint );
389 if ( p1Angle >= 270 || p3Angle <= 270 )
391 pointList.append( sPoint );
397 if ( p2Angle < p1Angle && p2Angle > p3Angle )
399 if ( p1Angle >= 270 && p3Angle <= 270 )
401 pointList.append( sPoint );
403 if ( p1Angle >= 180 && p3Angle <= 180 )
405 pointList.append( wPoint );
407 if ( p1Angle >= 90 && p3Angle <= 90 )
409 pointList.append( nPoint );
414 pointList.append( ePoint );
415 if ( p1Angle <= 270 || p3Angle >= 270 )
417 pointList.append( sPoint );
419 if ( p1Angle <= 180 || p3Angle >= 180 )
421 pointList.append( wPoint );
423 if ( p1Angle <= 90 || p3Angle >= 90 )
425 pointList.append( nPoint );
446 const bool hasZ =
is3D();
450 mX.resize( nVertices );
451 mY.resize( nVertices );
453 mZ.resize( nVertices );
457 mM.resize( nVertices );
460 for (
int i = 0; i < nVertices; ++i )
487 parts.second =
parts.second.remove(
'(' ).remove(
')' );
488 QString secondWithoutParentheses =
parts.second;
489 secondWithoutParentheses = secondWithoutParentheses.simplified().remove(
' ' );
490 if ( (
parts.second.compare(
"EMPTY"_L1, Qt::CaseInsensitive ) == 0 ) ||
491 secondWithoutParentheses.isEmpty() )
504 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
515 wkb << static_cast<quint32>(
wkbType() );
540 std::unique_ptr< QgsLineString > line(
curveToLine() );
541 QDomElement gml = line->asGml2( doc, precision, ns, axisOrder );
550 QDomElement elemCurve = doc.createElementNS( ns, u
"Curve"_s );
555 QDomElement elemSegments = doc.createElementNS( ns, u
"segments"_s );
556 QDomElement elemArcString = doc.createElementNS( ns, u
"ArcString"_s );
558 elemSegments.appendChild( elemArcString );
559 elemCurve.appendChild( elemSegments );
567 std::unique_ptr< QgsLineString > line(
curveToLine() );
568 return line->asJsonObject( precision );
580 error = QObject::tr(
"CircularString has less than 3 points and is not empty." );
591 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
622 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
637 bool res =
snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM,
638 result->mX, result->mY, result->mZ, result->mM,
false );
640 return result.release();
647 std::unique_ptr< QgsLineString > line(
curveToLine() );
648 return line->simplifyByDistance( tolerance );
653 if ( mX.count() <= 3 )
656 double prevX = mX.at( 0 );
657 double prevY = mY.at( 0 );
659 bool useZ = hasZ && useZValues;
660 double prevZ = useZ ? mZ.at( 0 ) : 0;
662 int remaining = mX.count();
665 while ( i + 1 < remaining )
667 double currentCurveX = mX.at( i );
668 double currentCurveY = mY.at( i );
669 double currentX = mX.at( i + 1 );
670 double currentY = mY.at( i + 1 );
671 double currentZ = useZ ? mZ.at( i + 1 ) : 0;
704 return std::min( mX.size(), mY.size() );
709 const int size = mX.size();
713 const double *x = mX.constData();
714 const double *y = mY.constData();
715 const bool useZ =
is3D();
717 const double *z = useZ ? mZ.constData() :
nullptr;
718 const double *m = useM ? mM.constData() :
nullptr;
720 for (
int i = 0; i < size; i += 2 )
749 if ( i < 0 || std::min( mX.size(), mY.size() ) <= i )
754 double x = mX.at( i );
755 double y = mY.at( i );
786 if ( index >= 0 && index < mX.size() )
787 return mX.at( index );
794 if ( index >= 0 && index < mY.size() )
795 return mY.at( index );
802 if ( index >= 0 && index < mZ.size() )
803 return mZ.at( index );
810 if ( index >= 0 && index < mM.size() )
811 return mM.at( index );
823 int size = mX.size();
825 double *srcX = mX.data();
826 double *srcY = mY.data();
827 double *srcM = hasM ? mM.data() :
nullptr;
828 double *srcZ = hasZ ? mZ.data() :
nullptr;
831 for (
int i = 0; i < size; ++i )
835 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
836 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
864 int size = mX.size();
866 double *srcX = mX.data();
867 double *srcY = mY.data();
868 double *srcM = hasM ? mM.data() :
nullptr;
869 double *srcZ = hasZ ? mZ.data() :
nullptr;
871 double *destX = srcX;
872 double *destY = srcY;
873 double *destM = srcM;
874 double *destZ = srcZ;
876 int filteredPoints = 0;
877 for (
int i = 0; i < size; ++i )
881 double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
882 double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
884 if ( filter(
QgsPoint( x, y, z, m ) ) )
896 mX.resize( filteredPoints );
897 mY.resize( filteredPoints );
899 mZ.resize( filteredPoints );
901 mM.resize( filteredPoints );
910 int size = mX.size();
912 double *srcX = mX.data();
913 double *srcY = mY.data();
914 double *srcM = hasM ? mM.data() :
nullptr;
915 double *srcZ = hasZ ? mZ.data() :
nullptr;
917 for (
int i = 0; i < size; ++i )
921 double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
922 double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
936 const bool useZ =
is3D();
939 const int size = mX.size();
941 return std::make_tuple( std::make_unique< QgsCircularString >(), std::make_unique< QgsCircularString >() );
943 index = std::clamp( index, 0, size - 1 );
945 const int part1Size = index + 1;
946 QVector< double > x1( part1Size );
947 QVector< double > y1( part1Size );
948 QVector< double > z1( useZ ? part1Size : 0 );
949 QVector< double > m1( useM ? part1Size : 0 );
951 const double *sourceX = mX.constData();
952 const double *sourceY = mY.constData();
953 const double *sourceZ = useZ ? mZ.constData() :
nullptr;
954 const double *sourceM = useM ? mM.constData() :
nullptr;
956 double *destX = x1.data();
957 double *destY = y1.data();
958 double *destZ = useZ ? z1.data() :
nullptr;
959 double *destM = useM ? m1.data() :
nullptr;
961 std::copy( sourceX, sourceX + part1Size, destX );
962 std::copy( sourceY, sourceY + part1Size, destY );
964 std::copy( sourceZ, sourceZ + part1Size, destZ );
966 std::copy( sourceM, sourceM + part1Size, destM );
968 const int part2Size = size - index;
970 return std::make_tuple( std::make_unique< QgsCircularString >( x1, y1, z1, m1 ), std::make_unique< QgsCircularString >() );
972 QVector< double > x2( part2Size );
973 QVector< double > y2( part2Size );
974 QVector< double > z2( useZ ? part2Size : 0 );
975 QVector< double > m2( useM ? part2Size : 0 );
978 destZ = useZ ? z2.data() :
nullptr;
979 destM = useM ? m2.data() :
nullptr;
980 std::copy( sourceX + index, sourceX + size, destX );
981 std::copy( sourceY + index, sourceY + size, destY );
983 std::copy( sourceZ + index, sourceZ + size, destZ );
985 std::copy( sourceM + index, sourceM + size, destM );
988 return std::make_tuple( std::make_unique< QgsCircularString >(), std::make_unique< QgsCircularString >( x2, y2, z2, m2 ) );
990 return std::make_tuple( std::make_unique< QgsCircularString >( x1, y1, z1, m1 ), std::make_unique< QgsCircularString >( x2, y2, z2, m2 ) );
997 for (
int i = 0; i < nPts; ++i )
999 pts.push_back(
pointN( i ) );
1019 bool hasZ = firstPt.
is3D();
1024 mX.resize(
points.size() );
1025 mY.resize(
points.size() );
1028 mZ.resize(
points.size() );
1036 mM.resize(
points.size() );
1043 for (
int i = 0; i <
points.size(); ++i )
1049 double z =
points.at( i ).z();
1050 mZ[i] = std::isnan( z ) ? 0 : z;
1054 double m =
points.at( i ).m();
1055 mM[i] = std::isnan( m ) ? 0 : m;
1062 if ( !line || line->
isEmpty() )
1105 mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
1118 mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
1136 double *zArray =
nullptr;
1142 std::unique_ptr< double[] > dummyZ;
1143 if ( !hasZ || !transformZ )
1145 dummyZ = std::make_unique<double[]>( nPoints );
1146 zArray = dummyZ.get();
1162 for (
int i = 0; i < nPoints; ++i )
1165 t.map( mX.at( i ), mY.at( i ), &x, &y );
1170 mZ[i] = mZ.at( i ) * zScale + zTranslate;
1174 mM[i] = mM.at( i ) * mScale + mTranslate;
1179void arcTo( QPainterPath &path, QPointF pt1, QPointF pt2, QPointF pt3 )
1181 double centerX, centerY, radius;
1183 radius, centerX, centerY );
1188 double diameter = 2 * radius;
1189 path.arcTo( centerX - radius, centerY - radius, diameter, diameter, -p1Angle, -sweepAngle );
1200 if ( path.isEmpty() || path.currentPosition() != QPointF( mX[0], mY[0] ) )
1202 path.moveTo( QPointF( mX[0], mY[0] ) );
1205 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
1207 arcTo( path, QPointF( mX[i], mY[i] ), QPointF( mX[i + 1], mY[i + 1] ), QPointF( mX[i + 2], mY[i + 2] ) );
1211 if ( nPoints % 2 == 0 )
1213 path.lineTo( mX[ nPoints - 1 ], mY[ nPoints - 1 ] );
1224 if ( position.
vertex >= mX.size() || position.
vertex < 1 )
1229 mX.insert( position.
vertex, vertex.
x() );
1230 mY.insert( position.
vertex, vertex.
y() );
1233 mZ.insert( position.
vertex, vertex.
z() );
1237 mM.insert( position.
vertex, vertex.
m() );
1240 bool vertexNrEven = ( position.
vertex % 2 == 0 );
1255 if ( position.
vertex < 0 || position.
vertex >= mX.size() )
1260 mX[position.
vertex] = newPos.
x();
1261 mY[position.
vertex] = newPos.
y();
1264 mZ[position.
vertex] = newPos.
z();
1268 mM[position.
vertex] = newPos.
m();
1277 if ( nVertices < 4 )
1282 if ( position.
vertex < 0 || position.
vertex > ( nVertices - 1 ) )
1287 if ( position.
vertex < ( nVertices - 2 ) )
1320 double minDist = std::numeric_limits<double>::max();
1323 int minDistLeftOf = 0;
1325 double currentDist = 0.0;
1328 for (
int i = 0; i < ( nPoints - 2 ) ; i += 2 )
1330 currentDist = closestPointOnArc( mX[i], mY[i], mX[i + 1], mY[i + 1], mX[i + 2], mY[i + 2], pt, segmentPt, vertexAfter, leftOf, epsilon );
1331 if ( currentDist < minDist )
1333 minDist = currentDist;
1334 minDistSegmentPoint = segmentPt;
1338 minDistLeftOf = *leftOf;
1343 if ( minDist == std::numeric_limits<double>::max() )
1346 segmentPt = minDistSegmentPoint;
1347 vertexAfter = minDistVertexAfter;
1348 vertexAfter.
part = 0;
1349 vertexAfter.
ring = 0;
1352 *leftOf =
qgsDoubleNear( minDist, 0.0 ) ? 0 : minDistLeftOf;
1378 for (
int i = 0; i < maxIndex; i += 2 )
1381 QgsPoint p2( mX[i + 1], mY[i + 1] );
1382 QgsPoint p3( mX[i + 2], mY[i + 2] );
1392 mSummedUpArea += 0.5 * ( mX[i] * mY[i + 2] - mY[i] * mX[i + 2] );
1395 double midPointX = ( p1.
x() + p3.
x() ) / 2.0;
1396 double midPointY = ( p1.
y() + p3.
y() ) / 2.0;
1398 double radius, centerX, centerY;
1402 double r2 = radius * radius;
1413 double cov = 0.5 - d * std::sqrt( r2 - d * d ) / ( M_PI * r2 ) - M_1_PI * std::asin( d / radius );
1414 double circleChordArea = 0;
1415 if ( circlePointLeftOfLine == centerPointLeftOfLine )
1417 circleChordArea = M_PI * r2 * ( 1 - cov );
1421 circleChordArea = M_PI * r2 * cov;
1424 if ( !circlePointLeftOfLine )
1477 double normalSign = 1.0;
1497 QVector<double> projX;
1498 QVector<double> projY;
1499 projX.reserve( nrPoints );
1500 projY.reserve( nrPoints );
1501 for (
int i = 0; i < nrPoints; i++ )
1503 const double vecAX = mX[i] - ptA.
x();
1504 const double vecAY = mY[i] - ptA.
y();
1505 const double vecAZ = mZ[i] - ptA.
z();
1507 projX.push_back( vecAX * ux.
x() + vecAY * ux.
y() + vecAZ * ux.
z() );
1508 projY.push_back( vecAX * uy.
x() + vecAY * uy.
y() + vecAZ * uy.
z() );
1525double QgsCircularString::closestPointOnArc(
double x1,
double y1,
double x2,
double y2,
double x3,
double y3,
1528 double radius, centerX, centerY;
1553 segmentPt = ( distPtPt1 <= distPtPt3 ) ? pt1 : pt3;
1554 vertexAfter.
vertex = ( distPtPt1 <= distPtPt3 ) ? 1 : 2;
1561 segmentPt.
setX( pt.
x() );
1562 segmentPt.
setY( pt.
y() );
1568 double sqrDistancePointToCenter = pt.
distanceSquared( centerX, centerY );
1569 *
leftOf = clockwise ? ( sqrDistancePointToCenter > radius * radius ? -1 : 1 )
1570 : ( sqrDistancePointToCenter < radius * radius ? -1 : 1 );
1576void QgsCircularString::insertVertexBetween(
int after,
int before,
int pointOnCircle )
1578 double xAfter = mX.at( after );
1579 double yAfter = mY.at( after );
1580 double xBefore = mX.at( before );
1581 double yBefore = mY.at( before );
1582 double xOnCircle = mX.at( pointOnCircle );
1583 double yOnCircle = mY.at( pointOnCircle );
1585 double radius, centerX, centerY;
1588 double x = ( xAfter + xBefore ) / 2.0;
1589 double y = ( yAfter + yBefore ) / 2.0;
1592 mX.insert( before, newVertex.
x() );
1593 mY.insert( before, newVertex.
y() );
1597 mZ.insert( before, ( mZ[after] + mZ[before] ) / 2.0 );
1601 mM.insert( before, ( mM[after] + mM[before] ) / 2.0 );
1614 int before = vId.
vertex - 1;
1616 int after = vId.
vertex + 1;
1618 if ( vId.
vertex % 2 != 0 )
1648 int vertex1 = vId.
vertex - 2;
1649 int vertex2 = vId.
vertex - 1;
1650 int vertex3 = vId.
vertex;
1652 QgsPoint( mX[vertex1], mY[vertex1] ),
QgsPoint( mX[vertex2], mY[vertex2] ),
QgsPoint( mX[vertex3], mY[vertex3] ) );
1653 int vertex4 = vId.
vertex + 1;
1654 int vertex5 = vId.
vertex + 2;
1656 QgsPoint( mX[vertex3], mY[vertex3] ),
QgsPoint( mX[vertex4], mY[vertex4] ),
QgsPoint( mX[vertex5], mY[vertex5] ) );
1665 if ( startVertex.
vertex % 2 == 1 )
1668 if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 2 )
1671 double x1 = mX.at( startVertex.
vertex );
1672 double y1 = mY.at( startVertex.
vertex );
1673 double x2 = mX.at( startVertex.
vertex + 1 );
1674 double y2 = mY.at( startVertex.
vertex + 1 );
1675 double x3 = mX.at( startVertex.
vertex + 2 );
1676 double y3 = mY.at( startVertex.
vertex + 2 );
1689 if ( fromVertex.
part != 0 || fromVertex.
ring != 0 || toVertex.
part != 0 || toVertex.
ring != 0 )
1692 const int fromVertexNumber = fromVertex.
vertex;
1693 const int toVertexNumber = toVertex.
vertex;
1696 if ( fromVertexNumber < 0 || fromVertexNumber >= nPoints || toVertexNumber < 0 || toVertexNumber >= nPoints )
1699 if ( fromVertexNumber == toVertexNumber )
1702 const double *xData = mX.constData();
1703 const double *yData = mY.constData();
1704 double totalDistance = 0.0;
1708 const int startArc = ( fromVertexNumber / 2 ) * 2;
1711 for (
int i = startArc; i < nPoints - 2; i += 2 )
1714 double x1 = xData[i];
1715 double y1 = yData[i];
1716 double x2 = xData[i + 1];
1717 double y2 = yData[i + 1];
1718 double x3 = xData[i + 2];
1719 double y3 = yData[i + 2];
1722 if ( fromVertexNumber >= i && toVertexNumber <= i + 2 )
1724 if ( fromVertexNumber == i && toVertexNumber == i + 2 )
1729 else if ( fromVertexNumber == i && toVertexNumber == i + 1 )
1732 double centerX, centerY, radius;
1735 return QgsGeometryUtilsBase::calculateArcLength( centerX, centerY, radius, x1, y1, x2, y2, x3, y3, 0, 1 );
1737 else if ( fromVertexNumber == i + 1 && toVertexNumber == i + 2 )
1740 double centerX, centerY, radius;
1743 return QgsGeometryUtilsBase::calculateArcLength( centerX, centerY, radius, x1, y1, x2, y2, x3, y3, 1, 2 );
1745 else if ( fromVertexNumber == i + 1 && toVertexNumber == i + 1 )
1752 bool startInThisSegment = ( fromVertexNumber >= i && fromVertexNumber <= i + 2 );
1753 bool endInThisSegment = ( toVertexNumber >= i && toVertexNumber <= i + 2 );
1754 bool segmentInRange = ( fromVertexNumber < i && toVertexNumber > i + 2 );
1756 if ( startInThisSegment && !endInThisSegment )
1759 if ( fromVertexNumber == i )
1761 else if ( fromVertexNumber == i + 1 )
1764 double centerX, centerY, radius;
1766 totalDistance +=
QgsGeometryUtilsBase::calculateArcLength( centerX, centerY, radius, x1, y1, x2, y2, x3, y3, 1, 2 );
1769 else if ( !startInThisSegment && endInThisSegment )
1772 if ( toVertexNumber == i + 1 )
1775 double centerX, centerY, radius;
1777 totalDistance +=
QgsGeometryUtilsBase::calculateArcLength( centerX, centerY, radius, x1, y1, x2, y2, x3, y3, 0, 1 );
1779 else if ( toVertexNumber == i + 2 )
1783 else if ( segmentInRange )
1790 return totalDistance;
1797 std::reverse( copy->mX.begin(), copy->mX.end() );
1798 std::reverse( copy->mY.begin(), copy->mY.end() );
1801 std::reverse( copy->mZ.begin(), copy->mZ.end() );
1805 std::reverse( copy->mM.begin(), copy->mM.end() );
1817 double distanceTraversed = 0;
1819 if ( totalPoints == 0 )
1828 const double *x = mX.constData();
1829 const double *y = mY.constData();
1830 const double *z =
is3D() ? mZ.constData() :
nullptr;
1831 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1833 double prevX = *x++;
1834 double prevY = *y++;
1835 double prevZ = z ? *z++ : 0.0;
1836 double prevM = m ? *m++ : 0.0;
1840 return new QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1843 for (
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
1852 double z2 = z ? *z++ : 0.0;
1853 double m2 = m ? *m++ : 0.0;
1857 double z3 = z ? *z++ : 0.0;
1858 double m3 = m ? *m++ : 0.0;
1864 const double distanceToPoint = std::min( distance - distanceTraversed,
segmentLength );
1866 QgsPoint( pointType, x2, y2, z2, m2 ),
1867 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToPoint ) );
1883 if ( startDistance < 0 && endDistance < 0 )
1886 endDistance = std::max( startDistance, endDistance );
1889 if ( totalPoints == 0 )
1892 QVector< QgsPoint > substringPoints;
1893 substringPoints.reserve( totalPoints );
1901 const double *x = mX.constData();
1902 const double *y = mY.constData();
1903 const double *z =
is3D() ? mZ.constData() :
nullptr;
1904 const double *m =
isMeasure() ? mM.constData() :
nullptr;
1906 double distanceTraversed = 0;
1907 double prevX = *x++;
1908 double prevY = *y++;
1909 double prevZ = z ? *z++ : 0.0;
1910 double prevM = m ? *m++ : 0.0;
1911 bool foundStart =
false;
1913 if ( startDistance < 0 )
1916 for (
int i = 0; i < ( totalPoints - 2 ) ; i += 2 )
1925 double z2 = z ? *z++ : 0.0;
1926 double m2 = m ? *m++ : 0.0;
1930 double z3 = z ? *z++ : 0.0;
1931 double m3 = m ? *m++ : 0.0;
1933 bool addedSegmentEnd =
false;
1935 if ( distanceTraversed <= startDistance && startDistance < distanceTraversed +
segmentLength )
1938 const double distanceToStart = startDistance - distanceTraversed;
1940 QgsPoint( pointType, x2, y2, z2, m2 ),
1941 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToStart );
1944 const bool endPointOnSegment = distanceTraversed +
segmentLength > endDistance;
1945 if ( endPointOnSegment )
1947 const double distanceToEnd = endDistance - distanceTraversed;
1948 const double midPointDistance = ( distanceToEnd - distanceToStart ) * 0.5 + distanceToStart;
1951 QgsPoint( pointType, x2, y2, z2, m2 ),
1952 QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
1954 QgsPoint( pointType, x2, y2, z2, m2 ),
1955 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
1956 addedSegmentEnd =
true;
1960 const double midPointDistance = (
segmentLength - distanceToStart ) * 0.5 + distanceToStart;
1963 QgsPoint( pointType, x2, y2, z2, m2 ),
1964 QgsPoint( pointType, x3, y3, z3, m3 ), midPointDistance )
1965 <<
QgsPoint( pointType, x3, y3, z3, m3 );
1966 addedSegmentEnd =
true;
1970 if ( !addedSegmentEnd && foundStart && ( distanceTraversed +
segmentLength > endDistance ) )
1973 const double distanceToEnd = endDistance - distanceTraversed;
1976 QgsPoint( pointType, x2, y2, z2, m2 ),
1977 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd / 2.0 )
1980 QgsPoint( pointType, x2, y2, z2, m2 ),
1981 QgsPoint( pointType, x3, y3, z3, m3 ), distanceToEnd );
1983 else if ( !addedSegmentEnd && foundStart )
1985 substringPoints <<
QgsPoint( pointType, x2, y2, z2, m2 )
1986 <<
QgsPoint( pointType, x3, y3, z3, m3 );
1994 if ( distanceTraversed >= endDistance )
1999 if ( !foundStart &&
qgsDoubleNear( distanceTraversed, startDistance ) )
2001 substringPoints <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
2002 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM )
2003 <<
QgsPoint( pointType, prevX, prevY, prevZ, prevM );
2006 auto result = std::make_unique< QgsCircularString >();
2007 result->setPoints( substringPoints );
2008 return result.release();
2021 mZ.reserve( nPoints );
2022 for (
int i = 0; i < nPoints; ++i )
2039 mM.reserve( nPoints );
2040 for (
int i = 0; i < nPoints; ++i )
2073 std::swap( mX, mY );
QFlags< GeometryValidityFlag > GeometryValidityFlags
Geometry validity flags.
VertexType
Types of vertex.
@ Curve
An intermediate point on a segment defining the curvature of the segment.
@ Segment
The actual start or end point of a segment.
WkbType
The WKB type describes the number of dimensions a geometry has.
@ CircularString
CircularString.
@ CircularStringZ
CircularStringZ.
TransformDirection
Indicates the direction (forward or inverse) of a transform.
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
bool isMeasure() const
Returns true if the geometry contains m values.
QFlags< WkbFlag > WkbFlags
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
AxisOrder
Axis order for GML generation.
QString wktTypeStr() const
Returns the WKT type string of the geometry.
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, Qgis::WkbType baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
QgsAbstractGeometry()=default
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts of the geometry.
static endian_t endian()
Returns whether this machine uses big or little endian.
A 3-dimensional box composed of x, y, z coordinates.
void combineWith(const QgsBox3D &box)
Expands the bbox so that it covers both the original rectangle and the given rectangle.
QgsCircularString * snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0, bool removeRedundantPoints=false) const override
Makes a new geometry with all the points or vertices snapped to the closest point of the grid.
double length() const override
Returns the planar, 2-dimensional length of the geometry.
QString geometryType() const override
Returns a unique string representing the geometry type.
void points(QgsPointSequence &pts) const override
Returns a list of points within the curve.
bool moveVertex(QgsVertexId position, const QgsPoint &newPos) override
Moves a vertex within the geometry.
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
QgsCircularString * clone() const override
Clones the geometry by performing a deep copy.
QgsPoint endPoint() const override
Returns the end point of the curve.
void append(const QgsCircularString *string)
Appends the contents of another circular string to the end of this circular string.
bool fromWkb(QgsConstWkbPtr &wkb) override
Sets the geometry from a WKB string.
void draw(QPainter &p) const override
Draws the geometry using the specified QPainter.
QgsCircularString * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
double closestSegment(const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf=nullptr, double epsilon=4 *std::numeric_limits< double >::epsilon()) const override
Searches for the closest segment of the geometry to a given point.
void swapXy() override
Swaps the x and y coordinates from the geometry.
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
double distanceBetweenVertices(QgsVertexId fromVertex, QgsVertexId toVertex) const override
Returns the distance along the curve between two vertices.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
static QgsCircularString fromTwoPointsAndCenter(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint ¢er, bool useShortestArc=true)
Creates a circular string with a single arc representing the curve from p1 to p2 with the specified c...
void filterVertices(const std::function< bool(const QgsPoint &) > &filter) override
Filters the vertices from the geometry in place, removing any which do not return true for the filter...
double segmentLength(QgsVertexId startVertex) const override
Returns the length of the segment of the geometry which begins at startVertex.
bool removeDuplicateNodes(double epsilon=4 *std::numeric_limits< double >::epsilon(), bool useZValues=false) override
Removes duplicate nodes from the geometry, wherever removing the nodes does not result in a degenerat...
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) override
Transforms the geometry using a coordinate transform.
QDomElement asGml2(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML2 representation of the geometry.
void sumUpArea(double &sum) const override
Sums up the area of the curve by iterating over the vertices (shoelace formula).
QgsCircularString * reversed() const override
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
QgsBox3D calculateBoundingBox3D() const override
Calculates the minimal 3D bounding box for the geometry.
QgsPoint startPoint() const override
Returns the starting point of the curve.
bool pointAt(int node, QgsPoint &point, Qgis::VertexType &type) const override
Returns the point and vertex id of a point within the curve.
bool isEmpty() const override
Returns true if the geometry is empty.
int indexOf(const QgsPoint &point) const final
Returns the index of the first vertex matching the given point, or -1 if a matching vertex is not fou...
bool dropMValue() override
Drops any measure values which exist in the geometry.
int numPoints() const override
Returns the number of points in the curve.
void addToPainterPath(QPainterPath &path) const override
Adds a curve to a painter path.
int wkbSize(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns the length of the QByteArray returned by asWkb().
QgsCircularString * curveSubstring(double startDistance, double endDistance) const override
Returns a new curve representing a substring of this curve.
void drawAsPolygon(QPainter &p) const override
Draws the curve as a polygon on the specified QPainter.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
int dimension() const override
Returns the inherent dimension of the geometry.
void setPoints(const QgsPointSequence &points)
Sets the circular string's points.
QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a new line string geometry corresponding to a segmentized approximation of the curve.
void sumUpArea3D(double &sum) const override
Sums up the 3d area of the curve by iterating over the vertices (shoelace formula).
double vertexAngle(QgsVertexId vertex) const override
Returns approximate angle at a vertex.
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
QgsAbstractGeometry * simplifyByDistance(double tolerance) const override
Simplifies the geometry by applying the Douglas Peucker simplification by distance algorithm.
QDomElement asGml3(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML3 representation of the geometry.
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns a WKB representation of the geometry.
void clear() override
Clears the geometry, ie reset it to a null geometry.
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
bool hasCurvedSegments() const override
Returns true if the geometry contains curved segments.
void scroll(int firstVertexIndex) final
Scrolls the curve vertices so that they start with the vertex at the given index.
QgsPoint * interpolatePoint(double distance) const override
Returns an interpolated point on the curve at the specified distance.
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
double zAt(int index) const override
Returns the z-coordinate of the specified node in the line string.
bool insertVertex(QgsVertexId position, const QgsPoint &vertex) override
Inserts a vertex into the geometry.
QgsCircularString()
Constructs an empty circular string.
QgsPoint pointN(int i) const
Returns the point at index i within the circular string.
std::tuple< std::unique_ptr< QgsCurve >, std::unique_ptr< QgsCurve > > splitCurveAtVertex(int index) const final
Splits the curve at the specified vertex index, returning two curves which represent the portion of t...
double mAt(int index) const override
Returns the m-coordinate of the specified node in the line string.
int compareToSameClass(const QgsAbstractGeometry *other) const final
Compares to an other geometry of the same class, and returns a integer for sorting of the two geometr...
json asJsonObject(int precision=17) const override
Returns a json object representation of the geometry.
void transformVertices(const std::function< QgsPoint(const QgsPoint &) > &transform) override
Transforms the vertices from the geometry in place, applying the transform function to every vertex.
Qgis::WkbType readHeader() const
readHeader
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
bool mHasCachedSummedUpArea
bool mHasCachedSummedUpArea3D
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
bool snapToGridPrivate(double hSpacing, double vSpacing, double dSpacing, double mSpacing, const QVector< double > &srcX, const QVector< double > &srcY, const QVector< double > &srcZ, const QVector< double > &srcM, QVector< double > &outX, QVector< double > &outY, QVector< double > &outZ, QVector< double > &outM, bool removeRedundantPoints) const
Helper function for QgsCurve subclasses to snap to grids.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const
Tells whether the operation has been canceled already.
static double circleLength(double x1, double y1, double x2, double y2, double x3, double y3)
Length of a circular string segment defined by pt1, pt2, pt3.
static double calculateArcLength(double centerX, double centerY, double radius, double x1, double y1, double x2, double y2, double x3, double y3, int fromVertex, int toVertex)
Calculates the precise arc length between two vertices on a circular arc.
static double ccwAngle(double dy, double dx)
Returns the counter clockwise angle between a line with components dx, dy and the line with dx > 0 an...
static bool circleClockwise(double angle1, double angle2, double angle3)
Returns true if the circle defined by three angles is ordered clockwise.
static double sweepAngle(double centerX, double centerY, double x1, double y1, double x2, double y2, double x3, double y3)
Calculates angle of a circular string part defined by pt1, pt2, pt3.
static double averageAngle(double x1, double y1, double x2, double y2, double x3, double y3)
Calculates the average angle (in radians) between the two linear segments from (x1,...
static bool circleAngleBetween(double angle, double angle1, double angle2, bool clockwise)
Returns true if, in a circle, angle is between angle1 and angle2.
static bool angleOnCircle(double angle, double angle1, double angle2, double angle3)
Returns true if an angle is between angle1 and angle3 on a circle described by angle1,...
static int leftOfLine(const double x, const double y, const double x1, const double y1, const double x2, const double y2)
Returns a value < 0 if the point (x, y) is left of the line from (x1, y1) -> (x2, y2).
static void circleCenterRadius(double x1, double y1, double x2, double y2, double x3, double y3, double &radius, double ¢erX, double ¢erY)
Returns radius and center of the circle through (x1 y1), (x2 y2), (x3 y3).
static double circleTangentDirection(const QgsPoint &tangentPoint, const QgsPoint &cp1, const QgsPoint &cp2, const QgsPoint &cp3)
Calculates the direction angle of a circle tangent (clockwise from north in radians).
static QgsPoint pointOnLineWithDistance(const QgsPoint &startPoint, const QgsPoint &directionPoint, double distance)
Returns a point a specified distance toward a second point.
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure, QgsAbstractGeometry::WkbFlags flags)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
static QPair< Qgis::WkbType, QString > wktReadBlock(const QString &wkt)
Parses a WKT block of the format "TYPE( contents )" and returns a pair of geometry type to contents (...
static void circleCenterRadius(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double &radius, double ¢erX, double ¢erY)
Returns radius and center of the circle through pt1, pt2, pt3.
static QgsPoint interpolatePointOnArc(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double distance)
Interpolates a point on an arc defined by three points, pt1, pt2 and pt3.
static QgsPointSequence pointsFromWKT(const QString &wktCoordinateList, bool is3D, bool isMeasure)
Returns a list of points contained in a WKT string.
static void segmentizeArc(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3, QgsPointSequence &points, double tolerance=M_PI_2/90, QgsAbstractGeometry::SegmentationToleranceType toleranceType=QgsAbstractGeometry::MaximumAngle, bool hasZ=false, bool hasM=false)
Convert circular arc defined by p1, p2, p3 (p1/p3 being start resp.
static Q_DECL_DEPRECATED double sqrDistance2D(double x1, double y1, double x2, double y2)
Returns the squared 2D distance between (x1, y1) and (x2, y2).
static bool checkWeaklyFor3DPlane(const QgsAbstractGeometry *geom, QgsPoint &pt1, QgsPoint &pt2, QgsPoint &pt3, double epsilon=std::numeric_limits< double >::epsilon())
Checks if a 3D geometry has a plane defined by at least 3 non-collinear points.
static QDomElement pointsToGML3(const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, bool is3D, QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY)
Returns a gml::posList DOM element.
static QString pointsToWKT(const QgsPointSequence &points, int precision, bool is3D, bool isMeasure)
Returns a WKT coordinate list.
static QgsPoint segmentMidPointFromCenter(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint ¢er, bool useShortestArc=true)
Calculates the midpoint on the circle passing through p1 and p2, with the specified center coordinate...
Line string geometry type, with support for z-dimension and m-values.
void setPoints(size_t size, const double *x, const double *y, const double *z=nullptr, const double *m=nullptr)
Resets the line string to match the specified point data.
Point geometry type, with support for z-dimension and m-values.
void setY(double y)
Sets the point's y-coordinate.
void setX(double x)
Sets the point's x-coordinate.
double distanceSquared(double x, double y) const
Returns the Cartesian 2D squared distance between this point a specified x, y coordinate.
A rectangle specified with double values.
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
double y() const
Returns Y coordinate.
double z() const
Returns Z coordinate.
double x() const
Returns X coordinate.
void normalize()
Normalizes the current vector in place.
static QgsVector3D crossProduct(const QgsVector3D &v1, const QgsVector3D &v2)
Returns the cross product of two vectors.
static Qgis::WkbType dropM(Qgis::WkbType type)
Drops the m dimension (if present) for a WKB type and returns the new type.
static Qgis::WkbType dropZ(Qgis::WkbType type)
Drops the z dimension (if present) for a WKB type and returns the new type.
static Qgis::WkbType addM(Qgis::WkbType type)
Adds the m dimension to a WKB type and returns the new type.
static Qgis::WkbType addZ(Qgis::WkbType type)
Adds the z dimension to a WKB type and returns the new type.
static Q_INVOKABLE bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
static Q_INVOKABLE bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
double ANALYSIS_EXPORT leftOf(const QgsPoint &thepoint, const QgsPoint *p1, const QgsPoint *p2)
Returns whether 'thepoint' is left or right of the line from 'p1' to 'p2'. Negative values mean left ...
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
T qgsgeometry_cast(QgsAbstractGeometry *geom)
QVector< QgsPoint > QgsPointSequence
void arcTo(QPainterPath &path, QPointF pt1, QPointF pt2, QPointF pt3)
Utility class for identifying a unique vertex within a geometry.