26 #include <QStringList>
28 #include <QRegularExpression>
29 #include <nlohmann/json.hpp>
33 QVector< QgsLineString * > linestrings;
37 QVector< const QgsAbstractGeometry * > geometries;
39 while ( ! geometries.isEmpty() )
42 if (
const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( g ) )
44 linestrings << static_cast< QgsLineString * >( curve->segmentize() );
46 else if (
const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( g ) )
48 for (
int i = 0; i < collection->numGeometries(); ++i )
50 geometries.append( collection->geometryN( i ) );
53 else if (
const QgsCurvePolygon *curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( g ) )
55 if ( curvePolygon->exteriorRing() )
56 linestrings << static_cast< QgsLineString * >( curvePolygon->exteriorRing()->segmentize() );
58 for (
int i = 0; i < curvePolygon->numInteriorRings(); ++i )
60 linestrings << static_cast< QgsLineString * >( curvePolygon->interiorRing( i )->segmentize() );
69 double minDist = std::numeric_limits<double>::max();
70 double currentDist = 0;
87 if ( currentDist <= minDist )
89 minDist = currentDist;
90 minDistPoint = vertex;
91 id.part = vertexId.
part;
92 id.ring = vertexId.
ring;
93 id.vertex = vertexId.
vertex;
94 id.type = vertexId.
type;
109 if ( vertexAfter.
vertex > 0 )
114 const double length = pointBefore.
distance( pointAfter );
136 double currentDist = 0;
141 if ( vertexId ==
id )
155 double currentDist = 0;
165 nextVertex = previousVertex;
170 while ( currentDist < distance && geometry.
nextVertex( nextVertex, point ) )
172 if ( !first && nextVertex.
part == previousVertex.
part && nextVertex.
ring == previousVertex.
ring )
180 previousVertex = nextVertex;
184 if ( currentDist > distance )
189 previousVertex = nextVertex;
190 previousPoint = point;
200 return ( pt1.
x() - pt2.
x() ) * ( pt1.
x() - pt2.
x() ) + ( pt1.
y() - pt2.
y() ) * ( pt1.
y() - pt2.
y() );
213 const double t = ( ( ptX - x1 ) * dx + ( ptY - y1 ) * dy ) / ( dx * dx + dy * dy );
229 const double dist = dx * dx + dy * dy;
244 const double d = v1.
y() * v2.
x() - v1.
x() * v2.
y();
249 const double dx = p2.
x() - p1.
x();
250 const double dy = p2.
y() - p1.
y();
251 const double k = ( dy * v2.
x() - dx * v2.
y() ) / d;
253 intersection =
QgsPoint( p1.
x() + v1.
x() * k, p1.
y() + v1.
y() * k );
263 isIntersection =
false;
267 const double vl = v.
length();
268 const double wl = w.
length();
282 isIntersection =
true;
283 if ( acceptImproperIntersection )
285 if ( ( p1 == q1 ) || ( p1 == q2 ) )
287 intersectionPoint = p1;
290 else if ( ( p2 == q1 ) || ( p2 == q2 ) )
292 intersectionPoint = p2;
299 qgsDoubleNear(
QgsGeometryUtils::sqrDistToLine( p1.
x(), p1.
y(), q1.
x(), q1.
y(), q2.
x(), q2.
y(), x, y, tolerance ), 0.0, tolerance ) ||
301 qgsDoubleNear(
QgsGeometryUtils::sqrDistToLine( p2.
x(), p2.
y(), q1.
x(), q1.
y(), q2.
x(), q2.
y(), x, y, tolerance ), 0.0, tolerance ) ||
303 qgsDoubleNear(
QgsGeometryUtils::sqrDistToLine( q1.
x(), q1.
y(), p1.
x(), p1.
y(), p2.
x(), p2.
y(), x, y, tolerance ), 0.0, tolerance ) ||
305 qgsDoubleNear(
QgsGeometryUtils::sqrDistToLine( q2.
x(), q2.
y(), p1.
x(), p1.
y(), p2.
x(), p2.
y(), x, y, tolerance ), 0.0, tolerance )
312 const double lambdav =
QgsVector( intersectionPoint.
x() - p1.
x(), intersectionPoint.
y() - p1.
y() ) * v;
313 if ( lambdav < 0. + tolerance || lambdav > vl - tolerance )
316 const double lambdaw =
QgsVector( intersectionPoint.
x() - q1.
x(), intersectionPoint.
y() - q1.
y() ) * w;
317 return !( lambdaw < 0. + tolerance || lambdaw >= wl - tolerance );
327 const double x1 = linePoint1.
x() - center.
x();
328 const double y1 = linePoint1.
y() - center.
y();
329 const double x2 = linePoint2.
x() - center.
x();
330 const double y2 = linePoint2.
y() - center.
y();
331 const double dx = x2 - x1;
332 const double dy = y2 - y1;
334 const double dr2 = std::pow( dx, 2 ) + std::pow( dy, 2 );
335 const double d = x1 * y2 - x2 * y1;
337 const double disc = std::pow( radius, 2 ) * dr2 - std::pow( d, 2 );
347 const int sgnDy = dy < 0 ? -1 : 1;
349 const double sqrDisc = std::sqrt( disc );
351 const double ax = center.
x() + ( d * dy + sgnDy * dx * sqrDisc ) / dr2;
352 const double ay = center.
y() + ( -d * dx + std::fabs( dy ) * sqrDisc ) / dr2;
355 const double bx = center.
x() + ( d * dy - sgnDy * dx * sqrDisc ) / dr2;
356 const double by = center.
y() + ( -d * dx - std::fabs( dy ) * sqrDisc ) / dr2;
363 intersection.
set( p1.
x(), p1.
y() );
367 intersection.
set( p2.
x(), p2.
y() );
378 const double d = center1.
distance( center2 );
381 if ( d > ( r1 + r2 ) )
386 else if ( d < std::fabs( r1 - r2 ) )
403 const double a = ( ( r1 * r1 ) - ( r2 * r2 ) + ( d * d ) ) / ( 2.0 * d ) ;
408 const double dx = center2.
x() - center1.
x();
409 const double dy = center2.
y() - center1.
y();
412 const double x2 = center1.
x() + ( dx * a / d );
413 const double y2 = center1.
y() + ( dy * a / d );
418 const double h = std::sqrt( ( r1 * r1 ) - ( a * a ) );
423 const double rx = dy * ( h / d );
424 const double ry = dx * ( h / d );
427 intersection1 =
QgsPointXY( x2 + rx, y2 - ry );
428 intersection2 =
QgsPointXY( x2 - rx, y2 + ry );
442 const double dx = center.
x() - p.
x();
443 const double dy = center.
y() - p.
y();
444 const double distanceSquared = dx * dx + dy * dy;
445 const double radiusSquared = radius * radius;
446 if ( distanceSquared < radiusSquared )
453 const double distanceToTangent = std::sqrt( distanceSquared - radiusSquared );
465 if ( radius1 > radius2 )
468 const double radius2a = radius2 - radius1;
477 QgsVector v1( -( line1P2.
y() - center1.
y() ), line1P2.
x() - center1.
x() );
478 const double v1Length = v1.
length();
479 v1 = v1 * ( radius1 / v1Length );
482 line1P1 = center1 + v1;
483 line1P2 = line1P2 + v1;
487 QgsVector v2( line2P2.
y() - center1.
y(), -( line2P2.
x() - center1.
x() ) );
488 const double v2Length = v2.
length();
489 v2 = v2 * ( radius1 / v2Length );
492 line2P1 = center1 + v2;
493 line2P2 = line2P2 + v2;
501 if ( radius1 > radius2 )
505 const double d = center1.
distance( center2 );
506 const double radius1a = radius1 + radius2;
523 QgsVector v1( ( line1P2.
y() - center2.
y() ), -( line1P2.
x() - center2.
x() ) );
524 const double v1Length = v1.
length();
525 v1 = v1 * ( radius2 / v1Length );
528 line1P1 = center2 + v1;
529 line1P2 = line1P2 + v1;
533 QgsVector v2( -( line2P2.
y() - center2.
y() ), line2P2.
x() - center2.
x() );
534 const double v2Length = v2.
length();
535 v2 = v2 * ( radius2 / v2Length );
538 line2P1 = center2 + v2;
539 line2P2 = line2P2 + v2;
546 QVector<SelfIntersection> intersections;
552 for (
int i = 0, j = 1; j < n; i = j++ )
559 const int start = j + 1;
560 const int end = i == 0 && isClosed ? n - 1 : n;
561 for (
int k = start, l = start + 1; l < end; k = l++ )
567 bool intersection =
false;
578 intersections.append( s );
581 return intersections;
591 const double f1 = x - x1;
592 const double f2 = y2 - y1;
593 const double f3 = y - y1;
594 const double f4 = x2 - x1;
595 const double test = ( f1 * f2 - f3 * f4 );
597 return qgsDoubleNear( test, 0.0 ) ? 0 : ( test < 0 ? -1 : 1 );
607 void QgsGeometryUtils::pointOnLineWithDistance(
double x1,
double y1,
double x2,
double y2,
double distance,
double &x,
double &y,
double *z1,
double *z2,
double *z,
double *m1,
double *m2,
double *m )
609 const double dx = x2 - x1;
610 const double dy = y2 - y1;
611 const double length = std::sqrt( dx * dx + dy * dy );
624 const double scaleFactor = distance / length;
625 x = x1 + dx * scaleFactor;
626 y = y1 + dy * scaleFactor;
628 *z = *z1 + ( *z2 - *z1 ) * scaleFactor;
630 *m = *m1 + ( *m2 - *m1 ) * scaleFactor;
637 const double mX = x1 + ( x2 - x1 ) * proportion;
638 const double mY = y1 + ( y2 - y1 ) * proportion;
639 const double pX = x1 - x2;
640 const double pY = y1 - y2;
641 double normalX = -pY;
643 const double normalLength = sqrt( ( normalX * normalX ) + ( normalY * normalY ) );
644 normalX /= normalLength;
645 normalY /= normalLength;
647 *x = mX + offset * normalX;
648 *y = mY + offset * normalY;
653 double centerX, centerY, radius;
656 const double theta = distance / radius;
657 const double anglePt1 = std::atan2( pt1.
y() - centerY, pt1.
x() - centerX );
658 const double anglePt2 = std::atan2( pt2.
y() - centerY, pt2.
x() - centerX );
659 const double anglePt3 = std::atan2( pt3.
y() - centerY, pt3.
x() - centerX );
661 const double angleDest = anglePt1 + (
isClockwise ? -theta : theta );
663 const double x = centerX + radius * ( std::cos( angleDest ) );
664 const double y = centerY + radius * ( std::sin( angleDest ) );
666 const double z = pt1.
is3D() ?
678 const double angle = std::atan2( dy, dx ) * 180 / M_PI;
683 else if (
angle > 360 )
692 double dx21, dy21, dx31, dy31, h21, h31, d;
697 centerX = ( pt1.
x() + pt2.
x() ) / 2.0;
698 centerY = ( pt1.
y() + pt2.
y() ) / 2.0;
699 radius = std::sqrt( std::pow( centerX - pt1.
x(), 2.0 ) + std::pow( centerY - pt1.
y(), 2.0 ) );
704 dx21 = pt2.
x() - pt1.
x();
705 dy21 = pt2.
y() - pt1.
y();
706 dx31 = pt3.
x() - pt1.
x();
707 dy31 = pt3.
y() - pt1.
y();
709 h21 = std::pow( dx21, 2.0 ) + std::pow( dy21, 2.0 );
710 h31 = std::pow( dx31, 2.0 ) + std::pow( dy31, 2.0 );
713 d = 2 * ( dx21 * dy31 - dx31 * dy21 );
723 centerX = pt1.
x() + ( h21 * dy31 - h31 * dy21 ) / d;
724 centerY = pt1.
y() - ( h21 * dx31 - h31 * dx21 ) / d;
725 radius = std::sqrt( std::pow( centerX - pt1.
x(), 2.0 ) + std::pow( centerY - pt1.
y(), 2.0 ) );
730 if ( angle3 >= angle1 )
732 return !( angle2 > angle1 && angle2 < angle3 );
736 return !( angle2 > angle1 || angle2 < angle3 );
744 if ( angle2 < angle1 )
746 return ( angle <= angle1 && angle >= angle2 );
750 return ( angle <= angle1 || angle >= angle2 );
755 if ( angle2 > angle1 )
757 return (
angle >= angle1 &&
angle <= angle2 );
761 return (
angle >= angle1 ||
angle <= angle2 );
774 double centerX, centerY, radius;
776 double length = M_PI / 180.0 * radius *
sweepAngle( centerX, centerY, x1, y1, x2, y2, x3, y3 );
790 if ( p3Angle >= p1Angle )
792 if ( p2Angle > p1Angle && p2Angle < p3Angle )
794 return ( p3Angle - p1Angle );
798 return ( - ( p1Angle + ( 360 - p3Angle ) ) );
803 if ( p2Angle < p1Angle && p2Angle > p3Angle )
805 return ( -( p1Angle - p3Angle ) );
809 return ( p3Angle + ( 360 - p1Angle ) );
816 const QgsPoint midPoint( ( p1.
x() + p2.
x() ) / 2.0, ( p1.
y() + p2.
y() ) / 2.0 );
817 const double midDist = std::sqrt(
sqrDistance2D( p1, midPoint ) );
818 if ( radius < midDist )
822 const double centerMidDist = std::sqrt( radius * radius - midDist * midDist );
823 const double dist = radius - centerMidDist;
825 const double midDx = midPoint.
x() - p1.
x();
826 const double midDy = midPoint.
y() - p1.
y();
829 QVector<QgsPoint> possibleMidPoints;
836 double minDist = std::numeric_limits<double>::max();
837 int minDistIndex = -1;
838 for (
int i = 0; i < possibleMidPoints.size(); ++i )
840 const double currentDist =
sqrDistance2D( mousePos, possibleMidPoints.at( i ) );
841 if ( currentDist < minDist )
844 minDist = currentDist;
848 if ( minDistIndex == -1 )
853 result = possibleMidPoints.at( minDistIndex );
865 if ( !useShortestArc )
866 midPointAngle += M_PI;
867 return center.
project( center.
distance( p1 ), midPointAngle * 180 / M_PI );
874 double mX, mY, radius;
907 const double bDistance = std::sqrt( ( b.
x() - centerX ) * ( b.
x() - centerX ) +
908 ( b.
y() - centerY ) * ( b.
y() - centerY ) );
910 double diff = std::fabs( radius - bDistance );
914 const double abX = b.
x() - a.
x();
915 const double abY = b.
y() - a.
y();
917 const double cbX = b.
x() -
c.x();
918 const double cbY = b.
y() -
c.y();
920 const double dot = ( abX * cbX + abY * cbY );
921 const double cross = ( abX * cbY - abY * cbX );
923 const double alpha = std::atan2( cross, dot );
929 if ( diff < distanceTolerance )
931 const double angle1 = arcAngle( a1, a2, a3 );
932 const double angle2 = arcAngle( a2, a3, b );
937 diff = std::fabs( angle1 - angle2 );
938 if ( diff > pointSpacingAngleTolerance )
943 const int a2Side =
leftOfLine( a2.
x(), a2.
y(), a1.
x(), a1.
y(), a3.
x(), a3.
y() );
944 const int bSide =
leftOfLine( b.
x(), b.
y(), a1.
x(), a1.
y(), a3.
x(), a3.
y() );
948 if ( bSide != a2Side )
956 bool reversed =
false;
980 circleCenterRadius( circlePoint1, circlePoint2, circlePoint3, radius, centerX, centerY );
982 if ( circlePoint1 != circlePoint3 && ( radius < 0 ||
qgsDoubleNear( segSide, 0.0 ) ) )
990 double increment = tolerance;
994 tolerance = std::min( tolerance, radius * 2 );
995 const double halfAngle = std::acos( -tolerance / radius + 1 );
996 increment = 2 * halfAngle;
1000 const double a1 = std::atan2( circlePoint1.
y() - centerY, circlePoint1.
x() - centerX );
1001 double a2 = std::atan2( circlePoint2.
y() - centerY, circlePoint2.
x() - centerX );
1002 double a3 = std::atan2( circlePoint3.
y() - centerY, circlePoint3.
x() - centerX );
1005 const bool symmetric =
true;
1008 double angle = a3 - a1;
1013 const int segs = ceil(
angle / increment );
1015 increment =
angle / segs;
1029 QVector<QgsPoint> stringPoints;
1030 stringPoints.insert( 0, circlePoint1 );
1031 if ( circlePoint2 != circlePoint3 && circlePoint1 != circlePoint2 )
1045 const double tolError = increment / 100;
1046 const double stopAngle = a3 - tolError;
1047 for (
double angle = a1 + increment;
angle < stopAngle;
angle += increment )
1049 x = centerX + radius * std::cos(
angle );
1050 y = centerY + radius * std::sin(
angle );
1061 stringPoints.insert( stringPoints.size(),
QgsPoint( pointWkbType, x, y, z, m ) );
1064 stringPoints.insert( stringPoints.size(), circlePoint3 );
1069 std::reverse( stringPoints.begin(), stringPoints.end() );
1071 if ( ! points.empty() && stringPoints.front() == points.back() ) stringPoints.pop_front();
1072 points.append( stringPoints );
1077 const double side = ( ( pt2.
x() - pt1.
x() ) * ( pt3.
y() - pt1.
y() ) - ( pt3.
x() - pt1.
x() ) * ( pt2.
y() - pt1.
y() ) );
1102 return zm1 + ( zm2 - zm1 ) * (
angle - a1 ) / ( a2 - a1 );
1104 return zm2 + ( zm3 - zm2 ) * (
angle - a2 ) / ( a3 - a2 );
1110 return zm1 + ( zm2 - zm1 ) * ( a1 -
angle ) / ( a1 - a2 );
1112 return zm2 + ( zm3 - zm2 ) * ( a2 -
angle ) / ( a2 - a3 );
1118 const int dim = 2 + is3D + isMeasure;
1121 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
1122 const QStringList coordList = wktCoordinateList.split(
',', QString::SkipEmptyParts );
1124 const QStringList coordList = wktCoordinateList.split(
',', Qt::SkipEmptyParts );
1128 bool foundZ =
false;
1129 bool foundM =
false;
1130 const thread_local QRegularExpression rx( QStringLiteral(
"\\s" ) );
1131 const thread_local QRegularExpression rxIsNumber( QStringLiteral(
"^[+-]?(\\d\\.?\\d*[Ee][+\\-]?\\d+|(\\d+\\.\\d*|\\d*\\.\\d+)|\\d+)$" ) );
1132 for (
const QString &pointCoordinates : coordList )
1134 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
1135 QStringList coordinates = pointCoordinates.split( rx, QString::SkipEmptyParts );
1137 const QStringList coordinates = pointCoordinates.split( rx, Qt::SkipEmptyParts );
1141 if ( coordinates.filter( rxIsNumber ).size() != coordinates.size() )
1144 if ( coordinates.size() == 3 && !foundZ && !foundM && !is3D && !isMeasure )
1150 else if ( coordinates.size() >= 4 && ( !( is3D || foundZ ) || !( isMeasure || foundM ) ) )
1159 for (
const QString &pointCoordinates : coordList )
1161 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
1162 QStringList coordinates = pointCoordinates.split( rx, QString::SkipEmptyParts );
1164 QStringList coordinates = pointCoordinates.split( rx, Qt::SkipEmptyParts );
1166 if ( coordinates.size() < dim )
1170 const double x = coordinates[idx++].toDouble();
1171 const double y = coordinates[idx++].toDouble();
1174 if ( ( is3D || foundZ ) && coordinates.length() > idx )
1175 z = coordinates[idx++].toDouble();
1178 if ( ( isMeasure || foundM ) && coordinates.length() > idx )
1179 m = coordinates[idx++].toDouble();
1182 if ( is3D || foundZ )
1184 if ( isMeasure || foundM )
1191 if ( isMeasure || foundM )
1197 points.append(
QgsPoint( t, x, y, z, m ) );
1205 wkb << static_cast<quint32>( points.size() );
1206 for (
const QgsPoint &point : points )
1208 wkb << point.x() << point.y();
1222 QString wkt = QStringLiteral(
"(" );
1231 wkt += QLatin1String(
", " );
1233 if ( wkt.endsWith( QLatin1String(
", " ) ) )
1241 QDomElement elemCoordinates = doc.createElementNS( ns, QStringLiteral(
"coordinates" ) );
1244 const QString cs = QStringLiteral(
"," );
1246 const QString ts = QStringLiteral(
" " );
1248 elemCoordinates.setAttribute( QStringLiteral(
"cs" ), cs );
1249 elemCoordinates.setAttribute( QStringLiteral(
"ts" ), ts );
1251 QString strCoordinates;
1254 if ( axisOrder == QgsAbstractGeometry::AxisOrder::XY )
1259 if ( strCoordinates.endsWith( ts ) )
1260 strCoordinates.chop( 1 );
1262 elemCoordinates.appendChild( doc.createTextNode( strCoordinates ) );
1263 return elemCoordinates;
1268 QDomElement elemPosList = doc.createElementNS( ns, QStringLiteral(
"posList" ) );
1269 elemPosList.setAttribute( QStringLiteral(
"srsDimension" ), is3D ? 3 : 2 );
1271 QString strCoordinates;
1274 if ( axisOrder == QgsAbstractGeometry::AxisOrder::XY )
1281 if ( strCoordinates.endsWith(
' ' ) )
1282 strCoordinates.chop( 1 );
1284 elemPosList.appendChild( doc.createTextNode( strCoordinates ) );
1290 QString json = QStringLiteral(
"[ " );
1295 if ( json.endsWith( QLatin1String(
", " ) ) )
1306 json coordinates( json::array() );
1323 double clippedAngle =
angle;
1324 if ( clippedAngle >= M_PI * 2 || clippedAngle <= -2 * M_PI )
1326 clippedAngle = std::fmod( clippedAngle, 2 * M_PI );
1328 if ( clippedAngle < 0.0 )
1330 clippedAngle += 2 * M_PI;
1332 return clippedAngle;
1337 QString wktParsed = wkt;
1339 if ( wkt.contains( QLatin1String(
"EMPTY" ), Qt::CaseInsensitive ) )
1341 const thread_local QRegularExpression sWktRegEx( QStringLiteral(
"^\\s*(\\w+)\\s+(\\w+)\\s*$" ), QRegularExpression::DotMatchesEverythingOption );
1342 const QRegularExpressionMatch match = sWktRegEx.match( wkt );
1343 if ( match.hasMatch() )
1345 wktParsed = match.captured( 1 );
1346 contents = match.captured( 2 ).toUpper();
1351 const int openedParenthesisCount = wktParsed.count(
'(' );
1352 const int closedParenthesisCount = wktParsed.count(
')' );
1354 for (
int i = 0 ; i < openedParenthesisCount - closedParenthesisCount; ++i )
1355 wktParsed.push_back(
')' );
1357 wktParsed.truncate( wktParsed.size() - ( closedParenthesisCount - openedParenthesisCount ) );
1359 const thread_local QRegularExpression cooRegEx( QStringLiteral(
"^[^\\(]*\\((.*)\\)[^\\)]*$" ), QRegularExpression::DotMatchesEverythingOption );
1360 const QRegularExpressionMatch match = cooRegEx.match( wktParsed );
1361 contents = match.hasMatch() ? match.captured( 1 ) : QString();
1364 return qMakePair( wkbType, contents );
1371 block.reserve( wkt.size() );
1374 const QChar *wktData = wkt.data();
1375 const int wktLength = wkt.length();
1376 for (
int i = 0, n = wktLength; i < n; ++i, ++wktData )
1378 if ( ( wktData->isSpace() || *wktData ==
'\n' || *wktData ==
'\t' ) && level == 0 )
1381 if ( *wktData ==
',' && level == 0 )
1383 if ( !block.isEmpty() )
1385 if ( block.startsWith(
'(' ) && !defaultType.isEmpty() )
1386 block.prepend( defaultType +
' ' );
1387 blocks.append( block );
1392 if ( *wktData ==
'(' )
1394 else if ( *wktData ==
')' )
1398 if ( !block.isEmpty() )
1400 if ( block.startsWith(
'(' ) && !defaultType.isEmpty() )
1401 block.prepend( defaultType +
' ' );
1402 blocks.append( block );
1410 if ( x <= left && y <= bottom )
1412 const double dx = left - x;
1413 const double dy = bottom - y;
1421 else if ( x >= right && y >= top )
1423 const double dx = x - right;
1424 const double dy = y - top;
1432 else if ( x >= right && y <= bottom )
1434 const double dx = x - right;
1435 const double dy = bottom - y;
1443 else if ( x <= left && y >= top )
1445 const double dx = left - x;
1446 const double dy = y - top;
1454 else if ( x <= left )
1456 else if ( x >= right )
1458 else if ( y <= bottom )
1460 else if ( y >= top )
1464 const double smallestX = std::min( right - x, x - left );
1465 const double smallestY = std::min( top - y, y - bottom );
1466 if ( smallestX < smallestY )
1469 if ( right - x < x - left )
1477 if ( top - y < y - bottom )
1489 const double x = ( pt1.
x() + pt2.
x() ) / 2.0;
1490 const double y = ( pt1.
y() + pt2.
y() ) / 2.0;
1491 double z = std::numeric_limits<double>::quiet_NaN();
1492 double m = std::numeric_limits<double>::quiet_NaN();
1497 z = ( pt1.
z() + pt2.
z() ) / 2.0;
1503 m = ( pt1.
m() + pt2.
m() ) / 2.0;
1506 return QgsPoint( pType, x, y, z, m );
1511 const double _fraction = 1 - fraction;
1513 p1.
x() * _fraction + p2.
x() * fraction,
1514 p1.
y() * _fraction + p2.
y() * fraction,
1515 p1.
is3D() ? p1.
z() * _fraction + p2.
z() * fraction : std::numeric_limits<double>::quiet_NaN(),
1516 p1.
isMeasure() ? p1.
m() * _fraction + p2.
m() * fraction : std::numeric_limits<double>::quiet_NaN() );
1521 const double deltaX = ( x2 - x1 ) * fraction;
1522 const double deltaY = ( y2 - y1 ) * fraction;
1523 return QgsPointXY( x1 + deltaX, y1 + deltaY );
1531 const double fraction = ( value - v1 ) / ( v2 - v1 );
1537 const double delta_x = pt2.
x() - pt1.
x();
1538 const double delta_y = pt2.
y() - pt1.
y();
1544 return delta_y / delta_x;
1563 a = pt1.
y() - pt2.
y();
1564 b = pt2.
x() - pt1.
x();
1565 c = pt1.
x() * pt2.
y() - pt1.
y() * pt2.
x();
1575 if ( ( p == s1 ) || ( p == s2 ) )
1593 const double y = ( -
c - a * p.
x() ) / b;
1594 const double m =
gradient( s1, s2 );
1595 const double d2 = 1 + m * m;
1596 const double H = p.
y() - y;
1597 const double dx = m * H / d2;
1598 const double dy = m * dx;
1610 const double at = std::atan2( y2 - y1, x2 - x1 );
1611 const double a = -at + M_PI_2;
1617 const double angle1 = std::atan2( y1 - y2, x1 - x2 );
1618 const double angle2 = std::atan2( y3 - y2, x3 - x2 );
1632 const double a1 =
lineAngle( x1, y1, x2, y2 );
1633 const double a2 =
lineAngle( x2, y2, x3, y3 );
1641 double clockwiseDiff = 0.0;
1644 clockwiseDiff = a2 - a1;
1648 clockwiseDiff = a2 + ( 2 * M_PI - a1 );
1650 const double counterClockwiseDiff = 2 * M_PI - clockwiseDiff;
1652 double resultAngle = 0;
1653 if ( clockwiseDiff <= counterClockwiseDiff )
1655 resultAngle = a1 + clockwiseDiff / 2.0;
1659 resultAngle = a1 - counterClockwiseDiff / 2.0;
1670 if ( u3.
length() == 0 )
return 1;
1687 if ( std::fabs( u3.
x() ) <= epsilon &&
1688 std::fabs( u3.
y() ) <= epsilon &&
1689 std::fabs( u3.
z() ) <= epsilon )
1701 if ( !( std::fabs( b1 ) > epsilon ) )
1706 if ( !( a2 != -1 && a2 != 1 ) )
1712 const double r1 = ( c2 - b2 * c1 / b1 ) / ( a2 - b2 * a1 / b1 );
1728 bool isIntersection;
1737 intersection.
set( ptInter.
x(), ptInter.
y(), La1.
z() );
1777 if ( !firstIsDone || !secondIsDone )
1783 intersection = ( X1 + X2 ) / 2.0;
1789 return 0.5 * std::abs( ( aX - cX ) * ( bY - aY ) - ( aX - bX ) * ( cY - aY ) );
1793 double weightB,
double weightC,
double &pointX,
double &pointY )
1796 if ( weightB + weightC > 1 )
1798 weightB = 1 - weightB;
1799 weightC = 1 - weightC;
1802 const double rBx = weightB * ( bX - aX );
1803 const double rBy = weightB * ( bY - aY );
1804 const double rCx = weightC * ( cX - aX );
1805 const double rCy = weightC * ( cY - aY );
1807 pointX = rBx + rCx + aX;
1808 pointY = rBy + rCy + aY;
1815 for (
const QgsPoint &pt : points )
1817 if ( pt.isMeasure() )
1820 point.
setM( pt.m() );
1833 for (
const QgsPoint &pt : points )
1838 point.
setZ( pt.z() );
1857 bool intersection =
false;
1863 return intersection;
1875 bool intersection =
false;
1881 return intersection;
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...
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
virtual int vertexCount(int part=0, int ring=0) const =0
Returns the number of vertices of which this geometry is built.
AxisOrder
Axis order for GML generation.
virtual QgsPoint vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
virtual bool isEmpty() const
Returns true if the geometry is empty.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
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.
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
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.
Curve polygon geometry type.
Abstract base class for curved geometry type.
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 QString pointsToJSON(const QgsPointSequence &points, int precision)
Returns a geoJSON coordinates string.
static QgsPoint midpoint(const QgsPoint &pt1, const QgsPoint &pt2) SIP_HOLDGIL
Returns a middle point between points pt1 and pt2.
static bool bisector(double aX, double aY, double bX, double bY, double cX, double cY, double &pointX, double &pointY) SIP_HOLDGIL
Returns the point (pointX, pointY) forming the bisector from point (aX, aY) to the segment (bX,...
static double sqrDistance2D(const QgsPoint &pt1, const QgsPoint &pt2) SIP_HOLDGIL
Returns the squared 2D distance between two points.
static bool skewLinesProjection(const QgsVector3D &P1, const QgsVector3D &P12, const QgsVector3D &P2, const QgsVector3D &P22, QgsVector3D &X1, double epsilon=0.0001) SIP_HOLDGIL
A method to project one skew line onto another.
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 double triangleArea(double aX, double aY, double bX, double bY, double cX, double cY) SIP_HOLDGIL
Returns the area of the triangle denoted by the points (aX, aY), (bX, bY) and (cX,...
static bool segmentMidPoint(const QgsPoint &p1, const QgsPoint &p2, QgsPoint &result, double radius, const QgsPoint &mousePos) SIP_HOLDGIL
Calculates midpoint on circle passing through p1 and p2, closest to the given coordinate mousePos.
static json pointsToJson(const QgsPointSequence &points, int precision)
Returns coordinates as json object.
static int circleCircleInnerTangents(const QgsPointXY ¢er1, double radius1, const QgsPointXY ¢er2, double radius2, QgsPointXY &line1P1, QgsPointXY &line1P2, QgsPointXY &line2P1, QgsPointXY &line2P2) SIP_HOLDGIL
Calculates the inner tangent points for two circles, centered at center1 and center2 and with radii o...
static QVector< QgsLineString * > extractLineStrings(const QgsAbstractGeometry *geom)
Returns list of linestrings extracted from the passed geometry.
static bool lineIntersection(const QgsPoint &p1, QgsVector v1, const QgsPoint &p2, QgsVector v2, QgsPoint &intersection) SIP_HOLDGIL
Computes the intersection between two lines.
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
static double normalizedAngle(double angle) SIP_HOLDGIL
Ensures that an angle is in the range 0 <= angle < 2 pi.
static QgsPointXY interpolatePointOnLineByValue(double x1, double y1, double v1, double x2, double y2, double v2, double value) SIP_HOLDGIL
Interpolates the position of a point along the line from (x1, y1) to (x2, y2).
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 QgsPoint closestPoint(const QgsAbstractGeometry &geometry, const QgsPoint &point)
Returns the nearest point on a segment of a geometry for the specified point.
static int segmentSide(const QgsPoint &pt1, const QgsPoint &pt3, const QgsPoint &pt2) SIP_HOLDGIL
For line defined by points pt1 and pt3, find out on which side of the line is point pt3.
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 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 bool lineCircleIntersection(const QgsPointXY ¢er, double radius, const QgsPointXY &linePoint1, const QgsPointXY &linePoint2, QgsPointXY &intersection) SIP_HOLDGIL
Compute the intersection of a line and a circle.
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) SIP_HOLDGIL
Compute the intersection between two segments.
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 distanceToVertex(const QgsAbstractGeometry &geom, QgsVertexId id)
Returns the distance along a geometry from its first vertex to the specified vertex.
static double skewLinesDistance(const QgsVector3D &P1, const QgsVector3D &P12, const QgsVector3D &P2, const QgsVector3D &P22) SIP_HOLDGIL
An algorithm to calculate the shortest distance between two skew lines.
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 double lineAngle(double x1, double y1, double x2, double y2) SIP_HOLDGIL
Calculates the direction of line joining two points in radians, clockwise from the north direction.
static double sqrDistToLine(double ptX, double ptY, double x1, double y1, double x2, double y2, double &minDistX, double &minDistY, double epsilon) SIP_HOLDGIL
Returns the squared distance between a point and a line.
static void perpendicularOffsetPointAlongSegment(double x1, double y1, double x2, double y2, double proportion, double offset, double *x, double *y)
Calculates a point a certain proportion of the way along the segment from (x1, y1) to (x2,...
static bool circleClockwise(double angle1, double angle2, double angle3) SIP_HOLDGIL
Returns true if the circle defined by three angles is ordered clockwise.
static bool angleBisector(double aX, double aY, double bX, double bY, double cX, double cY, double dX, double dY, double &pointX, double &pointY, double &angle) SIP_HOLDGIL
Returns the point (pointX, pointY) forming the bisector from segment (aX aY) (bX bY) and segment (bX,...
static int circleCircleOuterTangents(const QgsPointXY ¢er1, double radius1, const QgsPointXY ¢er2, double radius2, QgsPointXY &line1P1, QgsPointXY &line1P2, QgsPointXY &line2P1, QgsPointXY &line2P2) SIP_HOLDGIL
Calculates the outer tangent points for two circles, centered at center1 and center2 and with radii o...
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 double gradient(const QgsPoint &pt1, const QgsPoint &pt2) SIP_HOLDGIL
Returns the gradient of a line defined by points pt1 and pt2.
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 angleBetweenThreePoints(double x1, double y1, double x2, double y2, double x3, double y3) SIP_HOLDGIL
Calculates the angle between the lines AB and BC, where AB and BC described by points a,...
static QgsPoint closestVertex(const QgsAbstractGeometry &geom, const QgsPoint &pt, QgsVertexId &id)
Returns the closest vertex to a geometry for a specified point.
static double interpolateArcValue(double angle, double a1, double a2, double a3, double zm1, double zm2, double zm3) SIP_HOLDGIL
Interpolate a value at given angle on circular arc given values (zm1, zm2, zm3) at three different an...
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 QgsLineString perpendicularSegment(const QgsPoint &p, const QgsPoint &s1, const QgsPoint &s2) SIP_HOLDGIL
Create a perpendicular line segment from p to segment [s1, s2].
static int circleCircleIntersections(const QgsPointXY ¢er1, double radius1, const QgsPointXY ¢er2, double radius2, QgsPointXY &intersection1, QgsPointXY &intersection2) SIP_HOLDGIL
Calculates the intersections points between the circle with center center1 and radius radius1 and the...
static void coefficients(const QgsPoint &pt1, const QgsPoint &pt2, double &a, double &b, double &c) SIP_HOLDGIL
Returns the coefficients (a, b, c for equation "ax + by + c = 0") of a line defined by points pt1 and...
static double linePerpendicularAngle(double x1, double y1, double x2, double y2) SIP_HOLDGIL
Calculates the perpendicular angle to a line joining two points.
static bool tangentPointAndCircle(const QgsPointXY ¢er, double radius, const QgsPointXY &p, QgsPointXY &pt1, QgsPointXY &pt2) SIP_HOLDGIL
Calculates the tangent points between the circle with the specified center and radius and the point p...
static QgsPoint pointOnLineWithDistance(const QgsPoint &startPoint, const QgsPoint &directionPoint, double distance) SIP_HOLDGIL
Returns a point a specified distance toward a second point.
static int closestSideOfRectangle(double right, double bottom, double left, double top, double x, double y)
Returns a number representing the closest side of a rectangle defined by /a right,...
static bool pointContinuesArc(const QgsPoint &a1, const QgsPoint &a2, const QgsPoint &a3, const QgsPoint &b, double distanceTolerance, double pointSpacingAngleTolerance) SIP_HOLDGIL
Returns true if point b is on the arc formed by points a1, a2, and a3, but not within that arc portio...
static void weightedPointInTriangle(double aX, double aY, double bX, double bY, double cX, double cY, double weightB, double weightC, double &pointX, double &pointY) SIP_HOLDGIL
Returns a weighted point inside the triangle denoted by the points (aX, aY), (bX, bY) and (cX,...
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 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 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 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 bool linesIntersection3D(const QgsVector3D &La1, const QgsVector3D &La2, const QgsVector3D &Lb1, const QgsVector3D &Lb2, QgsVector3D &intersection) SIP_HOLDGIL
An algorithm to calculate an (approximate) intersection of two lines in 3D.
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.
static QgsPointXY interpolatePointOnLine(double x1, double y1, double x2, double y2, double fraction) SIP_HOLDGIL
Interpolates the position of a point a fraction of the way along the line from (x1,...
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.
A class to represent a 2D point.
void set(double x, double y) SIP_HOLDGIL
Sets the x and y value of the point.
double sqrDist(double x, double y) const SIP_HOLDGIL
Returns the squared distance between this point a specified x, y coordinate.
double distance(double x, double y) const SIP_HOLDGIL
Returns the distance between this point and a specified x, y coordinate.
Point geometry type, with support for z-dimension and m-values.
double distance(double x, double y) const SIP_HOLDGIL
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
QgsPoint project(double distance, double azimuth, double inclination=90.0) const SIP_HOLDGIL
Returns a new point which corresponds to this point projected by a specified distance with specified ...
bool convertTo(QgsWkbTypes::Type type) override
Converts the geometry to a specified type.
void setZ(double z) SIP_HOLDGIL
Sets the point's z-coordinate.
double azimuth(const QgsPoint &other) const SIP_HOLDGIL
Calculates Cartesian azimuth between this point and other one (clockwise in degree,...
void setM(double m) SIP_HOLDGIL
Sets the point's m-value.
double y() const
Returns Y coordinate.
double z() const
Returns Z coordinate.
static double dotProduct(const QgsVector3D &v1, const QgsVector3D &v2)
Returns the dot product of two vectors.
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.
void set(double x, double y, double z)
Sets vector coordinates.
double length() const
Returns the length of the vector.
A class to represent a vector.
double y() const SIP_HOLDGIL
Returns the vector's y-component.
double x() const SIP_HOLDGIL
Returns the vector's x-component.
double length() const SIP_HOLDGIL
Returns the length of the vector.
static Type parseType(const QString &wktStr)
Attempts to extract the WKB type from a WKT string.
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 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.
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)
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.
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)
const double DEFAULT_SEGMENT_EPSILON
Default snapping tolerance for segments.
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.
Qgis::VertexType type
Vertex type.
bool isValid() const SIP_HOLDGIL
Returns true if the vertex id is valid.