20#include <nlohmann/json.hpp>
34#include <QRegularExpression>
40 QVector< QgsLineString * > linestrings;
44 QVector< const QgsAbstractGeometry * > geometries;
46 while ( ! geometries.isEmpty() )
51 linestrings << static_cast< QgsLineString * >( curve->segmentize() );
55 for (
int i = 0; i < collection->numGeometries(); ++i )
57 geometries.append( collection->geometryN( i ) );
62 if ( curvePolygon->exteriorRing() )
63 linestrings << static_cast< QgsLineString * >( curvePolygon->exteriorRing()->segmentize() );
65 for (
int i = 0; i < curvePolygon->numInteriorRings(); ++i )
67 linestrings << static_cast< QgsLineString * >( curvePolygon->interiorRing( i )->segmentize() );
76 double minDist = std::numeric_limits<double>::max();
77 double currentDist = 0;
94 if ( currentDist <= minDist )
96 minDist = currentDist;
97 minDistPoint = vertex;
98 id.part = vertexId.
part;
99 id.ring = vertexId.
ring;
100 id.vertex = vertexId.
vertex;
101 id.type = vertexId.
type;
116 if ( vertexAfter.
vertex > 0 )
121 const double length = pointBefore.
distance( pointAfter );
131 closestPoint.addZValue( pointBefore.
z() + ( pointAfter.
z() - pointBefore.
z() ) * distance / length );
133 closestPoint.addMValue( pointBefore.
m() + ( pointAfter.
m() - pointBefore.
m() ) * distance / length );
143 double currentDist = 0;
148 if ( vertexId ==
id )
162 double currentDist = 0;
177 nextVertex = previousVertex;
182 while ( currentDist < distance && geometry.
nextVertex( nextVertex, point ) )
184 if ( !first && nextVertex.
part == previousVertex.
part && nextVertex.
ring == previousVertex.
ring )
192 previousVertex = nextVertex;
196 if ( currentDist > distance )
201 previousVertex = nextVertex;
202 previousPoint = point;
212 const double area = std::abs(
213 ( linePoint1.
x() - linePoint2.
x() ) * ( point.
y() - linePoint2.
y() ) -
214 ( linePoint1.
y() - linePoint2.
y() ) * ( point.
x() - linePoint2.
x() )
217 const double length = std::sqrt(
218 std::pow( linePoint1.
x() - linePoint2.
x(), 2 ) +
219 std::pow( linePoint1.
y() - linePoint2.
y(), 2 )
222 const double distance = area / length;
223 return qgsDoubleNear( distance, 0.0, epsilon ) ? 0.0 : distance;
232 const double x1 = linePoint1.
x() - center.
x();
233 const double y1 = linePoint1.
y() - center.
y();
234 const double x2 = linePoint2.
x() - center.
x();
235 const double y2 = linePoint2.
y() - center.
y();
236 const double dx = x2 - x1;
237 const double dy = y2 - y1;
239 const double dr2 = std::pow( dx, 2 ) + std::pow( dy, 2 );
240 const double d = x1 * y2 - x2 * y1;
242 const double disc = std::pow( radius, 2 ) * dr2 - std::pow( d, 2 );
252 const int sgnDy = dy < 0 ? -1 : 1;
254 const double sqrDisc = std::sqrt( disc );
256 const double ax = center.
x() + ( d * dy + sgnDy * dx * sqrDisc ) / dr2;
257 const double ay = center.
y() + ( -d * dx + std::fabs( dy ) * sqrDisc ) / dr2;
260 const double bx = center.
x() + ( d * dy - sgnDy * dx * sqrDisc ) / dr2;
261 const double by = center.
y() + ( -d * dx - std::fabs( dy ) * sqrDisc ) / dr2;
268 intersection.
set( p1.
x(), p1.
y() );
272 intersection.
set( p2.
x(), p2.
y() );
283 const double d = center1.
distance( center2 );
287 const bool singleSolutionInt =
qgsDoubleNear( d, std::fabs( r1 - r2 ) );
290 if ( !singleSolutionExt && d > ( r1 + r2 ) )
295 else if ( !singleSolutionInt && d < std::fabs( r1 - r2 ) )
315 const double a = singleSolutionExt ? r1 : ( singleSolutionInt ? ( r1 > r2 ? r1 : -r1 ) : ( ( r1 * r1 ) - ( r2 * r2 ) + ( d * d ) ) / ( 2.0 * d ) );
320 const double dx = center2.
x() - center1.
x();
321 const double dy = center2.
y() - center1.
y();
324 const double x2 = center1.
x() + ( dx * a / d );
325 const double y2 = center1.
y() + ( dy * a / d );
328 if ( singleSolutionExt || singleSolutionInt )
341 const double h = std::sqrt( ( r1 * r1 ) - ( a * a ) );
346 const double rx = dy * ( h / d );
347 const double ry = dx * ( h / d );
350 intersection1 =
QgsPointXY( x2 + rx, y2 - ry );
351 intersection2 =
QgsPointXY( x2 - rx, y2 + ry );
361 const double dx = center.
x() - p.
x();
362 const double dy = center.
y() - p.
y();
363 const double distanceSquared = dx * dx + dy * dy;
364 const double radiusSquared = radius * radius;
365 if ( distanceSquared < radiusSquared )
372 const double distanceToTangent = std::sqrt( distanceSquared - radiusSquared );
384 if ( radius1 > radius2 )
387 const double radius2a = radius2 - radius1;
396 QgsVector v1( -( line1P2.
y() - center1.
y() ), line1P2.
x() - center1.
x() );
397 const double v1Length = v1.
length();
398 v1 = v1 * ( radius1 / v1Length );
401 line1P1 = center1 + v1;
402 line1P2 = line1P2 + v1;
406 QgsVector v2( line2P2.
y() - center1.
y(), -( line2P2.
x() - center1.
x() ) );
407 const double v2Length = v2.
length();
408 v2 = v2 * ( radius1 / v2Length );
411 line2P1 = center1 + v2;
412 line2P2 = line2P2 + v2;
420 if ( radius1 > radius2 )
424 const double d = center1.
distance( center2 );
425 const double radius1a = radius1 + radius2;
442 QgsVector v1( ( line1P2.
y() - center2.
y() ), -( line1P2.
x() - center2.
x() ) );
443 const double v1Length = v1.
length();
444 v1 = v1 * ( radius2 / v1Length );
447 line1P1 = center2 + v1;
448 line1P2 = line1P2 + v1;
452 QgsVector v2( -( line2P2.
y() - center2.
y() ), line2P2.
x() - center2.
x() );
453 const double v2Length = v2.
length();
454 v2 = v2 * ( radius2 / v2Length );
457 line2P1 = center2 + v2;
458 line2P2 = line2P2 + v2;
465 QVector<SelfIntersection> intersections;
471 for (
int i = 0, j = 1; j < n; i = j++ )
478 const int start = j + 1;
479 const int end = i == 0 && isClosed ? n - 1 : n;
480 for (
int k = start, l = start + 1; l < end; k = l++ )
486 bool intersection =
false;
497 intersections.append( s );
500 return intersections;
518 double centerX, centerY, radius;
521 const double theta = distance / radius;
522 const double anglePt1 = std::atan2( pt1.
y() - centerY, pt1.
x() - centerX );
523 const double anglePt2 = std::atan2( pt2.
y() - centerY, pt2.
x() - centerX );
524 const double anglePt3 = std::atan2( pt3.
y() - centerY, pt3.
x() - centerX );
526 const double angleDest = anglePt1 + (
isClockwise ? -theta : theta );
528 const double x = centerX + radius * ( std::cos( angleDest ) );
529 const double y = centerY + radius * ( std::sin( angleDest ) );
531 const double z = pt1.
is3D() ?
543 const QgsPoint midPoint( ( p1.
x() + p2.
x() ) / 2.0, ( p1.
y() + p2.
y() ) / 2.0 );
544 const double midDist = std::sqrt(
sqrDistance2D( p1, midPoint ) );
545 if ( radius < midDist )
549 const double centerMidDist = std::sqrt( radius * radius - midDist * midDist );
550 const double dist = radius - centerMidDist;
552 const double midDx = midPoint.
x() - p1.
x();
553 const double midDy = midPoint.
y() - p1.
y();
556 QVector<QgsPoint> possibleMidPoints;
563 double minDist = std::numeric_limits<double>::max();
564 int minDistIndex = -1;
565 for (
int i = 0; i < possibleMidPoints.size(); ++i )
567 const double currentDist =
sqrDistance2D( mousePos, possibleMidPoints.at( i ) );
568 if ( currentDist < minDist )
571 minDist = currentDist;
575 if ( minDistIndex == -1 )
580 result = possibleMidPoints.at( minDistIndex );
592 if ( !useShortestArc )
593 midPointAngle += M_PI;
594 return center.
project( center.
distance( p1 ), midPointAngle * 180 / M_PI );
601 double mX, mY, radius;
634 const double bDistance = std::sqrt( ( b.
x() - centerX ) * ( b.
x() - centerX ) +
635 ( b.
y() - centerY ) * ( b.
y() - centerY ) );
637 double diff = std::fabs( radius - bDistance );
641 const double abX = b.
x() - a.
x();
642 const double abY = b.
y() - a.
y();
644 const double cbX = b.
x() -
c.x();
645 const double cbY = b.
y() -
c.y();
647 const double dot = ( abX * cbX + abY * cbY );
648 const double cross = ( abX * cbY - abY * cbX );
650 const double alpha = std::atan2( cross, dot );
656 if ( diff < distanceTolerance )
658 const double angle1 = arcAngle( a1, a2, a3 );
659 const double angle2 = arcAngle( a2, a3, b );
664 diff = std::fabs( angle1 - angle2 );
665 if ( diff > pointSpacingAngleTolerance )
675 if ( bSide != a2Side )
683 bool reversed =
false;
707 circleCenterRadius( circlePoint1, circlePoint2, circlePoint3, radius, centerX, centerY );
709 if ( circlePoint1 != circlePoint3 && ( radius < 0 ||
qgsDoubleNear( segSide, 0.0 ) ) )
717 double increment = tolerance;
721 tolerance = std::min( tolerance, radius * 2 );
722 const double halfAngle = std::acos( -tolerance / radius + 1 );
723 increment = 2 * halfAngle;
727 const double a1 = std::atan2( circlePoint1.
y() - centerY, circlePoint1.
x() - centerX );
728 double a2 = std::atan2( circlePoint2.
y() - centerY, circlePoint2.
x() - centerX );
729 double a3 = std::atan2( circlePoint3.
y() - centerY, circlePoint3.
x() - centerX );
732 const bool symmetric =
true;
735 double angle = a3 - a1;
737 if ( angle <= 0 ) angle += M_PI * 2;
740 const int segs = ceil( angle / increment );
742 increment = angle / segs;
756 QVector<QgsPoint> stringPoints;
757 stringPoints.insert( 0, circlePoint1 );
758 if ( circlePoint2 != circlePoint3 && circlePoint1 != circlePoint2 )
772 const double tolError = increment / 100;
773 const double stopAngle = a3 - tolError;
774 for (
double angle = a1 + increment; angle < stopAngle; angle += increment )
776 x = centerX + radius * std::cos( angle );
777 y = centerY + radius * std::sin( angle );
788 stringPoints.insert( stringPoints.size(),
QgsPoint( pointWkbType, x, y, z, m ) );
791 stringPoints.insert( stringPoints.size(), circlePoint3 );
796 std::reverse( stringPoints.begin(), stringPoints.end() );
798 if ( ! points.empty() && stringPoints.front() == points.back() ) stringPoints.pop_front();
799 points.append( stringPoints );
804 const double side = ( ( pt2.
x() - pt1.
x() ) * ( pt3.
y() - pt1.
y() ) - ( pt3.
x() - pt1.
x() ) * ( pt2.
y() - pt1.
y() ) );
825 const int dim = 2 + is3D + isMeasure;
828 const QStringList coordList = wktCoordinateList.split(
',', Qt::SkipEmptyParts );
833 const thread_local QRegularExpression rx( QStringLiteral(
"\\s" ) );
834 const thread_local QRegularExpression rxIsNumber( QStringLiteral(
"^[+-]?(\\d\\.?\\d*[Ee][+\\-]?\\d+|(\\d+\\.\\d*|\\d*\\.\\d+)|\\d+)$" ) );
835 for (
const QString &pointCoordinates : coordList )
837 const QStringList coordinates = pointCoordinates.split( rx, Qt::SkipEmptyParts );
840 if ( coordinates.filter( rxIsNumber ).size() != coordinates.size() )
843 if ( coordinates.size() == 3 && !foundZ && !foundM && !is3D && !isMeasure )
849 else if ( coordinates.size() >= 4 && ( !( is3D || foundZ ) || !( isMeasure || foundM ) ) )
858 for (
const QString &pointCoordinates : coordList )
860 QStringList coordinates = pointCoordinates.split( rx, Qt::SkipEmptyParts );
861 if ( coordinates.size() < dim )
865 const double x = coordinates[idx++].toDouble();
866 const double y = coordinates[idx++].toDouble();
869 if ( ( is3D || foundZ ) && coordinates.length() > idx )
870 z = coordinates[idx++].toDouble();
873 if ( ( isMeasure || foundM ) && coordinates.length() > idx )
874 m = coordinates[idx++].toDouble();
877 if ( is3D || foundZ )
879 if ( isMeasure || foundM )
886 if ( isMeasure || foundM )
892 points.append(
QgsPoint( t, x, y, z, m ) );
900 wkb << static_cast<quint32>( points.size() );
901 for (
const QgsPoint &point : points )
903 wkb << point.x() << point.y();
906 double z = point.z();
909 z = -std::numeric_limits<double>::max();
915 double m = point.m();
918 m = -std::numeric_limits<double>::max();
927 QString wkt = QStringLiteral(
"(" );
936 wkt += QLatin1String(
", " );
938 if ( wkt.endsWith( QLatin1String(
", " ) ) )
946 QDomElement elemCoordinates = doc.createElementNS( ns, QStringLiteral(
"coordinates" ) );
949 const QString cs = QStringLiteral(
"," );
951 const QString ts = QStringLiteral(
" " );
953 elemCoordinates.setAttribute( QStringLiteral(
"cs" ), cs );
954 elemCoordinates.setAttribute( QStringLiteral(
"ts" ), ts );
956 QString strCoordinates;
964 if ( strCoordinates.endsWith( ts ) )
965 strCoordinates.chop( 1 );
967 elemCoordinates.appendChild( doc.createTextNode( strCoordinates ) );
968 return elemCoordinates;
973 QDomElement elemPosList = doc.createElementNS( ns, QStringLiteral(
"posList" ) );
974 elemPosList.setAttribute( QStringLiteral(
"srsDimension" ), is3D ? 3 : 2 );
976 QString strCoordinates;
986 if ( strCoordinates.endsWith(
' ' ) )
987 strCoordinates.chop( 1 );
989 elemPosList.appendChild( doc.createTextNode( strCoordinates ) );
995 QString json = QStringLiteral(
"[ " );
1000 if ( json.endsWith( QLatin1String(
", " ) ) )
1011 json coordinates( json::array() );
1016 coordinates.push_back( {
qgsRound( p.x(), precision ),
qgsRound( p.y(), precision ),
qgsRound( p.z(), precision ) } );
1020 coordinates.push_back( {
qgsRound( p.x(), precision ),
qgsRound( p.y(), precision ) } );
1028 QString wktParsed = wkt;
1030 bool isEmpty =
false;
1031 const QLatin1String empty {
"EMPTY" };
1032 if ( wkt.contains( empty, Qt::CaseInsensitive ) )
1034 const thread_local QRegularExpression whiteSpaces(
"\\s" );
1035 wktParsed.remove( whiteSpaces );
1036 const int index = wktParsed.indexOf( empty, 0, Qt::CaseInsensitive );
1038 if ( index == wktParsed.length() - empty.size() )
1042 wktParsed = wktParsed.left( index );
1053 const int openedParenthesisCount = wktParsed.count(
'(' );
1054 const int closedParenthesisCount = wktParsed.count(
')' );
1056 for (
int i = 0 ; i < openedParenthesisCount - closedParenthesisCount; ++i )
1057 wktParsed.push_back(
')' );
1059 wktParsed.truncate( wktParsed.size() - ( closedParenthesisCount - openedParenthesisCount ) );
1061 const thread_local QRegularExpression cooRegEx( QStringLiteral(
"^[^\\(]*\\((.*)\\)[^\\)]*$" ), QRegularExpression::DotMatchesEverythingOption );
1062 const QRegularExpressionMatch match = cooRegEx.match( wktParsed );
1063 contents = match.hasMatch() ? match.captured( 1 ) : QString();
1066 return qMakePair( wkbType, contents );
1073 block.reserve( wkt.size() );
1076 const QChar *wktData = wkt.data();
1077 const int wktLength = wkt.length();
1078 for (
int i = 0, n = wktLength; i < n; ++i, ++wktData )
1080 if ( ( wktData->isSpace() || *wktData ==
'\n' || *wktData ==
'\t' ) && level == 0 )
1083 if ( *wktData ==
',' && level == 0 )
1085 if ( !block.isEmpty() )
1087 if ( block.startsWith(
'(' ) && !defaultType.isEmpty() )
1088 block.prepend( defaultType +
' ' );
1089 blocks.append( block );
1094 if ( *wktData ==
'(' )
1096 else if ( *wktData ==
')' )
1100 if ( !block.isEmpty() )
1102 if ( block.startsWith(
'(' ) && !defaultType.isEmpty() )
1103 block.prepend( defaultType +
' ' );
1104 blocks.append( block );
1114 const double x = ( pt1.
x() + pt2.
x() ) / 2.0;
1115 const double y = ( pt1.
y() + pt2.
y() ) / 2.0;
1116 double z = std::numeric_limits<double>::quiet_NaN();
1117 double m = std::numeric_limits<double>::quiet_NaN();
1122 z = ( pt1.
z() + pt2.
z() ) / 2.0;
1128 m = ( pt1.
m() + pt2.
m() ) / 2.0;
1131 return QgsPoint( pType, x, y, z, m );
1136 const double _fraction = 1 - fraction;
1138 p1.
x() * _fraction + p2.
x() * fraction,
1139 p1.
y() * _fraction + p2.
y() * fraction,
1140 p1.
is3D() ? p1.
z() * _fraction + p2.
z() * fraction : std::numeric_limits<double>::quiet_NaN(),
1141 p1.
isMeasure() ? p1.
m() * _fraction + p2.
m() * fraction : std::numeric_limits<double>::quiet_NaN() );
1146 const double deltaX = ( x2 - x1 ) * fraction;
1147 const double deltaY = ( y2 - y1 ) * fraction;
1148 return QgsPointXY( x1 + deltaX, y1 + deltaY );
1156 const double fraction = ( value - v1 ) / ( v2 - v1 );
1162 const double delta_x = pt2.
x() - pt1.
x();
1163 const double delta_y = pt2.
y() - pt1.
y();
1169 return delta_y / delta_x;
1188 a = pt1.
y() - pt2.
y();
1189 b = pt2.
x() - pt1.
x();
1190 c = pt1.
x() * pt2.
y() - pt1.
y() * pt2.
x();
1200 if ( ( p == s1 ) || ( p == s2 ) )
1218 const double y = ( -
c - a * p.
x() ) / b;
1219 const double m =
gradient( s1, s2 );
1220 const double d2 = 1 + m * m;
1221 const double H = p.
y() - y;
1222 const double dx = m * H / d2;
1223 const double dy = m * dx;
1237 for (
const QgsPoint &pt : points )
1239 if ( pt.isMeasure() )
1242 point.
setM( pt.m() );
1255 for (
const QgsPoint &pt : points )
1260 point.
setZ( pt.z() );
1273 else if ( reference.
is3D() )
1287 if ( segmentStart.
is3D() && segmentEnd.
is3D() )
1289 double z1 = segmentStart.
z();
1290 double z2 = segmentEnd.
z();
1291 double interpolatedZ;
1292 double tempX, tempY;
1294 segmentStart.
x(), segmentStart.
y(), segmentEnd.
x(), segmentEnd.
y(),
1295 distanceFromStart, tempX, tempY, &z1, &z2, &interpolatedZ );
1296 result.
setZ( interpolatedZ );
1301 double m1 = segmentStart.
m();
1302 double m2 = segmentEnd.
m();
1303 double interpolatedM;
1304 double tempX, tempY;
1306 segmentStart.
x(), segmentStart.
y(), segmentEnd.
x(), segmentEnd.
y(),
1307 distanceFromStart, tempX, tempY,
nullptr,
nullptr,
nullptr, &m1, &m2, &interpolatedM );
1308 result.
setM( interpolatedM );
1316 double distance1,
double distance2,
1321 double chamferStartX, chamferStartY, chamferEndX, chamferEndY;
1324 segment1Start.
x(), segment1Start.
y(), segment1End.
x(), segment1End.
y(),
1325 segment2Start.
x(), segment2Start.
y(), segment2End.
x(), segment2End.
y(),
1326 distance1, distance2,
1327 chamferStartX, chamferStartY,
1328 chamferEndX, chamferEndY,
1329 nullptr,
nullptr,
nullptr,
nullptr,
1330 nullptr,
nullptr,
nullptr,
nullptr,
1349 double filletPointsX[3], filletPointsY[3];
1352 segment1Start.
x(), segment1Start.
y(), segment1End.
x(), segment1End.
y(),
1353 segment2Start.
x(), segment2Start.
y(), segment2End.
x(), segment2End.
y(),
1355 filletPointsX, filletPointsY,
1356 nullptr,
nullptr,
nullptr,
nullptr,
1357 nullptr,
nullptr,
nullptr,
nullptr,
1366 if ( segment1Start.
is3D() && segment1End.
is3D() && segment2Start.
is3D() && segment2End.
is3D() )
1368 filletMidPoint.
setZ( ( filletPoint1.
z() + filletPoint2.
z() ) / 2.0 );
1372 filletMidPoint.
setM( ( filletPoint1.
m() + filletPoint2.
m() ) / 2.0 );
1385 createFillet( segment1Start, segment1End, segment2Start, segment2End, radius, p1, p2, p3, epsilon );
1386 filletPoints[0] = p1;
1387 filletPoints[1] = p2;
1388 filletPoints[2] = p3;
1395 double distance1,
double distance2 )
1398 createChamfer( segment1Start, segment1End, segment2Start, segment2End, distance1, distance2, chamferStart, chamferEnd );
1400 return std::make_unique<QgsLineString>(
1401 QVector<QgsPoint> { segment1Start, chamferStart, chamferEnd, segment2Start } );
1407 double radius,
int segments )
1410 createFilletArray( segment1Start, segment1End, segment2Start, segment2End, radius, filletPoints );
1413 double intersectionX, intersectionY;
1414 bool isIntersection;
1416 segment1Start.
x(), segment1Start.
y(), segment1End.
x(), segment1End.
y(),
1417 segment2Start.
x(), segment2Start.
y(), segment2End.
x(), segment2End.
y(),
1418 intersectionX, intersectionY, isIntersection, 1e-8,
true );
1420 if ( !isIntersection )
1430 const QgsPoint segment1FarEnd = ( dist1ToStart < dist1ToEnd ) ? segment1End : segment1Start;
1431 const QgsPoint segment2FarEnd = ( dist2ToStart < dist2ToEnd ) ? segment2End : segment2Start;
1433 if ( segments <= 0 )
1436 auto completeCurve = std::make_unique<QgsCompoundCurve>();
1439 auto firstSegment = std::make_unique<QgsLineString>(
1440 QVector<QgsPoint> { segment1FarEnd, filletPoints[0] } );
1441 completeCurve->addCurve( firstSegment.release() );
1444 auto circularString = std::make_unique<QgsCircularString>();
1445 circularString->setPoints( {filletPoints[0], filletPoints[1], filletPoints[2]} );
1446 completeCurve->addCurve( circularString.release() );
1449 auto lastSegment = std::make_unique<QgsLineString>(
1450 QVector<QgsPoint> { filletPoints[2], segment2FarEnd } );
1451 completeCurve->addCurve( lastSegment.release() );
1453 return completeCurve;
1458 QVector<QgsPoint> points;
1459 points.append( segment1FarEnd );
1463 tempArc.
setPoints( {filletPoints[0], filletPoints[1], filletPoints[2]} );
1467 const double angleTolerance = ( 2.0 * M_PI ) / ( 4.0 * segments );
1471 for (
int i = 0; i < segmentizedArc->numPoints(); ++i )
1473 points.append( segmentizedArc->vertexAt(
QgsVertexId( 0, 0, i ) ) );
1476 points.append( segment2FarEnd );
1478 return std::make_unique<QgsLineString>( points );
1490 const QgsCurve *curve,
int vertexIndex,
1491 double distance1,
double distance2 )
1497 const QgsCurve *curve,
int vertexIndex,
1498 double radius,
int segments )
1503std::unique_ptr< QgsAbstractGeometry > QgsGeometryUtils::doChamferFilletOnVertex(
1505 double value1,
double value2,
int segments
1514 if ( vertexIndex < 0 || vertexIndex > curve->
numPoints() - 1 )
1520 throw QgsInvalidArgumentException(
"Opened curve must have at least 3 points." );
1521 if ( vertexIndex <= 0 || vertexIndex >= curve->
numPoints() - 1 )
1522 throw QgsInvalidArgumentException( QStringLiteral(
"Vertex index out of range. %1 must be in (0, %2)." ).arg( vertexIndex ).arg( curve->
numPoints() - 1 ) );
1526 QgsPoint pPrev = curve->
vertexAt( QgsVertexId( 0, 0, vertexIndex - 1 ) );
1527 const QgsPoint p = curve->
vertexAt( QgsVertexId( 0, 0, vertexIndex ) );
1528 QgsPoint pNext = curve->
vertexAt( QgsVertexId( 0, 0, vertexIndex + 1 ) );
1531 if ( vertexIndex - 1 < 0 )
1533 if ( vertexIndex + 1 >= curve->
numPoints() )
1534 pNext = curve->
vertexAt( QgsVertexId( 0, 0, 1 ) );
1537 QgsPoint firstNewPoint, middlePoint, lastNewPoint;
1541 double rad = std::min( value1, pPrev.
distance( p ) * 0.95 );
1542 rad = std::min( rad, pNext.
distance( p ) * 0.95 );
1545 QgsPoint filletPoints[3];
1548 firstNewPoint = filletPoints[0];
1549 middlePoint = filletPoints[1];
1550 lastNewPoint = filletPoints[2];
1555 createChamfer( pPrev, p, p, pNext, value1, value2, firstNewPoint, lastNewPoint );
1558 throw QgsInvalidArgumentException( QStringLiteral(
"Operation '%1' is unknown." ).arg(
qgsEnumValueToKey( operation ) ) );
1563 QVector<QgsPoint> points;
1570 for (
int i = min; i < vertexIndex; ++i )
1572 points.append( curve->
vertexAt( QgsVertexId( 0, 0, i ) ) );
1577 if ( firstNewPoint != pPrev )
1578 points.append( firstNewPoint );
1582 QgsCircularString tempArc;
1583 tempArc.
setPoints( { firstNewPoint, middlePoint, lastNewPoint } );
1585 const double angleTolerance = ( 2.0 * M_PI ) / ( 4.0 * segments );
1588 for (
int i = 1; i < segmentizedArc->numPoints() - 1; ++i )
1590 points.append( segmentizedArc->vertexAt( QgsVertexId( 0, 0, i ) ) );
1595 points.append( middlePoint );
1598 if ( lastNewPoint != pNext )
1599 points.append( lastNewPoint );
1603 if ( firstNewPoint != pPrev )
1604 points.append( firstNewPoint );
1605 if ( lastNewPoint != pNext )
1606 points.append( lastNewPoint );
1610 if ( curve->
isClosed() && vertexIndex == 0 )
1613 for (
int i = vertexIndex + 1; i < max; ++i )
1615 points.append( curve->
vertexAt( QgsVertexId( 0, 0, i ) ) );
1618 return std::make_unique<QgsLineString>( points );
1623 auto newCompound = std::make_unique<QgsCompoundCurve>();
1625 int globalVertexIndex = 0;
1626 int targetCurveIndex = -1;
1627 int vertexInCurve = -1;
1629 for (
int curveIdx = 0; curveIdx < compound->nCurves(); ++curveIdx )
1631 const QgsCurve *subcurve = compound->curveAt( curveIdx );
1632 const int subcurvePoints = subcurve->
numPoints();
1634 if ( globalVertexIndex + subcurvePoints > vertexIndex )
1636 targetCurveIndex = curveIdx;
1637 vertexInCurve = vertexIndex - globalVertexIndex;
1640 globalVertexIndex += subcurvePoints - 1;
1643 if ( targetCurveIndex == -1 )
1645 throw QgsInvalidArgumentException(
"While generating output: unable to find curve within compound." );
1648 const QgsCurve *targetCurve = compound->curveAt( targetCurveIndex );
1651 for (
int i = 0; i < targetCurveIndex; ++i )
1653 std::unique_ptr<QgsCurve> tmpCurv( compound->curveAt( i )->clone() );
1656 tmpCurv->insertVertex( QgsVertexId( 0, 0, 1 ), lastNewPoint );
1657 tmpCurv->deleteVertex( QgsVertexId( 0, 0, 0 ) );
1659 newCompound->addCurve( tmpCurv.release() );
1663 if ( vertexInCurve > 0 )
1665 QVector<QgsPoint> beforePoints;
1666 for (
int j = 0; j < vertexInCurve; ++j )
1668 beforePoints.append( targetCurve->
vertexAt( QgsVertexId( 0, 0, j ) ) );
1670 beforePoints.append( firstNewPoint );
1672 if ( beforePoints.size() > 1 )
1674 auto beforeVertex = std::make_unique<QgsLineString>( beforePoints );
1675 newCompound->addCurve( beforeVertex.release() );
1682 if ( segments <= 0 )
1685 auto filletArc = std::make_unique<QgsCircularString>();
1686 filletArc->setPoints( { firstNewPoint, middlePoint, lastNewPoint } );
1687 newCompound->addCurve( filletArc.release() );
1692 QgsCircularString tempArc;
1693 tempArc.
setPoints( { firstNewPoint, middlePoint, lastNewPoint } );
1695 const double angleTolerance = ( 2.0 * M_PI ) / ( 4.0 * segments );
1698 newCompound->addCurve( segmentizedArc.release() );
1703 auto chamferLine = std::make_unique<QgsLineString>(
1704 QVector<QgsPoint> { firstNewPoint, lastNewPoint }
1706 newCompound->addCurve( chamferLine.release() );
1709 if ( vertexInCurve < targetCurve->numPoints() - 1 )
1711 QVector<QgsPoint> afterPoints;
1712 afterPoints.append( lastNewPoint );
1713 for (
int j = vertexInCurve + 1; j < targetCurve->
numPoints(); ++j )
1715 afterPoints.append( targetCurve->
vertexAt( QgsVertexId( 0, 0, j ) ) );
1718 if ( afterPoints.size() > 1 )
1720 auto afterVertex = std::make_unique<QgsLineString>( afterPoints );
1721 newCompound->addCurve( afterVertex.release() );
1726 for (
int i = targetCurveIndex + 1; i < compound->nCurves(); ++i )
1728 std::unique_ptr<QgsCurve> tmpCurv( compound->curveAt( i )->clone() );
1729 if ( curve->
isClosed() && vertexIndex == 0 )
1731 tmpCurv->insertVertex( QgsVertexId( 0, 0, tmpCurv->numPoints() - 1 ), firstNewPoint );
1732 tmpCurv->deleteVertex( QgsVertexId( 0, 0, tmpCurv->numPoints() - 1 ) );
1734 newCompound->addCurve( tmpCurv.release() );
1740 throw QgsInvalidArgumentException(
"While generating output: curse is not a QgsLineString nor a QgsCompoundCurve." );
static const double DEFAULT_SEGMENT_EPSILON
Default snapping tolerance for segments.
WkbType
The WKB type describes the number of dimensions a geometry has.
Abstract base class for all geometries.
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
@ MaximumDifference
Maximum distance between an arbitrary point on the original curve and closest point on its approximat...
@ MaximumAngle
Maximum angle between generating radii (lines from arc center to output vertices).
virtual int vertexCount(int part=0, int ring=0) const =0
Returns the number of vertices of which this geometry is built.
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.
@ XY
X comes before Y (or lon before lat).
virtual QgsPoint vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
virtual bool isEmpty() const
Returns true if the geometry is empty.
@ FlagExportNanAsDoubleMin
Use -DOUBLE_MAX to represent NaN.
virtual double segmentLength(QgsVertexId startVertex) const =0
Returns the length of the segment of the geometry which begins at startVertex.
virtual bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const =0
Returns next vertex id and coordinates.
virtual double closestSegment(const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf=nullptr, double epsilon=4 *std::numeric_limits< double >::epsilon()) const =0
Searches for the closest segment of the geometry to a given point.
Circular string geometry type.
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.
Curve polygon geometry type.
Abstract base class for curved geometry type.
virtual int numPoints() const =0
Returns the number of points in the curve.
virtual bool isClosed() const
Returns true if the curve is closed.
QgsPoint vertexAt(QgsVertexId id) const override
Returns the point corresponding to a specified vertex id.
static void pointOnLineWithDistance(double x1, double y1, double x2, double y2, double distance, double &x, double &y, double *z1=nullptr, double *z2=nullptr, double *z=nullptr, double *m1=nullptr, double *m2=nullptr, double *m=nullptr)
Calculates the point a specified distance from (x1, y1) toward a second point (x2,...
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 distance2D(double x1, double y1, double x2, double y2)
Returns the 2D distance between (x1, y1) and (x2, y2).
static bool createChamfer(const double segment1StartX, const double segment1StartY, const double segment1EndX, const double segment1EndY, const double segment2StartX, const double segment2StartY, const double segment2EndX, const double segment2EndY, const double distance1, const double distance2, double &chamferStartX, double &chamferStartY, double &chamferEndX, double &chamferEndY, double *trim1StartX=nullptr, double *trim1StartY=nullptr, double *trim1EndX=nullptr, double *trim1EndY=nullptr, double *trim2StartX=nullptr, double *trim2StartY=nullptr, double *trim2EndX=nullptr, double *trim2EndY=nullptr, const double epsilon=1e-8)
Creates a chamfer (angled corner) between two line segments.
static double lineAngle(double x1, double y1, double x2, double y2)
Calculates the direction of line joining two points in radians, clockwise from the north direction.
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 double interpolateArcValue(double angle, double a1, double a2, double a3, double zm1, double zm2, double zm3)
Interpolate a value at given angle on circular arc given values (zm1, zm2, zm3) at three different an...
static double maxFilletRadius(const double segment1StartX, const double segment1StartY, const double segment1EndX, const double segment1EndY, const double segment2StartX, const double segment2StartY, const double segment2EndX, const double segment2EndY, double epsilon=1e-8)
Calculates the maximum allowed fillet radius for the given segment configuration.
static bool segmentIntersection(double p1x, double p1y, double p2x, double p2y, double q1x, double q1y, double q2x, double q2y, double &intersectionPointX, double &intersectionPointY, bool &isIntersection, double tolerance=1e-8, bool acceptImproperIntersection=false)
Compute the intersection between two segments.
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 bool createFillet(const double segment1StartX, const double segment1StartY, const double segment1EndX, const double segment1EndY, const double segment2StartX, const double segment2StartY, const double segment2EndX, const double segment2EndY, const double radius, double *filletPointsX, double *filletPointsY, double *trim1StartX=nullptr, double *trim1StartY=nullptr, double *trim1EndX=nullptr, double *trim1EndY=nullptr, double *trim2StartX=nullptr, double *trim2StartY=nullptr, double *trim2EndX=nullptr, double *trim2EndY=nullptr, const double epsilon=1e-8)
Creates a fillet (rounded corner) between two line segments.
static int circleCircleIntersections(const QgsPointXY ¢er1, double radius1, const QgsPointXY ¢er2, double radius2, QgsPointXY &intersection1, QgsPointXY &intersection2)
Calculates the intersections points between the circle with center center1 and radius radius1 and the...
static std::unique_ptr< QgsLineString > createChamferGeometry(const QgsPoint &segment1Start, const QgsPoint &segment1End, const QgsPoint &segment2Start, const QgsPoint &segment2End, double distance1, double distance2)
Creates a complete chamfer geometry connecting two segments.
static QString pointsToJSON(const QgsPointSequence &points, int precision)
Returns a geoJSON coordinates string.
static QgsPointXY interpolatePointOnLine(double x1, double y1, double x2, double y2, double fraction)
Interpolates the position of a point a fraction of the way along the line from (x1,...
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 int leftOfLine(const QgsPoint &point, const QgsPoint &p1, const QgsPoint &p2)
Returns a value < 0 if the point point is left of the line from p1 -> p2.
static QgsPoint pointOnLineWithDistance(const QgsPoint &startPoint, const QgsPoint &directionPoint, double distance)
Returns a point a specified distance toward a second point.
static double gradient(const QgsPoint &pt1, const QgsPoint &pt2)
Returns the gradient of a line defined by points pt1 and pt2.
static json pointsToJson(const QgsPointSequence &points, int precision)
Returns coordinates as json object.
static double maxFilletRadius(const QgsPoint &segment1Start, const QgsPoint &segment1End, const QgsPoint &segment2Start, const QgsPoint &segment2End, double epsilon=1e-8)
Calculates the maximum allowed fillet radius for the given segment configuration.
static QgsPoint createPointWithMatchingDimensions(double x, double y, const QgsPoint &reference)
Creates a QgsPoint with dimensions matching a reference point.
static QVector< QgsLineString * > extractLineStrings(const QgsAbstractGeometry *geom)
Returns list of linestrings extracted from the passed geometry.
static std::unique_ptr< QgsAbstractGeometry > createFilletGeometry(const QgsPoint &segment1Start, const QgsPoint &segment1End, const QgsPoint &segment2Start, const QgsPoint &segment2End, double radius, int segments)
Creates a complete fillet geometry connecting two segments.
static QgsPoint interpolatePointOnSegment(double x, double y, const QgsPoint &segmentStart, const QgsPoint &segmentEnd)
Interpolates a point on a segment with proper Z and M value interpolation.
static QVector< SelfIntersection > selfIntersections(const QgsAbstractGeometry *geom, int part, int ring, double tolerance)
Find self intersections in a polyline.
static bool transferFirstZValueToPoint(const QgsPointSequence &points, QgsPoint &point)
A Z dimension is added to point if one of the point in the list points is in 3D.
static bool segmentMidPoint(const QgsPoint &p1, const QgsPoint &p2, QgsPoint &result, double radius, const QgsPoint &mousePos)
Calculates midpoint on circle passing through p1 and p2, closest to the given coordinate mousePos.
static QgsPointXY interpolatePointOnLineByValue(double x1, double y1, double v1, double x2, double y2, double v2, double value)
Interpolates the position of a point along the line from (x1, y1) to (x2, y2).
static QgsPoint closestPoint(const QgsAbstractGeometry &geometry, const QgsPoint &point)
Returns the nearest point on a segment of a geometry for the specified point.
static bool verticesAtDistance(const QgsAbstractGeometry &geometry, double distance, QgsVertexId &previousVertex, QgsVertexId &nextVertex)
Retrieves the vertices which are before and after the interpolated point at a specified distance alon...
static QStringList wktGetChildBlocks(const QString &wkt, const QString &defaultType=QString())
Parses a WKT string and returns of list of blocks contained in the WKT.
static bool segmentIntersection(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q1, const QgsPoint &q2, QgsPoint &intersectionPoint, bool &isIntersection, double tolerance=1e-8, bool acceptImproperIntersection=false)
Compute the intersection between two segments.
static QgsLineString perpendicularSegment(const QgsPoint &p, const QgsPoint &s1, const QgsPoint &s2)
Create a perpendicular line segment from p to segment [s1, s2].
static int segmentSide(const QgsPoint &pt1, const QgsPoint &pt3, const QgsPoint &pt2)
For line defined by points pt1 and pt3, find out on which side of the line is point pt2.
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure, QgsAbstractGeometry::WkbFlags flags)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
static bool createChamfer(const QgsPoint &segment1Start, const QgsPoint &segment1End, const QgsPoint &segment2Start, const QgsPoint &segment2End, double distance1, double distance2, QgsPoint &chamferStart, QgsPoint &chamferEnd, double epsilon=1e-8)
Creates a chamfer between two line segments using QgsPoint.
static double distanceToVertex(const QgsAbstractGeometry &geom, QgsVertexId id)
Returns the distance along a geometry from its first vertex to the specified vertex.
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 bool lineCircleIntersection(const QgsPointXY ¢er, double radius, const QgsPointXY &linePoint1, const QgsPointXY &linePoint2, QgsPointXY &intersection)
Compute the intersection of a line and a circle.
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 double distToInfiniteLine(const QgsPoint &point, const QgsPoint &linePoint1, const QgsPoint &linePoint2, double epsilon=1e-7)
Returns the distance between a point and an infinite line.
static void coefficients(const QgsPoint &pt1, const QgsPoint &pt2, double &a, double &b, double &c)
Returns the coefficients (a, b, c for equation "ax + by + c = 0") of a line defined by points pt1 and...
static bool transferFirstMValueToPoint(const QgsPointSequence &points, QgsPoint &point)
A M dimension is added to point if one of the points in the list points contains an M value.
static QgsPoint midpoint(const QgsPoint &pt1, const QgsPoint &pt2)
Returns a middle point between points pt1 and pt2.
static bool createFillet(const QgsPoint &segment1Start, const QgsPoint &segment1End, const QgsPoint &segment2Start, const QgsPoint &segment2End, double radius, QgsPoint &filletPoint1, QgsPoint &filletMidPoint, QgsPoint &filletPoint2, double epsilon=1e-8)
Creates a fillet (rounded corner) between two line segments using QgsPoint.
static QgsPoint closestVertex(const QgsAbstractGeometry &geom, const QgsPoint &pt, QgsVertexId &id)
Returns the closest vertex to a geometry for a specified point.
static bool pointContinuesArc(const QgsPoint &a1, const QgsPoint &a2, const QgsPoint &a3, const QgsPoint &b, double distanceTolerance, double pointSpacingAngleTolerance)
Returns true if point b is on the arc formed by points a1, a2, and a3, but not within that arc portio...
static QgsPoint interpolatePointOnArc(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double distance)
Interpolates a point on an arc defined by three points, pt1, pt2 and pt3.
static bool tangentPointAndCircle(const QgsPointXY ¢er, double radius, const QgsPointXY &p, QgsPointXY &pt1, QgsPointXY &pt2)
Calculates the tangent points between the circle with the specified center and radius and the point p...
static int circleCircleOuterTangents(const QgsPointXY ¢er1, double radius1, const QgsPointXY ¢er2, double radius2, QgsPointXY &line1P1, QgsPointXY &line1P2, QgsPointXY &line2P1, QgsPointXY &line2P2)
Calculates the outer tangent points for two circles, centered at center1 and center2 and with radii o...
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 QDomElement pointsToGML2(const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY)
Returns a gml::coordinates DOM element.
static std::unique_ptr< QgsAbstractGeometry > chamferVertex(const QgsCurve *curve, int vertexIndex, double distance1, double distance2)
Applies chamfer to a vertex in a curve geometry.
static bool transferFirstZOrMValueToPoint(Iterator verticesBegin, Iterator verticesEnd, QgsPoint &point)
A Z or M dimension is added to point if one of the points in the list points contains Z or M value.
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 circleCircleInnerTangents(const QgsPointXY ¢er1, double radius1, const QgsPointXY ¢er2, double radius2, QgsPointXY &line1P1, QgsPointXY &line1P2, QgsPointXY &line2P1, QgsPointXY &line2P2)
Calculates the inner tangent points for two circles, centered at center1 and center2 and with radii o...
static bool createFilletArray(const QgsPoint &segment1Start, const QgsPoint &segment1End, const QgsPoint &segment2Start, const QgsPoint &segment2End, double radius, QgsPoint filletPoints[3], double epsilon=1e-8)
Convenient method of createFillet using array output.
static QString pointsToWKT(const QgsPointSequence &points, int precision, bool is3D, bool isMeasure)
Returns a WKT coordinate list.
static QgsPoint segmentMidPointFromCenter(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint ¢er, bool useShortestArc=true)
Calculates the midpoint on the circle passing through p1 and p2, with the specified center coordinate...
static std::unique_ptr< QgsAbstractGeometry > filletVertex(const QgsCurve *curve, int vertexIndex, double radius, int segments)
Applies fillet to a vertex in a curve geometry.
ChamferFilletOperationType
Privatly used in chamfer/fillet functions.
Custom exception class when argument are invalid.
Line string geometry type, with support for z-dimension and m-values.
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
double sqrDist(double x, double y) const
Returns the squared distance between this point a specified x, y coordinate.
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
void set(double x, double y)
Sets the x and y value of the point.
Point geometry type, with support for z-dimension and m-values.
void setM(double m)
Sets the point's m-value.
bool convertTo(Qgis::WkbType type) override
Converts the geometry to a specified type.
bool isEmpty() const override
Returns true if the geometry is empty.
double distance(double x, double y) const
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
void setZ(double z)
Sets the point's z-coordinate.
QgsPoint project(double distance, double azimuth, double inclination=90.0) const
Returns a new point which corresponds to this point projected by a specified distance with specified ...
Represent a 2-dimensional vector.
double length() const
Returns the length of the vector.
static Qgis::WkbType parseType(const QString &wktStr)
Attempts to extract the WKB type from a WKT string.
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.
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
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
double qgsRound(double number, int places)
Returns a double number, rounded (as close as possible) to the specified number of places.
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
bool isClockwise(std::array< Direction, 4 > dirs)
Checks whether the 4 directions in dirs make up a clockwise rectangle.
Utility class for identifying a unique vertex within a geometry.
bool isValid() const
Returns true if the vertex id is valid.
Qgis::VertexType type
Vertex type.