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