QGIS API Documentation  3.10.0-A CoruĂ±a (6c816b4204)
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  // Ensure tolerance is not higher than twice the radius
914  tolerance = std::min( tolerance, radius * 2 );
915  double halfAngle = std::acos( -tolerance / radius + 1 );
916  increment = 2 * halfAngle;
917  }
918
919  //angles of pt1, pt2, pt3
920  double a1 = std::atan2( circlePoint1.y() - centerY, circlePoint1.x() - centerX );
921  double a2 = std::atan2( circlePoint2.y() - centerY, circlePoint2.x() - centerX );
922  double a3 = std::atan2( circlePoint3.y() - centerY, circlePoint3.x() - centerX );
923
924  // Make segmentation symmetric
925  const bool symmetric = true;
926  if ( symmetric )
927  {
928  double angle = a3 - a1;
929  // angle == 0 when full circle
930  if ( angle <= 0 ) angle += M_PI * 2;
931
932  /* Number of segments in output */
933  int segs = ceil( angle / increment );
934  /* Tweak increment to be regular for all the arc */
935  increment = angle / segs;
936  }
937
938  /* Adjust a3 up so we can increment from a1 to a3 cleanly */
939  // a3 == a1 when full circle
940  if ( a3 <= a1 )
941  a3 += 2.0 * M_PI;
942  if ( a2 < a1 )
943  a2 += 2.0 * M_PI;
944
945  double x, y;
946  double z = 0;
947  double m = 0;
948
949  QVector<QgsPoint> stringPoints;
950  stringPoints.insert( 0, circlePoint1 );
951  if ( circlePoint2 != circlePoint3 && circlePoint1 != circlePoint2 ) //draw straight line segment if two points have the same position
952  {
953  QgsWkbTypes::Type pointWkbType = QgsWkbTypes::Point;
954  if ( hasZ )
955  pointWkbType = QgsWkbTypes::addZ( pointWkbType );
956  if ( hasM )
957  pointWkbType = QgsWkbTypes::addM( pointWkbType );
958
959  // As we're adding the last point in any case, we'll avoid
960  // including a point which is at less than 1% increment distance
961  // from it (may happen to find them due to numbers approximation).
962  // NOTE that this effectively allows in output some segments which
963  // are more distant than requested. This is at most 1% off
964  // from requested MaxAngle and less for MaxError.
965  double tolError = increment / 100;
966  double stopAngle = a3 - tolError;
967  for ( double angle = a1 + increment; angle < stopAngle; angle += increment )
968  {
969  x = centerX + radius * std::cos( angle );
970  y = centerY + radius * std::sin( angle );
971
972  if ( hasZ )
973  {
974  z = interpolateArcValue( angle, a1, a2, a3, circlePoint1.z(), circlePoint2.z(), circlePoint3.z() );
975  }
976  if ( hasM )
977  {
978  m = interpolateArcValue( angle, a1, a2, a3, circlePoint1.m(), circlePoint2.m(), circlePoint3.m() );
979  }
980
981  stringPoints.insert( stringPoints.size(), QgsPoint( pointWkbType, x, y, z, m ) );
982  }
983  }
984  stringPoints.insert( stringPoints.size(), circlePoint3 );
985
986  // TODO: check if or implement QgsPointSequence directly taking an iterator to append
987  if ( reversed )
988  {
989  std::reverse( stringPoints.begin(), stringPoints.end() );
990  }
991  if ( ! points.empty() && stringPoints.front() == points.back() ) stringPoints.pop_front();
992  points.append( stringPoints );
993 }
994
995 int QgsGeometryUtils::segmentSide( const QgsPoint &pt1, const QgsPoint &pt3, const QgsPoint &pt2 )
996 {
997  double side = ( ( pt2.x() - pt1.x() ) * ( pt3.y() - pt1.y() ) - ( pt3.x() - pt1.x() ) * ( pt2.y() - pt1.y() ) );
998  if ( side == 0.0 )
999  {
1000  return 0;
1001  }
1002  else
1003  {
1004  if ( side < 0 )
1005  {
1006  return -1;
1007  }
1008  if ( side > 0 )
1009  {
1010  return 1;
1011  }
1012  return 0;
1013  }
1014 }
1015
1016 double QgsGeometryUtils::interpolateArcValue( double angle, double a1, double a2, double a3, double zm1, double zm2, double zm3 )
1017 {
1018  /* Counter-clockwise sweep */
1019  if ( a1 < a2 )
1020  {
1021  if ( angle <= a2 )
1022  return zm1 + ( zm2 - zm1 ) * ( angle - a1 ) / ( a2 - a1 );
1023  else
1024  return zm2 + ( zm3 - zm2 ) * ( angle - a2 ) / ( a3 - a2 );
1025  }
1026  /* Clockwise sweep */
1027  else
1028  {
1029  if ( angle >= a2 )
1030  return zm1 + ( zm2 - zm1 ) * ( a1 - angle ) / ( a1 - a2 );
1031  else
1032  return zm2 + ( zm3 - zm2 ) * ( a2 - angle ) / ( a2 - a3 );
1033  }
1034 }
1035
1036 QgsPointSequence QgsGeometryUtils::pointsFromWKT( const QString &wktCoordinateList, bool is3D, bool isMeasure )
1037 {
1038  int dim = 2 + is3D + isMeasure;
1039  QgsPointSequence points;
1040  const QStringList coordList = wktCoordinateList.split( ',', QString::SkipEmptyParts );
1041
1042  //first scan through for extra unexpected dimensions
1043  bool foundZ = false;
1044  bool foundM = false;
1045  QRegularExpression rx( QStringLiteral( "\\s" ) );
1046  for ( const QString &pointCoordinates : coordList )
1047  {
1048  QStringList coordinates = pointCoordinates.split( rx, QString::SkipEmptyParts );
1049  if ( coordinates.size() == 3 && !foundZ && !foundM && !is3D && !isMeasure )
1050  {
1051  // 3 dimensional coordinates, but not specifically marked as such. We allow this
1052  // anyway and upgrade geometry to have Z dimension
1053  foundZ = true;
1054  }
1055  else if ( coordinates.size() >= 4 && ( !( is3D || foundZ ) || !( isMeasure || foundM ) ) )
1056  {
1057  // 4 (or more) dimensional coordinates, but not specifically marked as such. We allow this
1058  // anyway and upgrade geometry to have Z&M dimensions
1059  foundZ = true;
1060  foundM = true;
1061  }
1062  }
1063
1064  for ( const QString &pointCoordinates : coordList )
1065  {
1066  QStringList coordinates = pointCoordinates.split( rx, QString::SkipEmptyParts );
1067  if ( coordinates.size() < dim )
1068  continue;
1069
1070  int idx = 0;
1071  double x = coordinates[idx++].toDouble();
1072  double y = coordinates[idx++].toDouble();
1073
1074  double z = 0;
1075  if ( ( is3D || foundZ ) && coordinates.length() > idx )
1076  z = coordinates[idx++].toDouble();
1077
1078  double m = 0;
1079  if ( ( isMeasure || foundM ) && coordinates.length() > idx )
1080  m = coordinates[idx++].toDouble();
1081
1083  if ( is3D || foundZ )
1084  {
1085  if ( isMeasure || foundM )
1087  else
1088  t = QgsWkbTypes::PointZ;
1089  }
1090  else
1091  {
1092  if ( isMeasure || foundM )
1093  t = QgsWkbTypes::PointM;
1094  else
1095  t = QgsWkbTypes::Point;
1096  }
1097
1098  points.append( QgsPoint( t, x, y, z, m ) );
1099  }
1100
1101  return points;
1102 }
1103
1105 {
1106  wkb << static_cast<quint32>( points.size() );
1107  for ( const QgsPoint &point : points )
1108  {
1109  wkb << point.x() << point.y();
1110  if ( is3D )
1111  {
1112  wkb << point.z();
1113  }
1114  if ( isMeasure )
1115  {
1116  wkb << point.m();
1117  }
1118  }
1119 }
1120
1121 QString QgsGeometryUtils::pointsToWKT( const QgsPointSequence &points, int precision, bool is3D, bool isMeasure )
1122 {
1123  QString wkt = QStringLiteral( "(" );
1124  for ( const QgsPoint &p : points )
1125  {
1126  wkt += qgsDoubleToString( p.x(), precision );
1127  wkt += ' ' + qgsDoubleToString( p.y(), precision );
1128  if ( is3D )
1129  wkt += ' ' + qgsDoubleToString( p.z(), precision );
1130  if ( isMeasure )
1131  wkt += ' ' + qgsDoubleToString( p.m(), precision );
1132  wkt += QLatin1String( ", " );
1133  }
1134  if ( wkt.endsWith( QLatin1String( ", " ) ) )
1135  wkt.chop( 2 ); // Remove last ", "
1136  wkt += ')';
1137  return wkt;
1138 }
1139
1140 QDomElement QgsGeometryUtils::pointsToGML2( const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, QgsAbstractGeometry::AxisOrder axisOrder )
1141 {
1142  QDomElement elemCoordinates = doc.createElementNS( ns, QStringLiteral( "coordinates" ) );
1143
1144  // coordinate separator
1145  QString cs = QStringLiteral( "," );
1146  // tupel separator
1147  QString ts = QStringLiteral( " " );
1148
1149  elemCoordinates.setAttribute( QStringLiteral( "cs" ), cs );
1150  elemCoordinates.setAttribute( QStringLiteral( "ts" ), ts );
1151
1152  QString strCoordinates;
1153
1154  for ( const QgsPoint &p : points )
1155  if ( axisOrder == QgsAbstractGeometry::AxisOrder::XY )
1156  strCoordinates += qgsDoubleToString( p.x(), precision ) + cs + qgsDoubleToString( p.y(), precision ) + ts;
1157  else
1158  strCoordinates += qgsDoubleToString( p.y(), precision ) + cs + qgsDoubleToString( p.x(), precision ) + ts;
1159
1160  if ( strCoordinates.endsWith( ts ) )
1161  strCoordinates.chop( 1 ); // Remove trailing space
1162
1163  elemCoordinates.appendChild( doc.createTextNode( strCoordinates ) );
1164  return elemCoordinates;
1165 }
1166
1167 QDomElement QgsGeometryUtils::pointsToGML3( const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, bool is3D, QgsAbstractGeometry::AxisOrder axisOrder )
1168 {
1169  QDomElement elemPosList = doc.createElementNS( ns, QStringLiteral( "posList" ) );
1170  elemPosList.setAttribute( QStringLiteral( "srsDimension" ), is3D ? 3 : 2 );
1171
1172  QString strCoordinates;
1173  for ( const QgsPoint &p : points )
1174  {
1175  if ( axisOrder == QgsAbstractGeometry::AxisOrder::XY )
1176  strCoordinates += qgsDoubleToString( p.x(), precision ) + ' ' + qgsDoubleToString( p.y(), precision ) + ' ';
1177  else
1178  strCoordinates += qgsDoubleToString( p.y(), precision ) + ' ' + qgsDoubleToString( p.x(), precision ) + ' ';
1179  if ( is3D )
1180  strCoordinates += qgsDoubleToString( p.z(), precision ) + ' ';
1181  }
1182  if ( strCoordinates.endsWith( ' ' ) )
1183  strCoordinates.chop( 1 ); // Remove trailing space
1184
1185  elemPosList.appendChild( doc.createTextNode( strCoordinates ) );
1186  return elemPosList;
1187 }
1188
1190 {
1191  QString json = QStringLiteral( "[ " );
1192  for ( const QgsPoint &p : points )
1193  {
1194  json += '[' + qgsDoubleToString( p.x(), precision ) + QLatin1String( ", " ) + qgsDoubleToString( p.y(), precision ) + QLatin1String( "], " );
1195  }
1196  if ( json.endsWith( QLatin1String( ", " ) ) )
1197  {
1198  json.chop( 2 ); // Remove last ", "
1199  }
1200  json += ']';
1201  return json;
1202 }
1203
1204
1206 {
1207  json coordinates( json::array() );
1208  for ( const QgsPoint &p : points )
1209  {
1210  if ( p.is3D() )
1211  {
1212  coordinates.push_back( { qgsRound( p.x(), precision ), qgsRound( p.y(), precision ), qgsRound( p.z(), precision ) } );
1213  }
1214  else
1215  {
1216  coordinates.push_back( { qgsRound( p.x(), precision ), qgsRound( p.y(), precision ) } );
1217  }
1218  }
1219  return coordinates;
1220 }
1221
1223 {
1224  double clippedAngle = angle;
1225  if ( clippedAngle >= M_PI * 2 || clippedAngle <= -2 * M_PI )
1226  {
1227  clippedAngle = std::fmod( clippedAngle, 2 * M_PI );
1228  }
1229  if ( clippedAngle < 0.0 )
1230  {
1231  clippedAngle += 2 * M_PI;
1232  }
1233  return clippedAngle;
1234 }
1235
1236 QPair<QgsWkbTypes::Type, QString> QgsGeometryUtils::wktReadBlock( const QString &wkt )
1237 {
1238  QString wktParsed = wkt;
1239  QString contents;
1240  if ( wkt.contains( QString( "EMPTY" ), Qt::CaseInsensitive ) )
1241  {
1242  QRegularExpression wktRegEx( QStringLiteral( "^\\s*(\\w+)\\s+(\\w+)\\s*\$" ) );
1243  wktRegEx.setPatternOptions( QRegularExpression::DotMatchesEverythingOption );
1244  QRegularExpressionMatch match = wktRegEx.match( wkt );
1245  if ( match.hasMatch() )
1246  {
1247  wktParsed = match.captured( 1 );
1248  contents = match.captured( 2 ).toUpper();
1249  }
1250  }
1251  else
1252  {
1253  QRegularExpression cooRegEx( QStringLiteral( "^[^\\(]*\\((.*)\\)[^\\)]*\$" ) );
1254  cooRegEx.setPatternOptions( QRegularExpression::DotMatchesEverythingOption );
1255  QRegularExpressionMatch match = cooRegEx.match( wktParsed );
1256  contents = match.hasMatch() ? match.captured( 1 ) : QString();
1257  }
1259  return qMakePair( wkbType, contents );
1260 }
1261
1262 QStringList QgsGeometryUtils::wktGetChildBlocks( const QString &wkt, const QString &defaultType )
1263 {
1264  int level = 0;
1265  QString block;
1266  QStringList blocks;
1267  for ( int i = 0, n = wkt.length(); i < n; ++i )
1268  {
1269  if ( ( wkt[i].isSpace() || wkt[i] == '\n' || wkt[i] == '\t' ) && level == 0 )
1270  continue;
1271
1272  if ( wkt[i] == ',' && level == 0 )
1273  {
1274  if ( !block.isEmpty() )
1275  {
1276  if ( block.startsWith( '(' ) && !defaultType.isEmpty() )
1277  block.prepend( defaultType + ' ' );
1278  blocks.append( block );
1279  }
1280  block.clear();
1281  continue;
1282  }
1283  if ( wkt[i] == '(' )
1284  ++level;
1285  else if ( wkt[i] == ')' )
1286  --level;
1287  block += wkt[i];
1288  }
1289  if ( !block.isEmpty() )
1290  {
1291  if ( block.startsWith( '(' ) && !defaultType.isEmpty() )
1292  block.prepend( defaultType + ' ' );
1293  blocks.append( block );
1294  }
1295  return blocks;
1296 }
1297
1299 {
1301
1302
1303  double x = ( pt1.x() + pt2.x() ) / 2.0;
1304  double y = ( pt1.y() + pt2.y() ) / 2.0;
1305  double z = std::numeric_limits<double>::quiet_NaN();
1306  double m = std::numeric_limits<double>::quiet_NaN();
1307
1308  if ( pt1.is3D() || pt2.is3D() )
1309  {
1310  pType = QgsWkbTypes::addZ( pType );
1311  z = ( pt1.z() + pt2.z() ) / 2.0;
1312  }
1313
1314  if ( pt1.isMeasure() || pt2.isMeasure() )
1315  {
1316  pType = QgsWkbTypes::addM( pType );
1317  m = ( pt1.m() + pt2.m() ) / 2.0;
1318  }
1319
1320  return QgsPoint( pType, x, y, z, m );
1321 }
1322
1323 QgsPoint QgsGeometryUtils::interpolatePointOnLine( const QgsPoint &p1, const QgsPoint &p2, const double fraction )
1324 {
1325  const double _fraction = 1 - fraction;
1326  return QgsPoint( p1.wkbType(),
1327  p1.x() * _fraction + p2.x() * fraction,
1328  p1.y() * _fraction + p2.y() * fraction,
1329  p1.is3D() ? p1.z() * _fraction + p2.z() * fraction : std::numeric_limits<double>::quiet_NaN(),
1330  p1.isMeasure() ? p1.m() * _fraction + p2.m() * fraction : std::numeric_limits<double>::quiet_NaN() );
1331 }
1332
1333 QgsPointXY QgsGeometryUtils::interpolatePointOnLine( const double x1, const double y1, const double x2, const double y2, const double fraction )
1334 {
1335  const double deltaX = ( x2 - x1 ) * fraction;
1336  const double deltaY = ( y2 - y1 ) * fraction;
1337  return QgsPointXY( x1 + deltaX, y1 + deltaY );
1338 }
1339
1340 QgsPointXY QgsGeometryUtils::interpolatePointOnLineByValue( const double x1, const double y1, const double v1, const double x2, const double y2, const double v2, const double value )
1341 {
1342  if ( qgsDoubleNear( v1, v2 ) )
1343  return QgsPointXY( x1, y1 );
1344
1345  const double fraction = ( value - v1 ) / ( v2 - v1 );
1346  return interpolatePointOnLine( x1, y1, x2, y2, fraction );
1347 }
1348
1349 double QgsGeometryUtils::gradient( const QgsPoint &pt1, const QgsPoint &pt2 )
1350 {
1351  double delta_x = pt2.x() - pt1.x();
1352  double delta_y = pt2.y() - pt1.y();
1353  if ( qgsDoubleNear( delta_x, 0.0 ) )
1354  {
1355  return INFINITY;
1356  }
1357
1358  return delta_y / delta_x;
1359 }
1360
1361 void QgsGeometryUtils::coefficients( const QgsPoint &pt1, const QgsPoint &pt2, double &a, double &b, double &c )
1362 {
1363  if ( qgsDoubleNear( pt1.x(), pt2.x() ) )
1364  {
1365  a = 1;
1366  b = 0;
1367  c = -pt1.x();
1368  }
1369  else if ( qgsDoubleNear( pt1.y(), pt2.y() ) )
1370  {
1371  a = 0;
1372  b = 1;
1373  c = -pt1.y();
1374  }
1375  else
1376  {
1377  a = pt1.y() - pt2.y();
1378  b = pt2.x() - pt1.x();
1379  c = pt1.x() * pt2.y() - pt1.y() * pt2.x();
1380  }
1381
1382 }
1383
1385 {
1386  QgsLineString line;
1387  QgsPoint p2;
1388
1389  if ( ( p == s1 ) || ( p == s2 ) )
1390  {
1391  return line;
1392  }
1393
1394  double a, b, c;
1395  coefficients( s1, s2, a, b, c );
1396
1397  if ( qgsDoubleNear( a, 0 ) )
1398  {
1399  p2 = QgsPoint( p.x(), s1.y() );
1400  }
1401  else if ( qgsDoubleNear( b, 0 ) )
1402  {
1403  p2 = QgsPoint( s1.x(), p.y() );
1404  }
1405  else
1406  {
1407  double y = ( -c - a * p.x() ) / b;
1408  double m = gradient( s1, s2 );
1409  double d2 = 1 + m * m;
1410  double H = p.y() - y;
1411  double dx = m * H / d2;
1412  double dy = m * dx;
1413  p2 = QgsPoint( p.x() + dx, y + dy );
1414  }
1415
1416  line.addVertex( p );
1417  line.addVertex( p2 );
1418
1419  return line;
1420 }
1421
1422 double QgsGeometryUtils::lineAngle( double x1, double y1, double x2, double y2 )
1423 {
1424  double at = std::atan2( y2 - y1, x2 - x1 );
1425  double a = -at + M_PI_2;
1426  return normalizedAngle( a );
1427 }
1428
1429 double QgsGeometryUtils::angleBetweenThreePoints( double x1, double y1, double x2, double y2, double x3, double y3 )
1430 {
1431  double angle1 = std::atan2( y1 - y2, x1 - x2 );
1432  double angle2 = std::atan2( y3 - y2, x3 - x2 );
1433  return normalizedAngle( angle1 - angle2 );
1434 }
1435
1436 double QgsGeometryUtils::linePerpendicularAngle( double x1, double y1, double x2, double y2 )
1437 {
1438  double a = lineAngle( x1, y1, x2, y2 );
1439  a += M_PI_2;
1440  return normalizedAngle( a );
1441 }
1442
1443 double QgsGeometryUtils::averageAngle( double x1, double y1, double x2, double y2, double x3, double y3 )
1444 {
1445  // calc average angle between the previous and next point
1446  double a1 = lineAngle( x1, y1, x2, y2 );
1447  double a2 = lineAngle( x2, y2, x3, y3 );
1448  return averageAngle( a1, a2 );
1449 }
1450
1451 double QgsGeometryUtils::averageAngle( double a1, double a2 )
1452 {
1453  a1 = normalizedAngle( a1 );
1454  a2 = normalizedAngle( a2 );
1455  double clockwiseDiff = 0.0;
1456  if ( a2 >= a1 )
1457  {
1458  clockwiseDiff = a2 - a1;
1459  }
1460  else
1461  {
1462  clockwiseDiff = a2 + ( 2 * M_PI - a1 );
1463  }
1464  double counterClockwiseDiff = 2 * M_PI - clockwiseDiff;
1465
1466  double resultAngle = 0;
1467  if ( clockwiseDiff <= counterClockwiseDiff )
1468  {
1469  resultAngle = a1 + clockwiseDiff / 2.0;
1470  }
1471  else
1472  {
1473  resultAngle = a1 - counterClockwiseDiff / 2.0;
1474  }
1475  return normalizedAngle( resultAngle );
1476 }
1477
1479  const QgsVector3D &P2, const QgsVector3D &P22 )
1480 {
1481  QgsVector3D u1 = P12 - P1;
1482  QgsVector3D u2 = P22 - P2;
1483  QgsVector3D u3 = QgsVector3D::crossProduct( u1, u2 );
1484  if ( u3.length() == 0 ) return 1;
1485  u3.normalize();
1486  QgsVector3D dir = P1 - P2;
1487  return std::fabs( ( QgsVector3D::dotProduct( dir, u3 ) ) ); // u3 is already normalized
1488 }
1489
1491  const QgsVector3D &P2, const QgsVector3D &P22,
1492  QgsVector3D &X1, double epsilon )
1493 {
1494  QgsVector3D d = P2 - P1;
1495  QgsVector3D u1 = P12 - P1;
1496  u1.normalize();
1497  QgsVector3D u2 = P22 - P2;
1498  u2.normalize();
1499  QgsVector3D u3 = QgsVector3D::crossProduct( u1, u2 );
1500
1501  if ( std::fabs( u3.x() ) <= epsilon &&
1502  std::fabs( u3.y() ) <= epsilon &&
1503  std::fabs( u3.z() ) <= epsilon )
1504  {
1505  // The rays are almost parallel.
1506  return false;
1507  }
1508
1509  // X1 and X2 are the closest points on lines
1510  // we want to find X1 (lies on u1)
1511  // solving the linear equation in r1 and r2: Xi = Pi + ri*ui
1512  // we are only interested in X1 so we only solve for r1.
1513  float a1 = QgsVector3D::dotProduct( u1, u1 ), b1 = QgsVector3D::dotProduct( u1, u2 ), c1 = QgsVector3D::dotProduct( u1, d );
1514  float a2 = QgsVector3D::dotProduct( u1, u2 ), b2 = QgsVector3D::dotProduct( u2, u2 ), c2 = QgsVector3D::dotProduct( u2, d );
1515  if ( !( std::fabs( b1 ) > epsilon ) )
1516  {
1517  // Denominator is close to zero.
1518  return false;
1519  }
1520  if ( !( a2 != -1 && a2 != 1 ) )
1521  {
1522  // Lines are parallel
1523  return false;
1524  }
1525
1526  double r1 = ( c2 - b2 * c1 / b1 ) / ( a2 - b2 * a1 / b1 );
1527  X1 = P1 + u1 * r1;
1528
1529  return true;
1530 }
1531
1533  const QgsVector3D &Lb1, const QgsVector3D &Lb2,
1534  QgsVector3D &intersection )
1535 {
1536
1537  // if all Vector are on the same plane (have the same Z), use the 2D intersection
1538  // else return a false result
1539  if ( qgsDoubleNear( La1.z(), La2.z() ) && qgsDoubleNear( La1.z(), Lb1.z() ) && qgsDoubleNear( La1.z(), Lb2.z() ) )
1540  {
1541  QgsPoint ptInter;
1542  bool isIntersection;
1543  segmentIntersection( QgsPoint( La1.x(), La1.y() ),
1544  QgsPoint( La2.x(), La2.y() ),
1545  QgsPoint( Lb1.x(), Lb1.y() ),
1546  QgsPoint( Lb2.x(), Lb2.y() ),
1547  ptInter,
1548  isIntersection,
1549  1e-8,
1550  true );
1551  intersection.set( ptInter.x(), ptInter.y(), La1.z() );
1552  return true;
1553  }
1554
1555  // first check if lines have an exact intersection point
1556  // do it by checking if the shortest distance is exactly 0
1557  float distance = skewLinesDistance( La1, La2, Lb1, Lb2 );
1558  if ( qgsDoubleNear( distance, 0.0 ) )
1559  {
1560  // 3d lines have exact intersection point.
1561  QgsVector3D C = La2;
1562  QgsVector3D D = Lb2;
1563  QgsVector3D e = La1 - La2;
1564  QgsVector3D f = Lb1 - Lb2;
1565  QgsVector3D g = D - C;
1566  if ( qgsDoubleNear( ( QgsVector3D::crossProduct( f, g ) ).length(), 0.0 ) || qgsDoubleNear( ( QgsVector3D::crossProduct( f, e ) ).length(), 0.0 ) )
1567  {
1568  // Lines have no intersection, are they parallel?
1569  return false;
1570  }
1571
1572  QgsVector3D fgn = QgsVector3D::crossProduct( f, g );
1573  fgn.normalize();
1574
1575  QgsVector3D fen = QgsVector3D::crossProduct( f, e );
1576  fen.normalize();
1577
1578  int di = -1;
1579  if ( fgn == fen ) // same direction?
1580  di *= -1;
1581
1582  intersection = C + e * di * ( QgsVector3D::crossProduct( f, g ).length() / QgsVector3D::crossProduct( f, e ).length() );
1583  return true;
1584  }
1585
1586  // try to calculate the approximate intersection point
1587  QgsVector3D X1, X2;
1588  bool firstIsDone = skewLinesProjection( La1, La2, Lb1, Lb2, X1 );
1589  bool secondIsDone = skewLinesProjection( Lb1, Lb2, La1, La2, X2 );
1590
1591  if ( !firstIsDone || !secondIsDone )
1592  {
1593  // Could not obtain projection point.
1594  return false;
1595  }
1596
1597  intersection = ( X1 + X2 ) / 2.0;
1598  return true;
1599 }
1600
1601 double QgsGeometryUtils::triangleArea( double aX, double aY, double bX, double bY, double cX, double cY )
1602 {
1603  return 0.5 * std::abs( ( aX - cX ) * ( bY - aY ) - ( aX - bX ) * ( cY - aY ) );
1604 }
1605
1606 void QgsGeometryUtils::weightedPointInTriangle( const double aX, const double aY, const double bX, const double bY, const double cX, const double cY,
1607  double weightB, double weightC, double &pointX, double &pointY )
1608 {
1609  // if point will be outside of the triangle, invert weights
1610  if ( weightB + weightC > 1 )
1611  {
1612  weightB = 1 - weightB;
1613  weightC = 1 - weightC;
1614  }
1615
1616  const double rBx = weightB * ( bX - aX );
1617  const double rBy = weightB * ( bY - aY );
1618  const double rCx = weightC * ( cX - aX );
1619  const double rCy = weightC * ( cY - aY );
1620
1621  pointX = rBx + rCx + aX;
1622  pointY = rBy + rCy + aY;
1623 }
1624
1626 {
1627  bool rc = false;
1628
1629  for ( const QgsPoint &pt : points )
1630  {
1631  if ( pt.is3D() )
1632  {
1633  point.convertTo( QgsWkbTypes::addZ( point.wkbType() ) );
1634  point.setZ( pt.z() );
1635  rc = true;
1636  break;
1637  }
1638  }
1639
1640  return rc;
1641 }
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:124
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:501
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:286
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 Cartesian 2D distance between this point and a specified x, y coordinate.
Definition: qgspoint.h:325
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:280
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:917
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:175
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 planar, 2-dimensional 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
static double triangleArea(double aX, double aY, double bX, double bY, double cX, double cY)
Returns the area of the triangle denoted by the points (aX, aY), (bX, bY) and (cX, cY).
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:1038
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:598
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:240
static Type addZ(Type type)
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1013
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:196
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:675
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.
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:328
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:570
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
Definition: qgspoint.cpp:512
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:967
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.
static void weightedPointInTriangle(double aX, double aY, double bX, double bY, double cX, double cY, double weightB, double weightC, double &pointX, double &pointY)
Returns a weighted point inside the triangle denoted by the points (aX, aY), (bX, bY) and (cX...
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