QGIS API Documentation  3.8.0-Zanzibar (11aff65)
qgsgeometryutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsgeometryutils.cpp
3  -------------------------------------------------------------------
4 Date : 21 Nov 2014
5 Copyright : (C) 2014 by Marco Hugentobler
6 email : marco.hugentobler at sourcepole dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsgeometryutils.h"
17 
18 #include "qgscurve.h"
19 #include "qgscurvepolygon.h"
20 #include "qgsgeometrycollection.h"
21 #include "qgslinestring.h"
22 #include "qgswkbptr.h"
23 #include "qgslogger.h"
24 
25 #include <memory>
26 #include <QStringList>
27 #include <QVector>
28 #include <QRegularExpression>
29 #include <nlohmann/json.hpp>
30 
31 QVector<QgsLineString *> QgsGeometryUtils::extractLineStrings( const QgsAbstractGeometry *geom )
32 {
33  QVector< QgsLineString * > linestrings;
34  if ( !geom )
35  return linestrings;
36 
37  QVector< const QgsAbstractGeometry * > geometries;
38  geometries << geom;
39  while ( ! geometries.isEmpty() )
40  {
41  const QgsAbstractGeometry *g = geometries.takeFirst();
42  if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( g ) )
43  {
44  linestrings << static_cast< QgsLineString * >( curve->segmentize() );
45  }
46  else if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( g ) )
47  {
48  for ( int i = 0; i < collection->numGeometries(); ++i )
49  {
50  geometries.append( collection->geometryN( i ) );
51  }
52  }
53  else if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( g ) )
54  {
55  if ( curvePolygon->exteriorRing() )
56  linestrings << static_cast< QgsLineString * >( curvePolygon->exteriorRing()->segmentize() );
57 
58  for ( int i = 0; i < curvePolygon->numInteriorRings(); ++i )
59  {
60  linestrings << static_cast< QgsLineString * >( curvePolygon->interiorRing( i )->segmentize() );
61  }
62  }
63  }
64  return linestrings;
65 }
66 
68 {
69  double minDist = std::numeric_limits<double>::max();
70  double currentDist = 0;
71  QgsPoint minDistPoint;
72  id = QgsVertexId(); // set as invalid
73 
74  QgsVertexId vertexId;
75  QgsPoint vertex;
76  while ( geom.nextVertex( vertexId, vertex ) )
77  {
78  currentDist = QgsGeometryUtils::sqrDistance2D( pt, vertex );
79  // The <= is on purpose: for geometries with closing vertices, this ensures
80  // that the closing vertex is returned. For the vertex tool, the rubberband
81  // of the closing vertex is above the opening vertex, hence with the <=
82  // situations where the covered opening vertex rubberband is selected are
83  // avoided.
84  if ( currentDist <= minDist )
85  {
86  minDist = currentDist;
87  minDistPoint = vertex;
88  id.part = vertexId.part;
89  id.ring = vertexId.ring;
90  id.vertex = vertexId.vertex;
91  id.type = vertexId.type;
92  }
93  }
94 
95  return minDistPoint;
96 }
97 
99 {
101  QgsVertexId vertexAfter;
102  geometry.closestSegment( point, closestPoint, vertexAfter, nullptr, DEFAULT_SEGMENT_EPSILON );
103  if ( vertexAfter.isValid() )
104  {
105  QgsPoint pointAfter = geometry.vertexAt( vertexAfter );
106  if ( vertexAfter.vertex > 0 )
107  {
108  QgsVertexId vertexBefore = vertexAfter;
109  vertexBefore.vertex--;
110  QgsPoint pointBefore = geometry.vertexAt( vertexBefore );
111  double length = pointBefore.distance( pointAfter );
112  double distance = pointBefore.distance( closestPoint );
113 
114  if ( qgsDoubleNear( distance, 0.0 ) )
115  closestPoint = pointBefore;
116  else if ( qgsDoubleNear( distance, length ) )
117  closestPoint = pointAfter;
118  else
119  {
120  if ( QgsWkbTypes::hasZ( geometry.wkbType() ) && length )
121  closestPoint.addZValue( pointBefore.z() + ( pointAfter.z() - pointBefore.z() ) * distance / length );
122  if ( QgsWkbTypes::hasM( geometry.wkbType() ) )
123  closestPoint.addMValue( pointBefore.m() + ( pointAfter.m() - pointBefore.m() ) * distance / length );
124  }
125  }
126  }
127 
128  return closestPoint;
129 }
130 
132 {
133  double currentDist = 0;
134  QgsVertexId vertexId;
135  QgsPoint vertex;
136  while ( geom.nextVertex( vertexId, vertex ) )
137  {
138  if ( vertexId == id )
139  {
140  //found target vertex
141  return currentDist;
142  }
143  currentDist += geom.segmentLength( vertexId );
144  }
145 
146  //could not find target vertex
147  return -1;
148 }
149 
150 bool QgsGeometryUtils::verticesAtDistance( const QgsAbstractGeometry &geometry, double distance, QgsVertexId &previousVertex, QgsVertexId &nextVertex )
151 {
152  double currentDist = 0;
153  previousVertex = QgsVertexId();
154  nextVertex = QgsVertexId();
155 
156  QgsPoint point;
157  QgsPoint previousPoint;
158 
159  if ( qgsDoubleNear( distance, 0.0 ) )
160  {
161  geometry.nextVertex( previousVertex, point );
162  nextVertex = previousVertex;
163  return true;
164  }
165 
166  bool first = true;
167  while ( currentDist < distance && geometry.nextVertex( nextVertex, point ) )
168  {
169  if ( !first )
170  {
171  currentDist += std::sqrt( QgsGeometryUtils::sqrDistance2D( previousPoint, point ) );
172  }
173 
174  if ( qgsDoubleNear( currentDist, distance ) )
175  {
176  // exact hit!
177  previousVertex = nextVertex;
178  return true;
179  }
180 
181  if ( currentDist > distance )
182  {
183  return true;
184  }
185 
186  previousVertex = nextVertex;
187  previousPoint = point;
188  first = false;
189  }
190 
191  //could not find target distance
192  return false;
193 }
194 
195 double QgsGeometryUtils::sqrDistance2D( const QgsPoint &pt1, const QgsPoint &pt2 )
196 {
197  return ( pt1.x() - pt2.x() ) * ( pt1.x() - pt2.x() ) + ( pt1.y() - pt2.y() ) * ( pt1.y() - pt2.y() );
198 }
199 
200 double QgsGeometryUtils::sqrDistToLine( double ptX, double ptY, double x1, double y1, double x2, double y2, double &minDistX, double &minDistY, double epsilon )
201 {
202  minDistX = x1;
203  minDistY = y1;
204 
205  double dx = x2 - x1;
206  double dy = y2 - y1;
207 
208  if ( !qgsDoubleNear( dx, 0.0 ) || !qgsDoubleNear( dy, 0.0 ) )
209  {
210  double t = ( ( ptX - x1 ) * dx + ( ptY - y1 ) * dy ) / ( dx * dx + dy * dy );
211  if ( t > 1 )
212  {
213  minDistX = x2;
214  minDistY = y2;
215  }
216  else if ( t > 0 )
217  {
218  minDistX += dx * t;
219  minDistY += dy * t;
220  }
221  }
222 
223  dx = ptX - minDistX;
224  dy = ptY - minDistY;
225 
226  double dist = dx * dx + dy * dy;
227 
228  //prevent rounding errors if the point is directly on the segment
229  if ( qgsDoubleNear( dist, 0.0, epsilon ) )
230  {
231  minDistX = ptX;
232  minDistY = ptY;
233  return 0.0;
234  }
235 
236  return dist;
237 }
238 
239 bool QgsGeometryUtils::lineIntersection( const QgsPoint &p1, QgsVector v1, const QgsPoint &p2, QgsVector v2, QgsPoint &intersection )
240 {
241  double d = v1.y() * v2.x() - v1.x() * v2.y();
242 
243  if ( qgsDoubleNear( d, 0 ) )
244  return false;
245 
246  double dx = p2.x() - p1.x();
247  double dy = p2.y() - p1.y();
248  double k = ( dy * v2.x() - dx * v2.y() ) / d;
249 
250  intersection = QgsPoint( p1.x() + v1.x() * k, p1.y() + v1.y() * k );
251 
252  // z support for intersection point
253  QgsGeometryUtils::setZValueFromPoints( QgsPointSequence() << p1 << p2, intersection );
254 
255  return true;
256 }
257 
258 bool QgsGeometryUtils::segmentIntersection( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q1, const QgsPoint &q2, QgsPoint &intersectionPoint, bool &isIntersection, const double tolerance, bool acceptImproperIntersection )
259 {
260  isIntersection = false;
261 
262  QgsVector v( p2.x() - p1.x(), p2.y() - p1.y() );
263  QgsVector w( q2.x() - q1.x(), q2.y() - q1.y() );
264  double vl = v.length();
265  double wl = w.length();
266 
267  if ( qgsDoubleNear( vl, 0.0, tolerance ) || qgsDoubleNear( wl, 0.0, tolerance ) )
268  {
269  return false;
270  }
271  v = v / vl;
272  w = w / wl;
273 
274  if ( !QgsGeometryUtils::lineIntersection( p1, v, q1, w, intersectionPoint ) )
275  {
276  return false;
277  }
278 
279  isIntersection = true;
280  if ( acceptImproperIntersection )
281  {
282  if ( ( p1 == q1 ) || ( p1 == q2 ) )
283  {
284  intersectionPoint = p1;
285  return true;
286  }
287  else if ( ( p2 == q1 ) || ( p2 == q2 ) )
288  {
289  intersectionPoint = p2;
290  return true;
291  }
292 
293  double x, y;
294  if (
295  // intersectionPoint = p1
296  qgsDoubleNear( QgsGeometryUtils::sqrDistToLine( p1.x(), p1.y(), q1.x(), q1.y(), q2.x(), q2.y(), x, y, tolerance ), 0.0, tolerance ) ||
297  // intersectionPoint = p2
298  qgsDoubleNear( QgsGeometryUtils::sqrDistToLine( p2.x(), p2.y(), q1.x(), q1.y(), q2.x(), q2.y(), x, y, tolerance ), 0.0, tolerance ) ||
299  // intersectionPoint = q1
300  qgsDoubleNear( QgsGeometryUtils::sqrDistToLine( q1.x(), q1.y(), p1.x(), p1.y(), p2.x(), p2.y(), x, y, tolerance ), 0.0, tolerance ) ||
301  // intersectionPoint = q2
302  qgsDoubleNear( QgsGeometryUtils::sqrDistToLine( q2.x(), q2.y(), p1.x(), p1.y(), p2.x(), p2.y(), x, y, tolerance ), 0.0, tolerance )
303  )
304  {
305  return true;
306  }
307  }
308 
309  double lambdav = QgsVector( intersectionPoint.x() - p1.x(), intersectionPoint.y() - p1.y() ) * v;
310  if ( lambdav < 0. + tolerance || lambdav > vl - tolerance )
311  return false;
312 
313  double lambdaw = QgsVector( intersectionPoint.x() - q1.x(), intersectionPoint.y() - q1.y() ) * w;
314  return !( lambdaw < 0. + tolerance || lambdaw >= wl - tolerance );
315 
316 }
317 
318 bool QgsGeometryUtils::lineCircleIntersection( const QgsPointXY &center, const double radius,
319  const QgsPointXY &linePoint1, const QgsPointXY &linePoint2,
320  QgsPointXY &intersection )
321 {
322  // formula taken from http://mathworld.wolfram.com/Circle-LineIntersection.html
323 
324  const double x1 = linePoint1.x() - center.x();
325  const double y1 = linePoint1.y() - center.y();
326  const double x2 = linePoint2.x() - center.x();
327  const double y2 = linePoint2.y() - center.y();
328  const double dx = x2 - x1;
329  const double dy = y2 - y1;
330 
331  const double dr2 = std::pow( dx, 2 ) + std::pow( dy, 2 );
332  const double d = x1 * y2 - x2 * y1;
333 
334  const double disc = std::pow( radius, 2 ) * dr2 - std::pow( d, 2 );
335 
336  if ( disc < 0 )
337  {
338  //no intersection or tangent
339  return false;
340  }
341  else
342  {
343  // two solutions
344  const int sgnDy = dy < 0 ? -1 : 1;
345 
346  const double sqrDisc = std::sqrt( disc );
347 
348  const double ax = center.x() + ( d * dy + sgnDy * dx * sqrDisc ) / dr2;
349  const double ay = center.y() + ( -d * dx + std::fabs( dy ) * sqrDisc ) / dr2;
350  const QgsPointXY p1( ax, ay );
351 
352  const double bx = center.x() + ( d * dy - sgnDy * dx * sqrDisc ) / dr2;
353  const double by = center.y() + ( -d * dx - std::fabs( dy ) * sqrDisc ) / dr2;
354  const QgsPointXY p2( bx, by );
355 
356  // snap to nearest intersection
357 
358  if ( intersection.sqrDist( p1 ) < intersection.sqrDist( p2 ) )
359  {
360  intersection.set( p1.x(), p1.y() );
361  }
362  else
363  {
364  intersection.set( p2.x(), p2.y() );
365  }
366  return true;
367  }
368 }
369 
370 // based on public domain work by 3/26/2005 Tim Voght
371 // see http://paulbourke.net/geometry/circlesphere/tvoght.c
372 int QgsGeometryUtils::circleCircleIntersections( QgsPointXY center0, const double r0, QgsPointXY center1, const double r1, QgsPointXY &intersection1, QgsPointXY &intersection2 )
373 {
374  // determine the straight-line distance between the centers
375  const double d = center0.distance( center1 );
376 
377  // check for solvability
378  if ( d > ( r0 + r1 ) )
379  {
380  // no solution. circles do not intersect.
381  return 0;
382  }
383  else if ( d < std::fabs( r0 - r1 ) )
384  {
385  // no solution. one circle is contained in the other
386  return 0;
387  }
388  else if ( qgsDoubleNear( d, 0 ) && ( qgsDoubleNear( r0, r1 ) ) )
389  {
390  // no solutions, the circles coincide
391  return 0;
392  }
393 
394  /* 'point 2' is the point where the line through the circle
395  * intersection points crosses the line between the circle
396  * centers.
397  */
398 
399  // Determine the distance from point 0 to point 2.
400  const double a = ( ( r0 * r0 ) - ( r1 * r1 ) + ( d * d ) ) / ( 2.0 * d ) ;
401 
402  /* dx and dy are the vertical and horizontal distances between
403  * the circle centers.
404  */
405  const double dx = center1.x() - center0.x();
406  const double dy = center1.y() - center0.y();
407 
408  // Determine the coordinates of point 2.
409  const double x2 = center0.x() + ( dx * a / d );
410  const double y2 = center0.y() + ( dy * a / d );
411 
412  /* Determine the distance from point 2 to either of the
413  * intersection points.
414  */
415  const double h = std::sqrt( ( r0 * r0 ) - ( a * a ) );
416 
417  /* Now determine the offsets of the intersection points from
418  * point 2.
419  */
420  const double rx = dy * ( h / d );
421  const double ry = dx * ( h / d );
422 
423  // determine the absolute intersection points
424  intersection1 = QgsPointXY( x2 + rx, y2 - ry );
425  intersection2 = QgsPointXY( x2 - rx, y2 + ry );
426 
427  // see if we have 1 or 2 solutions
428  if ( qgsDoubleNear( d, r0 + r1 ) )
429  return 1;
430 
431  return 2;
432 }
433 
434 // Using https://stackoverflow.com/a/1351794/1861260
435 // and inspired by http://csharphelper.com/blog/2014/11/find-the-tangent-lines-between-a-point-and-a-circle-in-c/
436 bool QgsGeometryUtils::tangentPointAndCircle( const QgsPointXY &center, double radius, const QgsPointXY &p, QgsPointXY &pt1, QgsPointXY &pt2 )
437 {
438  // distance from point to center of circle
439  const double dx = center.x() - p.x();
440  const double dy = center.y() - p.y();
441  const double distanceSquared = dx * dx + dy * dy;
442  const double radiusSquared = radius * radius;
443  if ( distanceSquared < radiusSquared )
444  {
445  // point is inside circle!
446  return false;
447  }
448 
449  // distance from point to tangent point, using pythagoras
450  const double distanceToTangent = std::sqrt( distanceSquared - radiusSquared );
451 
452  // tangent points are those where the original circle intersects a circle centered
453  // on p with radius distanceToTangent
454  circleCircleIntersections( center, radius, p, distanceToTangent, pt1, pt2 );
455 
456  return true;
457 }
458 
459 // inspired by http://csharphelper.com/blog/2014/12/find-the-tangent-lines-between-two-circles-in-c/
460 int QgsGeometryUtils::circleCircleOuterTangents( const QgsPointXY &center1, double radius1, const QgsPointXY &center2, double radius2, QgsPointXY &line1P1, QgsPointXY &line1P2, QgsPointXY &line2P1, QgsPointXY &line2P2 )
461 {
462  if ( radius1 > radius2 )
463  return circleCircleOuterTangents( center2, radius2, center1, radius1, line1P1, line1P2, line2P1, line2P2 );
464 
465  const double radius2a = radius2 - radius1;
466  if ( !tangentPointAndCircle( center2, radius2a, center1, line1P2, line2P2 ) )
467  {
468  // there are no tangents
469  return 0;
470  }
471 
472  // get the vector perpendicular to the
473  // first tangent with length radius1
474  QgsVector v1( -( line1P2.y() - center1.y() ), line1P2.x() - center1.x() );
475  const double v1Length = v1.length();
476  v1 = v1 * ( radius1 / v1Length );
477 
478  // offset the tangent vector's points
479  line1P1 = center1 + v1;
480  line1P2 = line1P2 + v1;
481 
482  // get the vector perpendicular to the
483  // second tangent with length radius1
484  QgsVector v2( line2P2.y() - center1.y(), -( line2P2.x() - center1.x() ) );
485  const double v2Length = v2.length();
486  v2 = v2 * ( radius1 / v2Length );
487 
488  // offset the tangent vector's points
489  line2P1 = center1 + v2;
490  line2P2 = line2P2 + v2;
491 
492  return 2;
493 }
494 
495 // inspired by http://csharphelper.com/blog/2014/12/find-the-tangent-lines-between-two-circles-in-c/
496 int QgsGeometryUtils::circleCircleInnerTangents( const QgsPointXY &center1, double radius1, const QgsPointXY &center2, double radius2, QgsPointXY &line1P1, QgsPointXY &line1P2, QgsPointXY &line2P1, QgsPointXY &line2P2 )
497 {
498  if ( radius1 > radius2 )
499  return circleCircleInnerTangents( center2, radius2, center1, radius1, line1P1, line1P2, line2P1, line2P2 );
500 
501  // determine the straight-line distance between the centers
502  const double d = center1.distance( center2 );
503  const double radius1a = radius1 + radius2;
504 
505  // check for solvability
506  if ( d <= radius1a || qgsDoubleNear( d, radius1a ) )
507  {
508  // no solution. circles intersect or touch.
509  return 0;
510  }
511 
512  if ( !tangentPointAndCircle( center1, radius1a, center2, line1P2, line2P2 ) )
513  {
514  // there are no tangents
515  return 0;
516  }
517 
518  // get the vector perpendicular to the
519  // first tangent with length radius2
520  QgsVector v1( ( line1P2.y() - center2.y() ), -( line1P2.x() - center2.x() ) );
521  const double v1Length = v1.length();
522  v1 = v1 * ( radius2 / v1Length );
523 
524  // offset the tangent vector's points
525  line1P1 = center2 + v1;
526  line1P2 = line1P2 + v1;
527 
528  // get the vector perpendicular to the
529  // second tangent with length radius2
530  QgsVector v2( -( line2P2.y() - center2.y() ), line2P2.x() - center2.x() );
531  const double v2Length = v2.length();
532  v2 = v2 * ( radius2 / v2Length );
533 
534  // offset the tangent vector's points in opposite direction
535  line2P1 = center2 + v2;
536  line2P2 = line2P2 + v2;
537 
538  return 2;
539 }
540 
541 QVector<QgsGeometryUtils::SelfIntersection> QgsGeometryUtils::selfIntersections( const QgsAbstractGeometry *geom, int part, int ring, double tolerance )
542 {
543  QVector<SelfIntersection> intersections;
544 
545  int n = geom->vertexCount( part, ring );
546  bool isClosed = geom->vertexAt( QgsVertexId( part, ring, 0 ) ) == geom->vertexAt( QgsVertexId( part, ring, n - 1 ) );
547 
548  // Check every pair of segments for intersections
549  for ( int i = 0, j = 1; j < n; i = j++ )
550  {
551  QgsPoint pi = geom->vertexAt( QgsVertexId( part, ring, i ) );
552  QgsPoint pj = geom->vertexAt( QgsVertexId( part, ring, j ) );
553  if ( QgsGeometryUtils::sqrDistance2D( pi, pj ) < tolerance * tolerance ) continue;
554 
555  // Don't test neighboring edges
556  int start = j + 1;
557  int end = i == 0 && isClosed ? n - 1 : n;
558  for ( int k = start, l = start + 1; l < end; k = l++ )
559  {
560  QgsPoint pk = geom->vertexAt( QgsVertexId( part, ring, k ) );
561  QgsPoint pl = geom->vertexAt( QgsVertexId( part, ring, l ) );
562 
563  QgsPoint inter;
564  bool intersection = false;
565  if ( !QgsGeometryUtils::segmentIntersection( pi, pj, pk, pl, inter, intersection, tolerance ) ) continue;
566 
568  s.segment1 = i;
569  s.segment2 = k;
570  if ( s.segment1 > s.segment2 )
571  {
572  std::swap( s.segment1, s.segment2 );
573  }
574  s.point = inter;
575  intersections.append( s );
576  }
577  }
578  return intersections;
579 }
580 
581 int QgsGeometryUtils::leftOfLine( const QgsPoint &point, const QgsPoint &p1, const QgsPoint &p2 )
582 {
583  return leftOfLine( point.x(), point.y(), p1.x(), p1.y(), p2.x(), p2.y() );
584 }
585 
586 int QgsGeometryUtils::leftOfLine( const double x, const double y, const double x1, const double y1, const double x2, const double y2 )
587 {
588  double f1 = x - x1;
589  double f2 = y2 - y1;
590  double f3 = y - y1;
591  double f4 = x2 - x1;
592  double test = ( f1 * f2 - f3 * f4 );
593  // return -1, 0, or 1
594  return qgsDoubleNear( test, 0.0 ) ? 0 : ( test < 0 ? -1 : 1 );
595 }
596 
597 QgsPoint QgsGeometryUtils::pointOnLineWithDistance( const QgsPoint &startPoint, const QgsPoint &directionPoint, double distance )
598 {
599  double x, y;
600  pointOnLineWithDistance( startPoint.x(), startPoint.y(), directionPoint.x(), directionPoint.y(), distance, x, y );
601  return QgsPoint( x, y );
602 }
603 
604 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 )
605 {
606  const double dx = x2 - x1;
607  const double dy = y2 - y1;
608  const double length = std::sqrt( dx * dx + dy * dy );
609 
610  if ( qgsDoubleNear( length, 0.0 ) )
611  {
612  x = x1;
613  y = y1;
614  if ( z && z1 )
615  *z = *z1;
616  if ( m && m1 )
617  *m = *m1;
618  }
619  else
620  {
621  const double scaleFactor = distance / length;
622  x = x1 + dx * scaleFactor;
623  y = y1 + dy * scaleFactor;
624  if ( z && z1 && z2 )
625  *z = *z1 + ( *z2 - *z1 ) * scaleFactor;
626  if ( m && m1 && m2 )
627  *m = *m1 + ( *m2 - *m1 ) * scaleFactor;
628  }
629 }
630 
631 QgsPoint QgsGeometryUtils::interpolatePointOnArc( const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double distance )
632 {
633  double centerX, centerY, radius;
634  circleCenterRadius( pt1, pt2, pt3, radius, centerX, centerY );
635 
636  const double theta = distance / radius; // angle subtended
637  const double anglePt1 = std::atan2( pt1.y() - centerY, pt1.x() - centerX );
638  const double anglePt2 = std::atan2( pt2.y() - centerY, pt2.x() - centerX );
639  const double anglePt3 = std::atan2( pt3.y() - centerY, pt3.x() - centerX );
640  const bool isClockwise = circleClockwise( anglePt1, anglePt2, anglePt3 );
641  const double angleDest = anglePt1 + ( isClockwise ? -theta : theta );
642 
643  const double x = centerX + radius * ( std::cos( angleDest ) );
644  const double y = centerY + radius * ( std::sin( angleDest ) );
645 
646  const double z = pt1.is3D() ?
647  interpolateArcValue( angleDest, anglePt1, anglePt2, anglePt3, pt1.z(), pt2.z(), pt3.z() )
648  : 0;
649  const double m = pt1.isMeasure() ?
650  interpolateArcValue( angleDest, anglePt1, anglePt2, anglePt3, pt1.m(), pt2.m(), pt3.m() )
651  : 0;
652 
653  return QgsPoint( pt1.wkbType(), x, y, z, m );
654 }
655 
656 double QgsGeometryUtils::ccwAngle( double dy, double dx )
657 {
658  double angle = std::atan2( dy, dx ) * 180 / M_PI;
659  if ( angle < 0 )
660  {
661  return 360 + angle;
662  }
663  else if ( angle > 360 )
664  {
665  return 360 - angle;
666  }
667  return angle;
668 }
669 
670 void QgsGeometryUtils::circleCenterRadius( const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double &radius, double &centerX, double &centerY )
671 {
672  double dx21, dy21, dx31, dy31, h21, h31, d;
673 
674  //closed circle
675  if ( qgsDoubleNear( pt1.x(), pt3.x() ) && qgsDoubleNear( pt1.y(), pt3.y() ) )
676  {
677  centerX = ( pt1.x() + pt2.x() ) / 2.0;
678  centerY = ( pt1.y() + pt2.y() ) / 2.0;
679  radius = std::sqrt( std::pow( centerX - pt1.x(), 2.0 ) + std::pow( centerY - pt1.y(), 2.0 ) );
680  return;
681  }
682 
683  // Using Cartesian circumcenter eguations from page https://en.wikipedia.org/wiki/Circumscribed_circle
684  dx21 = pt2.x() - pt1.x();
685  dy21 = pt2.y() - pt1.y();
686  dx31 = pt3.x() - pt1.x();
687  dy31 = pt3.y() - pt1.y();
688 
689  h21 = std::pow( dx21, 2.0 ) + std::pow( dy21, 2.0 );
690  h31 = std::pow( dx31, 2.0 ) + std::pow( dy31, 2.0 );
691 
692  // 2*Cross product, d<0 means clockwise and d>0 counterclockwise sweeping angle
693  d = 2 * ( dx21 * dy31 - dx31 * dy21 );
694 
695  // Check colinearity, Cross product = 0
696  if ( qgsDoubleNear( std::fabs( d ), 0.0, 0.00000000001 ) )
697  {
698  radius = -1.0;
699  return;
700  }
701 
702  // Calculate centroid coordinates and radius
703  centerX = pt1.x() + ( h21 * dy31 - h31 * dy21 ) / d;
704  centerY = pt1.y() - ( h21 * dx31 - h31 * dx21 ) / d;
705  radius = std::sqrt( std::pow( centerX - pt1.x(), 2.0 ) + std::pow( centerY - pt1.y(), 2.0 ) );
706 }
707 
708 bool QgsGeometryUtils::circleClockwise( double angle1, double angle2, double angle3 )
709 {
710  if ( angle3 >= angle1 )
711  {
712  return !( angle2 > angle1 && angle2 < angle3 );
713  }
714  else
715  {
716  return !( angle2 > angle1 || angle2 < angle3 );
717  }
718 }
719 
720 bool QgsGeometryUtils::circleAngleBetween( double angle, double angle1, double angle2, bool clockwise )
721 {
722  if ( clockwise )
723  {
724  if ( angle2 < angle1 )
725  {
726  return ( angle <= angle1 && angle >= angle2 );
727  }
728  else
729  {
730  return ( angle <= angle1 || angle >= angle2 );
731  }
732  }
733  else
734  {
735  if ( angle2 > angle1 )
736  {
737  return ( angle >= angle1 && angle <= angle2 );
738  }
739  else
740  {
741  return ( angle >= angle1 || angle <= angle2 );
742  }
743  }
744 }
745 
746 bool QgsGeometryUtils::angleOnCircle( double angle, double angle1, double angle2, double angle3 )
747 {
748  bool clockwise = circleClockwise( angle1, angle2, angle3 );
749  return circleAngleBetween( angle, angle1, angle3, clockwise );
750 }
751 
752 double QgsGeometryUtils::circleLength( double x1, double y1, double x2, double y2, double x3, double y3 )
753 {
754  double centerX, centerY, radius;
755  circleCenterRadius( QgsPoint( x1, y1 ), QgsPoint( x2, y2 ), QgsPoint( x3, y3 ), radius, centerX, centerY );
756  double length = M_PI / 180.0 * radius * sweepAngle( centerX, centerY, x1, y1, x2, y2, x3, y3 );
757  if ( length < 0 )
758  {
759  length = -length;
760  }
761  return length;
762 }
763 
764 double QgsGeometryUtils::sweepAngle( double centerX, double centerY, double x1, double y1, double x2, double y2, double x3, double y3 )
765 {
766  double p1Angle = QgsGeometryUtils::ccwAngle( y1 - centerY, x1 - centerX );
767  double p2Angle = QgsGeometryUtils::ccwAngle( y2 - centerY, x2 - centerX );
768  double p3Angle = QgsGeometryUtils::ccwAngle( y3 - centerY, x3 - centerX );
769 
770  if ( p3Angle >= p1Angle )
771  {
772  if ( p2Angle > p1Angle && p2Angle < p3Angle )
773  {
774  return ( p3Angle - p1Angle );
775  }
776  else
777  {
778  return ( - ( p1Angle + ( 360 - p3Angle ) ) );
779  }
780  }
781  else
782  {
783  if ( p2Angle < p1Angle && p2Angle > p3Angle )
784  {
785  return ( -( p1Angle - p3Angle ) );
786  }
787  else
788  {
789  return ( p3Angle + ( 360 - p1Angle ) );
790  }
791  }
792 }
793 
794 bool QgsGeometryUtils::segmentMidPoint( const QgsPoint &p1, const QgsPoint &p2, QgsPoint &result, double radius, const QgsPoint &mousePos )
795 {
796  QgsPoint midPoint( ( p1.x() + p2.x() ) / 2.0, ( p1.y() + p2.y() ) / 2.0 );
797  double midDist = std::sqrt( sqrDistance2D( p1, midPoint ) );
798  if ( radius < midDist )
799  {
800  return false;
801  }
802  double centerMidDist = std::sqrt( radius * radius - midDist * midDist );
803  double dist = radius - centerMidDist;
804 
805  double midDx = midPoint.x() - p1.x();
806  double midDy = midPoint.y() - p1.y();
807 
808  //get the four possible midpoints
809  QVector<QgsPoint> possibleMidPoints;
810  possibleMidPoints.append( pointOnLineWithDistance( midPoint, QgsPoint( midPoint.x() - midDy, midPoint.y() + midDx ), dist ) );
811  possibleMidPoints.append( pointOnLineWithDistance( midPoint, QgsPoint( midPoint.x() - midDy, midPoint.y() + midDx ), 2 * radius - dist ) );
812  possibleMidPoints.append( pointOnLineWithDistance( midPoint, QgsPoint( midPoint.x() + midDy, midPoint.y() - midDx ), dist ) );
813  possibleMidPoints.append( pointOnLineWithDistance( midPoint, QgsPoint( midPoint.x() + midDy, midPoint.y() - midDx ), 2 * radius - dist ) );
814 
815  //take the closest one
816  double minDist = std::numeric_limits<double>::max();
817  int minDistIndex = -1;
818  for ( int i = 0; i < possibleMidPoints.size(); ++i )
819  {
820  double currentDist = sqrDistance2D( mousePos, possibleMidPoints.at( i ) );
821  if ( currentDist < minDist )
822  {
823  minDistIndex = i;
824  minDist = currentDist;
825  }
826  }
827 
828  if ( minDistIndex == -1 )
829  {
830  return false;
831  }
832 
833  result = possibleMidPoints.at( minDistIndex );
834 
835  // add z support if necessary
837 
838  return true;
839 }
840 
841 QgsPoint QgsGeometryUtils::segmentMidPointFromCenter( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &center, const bool useShortestArc )
842 {
843  double midPointAngle = averageAngle( lineAngle( center.x(), center.y(), p1.x(), p1.y() ),
844  lineAngle( center.x(), center.y(), p2.x(), p2.y() ) );
845  if ( !useShortestArc )
846  midPointAngle += M_PI;
847  return center.project( center.distance( p1 ), midPointAngle * 180 / M_PI );
848 }
849 
850 double QgsGeometryUtils::circleTangentDirection( const QgsPoint &tangentPoint, const QgsPoint &cp1,
851  const QgsPoint &cp2, const QgsPoint &cp3 )
852 {
853  //calculate circle midpoint
854  double mX, mY, radius;
855  circleCenterRadius( cp1, cp2, cp3, radius, mX, mY );
856 
857  double p1Angle = QgsGeometryUtils::ccwAngle( cp1.y() - mY, cp1.x() - mX );
858  double p2Angle = QgsGeometryUtils::ccwAngle( cp2.y() - mY, cp2.x() - mX );
859  double p3Angle = QgsGeometryUtils::ccwAngle( cp3.y() - mY, cp3.x() - mX );
860  double angle = 0;
861  if ( circleClockwise( p1Angle, p2Angle, p3Angle ) )
862  {
863  angle = lineAngle( tangentPoint.x(), tangentPoint.y(), mX, mY ) - M_PI_2;
864  }
865  else
866  {
867  angle = lineAngle( mX, mY, tangentPoint.x(), tangentPoint.y() ) - M_PI_2;
868  }
869  if ( angle < 0 )
870  angle += 2 * M_PI;
871  return angle;
872 }
873 
874 void QgsGeometryUtils::segmentizeArc( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3, QgsPointSequence &points, double tolerance, QgsAbstractGeometry::SegmentationToleranceType toleranceType, bool hasZ, bool hasM )
875 {
876  bool reversed = false;
877  int segSide = segmentSide( p1, p3, p2 );
878 
879  QgsPoint circlePoint1;
880  const QgsPoint circlePoint2 = p2;
881  QgsPoint circlePoint3;
882 
883  if ( segSide == -1 )
884  {
885  // Reverse !
886  circlePoint1 = p3;
887  circlePoint3 = p1;
888  reversed = true;
889  }
890  else
891  {
892  circlePoint1 = p1;
893  circlePoint3 = p3;
894  }
895 
896  //adapted code from PostGIS
897  double radius = 0;
898  double centerX = 0;
899  double centerY = 0;
900  circleCenterRadius( circlePoint1, circlePoint2, circlePoint3, radius, centerX, centerY );
901 
902  if ( circlePoint1 != circlePoint3 && ( radius < 0 || qgsDoubleNear( segSide, 0.0 ) ) ) //points are colinear
903  {
904  points.append( p1 );
905  points.append( p2 );
906  points.append( p3 );
907  return;
908  }
909 
910  double increment = tolerance; //one segment per degree
911  if ( toleranceType == QgsAbstractGeometry::MaximumDifference )
912  {
913  double halfAngle = std::acos( -tolerance / radius + 1 );
914  increment = 2 * halfAngle;
915  }
916 
917  //angles of pt1, pt2, pt3
918  double a1 = std::atan2( circlePoint1.y() - centerY, circlePoint1.x() - centerX );
919  double a2 = std::atan2( circlePoint2.y() - centerY, circlePoint2.x() - centerX );
920  double a3 = std::atan2( circlePoint3.y() - centerY, circlePoint3.x() - centerX );
921 
922  // Make segmentation symmetric
923  const bool symmetric = true;
924  if ( symmetric )
925  {
926  double angle = a3 - a1;
927  // angle == 0 when full circle
928  if ( angle <= 0 ) angle += M_PI * 2;
929 
930  /* Number of segments in output */
931  int segs = ceil( angle / increment );
932  /* Tweak increment to be regular for all the arc */
933  increment = angle / segs;
934  }
935 
936  /* Adjust a3 up so we can increment from a1 to a3 cleanly */
937  // a3 == a1 when full circle
938  if ( a3 <= a1 )
939  a3 += 2.0 * M_PI;
940  if ( a2 < a1 )
941  a2 += 2.0 * M_PI;
942 
943  double x, y;
944  double z = 0;
945  double m = 0;
946 
947  QVector<QgsPoint> stringPoints;
948  stringPoints.insert( 0, circlePoint1 );
949  if ( circlePoint2 != circlePoint3 && circlePoint1 != circlePoint2 ) //draw straight line segment if two points have the same position
950  {
951  QgsWkbTypes::Type pointWkbType = QgsWkbTypes::Point;
952  if ( hasZ )
953  pointWkbType = QgsWkbTypes::addZ( pointWkbType );
954  if ( hasM )
955  pointWkbType = QgsWkbTypes::addM( pointWkbType );
956 
957  // As we're adding the last point in any case, we'll avoid
958  // including a point which is at less than 1% increment distance
959  // from it (may happen to find them due to numbers approximation).
960  // NOTE that this effectively allows in output some segments which
961  // are more distant than requested. This is at most 1% off
962  // from requested MaxAngle and less for MaxError.
963  double tolError = increment / 100;
964  double stopAngle = a3 - tolError;
965  for ( double angle = a1 + increment; angle < stopAngle; angle += increment )
966  {
967  x = centerX + radius * std::cos( angle );
968  y = centerY + radius * std::sin( angle );
969 
970  if ( hasZ )
971  {
972  z = interpolateArcValue( angle, a1, a2, a3, circlePoint1.z(), circlePoint2.z(), circlePoint3.z() );
973  }
974  if ( hasM )
975  {
976  m = interpolateArcValue( angle, a1, a2, a3, circlePoint1.m(), circlePoint2.m(), circlePoint3.m() );
977  }
978 
979  stringPoints.insert( stringPoints.size(), QgsPoint( pointWkbType, x, y, z, m ) );
980  }
981  }
982  stringPoints.insert( stringPoints.size(), circlePoint3 );
983 
984  // TODO: check if or implement QgsPointSequence directly taking an iterator to append
985  if ( reversed )
986  {
987  std::reverse( stringPoints.begin(), stringPoints.end() );
988  }
989  if ( ! points.empty() && stringPoints.front() == points.back() ) stringPoints.pop_front();
990  points.append( stringPoints );
991 }
992 
993 int QgsGeometryUtils::segmentSide( const QgsPoint &pt1, const QgsPoint &pt3, const QgsPoint &pt2 )
994 {
995  double side = ( ( pt2.x() - pt1.x() ) * ( pt3.y() - pt1.y() ) - ( pt3.x() - pt1.x() ) * ( pt2.y() - pt1.y() ) );
996  if ( side == 0.0 )
997  {
998  return 0;
999  }
1000  else
1001  {
1002  if ( side < 0 )
1003  {
1004  return -1;
1005  }
1006  if ( side > 0 )
1007  {
1008  return 1;
1009  }
1010  return 0;
1011  }
1012 }
1013 
1014 double QgsGeometryUtils::interpolateArcValue( double angle, double a1, double a2, double a3, double zm1, double zm2, double zm3 )
1015 {
1016  /* Counter-clockwise sweep */
1017  if ( a1 < a2 )
1018  {
1019  if ( angle <= a2 )
1020  return zm1 + ( zm2 - zm1 ) * ( angle - a1 ) / ( a2 - a1 );
1021  else
1022  return zm2 + ( zm3 - zm2 ) * ( angle - a2 ) / ( a3 - a2 );
1023  }
1024  /* Clockwise sweep */
1025  else
1026  {
1027  if ( angle >= a2 )
1028  return zm1 + ( zm2 - zm1 ) * ( a1 - angle ) / ( a1 - a2 );
1029  else
1030  return zm2 + ( zm3 - zm2 ) * ( a2 - angle ) / ( a2 - a3 );
1031  }
1032 }
1033 
1034 QgsPointSequence QgsGeometryUtils::pointsFromWKT( const QString &wktCoordinateList, bool is3D, bool isMeasure )
1035 {
1036  int dim = 2 + is3D + isMeasure;
1037  QgsPointSequence points;
1038  const QStringList coordList = wktCoordinateList.split( ',', QString::SkipEmptyParts );
1039 
1040  //first scan through for extra unexpected dimensions
1041  bool foundZ = false;
1042  bool foundM = false;
1043  QRegularExpression rx( QStringLiteral( "\\s" ) );
1044  for ( const QString &pointCoordinates : coordList )
1045  {
1046  QStringList coordinates = pointCoordinates.split( rx, QString::SkipEmptyParts );
1047  if ( coordinates.size() == 3 && !foundZ && !foundM && !is3D && !isMeasure )
1048  {
1049  // 3 dimensional coordinates, but not specifically marked as such. We allow this
1050  // anyway and upgrade geometry to have Z dimension
1051  foundZ = true;
1052  }
1053  else if ( coordinates.size() >= 4 && ( !( is3D || foundZ ) || !( isMeasure || foundM ) ) )
1054  {
1055  // 4 (or more) dimensional coordinates, but not specifically marked as such. We allow this
1056  // anyway and upgrade geometry to have Z&M dimensions
1057  foundZ = true;
1058  foundM = true;
1059  }
1060  }
1061 
1062  for ( const QString &pointCoordinates : coordList )
1063  {
1064  QStringList coordinates = pointCoordinates.split( rx, QString::SkipEmptyParts );
1065  if ( coordinates.size() < dim )
1066  continue;
1067 
1068  int idx = 0;
1069  double x = coordinates[idx++].toDouble();
1070  double y = coordinates[idx++].toDouble();
1071 
1072  double z = 0;
1073  if ( ( is3D || foundZ ) && coordinates.length() > idx )
1074  z = coordinates[idx++].toDouble();
1075 
1076  double m = 0;
1077  if ( ( isMeasure || foundM ) && coordinates.length() > idx )
1078  m = coordinates[idx++].toDouble();
1079 
1081  if ( is3D || foundZ )
1082  {
1083  if ( isMeasure || foundM )
1085  else
1086  t = QgsWkbTypes::PointZ;
1087  }
1088  else
1089  {
1090  if ( isMeasure || foundM )
1091  t = QgsWkbTypes::PointM;
1092  else
1093  t = QgsWkbTypes::Point;
1094  }
1095 
1096  points.append( QgsPoint( t, x, y, z, m ) );
1097  }
1098 
1099  return points;
1100 }
1101 
1103 {
1104  wkb << static_cast<quint32>( points.size() );
1105  for ( const QgsPoint &point : points )
1106  {
1107  wkb << point.x() << point.y();
1108  if ( is3D )
1109  {
1110  wkb << point.z();
1111  }
1112  if ( isMeasure )
1113  {
1114  wkb << point.m();
1115  }
1116  }
1117 }
1118 
1119 QString QgsGeometryUtils::pointsToWKT( const QgsPointSequence &points, int precision, bool is3D, bool isMeasure )
1120 {
1121  QString wkt = QStringLiteral( "(" );
1122  for ( const QgsPoint &p : points )
1123  {
1124  wkt += qgsDoubleToString( p.x(), precision );
1125  wkt += ' ' + qgsDoubleToString( p.y(), precision );
1126  if ( is3D )
1127  wkt += ' ' + qgsDoubleToString( p.z(), precision );
1128  if ( isMeasure )
1129  wkt += ' ' + qgsDoubleToString( p.m(), precision );
1130  wkt += QLatin1String( ", " );
1131  }
1132  if ( wkt.endsWith( QLatin1String( ", " ) ) )
1133  wkt.chop( 2 ); // Remove last ", "
1134  wkt += ')';
1135  return wkt;
1136 }
1137 
1138 QDomElement QgsGeometryUtils::pointsToGML2( const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, QgsAbstractGeometry::AxisOrder axisOrder )
1139 {
1140  QDomElement elemCoordinates = doc.createElementNS( ns, QStringLiteral( "coordinates" ) );
1141 
1142  // coordinate separator
1143  QString cs = QStringLiteral( "," );
1144  // tupel separator
1145  QString ts = QStringLiteral( " " );
1146 
1147  elemCoordinates.setAttribute( QStringLiteral( "cs" ), cs );
1148  elemCoordinates.setAttribute( QStringLiteral( "ts" ), ts );
1149 
1150  QString strCoordinates;
1151 
1152  for ( const QgsPoint &p : points )
1153  if ( axisOrder == QgsAbstractGeometry::AxisOrder::XY )
1154  strCoordinates += qgsDoubleToString( p.x(), precision ) + cs + qgsDoubleToString( p.y(), precision ) + ts;
1155  else
1156  strCoordinates += qgsDoubleToString( p.y(), precision ) + cs + qgsDoubleToString( p.x(), precision ) + ts;
1157 
1158  if ( strCoordinates.endsWith( ts ) )
1159  strCoordinates.chop( 1 ); // Remove trailing space
1160 
1161  elemCoordinates.appendChild( doc.createTextNode( strCoordinates ) );
1162  return elemCoordinates;
1163 }
1164 
1165 QDomElement QgsGeometryUtils::pointsToGML3( const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, bool is3D, QgsAbstractGeometry::AxisOrder axisOrder )
1166 {
1167  QDomElement elemPosList = doc.createElementNS( ns, QStringLiteral( "posList" ) );
1168  elemPosList.setAttribute( QStringLiteral( "srsDimension" ), is3D ? 3 : 2 );
1169 
1170  QString strCoordinates;
1171  for ( const QgsPoint &p : points )
1172  {
1173  if ( axisOrder == QgsAbstractGeometry::AxisOrder::XY )
1174  strCoordinates += qgsDoubleToString( p.x(), precision ) + ' ' + qgsDoubleToString( p.y(), precision ) + ' ';
1175  else
1176  strCoordinates += qgsDoubleToString( p.y(), precision ) + ' ' + qgsDoubleToString( p.x(), precision ) + ' ';
1177  if ( is3D )
1178  strCoordinates += qgsDoubleToString( p.z(), precision ) + ' ';
1179  }
1180  if ( strCoordinates.endsWith( ' ' ) )
1181  strCoordinates.chop( 1 ); // Remove trailing space
1182 
1183  elemPosList.appendChild( doc.createTextNode( strCoordinates ) );
1184  return elemPosList;
1185 }
1186 
1188 {
1189  QString json = QStringLiteral( "[ " );
1190  for ( const QgsPoint &p : points )
1191  {
1192  json += '[' + qgsDoubleToString( p.x(), precision ) + QLatin1String( ", " ) + qgsDoubleToString( p.y(), precision ) + QLatin1String( "], " );
1193  }
1194  if ( json.endsWith( QLatin1String( ", " ) ) )
1195  {
1196  json.chop( 2 ); // Remove last ", "
1197  }
1198  json += ']';
1199  return json;
1200 }
1201 
1202 
1204 {
1205  json coordinates( json::array() );
1206  for ( const QgsPoint &p : points )
1207  {
1208  if ( p.is3D() )
1209  {
1210  coordinates.push_back( { qgsRound( p.x(), precision ), qgsRound( p.y(), precision ), qgsRound( p.z(), precision ) } );
1211  }
1212  else
1213  {
1214  coordinates.push_back( { qgsRound( p.x(), precision ), qgsRound( p.y(), precision ) } );
1215  }
1216  }
1217  return coordinates;
1218 }
1219 
1221 {
1222  double clippedAngle = angle;
1223  if ( clippedAngle >= M_PI * 2 || clippedAngle <= -2 * M_PI )
1224  {
1225  clippedAngle = std::fmod( clippedAngle, 2 * M_PI );
1226  }
1227  if ( clippedAngle < 0.0 )
1228  {
1229  clippedAngle += 2 * M_PI;
1230  }
1231  return clippedAngle;
1232 }
1233 
1234 QPair<QgsWkbTypes::Type, QString> QgsGeometryUtils::wktReadBlock( const QString &wkt )
1235 {
1237 
1238  QRegularExpression cooRegEx( QStringLiteral( "^[^\\(]*\\((.*)\\)[^\\)]*$" ) );
1239  cooRegEx.setPatternOptions( QRegularExpression::DotMatchesEverythingOption );
1240  QRegularExpressionMatch match = cooRegEx.match( wkt );
1241  QString contents = match.hasMatch() ? match.captured( 1 ) : QString();
1242  return qMakePair( wkbType, contents );
1243 }
1244 
1245 QStringList QgsGeometryUtils::wktGetChildBlocks( const QString &wkt, const QString &defaultType )
1246 {
1247  int level = 0;
1248  QString block;
1249  QStringList blocks;
1250  for ( int i = 0, n = wkt.length(); i < n; ++i )
1251  {
1252  if ( ( wkt[i].isSpace() || wkt[i] == '\n' || wkt[i] == '\t' ) && level == 0 )
1253  continue;
1254 
1255  if ( wkt[i] == ',' && level == 0 )
1256  {
1257  if ( !block.isEmpty() )
1258  {
1259  if ( block.startsWith( '(' ) && !defaultType.isEmpty() )
1260  block.prepend( defaultType + ' ' );
1261  blocks.append( block );
1262  }
1263  block.clear();
1264  continue;
1265  }
1266  if ( wkt[i] == '(' )
1267  ++level;
1268  else if ( wkt[i] == ')' )
1269  --level;
1270  block += wkt[i];
1271  }
1272  if ( !block.isEmpty() )
1273  {
1274  if ( block.startsWith( '(' ) && !defaultType.isEmpty() )
1275  block.prepend( defaultType + ' ' );
1276  blocks.append( block );
1277  }
1278  return blocks;
1279 }
1280 
1282 {
1284 
1285 
1286  double x = ( pt1.x() + pt2.x() ) / 2.0;
1287  double y = ( pt1.y() + pt2.y() ) / 2.0;
1288  double z = std::numeric_limits<double>::quiet_NaN();
1289  double m = std::numeric_limits<double>::quiet_NaN();
1290 
1291  if ( pt1.is3D() || pt2.is3D() )
1292  {
1293  pType = QgsWkbTypes::addZ( pType );
1294  z = ( pt1.z() + pt2.z() ) / 2.0;
1295  }
1296 
1297  if ( pt1.isMeasure() || pt2.isMeasure() )
1298  {
1299  pType = QgsWkbTypes::addM( pType );
1300  m = ( pt1.m() + pt2.m() ) / 2.0;
1301  }
1302 
1303  return QgsPoint( pType, x, y, z, m );
1304 }
1305 
1306 QgsPoint QgsGeometryUtils::interpolatePointOnLine( const QgsPoint &p1, const QgsPoint &p2, const double fraction )
1307 {
1308  const double _fraction = 1 - fraction;
1309  return QgsPoint( p1.wkbType(),
1310  p1.x() * _fraction + p2.x() * fraction,
1311  p1.y() * _fraction + p2.y() * fraction,
1312  p1.is3D() ? p1.z() * _fraction + p2.z() * fraction : std::numeric_limits<double>::quiet_NaN(),
1313  p1.isMeasure() ? p1.m() * _fraction + p2.m() * fraction : std::numeric_limits<double>::quiet_NaN() );
1314 }
1315 
1316 QgsPointXY QgsGeometryUtils::interpolatePointOnLine( const double x1, const double y1, const double x2, const double y2, const double fraction )
1317 {
1318  const double deltaX = ( x2 - x1 ) * fraction;
1319  const double deltaY = ( y2 - y1 ) * fraction;
1320  return QgsPointXY( x1 + deltaX, y1 + deltaY );
1321 }
1322 
1323 QgsPointXY QgsGeometryUtils::interpolatePointOnLineByValue( const double x1, const double y1, const double v1, const double x2, const double y2, const double v2, const double value )
1324 {
1325  if ( qgsDoubleNear( v1, v2 ) )
1326  return QgsPointXY( x1, y1 );
1327 
1328  const double fraction = ( value - v1 ) / ( v2 - v1 );
1329  return interpolatePointOnLine( x1, y1, x2, y2, fraction );
1330 }
1331 
1332 double QgsGeometryUtils::gradient( const QgsPoint &pt1, const QgsPoint &pt2 )
1333 {
1334  double delta_x = pt2.x() - pt1.x();
1335  double delta_y = pt2.y() - pt1.y();
1336  if ( qgsDoubleNear( delta_x, 0.0 ) )
1337  {
1338  return INFINITY;
1339  }
1340 
1341  return delta_y / delta_x;
1342 }
1343 
1344 void QgsGeometryUtils::coefficients( const QgsPoint &pt1, const QgsPoint &pt2, double &a, double &b, double &c )
1345 {
1346  if ( qgsDoubleNear( pt1.x(), pt2.x() ) )
1347  {
1348  a = 1;
1349  b = 0;
1350  c = -pt1.x();
1351  }
1352  else if ( qgsDoubleNear( pt1.y(), pt2.y() ) )
1353  {
1354  a = 0;
1355  b = 1;
1356  c = -pt1.y();
1357  }
1358  else
1359  {
1360  a = pt1.y() - pt2.y();
1361  b = pt2.x() - pt1.x();
1362  c = pt1.x() * pt2.y() - pt1.y() * pt2.x();
1363  }
1364 
1365 }
1366 
1368 {
1369  QgsLineString line;
1370  QgsPoint p2;
1371 
1372  if ( ( p == s1 ) || ( p == s2 ) )
1373  {
1374  return line;
1375  }
1376 
1377  double a, b, c;
1378  coefficients( s1, s2, a, b, c );
1379 
1380  if ( qgsDoubleNear( a, 0 ) )
1381  {
1382  p2 = QgsPoint( p.x(), s1.y() );
1383  }
1384  else if ( qgsDoubleNear( b, 0 ) )
1385  {
1386  p2 = QgsPoint( s1.x(), p.y() );
1387  }
1388  else
1389  {
1390  double y = ( -c - a * p.x() ) / b;
1391  double m = gradient( s1, s2 );
1392  double d2 = 1 + m * m;
1393  double H = p.y() - y;
1394  double dx = m * H / d2;
1395  double dy = m * dx;
1396  p2 = QgsPoint( p.x() + dx, y + dy );
1397  }
1398 
1399  line.addVertex( p );
1400  line.addVertex( p2 );
1401 
1402  return line;
1403 }
1404 
1405 double QgsGeometryUtils::lineAngle( double x1, double y1, double x2, double y2 )
1406 {
1407  double at = std::atan2( y2 - y1, x2 - x1 );
1408  double a = -at + M_PI_2;
1409  return normalizedAngle( a );
1410 }
1411 
1412 double QgsGeometryUtils::angleBetweenThreePoints( double x1, double y1, double x2, double y2, double x3, double y3 )
1413 {
1414  double angle1 = std::atan2( y1 - y2, x1 - x2 );
1415  double angle2 = std::atan2( y3 - y2, x3 - x2 );
1416  return normalizedAngle( angle1 - angle2 );
1417 }
1418 
1419 double QgsGeometryUtils::linePerpendicularAngle( double x1, double y1, double x2, double y2 )
1420 {
1421  double a = lineAngle( x1, y1, x2, y2 );
1422  a += M_PI_2;
1423  return normalizedAngle( a );
1424 }
1425 
1426 double QgsGeometryUtils::averageAngle( double x1, double y1, double x2, double y2, double x3, double y3 )
1427 {
1428  // calc average angle between the previous and next point
1429  double a1 = lineAngle( x1, y1, x2, y2 );
1430  double a2 = lineAngle( x2, y2, x3, y3 );
1431  return averageAngle( a1, a2 );
1432 }
1433 
1434 double QgsGeometryUtils::averageAngle( double a1, double a2 )
1435 {
1436  a1 = normalizedAngle( a1 );
1437  a2 = normalizedAngle( a2 );
1438  double clockwiseDiff = 0.0;
1439  if ( a2 >= a1 )
1440  {
1441  clockwiseDiff = a2 - a1;
1442  }
1443  else
1444  {
1445  clockwiseDiff = a2 + ( 2 * M_PI - a1 );
1446  }
1447  double counterClockwiseDiff = 2 * M_PI - clockwiseDiff;
1448 
1449  double resultAngle = 0;
1450  if ( clockwiseDiff <= counterClockwiseDiff )
1451  {
1452  resultAngle = a1 + clockwiseDiff / 2.0;
1453  }
1454  else
1455  {
1456  resultAngle = a1 - counterClockwiseDiff / 2.0;
1457  }
1458  return normalizedAngle( resultAngle );
1459 }
1460 
1462  const QgsVector3D &P2, const QgsVector3D &P22 )
1463 {
1464  QgsVector3D u1 = P12 - P1;
1465  QgsVector3D u2 = P22 - P2;
1466  QgsVector3D u3 = QgsVector3D::crossProduct( u1, u2 );
1467  if ( u3.length() == 0 ) return 1;
1468  u3.normalize();
1469  QgsVector3D dir = P1 - P2;
1470  return std::fabs( ( QgsVector3D::dotProduct( dir, u3 ) ) ); // u3 is already normalized
1471 }
1472 
1474  const QgsVector3D &P2, const QgsVector3D &P22,
1475  QgsVector3D &X1, double epsilon )
1476 {
1477  QgsVector3D d = P2 - P1;
1478  QgsVector3D u1 = P12 - P1;
1479  u1.normalize();
1480  QgsVector3D u2 = P22 - P2;
1481  u2.normalize();
1482  QgsVector3D u3 = QgsVector3D::crossProduct( u1, u2 );
1483 
1484  if ( std::fabs( u3.x() ) <= epsilon &&
1485  std::fabs( u3.y() ) <= epsilon &&
1486  std::fabs( u3.z() ) <= epsilon )
1487  {
1488  // The rays are almost parallel.
1489  return false;
1490  }
1491 
1492  // X1 and X2 are the closest points on lines
1493  // we want to find X1 (lies on u1)
1494  // solving the linear equation in r1 and r2: Xi = Pi + ri*ui
1495  // we are only interested in X1 so we only solve for r1.
1496  float a1 = QgsVector3D::dotProduct( u1, u1 ), b1 = QgsVector3D::dotProduct( u1, u2 ), c1 = QgsVector3D::dotProduct( u1, d );
1497  float a2 = QgsVector3D::dotProduct( u1, u2 ), b2 = QgsVector3D::dotProduct( u2, u2 ), c2 = QgsVector3D::dotProduct( u2, d );
1498  if ( !( std::fabs( b1 ) > epsilon ) )
1499  {
1500  // Denominator is close to zero.
1501  return false;
1502  }
1503  if ( !( a2 != -1 && a2 != 1 ) )
1504  {
1505  // Lines are parallel
1506  return false;
1507  }
1508 
1509  double r1 = ( c2 - b2 * c1 / b1 ) / ( a2 - b2 * a1 / b1 );
1510  X1 = P1 + u1 * r1;
1511 
1512  return true;
1513 }
1514 
1516  const QgsVector3D &Lb1, const QgsVector3D &Lb2,
1517  QgsVector3D &intersection )
1518 {
1519 
1520  // if all Vector are on the same plane (have the same Z), use the 2D intersection
1521  // else return a false result
1522  if ( qgsDoubleNear( La1.z(), La2.z() ) && qgsDoubleNear( La1.z(), Lb1.z() ) && qgsDoubleNear( La1.z(), Lb2.z() ) )
1523  {
1524  QgsPoint ptInter;
1525  bool isIntersection;
1526  segmentIntersection( QgsPoint( La1.x(), La1.y() ),
1527  QgsPoint( La2.x(), La2.y() ),
1528  QgsPoint( Lb1.x(), Lb1.y() ),
1529  QgsPoint( Lb2.x(), Lb2.y() ),
1530  ptInter,
1531  isIntersection,
1532  1e-8,
1533  true );
1534  intersection.set( ptInter.x(), ptInter.y(), La1.z() );
1535  return true;
1536  }
1537 
1538  // first check if lines have an exact intersection point
1539  // do it by checking if the shortest distance is exactly 0
1540  float distance = skewLinesDistance( La1, La2, Lb1, Lb2 );
1541  if ( qgsDoubleNear( distance, 0.0 ) )
1542  {
1543  // 3d lines have exact intersection point.
1544  QgsVector3D C = La2;
1545  QgsVector3D D = Lb2;
1546  QgsVector3D e = La1 - La2;
1547  QgsVector3D f = Lb1 - Lb2;
1548  QgsVector3D g = D - C;
1549  if ( qgsDoubleNear( ( QgsVector3D::crossProduct( f, g ) ).length(), 0.0 ) || qgsDoubleNear( ( QgsVector3D::crossProduct( f, e ) ).length(), 0.0 ) )
1550  {
1551  // Lines have no intersection, are they parallel?
1552  return false;
1553  }
1554 
1555  QgsVector3D fgn = QgsVector3D::crossProduct( f, g );
1556  fgn.normalize();
1557 
1558  QgsVector3D fen = QgsVector3D::crossProduct( f, e );
1559  fen.normalize();
1560 
1561  int di = -1;
1562  if ( fgn == fen ) // same direction?
1563  di *= -1;
1564 
1565  intersection = C + e * di * ( QgsVector3D::crossProduct( f, g ).length() / QgsVector3D::crossProduct( f, e ).length() );
1566  return true;
1567  }
1568 
1569  // try to calculate the approximate intersection point
1570  QgsVector3D X1, X2;
1571  bool firstIsDone = skewLinesProjection( La1, La2, Lb1, Lb2, X1 );
1572  bool secondIsDone = skewLinesProjection( Lb1, Lb2, La1, La2, X2 );
1573 
1574  if ( !firstIsDone || !secondIsDone )
1575  {
1576  // Could not obtain projection point.
1577  return false;
1578  }
1579 
1580  intersection = ( X1 + X2 ) / 2.0;
1581  return true;
1582 }
1583 
1585 {
1586  bool rc = false;
1587 
1588  for ( const QgsPoint &pt : points )
1589  {
1590  if ( pt.is3D() )
1591  {
1592  point.convertTo( QgsWkbTypes::addZ( point.wkbType() ) );
1593  point.setZ( pt.z() );
1594  rc = true;
1595  break;
1596  }
1597  }
1598 
1599  return rc;
1600 }
bool isMeasure() const
Returns true if the geometry contains m values.
Maximum distance between an arbitrary point on the original curve and closest point on its approximat...
static bool lineCircleIntersection(const QgsPointXY &center, double radius, const QgsPointXY &linePoint1, const QgsPointXY &linePoint2, QgsPointXY &intersection)
Compute the intersection of a line and a circle.
3 Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double preci...
Definition: qgsvector3d.h:31
static double skewLinesDistance(const QgsVector3D &P1, const QgsVector3D &P12, const QgsVector3D &P2, const QgsVector3D &P22)
An algorithm to calculate the shortest distance between two skew lines.
static QString pointsToJSON(const QgsPointSequence &points, int precision)
Returns a geoJSON coordinates string.
int precision
void set(double x, double y)
Sets the x and y value of the point.
Definition: qgspointxy.h:119
double y
Definition: qgspoint.h:42
static bool circleAngleBetween(double angle, double angle1, double angle2, bool clockwise)
Returns true if, in a circle, angle is between angle1 and angle2.
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 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 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 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 QVector< SelfIntersection > selfIntersections(const QgsAbstractGeometry *geom, int part, int ring, double tolerance)
Find self intersections in a polyline.
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 pt3...
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
Definition: qgspoint.cpp:486
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...
bool isValid() const
Returns true if the vertex id is valid.
void setZ(double z)
Sets the point&#39;s z-coordinate.
Definition: qgspoint.h:237
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 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, y1) to (x2, y2) and (x2, y2) to (x3, y3).
static double angleBetweenThreePoints(double x1, double y1, double x2, double y2, double x3, double y3)
Calculates the angle between the lines AB and BC, where AB and BC described by points a...
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
Definition: qgspoint.h:276
static double gradient(const QgsPoint &pt1, const QgsPoint &pt2)
Returns the gradient of a line defined by points pt1 and pt2.
double length() const
Returns the length of the vector.
Definition: qgsvector3d.h:112
double y
Definition: qgspointxy.h:48
A class to represent a 2D point.
Definition: qgspointxy.h:43
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:265
static QgsPoint segmentMidPointFromCenter(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &center, bool useShortestArc=true)
Calculates the midpoint on the circle passing through p1 and p2, with the specified center coordinate...
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.
Curve polygon geometry type.
static double linePerpendicularAngle(double x1, double y1, double x2, double y2)
Calculates the perpendicular angle to a line joining two points.
static Type parseType(const QString &wktStr)
Attempts to extract the WKB type from a WKT string.
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 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.
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle...
static QgsPoint closestVertex(const QgsAbstractGeometry &geom, const QgsPoint &pt, QgsVertexId &id)
Returns the closest vertex to a geometry for a specified point.
virtual bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const =0
Returns next vertex id and coordinates.
double y() const
Returns Y coordinate.
Definition: qgsvector3d.h:51
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:771
static int circleCircleOuterTangents(const QgsPointXY &center1, double radius1, const QgsPointXY &center2, 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...
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)
Definition: MathUtils.cpp:786
static QStringList wktGetChildBlocks(const QString &wkt, const QString &defaultType=QString())
Parses a WKT string and returns of list of blocks contained in the WKT.
void set(double x, double y, double z)
Sets vector coordinates.
Definition: qgsvector3d.h:56
static double dotProduct(const QgsVector3D &v1, const QgsVector3D &v2)
Returns the dot product of two vectors.
Definition: qgsvector3d.h:98
static QgsVector3D crossProduct(const QgsVector3D &v1, const QgsVector3D &v2)
Returns the cross product of two vectors.
Definition: qgsvector3d.h:104
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.
void normalize()
Normalizes the current vector in place.
Definition: qgsvector3d.h:118
double sqrDist(double x, double y) const
Returns the squared distance between this point a specified x, y coordinate.
Definition: qgspointxy.h:169
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
virtual double length() const
Returns the length of the geometry.
static bool circleClockwise(double angle1, double angle2, double angle3)
Returns true if the circle defined by three angles is ordered clockwise.
double z() const
Returns Z coordinate.
Definition: qgsvector3d.h:53
static QString pointsToWKT(const QgsPointSequence &points, int precision, bool is3D, bool isMeasure)
Returns a WKT coordinate list.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
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.
static bool setZValueFromPoints(const QgsPointSequence &points, QgsPoint &point)
A Z dimension is added to point if one of the point in the list points is in 3D.
virtual double segmentLength(QgsVertexId startVertex) const =0
Returns the length of the segment of the geometry which begins at startVertex.
static Type addM(Type type)
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:892
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).
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
Utility class for identifying a unique vertex within a geometry.
const double DEFAULT_SEGMENT_EPSILON
Default snapping tolerance for segments.
Definition: qgis.h:573
Geometry collection.
static QgsPoint midpoint(const QgsPoint &pt1, const QgsPoint &pt2)
Returns a middle point between points pt1 and pt2.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:225
static Type addZ(Type type)
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:867
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 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, angle2 and angle3.
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
static bool linesIntersection3D(const QgsVector3D &La1, const QgsVector3D &La2, const QgsVector3D &Lb1, const QgsVector3D &Lb2, QgsVector3D &intersection)
An algorithm to calculate an (approximate) intersection of two lines in 3D.
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, y1) to (x2, y2).
Abstract base class for all geometries.
static QVector< QgsLineString * > extractLineStrings(const QgsAbstractGeometry *geom)
Returns list of linestrings extracted from the passed geometry.
static double normalizedAngle(double angle)
Ensures that an angle is in the range 0 <= angle < 2 pi.
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
Definition: qgspointxy.h:190
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
QgsPoint project(double distance, double azimuth, double inclination=90.0) const
Returns a new point which correspond to this point projected by a specified distance with specified a...
Definition: qgspoint.cpp:660
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
AxisOrder
Axis order for GML generation.
double length() const
Returns the length of the vector.
Definition: qgsvector.cpp:71
static bool lineIntersection(const QgsPoint &p1, QgsVector v1, const QgsPoint &p2, QgsVector v2, QgsPoint &intersection)
Computes the intersection between two lines.
nlohmann::json json
Definition: qgsjsonutils.h:27
double x
Definition: qgspointxy.h:47
A class to represent a vector.
Definition: qgsvector.h:29
static json pointsToJson(const QgsPointSequence &points, int precision)
Returns coordinates as json object.
static bool skewLinesProjection(const QgsVector3D &P1, const QgsVector3D &P12, const QgsVector3D &P2, const QgsVector3D &P22, QgsVector3D &X1, double epsilon=0.0001)
A method to project one skew line onto another.
QVector< QgsPoint > QgsPointSequence
static QgsPoint pointOnLineWithDistance(const QgsPoint &startPoint, const QgsPoint &directionPoint, double distance)
Returns a point a specified distance toward a second point.
static double sqrDistance2D(const QgsPoint &pt1, const QgsPoint &pt2)
Returns the squared 2D distance between two points.
double qgsRound(double number, int places)
Returns a double number, rounded (as close as possible) to the specified number of places...
Definition: qgis.h:304
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 QgsLineString perpendicularSegment(const QgsPoint &p, const QgsPoint &s1, const QgsPoint &s2)
Create a perpendicular line segment from p to segment [s1, s2].
static QgsPointSequence pointsFromWKT(const QString &wktCoordinateList, bool is3D, bool isMeasure)
Returns a list of points contained in a WKT string.
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:43
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.
virtual int vertexCount(int part=0, int ring=0) const =0
Returns the number of vertices of which this geometry is built.
static bool tangentPointAndCircle(const QgsPointXY &center, 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 void circleCenterRadius(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double &radius, double &centerX, double &centerY)
Returns radius and center of the circle through pt1, pt2, pt3.
bool convertTo(QgsWkbTypes::Type type) override
Converts the geometry to a specified type.
Definition: qgspoint.cpp:555
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
Definition: qgspoint.cpp:497
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
static int circleCircleInnerTangents(const QgsPointXY &center1, double radius1, const QgsPointXY &center2, 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 int circleCircleIntersections(QgsPointXY center1, double radius1, QgsPointXY center2, double radius2, QgsPointXY &intersection1, QgsPointXY &intersection2)
Calculates the intersections points between the circle with center center1 and radius radius1 and the...
static double sqrDistToLine(double ptX, double ptY, double x1, double y1, double x2, double y2, double &minDistX, double &minDistY, double epsilon)
Returns the squared distance between a point and a line.
double z
Definition: qgspoint.h:43
static bool hasM(Type type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:821
double x() const
Returns the vector&#39;s x-component.
Definition: qgsvector.cpp:76
static QgsPoint closestPoint(const QgsAbstractGeometry &geometry, const QgsPoint &point)
Returns the nearest point on a segment of a geometry for the specified point.
virtual QgsPoint vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
double y() const
Returns the vector&#39;s y-component.
Definition: qgsvector.cpp:81
static double distanceToVertex(const QgsAbstractGeometry &geom, QgsVertexId id)
Returns the distance along a geometry from its first vertex to the specified vertex.
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).
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
double x() const
Returns X coordinate.
Definition: qgsvector3d.h:49
double m
Definition: qgspoint.h:44
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 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...
double x
Definition: qgspoint.h:41