QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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 dr2 = 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 ) * dr2 - 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 sqrDisc = std::sqrt( disc );
346 
347  const double ax = center.x() + ( d * dy + sgnDy * dx * sqrDisc ) / dr2;
348  const double ay = center.y() + ( -d * dx + std::fabs( dy ) * sqrDisc ) / dr2;
349  const QgsPointXY p1( ax, ay );
350 
351  const double bx = center.x() + ( d * dy - sgnDy * dx * sqrDisc ) / dr2;
352  const double by = center.y() + ( -d * dx - std::fabs( dy ) * sqrDisc ) / dr2;
353  const QgsPointXY p2( bx, by );
354 
355  // snap to nearest intersection
356 
357  if ( intersection.sqrDist( p1 ) < intersection.sqrDist( p2 ) )
358  {
359  intersection.set( p1.x(), p1.y() );
360  }
361  else
362  {
363  intersection.set( p2.x(), p2.y() );
364  }
365  return true;
366  }
367 }
368 
369 // based on public domain work by 3/26/2005 Tim Voght
370 // see http://paulbourke.net/geometry/circlesphere/tvoght.c
371 int QgsGeometryUtils::circleCircleIntersections( QgsPointXY center0, const double r0, QgsPointXY center1, const double r1, QgsPointXY &intersection1, QgsPointXY &intersection2 )
372 {
373  // determine the straight-line distance between the centers
374  const double d = center0.distance( center1 );
375 
376  // check for solvability
377  if ( d > ( r0 + r1 ) )
378  {
379  // no solution. circles do not intersect.
380  return 0;
381  }
382  else if ( d < std::fabs( r0 - r1 ) )
383  {
384  // no solution. one circle is contained in the other
385  return 0;
386  }
387  else if ( qgsDoubleNear( d, 0 ) && ( qgsDoubleNear( r0, r1 ) ) )
388  {
389  // no solutions, the circles coincide
390  return 0;
391  }
392 
393  /* 'point 2' is the point where the line through the circle
394  * intersection points crosses the line between the circle
395  * centers.
396  */
397 
398  // Determine the distance from point 0 to point 2.
399  const double a = ( ( r0 * r0 ) - ( r1 * r1 ) + ( d * d ) ) / ( 2.0 * d ) ;
400 
401  /* dx and dy are the vertical and horizontal distances between
402  * the circle centers.
403  */
404  const double dx = center1.x() - center0.x();
405  const double dy = center1.y() - center0.y();
406 
407  // Determine the coordinates of point 2.
408  const double x2 = center0.x() + ( dx * a / d );
409  const double y2 = center0.y() + ( dy * a / d );
410 
411  /* Determine the distance from point 2 to either of the
412  * intersection points.
413  */
414  const double h = std::sqrt( ( r0 * r0 ) - ( a * a ) );
415 
416  /* Now determine the offsets of the intersection points from
417  * point 2.
418  */
419  const double rx = dy * ( h / d );
420  const double ry = dx * ( h / d );
421 
422  // determine the absolute intersection points
423  intersection1 = QgsPointXY( x2 + rx, y2 - ry );
424  intersection2 = QgsPointXY( x2 - rx, y2 + ry );
425 
426  // see if we have 1 or 2 solutions
427  if ( qgsDoubleNear( d, r0 + r1 ) )
428  return 1;
429 
430  return 2;
431 }
432 
433 // Using https://stackoverflow.com/a/1351794/1861260
434 // and inspired by http://csharphelper.com/blog/2014/11/find-the-tangent-lines-between-a-point-and-a-circle-in-c/
435 bool QgsGeometryUtils::tangentPointAndCircle( const QgsPointXY &center, double radius, const QgsPointXY &p, QgsPointXY &pt1, QgsPointXY &pt2 )
436 {
437  // distance from point to center of circle
438  const double dx = center.x() - p.x();
439  const double dy = center.y() - p.y();
440  const double distanceSquared = dx * dx + dy * dy;
441  const double radiusSquared = radius * radius;
442  if ( distanceSquared < radiusSquared )
443  {
444  // point is inside circle!
445  return false;
446  }
447 
448  // distance from point to tangent point, using pythagoras
449  const double distanceToTangent = std::sqrt( distanceSquared - radiusSquared );
450 
451  // tangent points are those where the original circle intersects a circle centered
452  // on p with radius distanceToTangent
453  circleCircleIntersections( center, radius, p, distanceToTangent, pt1, pt2 );
454 
455  return true;
456 }
457 
458 // inspired by http://csharphelper.com/blog/2014/12/find-the-tangent-lines-between-two-circles-in-c/
459 int QgsGeometryUtils::circleCircleOuterTangents( const QgsPointXY &center1, double radius1, const QgsPointXY &center2, double radius2, QgsPointXY &line1P1, QgsPointXY &line1P2, QgsPointXY &line2P1, QgsPointXY &line2P2 )
460 {
461  if ( radius1 > radius2 )
462  return circleCircleOuterTangents( center2, radius2, center1, radius1, line1P1, line1P2, line2P1, line2P2 );
463 
464  const double radius2a = radius2 - radius1;
465  if ( !tangentPointAndCircle( center2, radius2a, center1, line1P2, line2P2 ) )
466  {
467  // there are no tangents
468  return 0;
469  }
470 
471  // get the vector perpendicular to the
472  // first tangent with length radius1
473  QgsVector v1( -( line1P2.y() - center1.y() ), line1P2.x() - center1.x() );
474  const double v1Length = v1.length();
475  v1 = v1 * ( radius1 / v1Length );
476 
477  // offset the tangent vector's points
478  line1P1 = center1 + v1;
479  line1P2 = line1P2 + v1;
480 
481  // get the vector perpendicular to the
482  // second tangent with length radius1
483  QgsVector v2( line2P2.y() - center1.y(), -( line2P2.x() - center1.x() ) );
484  const double v2Length = v2.length();
485  v2 = v2 * ( radius1 / v2Length );
486 
487  // offset the tangent vector's points
488  line2P1 = center1 + v2;
489  line2P2 = line2P2 + v2;
490 
491  return 2;
492 }
493 
494 QVector<QgsGeometryUtils::SelfIntersection> QgsGeometryUtils::selfIntersections( const QgsAbstractGeometry *geom, int part, int ring, double tolerance )
495 {
496  QVector<SelfIntersection> intersections;
497 
498  int n = geom->vertexCount( part, ring );
499  bool isClosed = geom->vertexAt( QgsVertexId( part, ring, 0 ) ) == geom->vertexAt( QgsVertexId( part, ring, n - 1 ) );
500 
501  // Check every pair of segments for intersections
502  for ( int i = 0, j = 1; j < n; i = j++ )
503  {
504  QgsPoint pi = geom->vertexAt( QgsVertexId( part, ring, i ) );
505  QgsPoint pj = geom->vertexAt( QgsVertexId( part, ring, j ) );
506  if ( QgsGeometryUtils::sqrDistance2D( pi, pj ) < tolerance * tolerance ) continue;
507 
508  // Don't test neighboring edges
509  int start = j + 1;
510  int end = i == 0 && isClosed ? n - 1 : n;
511  for ( int k = start, l = start + 1; l < end; k = l++ )
512  {
513  QgsPoint pk = geom->vertexAt( QgsVertexId( part, ring, k ) );
514  QgsPoint pl = geom->vertexAt( QgsVertexId( part, ring, l ) );
515 
516  QgsPoint inter;
517  bool intersection = false;
518  if ( !QgsGeometryUtils::segmentIntersection( pi, pj, pk, pl, inter, intersection, tolerance ) ) continue;
519 
521  s.segment1 = i;
522  s.segment2 = k;
523  if ( s.segment1 > s.segment2 )
524  {
525  std::swap( s.segment1, s.segment2 );
526  }
527  s.point = inter;
528  intersections.append( s );
529  }
530  }
531  return intersections;
532 }
533 
534 int QgsGeometryUtils::leftOfLine( double x, double y, double x1, double y1, double x2, double y2 )
535 {
536  double f1 = x - x1;
537  double f2 = y2 - y1;
538  double f3 = y - y1;
539  double f4 = x2 - x1;
540  double test = ( f1 * f2 - f3 * f4 );
541  // return -1, 0, or 1
542  return qgsDoubleNear( test, 0.0 ) ? 0 : ( test < 0 ? -1 : 1 );
543 }
544 
545 QgsPoint QgsGeometryUtils::pointOnLineWithDistance( const QgsPoint &startPoint, const QgsPoint &directionPoint, double distance )
546 {
547  double x, y;
548  pointOnLineWithDistance( startPoint.x(), startPoint.y(), directionPoint.x(), directionPoint.y(), distance, x, y );
549  return QgsPoint( x, y );
550 }
551 
552 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 )
553 {
554  const double dx = x2 - x1;
555  const double dy = y2 - y1;
556  const double length = std::sqrt( dx * dx + dy * dy );
557 
558  if ( qgsDoubleNear( length, 0.0 ) )
559  {
560  x = x1;
561  y = y1;
562  if ( z && z1 )
563  *z = *z1;
564  if ( m && m1 )
565  *m = *m1;
566  }
567  else
568  {
569  const double scaleFactor = distance / length;
570  x = x1 + dx * scaleFactor;
571  y = y1 + dy * scaleFactor;
572  if ( z && z1 && z2 )
573  *z = *z1 + ( *z2 - *z1 ) * scaleFactor;
574  if ( m && m1 && m2 )
575  *m = *m1 + ( *m2 - *m1 ) * scaleFactor;
576  }
577 }
578 
579 QgsPoint QgsGeometryUtils::interpolatePointOnArc( const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double distance )
580 {
581  double centerX, centerY, radius;
582  circleCenterRadius( pt1, pt2, pt3, radius, centerX, centerY );
583 
584  const double theta = distance / radius; // angle subtended
585  const double anglePt1 = std::atan2( pt1.y() - centerY, pt1.x() - centerX );
586  const double anglePt2 = std::atan2( pt2.y() - centerY, pt2.x() - centerX );
587  const double anglePt3 = std::atan2( pt3.y() - centerY, pt3.x() - centerX );
588  const bool isClockwise = circleClockwise( anglePt1, anglePt2, anglePt3 );
589  const double angleDest = anglePt1 + ( isClockwise ? -theta : theta );
590 
591  const double x = centerX + radius * ( std::cos( angleDest ) );
592  const double y = centerY + radius * ( std::sin( angleDest ) );
593 
594  const double z = pt1.is3D() ?
595  interpolateArcValue( angleDest, anglePt1, anglePt2, anglePt3, pt1.z(), pt2.z(), pt3.z() )
596  : 0;
597  const double m = pt1.isMeasure() ?
598  interpolateArcValue( angleDest, anglePt1, anglePt2, anglePt3, pt1.m(), pt2.m(), pt3.m() )
599  : 0;
600 
601  return QgsPoint( pt1.wkbType(), x, y, z, m );
602 }
603 
604 double QgsGeometryUtils::ccwAngle( double dy, double dx )
605 {
606  double angle = std::atan2( dy, dx ) * 180 / M_PI;
607  if ( angle < 0 )
608  {
609  return 360 + angle;
610  }
611  else if ( angle > 360 )
612  {
613  return 360 - angle;
614  }
615  return angle;
616 }
617 
618 void QgsGeometryUtils::circleCenterRadius( const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double &radius, double &centerX, double &centerY )
619 {
620  double dx21, dy21, dx31, dy31, h21, h31, d;
621 
622  //closed circle
623  if ( qgsDoubleNear( pt1.x(), pt3.x() ) && qgsDoubleNear( pt1.y(), pt3.y() ) )
624  {
625  centerX = ( pt1.x() + pt2.x() ) / 2.0;
626  centerY = ( pt1.y() + pt2.y() ) / 2.0;
627  radius = std::sqrt( std::pow( centerX - pt1.x(), 2.0 ) + std::pow( centerY - pt1.y(), 2.0 ) );
628  return;
629  }
630 
631  // Using Cartesian circumcenter eguations from page https://en.wikipedia.org/wiki/Circumscribed_circle
632  dx21 = pt2.x() - pt1.x();
633  dy21 = pt2.y() - pt1.y();
634  dx31 = pt3.x() - pt1.x();
635  dy31 = pt3.y() - pt1.y();
636 
637  h21 = std::pow( dx21, 2.0 ) + std::pow( dy21, 2.0 );
638  h31 = std::pow( dx31, 2.0 ) + std::pow( dy31, 2.0 );
639 
640  // 2*Cross product, d<0 means clockwise and d>0 counterclockwise sweeping angle
641  d = 2 * ( dx21 * dy31 - dx31 * dy21 );
642 
643  // Check colinearity, Cross product = 0
644  if ( qgsDoubleNear( std::fabs( d ), 0.0, 0.00000000001 ) )
645  {
646  radius = -1.0;
647  return;
648  }
649 
650  // Calculate centroid coordinates and radius
651  centerX = pt1.x() + ( h21 * dy31 - h31 * dy21 ) / d;
652  centerY = pt1.y() - ( h21 * dx31 - h31 * dx21 ) / d;
653  radius = std::sqrt( std::pow( centerX - pt1.x(), 2.0 ) + std::pow( centerY - pt1.y(), 2.0 ) );
654 }
655 
656 bool QgsGeometryUtils::circleClockwise( double angle1, double angle2, double angle3 )
657 {
658  if ( angle3 >= angle1 )
659  {
660  return !( angle2 > angle1 && angle2 < angle3 );
661  }
662  else
663  {
664  return !( angle2 > angle1 || angle2 < angle3 );
665  }
666 }
667 
668 bool QgsGeometryUtils::circleAngleBetween( double angle, double angle1, double angle2, bool clockwise )
669 {
670  if ( clockwise )
671  {
672  if ( angle2 < angle1 )
673  {
674  return ( angle <= angle1 && angle >= angle2 );
675  }
676  else
677  {
678  return ( angle <= angle1 || angle >= angle2 );
679  }
680  }
681  else
682  {
683  if ( angle2 > angle1 )
684  {
685  return ( angle >= angle1 && angle <= angle2 );
686  }
687  else
688  {
689  return ( angle >= angle1 || angle <= angle2 );
690  }
691  }
692 }
693 
694 bool QgsGeometryUtils::angleOnCircle( double angle, double angle1, double angle2, double angle3 )
695 {
696  bool clockwise = circleClockwise( angle1, angle2, angle3 );
697  return circleAngleBetween( angle, angle1, angle3, clockwise );
698 }
699 
700 double QgsGeometryUtils::circleLength( double x1, double y1, double x2, double y2, double x3, double y3 )
701 {
702  double centerX, centerY, radius;
703  circleCenterRadius( QgsPoint( x1, y1 ), QgsPoint( x2, y2 ), QgsPoint( x3, y3 ), radius, centerX, centerY );
704  double length = M_PI / 180.0 * radius * sweepAngle( centerX, centerY, x1, y1, x2, y2, x3, y3 );
705  if ( length < 0 )
706  {
707  length = -length;
708  }
709  return length;
710 }
711 
712 double QgsGeometryUtils::sweepAngle( double centerX, double centerY, double x1, double y1, double x2, double y2, double x3, double y3 )
713 {
714  double p1Angle = QgsGeometryUtils::ccwAngle( y1 - centerY, x1 - centerX );
715  double p2Angle = QgsGeometryUtils::ccwAngle( y2 - centerY, x2 - centerX );
716  double p3Angle = QgsGeometryUtils::ccwAngle( y3 - centerY, x3 - centerX );
717 
718  if ( p3Angle >= p1Angle )
719  {
720  if ( p2Angle > p1Angle && p2Angle < p3Angle )
721  {
722  return ( p3Angle - p1Angle );
723  }
724  else
725  {
726  return ( - ( p1Angle + ( 360 - p3Angle ) ) );
727  }
728  }
729  else
730  {
731  if ( p2Angle < p1Angle && p2Angle > p3Angle )
732  {
733  return ( -( p1Angle - p3Angle ) );
734  }
735  else
736  {
737  return ( p3Angle + ( 360 - p1Angle ) );
738  }
739  }
740 }
741 
742 bool QgsGeometryUtils::segmentMidPoint( const QgsPoint &p1, const QgsPoint &p2, QgsPoint &result, double radius, const QgsPoint &mousePos )
743 {
744  QgsPoint midPoint( ( p1.x() + p2.x() ) / 2.0, ( p1.y() + p2.y() ) / 2.0 );
745  double midDist = std::sqrt( sqrDistance2D( p1, midPoint ) );
746  if ( radius < midDist )
747  {
748  return false;
749  }
750  double centerMidDist = std::sqrt( radius * radius - midDist * midDist );
751  double dist = radius - centerMidDist;
752 
753  double midDx = midPoint.x() - p1.x();
754  double midDy = midPoint.y() - p1.y();
755 
756  //get the four possible midpoints
757  QVector<QgsPoint> possibleMidPoints;
758  possibleMidPoints.append( pointOnLineWithDistance( midPoint, QgsPoint( midPoint.x() - midDy, midPoint.y() + midDx ), dist ) );
759  possibleMidPoints.append( pointOnLineWithDistance( midPoint, QgsPoint( midPoint.x() - midDy, midPoint.y() + midDx ), 2 * radius - dist ) );
760  possibleMidPoints.append( pointOnLineWithDistance( midPoint, QgsPoint( midPoint.x() + midDy, midPoint.y() - midDx ), dist ) );
761  possibleMidPoints.append( pointOnLineWithDistance( midPoint, QgsPoint( midPoint.x() + midDy, midPoint.y() - midDx ), 2 * radius - dist ) );
762 
763  //take the closest one
764  double minDist = std::numeric_limits<double>::max();
765  int minDistIndex = -1;
766  for ( int i = 0; i < possibleMidPoints.size(); ++i )
767  {
768  double currentDist = sqrDistance2D( mousePos, possibleMidPoints.at( i ) );
769  if ( currentDist < minDist )
770  {
771  minDistIndex = i;
772  minDist = currentDist;
773  }
774  }
775 
776  if ( minDistIndex == -1 )
777  {
778  return false;
779  }
780 
781  result = possibleMidPoints.at( minDistIndex );
782 
783  // add z support if necessary
785 
786  return true;
787 }
788 
789 QgsPoint QgsGeometryUtils::segmentMidPointFromCenter( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &center, const bool useShortestArc )
790 {
791  double midPointAngle = averageAngle( lineAngle( center.x(), center.y(), p1.x(), p1.y() ),
792  lineAngle( center.x(), center.y(), p2.x(), p2.y() ) );
793  if ( !useShortestArc )
794  midPointAngle += M_PI;
795  return center.project( center.distance( p1 ), midPointAngle * 180 / M_PI );
796 }
797 
798 double QgsGeometryUtils::circleTangentDirection( const QgsPoint &tangentPoint, const QgsPoint &cp1,
799  const QgsPoint &cp2, const QgsPoint &cp3 )
800 {
801  //calculate circle midpoint
802  double mX, mY, radius;
803  circleCenterRadius( cp1, cp2, cp3, radius, mX, mY );
804 
805  double p1Angle = QgsGeometryUtils::ccwAngle( cp1.y() - mY, cp1.x() - mX );
806  double p2Angle = QgsGeometryUtils::ccwAngle( cp2.y() - mY, cp2.x() - mX );
807  double p3Angle = QgsGeometryUtils::ccwAngle( cp3.y() - mY, cp3.x() - mX );
808  double angle = 0;
809  if ( circleClockwise( p1Angle, p2Angle, p3Angle ) )
810  {
811  angle = lineAngle( tangentPoint.x(), tangentPoint.y(), mX, mY ) - M_PI_2;
812  }
813  else
814  {
815  angle = lineAngle( mX, mY, tangentPoint.x(), tangentPoint.y() ) - M_PI_2;
816  }
817  if ( angle < 0 )
818  angle += 2 * M_PI;
819  return angle;
820 }
821 
822 void QgsGeometryUtils::segmentizeArc( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3, QgsPointSequence &points, double tolerance, QgsAbstractGeometry::SegmentationToleranceType toleranceType, bool hasZ, bool hasM )
823 {
824  bool reversed = false;
825  int segSide = segmentSide( p1, p3, p2 );
826 
827  QgsPoint circlePoint1;
828  const QgsPoint circlePoint2 = p2;
829  QgsPoint circlePoint3;
830 
831  if ( segSide == -1 )
832  {
833  // Reverse !
834  circlePoint1 = p3;
835  circlePoint3 = p1;
836  reversed = true;
837  }
838  else
839  {
840  circlePoint1 = p1;
841  circlePoint3 = p3;
842  }
843 
844  //adapted code from PostGIS
845  double radius = 0;
846  double centerX = 0;
847  double centerY = 0;
848  circleCenterRadius( circlePoint1, circlePoint2, circlePoint3, radius, centerX, centerY );
849 
850  if ( circlePoint1 != circlePoint3 && ( radius < 0 || qgsDoubleNear( segSide, 0.0 ) ) ) //points are colinear
851  {
852  points.append( p1 );
853  points.append( p2 );
854  points.append( p3 );
855  return;
856  }
857 
858  double increment = tolerance; //one segment per degree
859  if ( toleranceType == QgsAbstractGeometry::MaximumDifference )
860  {
861  // Ensure tolerance is not higher than twice the radius
862  tolerance = std::min( tolerance, radius * 2 );
863  double halfAngle = std::acos( -tolerance / radius + 1 );
864  increment = 2 * halfAngle;
865  }
866 
867  //angles of pt1, pt2, pt3
868  double a1 = std::atan2( circlePoint1.y() - centerY, circlePoint1.x() - centerX );
869  double a2 = std::atan2( circlePoint2.y() - centerY, circlePoint2.x() - centerX );
870  double a3 = std::atan2( circlePoint3.y() - centerY, circlePoint3.x() - centerX );
871 
872  // Make segmentation symmetric
873  const bool symmetric = true;
874  if ( symmetric )
875  {
876  double angle = a3 - a1;
877  // angle == 0 when full circle
878  if ( angle <= 0 ) angle += M_PI * 2;
879 
880  /* Number of segments in output */
881  int segs = ceil( angle / increment );
882  /* Tweak increment to be regular for all the arc */
883  increment = angle / segs;
884  }
885 
886  /* Adjust a3 up so we can increment from a1 to a3 cleanly */
887  // a3 == a1 when full circle
888  if ( a3 <= a1 )
889  a3 += 2.0 * M_PI;
890  if ( a2 < a1 )
891  a2 += 2.0 * M_PI;
892 
893  double x, y;
894  double z = 0;
895  double m = 0;
896 
897  QVector<QgsPoint> stringPoints;
898  stringPoints.insert( 0, circlePoint1 );
899  if ( circlePoint2 != circlePoint3 && circlePoint1 != circlePoint2 ) //draw straight line segment if two points have the same position
900  {
901  QgsWkbTypes::Type pointWkbType = QgsWkbTypes::Point;
902  if ( hasZ )
903  pointWkbType = QgsWkbTypes::addZ( pointWkbType );
904  if ( hasM )
905  pointWkbType = QgsWkbTypes::addM( pointWkbType );
906 
907  // As we're adding the last point in any case, we'll avoid
908  // including a point which is at less than 1% increment distance
909  // from it (may happen to find them due to numbers approximation).
910  // NOTE that this effectively allows in output some segments which
911  // are more distant than requested. This is at most 1% off
912  // from requested MaxAngle and less for MaxError.
913  double tolError = increment / 100;
914  double stopAngle = a3 - tolError;
915  for ( double angle = a1 + increment; angle < stopAngle; angle += increment )
916  {
917  x = centerX + radius * std::cos( angle );
918  y = centerY + radius * std::sin( angle );
919 
920  if ( hasZ )
921  {
922  z = interpolateArcValue( angle, a1, a2, a3, circlePoint1.z(), circlePoint2.z(), circlePoint3.z() );
923  }
924  if ( hasM )
925  {
926  m = interpolateArcValue( angle, a1, a2, a3, circlePoint1.m(), circlePoint2.m(), circlePoint3.m() );
927  }
928 
929  stringPoints.insert( stringPoints.size(), QgsPoint( pointWkbType, x, y, z, m ) );
930  }
931  }
932  stringPoints.insert( stringPoints.size(), circlePoint3 );
933 
934  // TODO: check if or implement QgsPointSequence directly taking an iterator to append
935  if ( reversed )
936  {
937  std::reverse( stringPoints.begin(), stringPoints.end() );
938  }
939  if ( ! points.empty() && stringPoints.front() == points.back() ) stringPoints.pop_front();
940  points.append( stringPoints );
941 }
942 
943 int QgsGeometryUtils::segmentSide( const QgsPoint &pt1, const QgsPoint &pt3, const QgsPoint &pt2 )
944 {
945  double side = ( ( pt2.x() - pt1.x() ) * ( pt3.y() - pt1.y() ) - ( pt3.x() - pt1.x() ) * ( pt2.y() - pt1.y() ) );
946  if ( side == 0.0 )
947  {
948  return 0;
949  }
950  else
951  {
952  if ( side < 0 )
953  {
954  return -1;
955  }
956  if ( side > 0 )
957  {
958  return 1;
959  }
960  return 0;
961  }
962 }
963 
964 double QgsGeometryUtils::interpolateArcValue( double angle, double a1, double a2, double a3, double zm1, double zm2, double zm3 )
965 {
966  /* Counter-clockwise sweep */
967  if ( a1 < a2 )
968  {
969  if ( angle <= a2 )
970  return zm1 + ( zm2 - zm1 ) * ( angle - a1 ) / ( a2 - a1 );
971  else
972  return zm2 + ( zm3 - zm2 ) * ( angle - a2 ) / ( a3 - a2 );
973  }
974  /* Clockwise sweep */
975  else
976  {
977  if ( angle >= a2 )
978  return zm1 + ( zm2 - zm1 ) * ( a1 - angle ) / ( a1 - a2 );
979  else
980  return zm2 + ( zm3 - zm2 ) * ( a2 - angle ) / ( a2 - a3 );
981  }
982 }
983 
984 QgsPointSequence QgsGeometryUtils::pointsFromWKT( const QString &wktCoordinateList, bool is3D, bool isMeasure )
985 {
986  int dim = 2 + is3D + isMeasure;
987  QgsPointSequence points;
988  const QStringList coordList = wktCoordinateList.split( ',', QString::SkipEmptyParts );
989 
990  //first scan through for extra unexpected dimensions
991  bool foundZ = false;
992  bool foundM = false;
993  QRegularExpression rx( QStringLiteral( "\\s" ) );
994  for ( const QString &pointCoordinates : coordList )
995  {
996  QStringList coordinates = pointCoordinates.split( rx, QString::SkipEmptyParts );
997  if ( coordinates.size() == 3 && !foundZ && !foundM && !is3D && !isMeasure )
998  {
999  // 3 dimensional coordinates, but not specifically marked as such. We allow this
1000  // anyway and upgrade geometry to have Z dimension
1001  foundZ = true;
1002  }
1003  else if ( coordinates.size() >= 4 && ( !( is3D || foundZ ) || !( isMeasure || foundM ) ) )
1004  {
1005  // 4 (or more) dimensional coordinates, but not specifically marked as such. We allow this
1006  // anyway and upgrade geometry to have Z&M dimensions
1007  foundZ = true;
1008  foundM = true;
1009  }
1010  }
1011 
1012  for ( const QString &pointCoordinates : coordList )
1013  {
1014  QStringList coordinates = pointCoordinates.split( rx, QString::SkipEmptyParts );
1015  if ( coordinates.size() < dim )
1016  continue;
1017 
1018  int idx = 0;
1019  double x = coordinates[idx++].toDouble();
1020  double y = coordinates[idx++].toDouble();
1021 
1022  double z = 0;
1023  if ( ( is3D || foundZ ) && coordinates.length() > idx )
1024  z = coordinates[idx++].toDouble();
1025 
1026  double m = 0;
1027  if ( ( isMeasure || foundM ) && coordinates.length() > idx )
1028  m = coordinates[idx++].toDouble();
1029 
1031  if ( is3D || foundZ )
1032  {
1033  if ( isMeasure || foundM )
1035  else
1036  t = QgsWkbTypes::PointZ;
1037  }
1038  else
1039  {
1040  if ( isMeasure || foundM )
1041  t = QgsWkbTypes::PointM;
1042  else
1043  t = QgsWkbTypes::Point;
1044  }
1045 
1046  points.append( QgsPoint( t, x, y, z, m ) );
1047  }
1048 
1049  return points;
1050 }
1051 
1053 {
1054  wkb << static_cast<quint32>( points.size() );
1055  for ( const QgsPoint &point : points )
1056  {
1057  wkb << point.x() << point.y();
1058  if ( is3D )
1059  {
1060  wkb << point.z();
1061  }
1062  if ( isMeasure )
1063  {
1064  wkb << point.m();
1065  }
1066  }
1067 }
1068 
1069 QString QgsGeometryUtils::pointsToWKT( const QgsPointSequence &points, int precision, bool is3D, bool isMeasure )
1070 {
1071  QString wkt = QStringLiteral( "(" );
1072  for ( const QgsPoint &p : points )
1073  {
1074  wkt += qgsDoubleToString( p.x(), precision );
1075  wkt += ' ' + qgsDoubleToString( p.y(), precision );
1076  if ( is3D )
1077  wkt += ' ' + qgsDoubleToString( p.z(), precision );
1078  if ( isMeasure )
1079  wkt += ' ' + qgsDoubleToString( p.m(), precision );
1080  wkt += QLatin1String( ", " );
1081  }
1082  if ( wkt.endsWith( QLatin1String( ", " ) ) )
1083  wkt.chop( 2 ); // Remove last ", "
1084  wkt += ')';
1085  return wkt;
1086 }
1087 
1088 QDomElement QgsGeometryUtils::pointsToGML2( const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, QgsAbstractGeometry::AxisOrder axisOrder )
1089 {
1090  QDomElement elemCoordinates = doc.createElementNS( ns, QStringLiteral( "coordinates" ) );
1091 
1092  // coordinate separator
1093  QString cs = QStringLiteral( "," );
1094  // tupel separator
1095  QString ts = QStringLiteral( " " );
1096 
1097  elemCoordinates.setAttribute( QStringLiteral( "cs" ), cs );
1098  elemCoordinates.setAttribute( QStringLiteral( "ts" ), ts );
1099 
1100  QString strCoordinates;
1101 
1102  for ( const QgsPoint &p : points )
1103  if ( axisOrder == QgsAbstractGeometry::AxisOrder::XY )
1104  strCoordinates += qgsDoubleToString( p.x(), precision ) + cs + qgsDoubleToString( p.y(), precision ) + ts;
1105  else
1106  strCoordinates += qgsDoubleToString( p.y(), precision ) + cs + qgsDoubleToString( p.x(), precision ) + ts;
1107 
1108  if ( strCoordinates.endsWith( ts ) )
1109  strCoordinates.chop( 1 ); // Remove trailing space
1110 
1111  elemCoordinates.appendChild( doc.createTextNode( strCoordinates ) );
1112  return elemCoordinates;
1113 }
1114 
1115 QDomElement QgsGeometryUtils::pointsToGML3( const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, bool is3D, QgsAbstractGeometry::AxisOrder axisOrder )
1116 {
1117  QDomElement elemPosList = doc.createElementNS( ns, QStringLiteral( "posList" ) );
1118  elemPosList.setAttribute( QStringLiteral( "srsDimension" ), is3D ? 3 : 2 );
1119 
1120  QString strCoordinates;
1121  for ( const QgsPoint &p : points )
1122  {
1123  if ( axisOrder == QgsAbstractGeometry::AxisOrder::XY )
1124  strCoordinates += qgsDoubleToString( p.x(), precision ) + ' ' + qgsDoubleToString( p.y(), precision ) + ' ';
1125  else
1126  strCoordinates += qgsDoubleToString( p.y(), precision ) + ' ' + qgsDoubleToString( p.x(), precision ) + ' ';
1127  if ( is3D )
1128  strCoordinates += qgsDoubleToString( p.z(), precision ) + ' ';
1129  }
1130  if ( strCoordinates.endsWith( ' ' ) )
1131  strCoordinates.chop( 1 ); // Remove trailing space
1132 
1133  elemPosList.appendChild( doc.createTextNode( strCoordinates ) );
1134  return elemPosList;
1135 }
1136 
1138 {
1139  QString json = QStringLiteral( "[ " );
1140  for ( const QgsPoint &p : points )
1141  {
1142  json += '[' + qgsDoubleToString( p.x(), precision ) + ", " + qgsDoubleToString( p.y(), precision ) + "], ";
1143  }
1144  if ( json.endsWith( QLatin1String( ", " ) ) )
1145  {
1146  json.chop( 2 ); // Remove last ", "
1147  }
1148  json += ']';
1149  return json;
1150 }
1151 
1153 {
1154  double clippedAngle = angle;
1155  if ( clippedAngle >= M_PI * 2 || clippedAngle <= -2 * M_PI )
1156  {
1157  clippedAngle = std::fmod( clippedAngle, 2 * M_PI );
1158  }
1159  if ( clippedAngle < 0.0 )
1160  {
1161  clippedAngle += 2 * M_PI;
1162  }
1163  return clippedAngle;
1164 }
1165 
1166 QPair<QgsWkbTypes::Type, QString> QgsGeometryUtils::wktReadBlock( const QString &wkt )
1167 {
1169 
1170  QRegularExpression cooRegEx( QStringLiteral( "^[^\\(]*\\((.*)\\)[^\\)]*$" ) );
1171  cooRegEx.setPatternOptions( QRegularExpression::DotMatchesEverythingOption );
1172  QRegularExpressionMatch match = cooRegEx.match( wkt );
1173  QString contents = match.hasMatch() ? match.captured( 1 ) : QString();
1174  return qMakePair( wkbType, contents );
1175 }
1176 
1177 QStringList QgsGeometryUtils::wktGetChildBlocks( const QString &wkt, const QString &defaultType )
1178 {
1179  int level = 0;
1180  QString block;
1181  QStringList blocks;
1182  for ( int i = 0, n = wkt.length(); i < n; ++i )
1183  {
1184  if ( ( wkt[i].isSpace() || wkt[i] == '\n' || wkt[i] == '\t' ) && level == 0 )
1185  continue;
1186 
1187  if ( wkt[i] == ',' && level == 0 )
1188  {
1189  if ( !block.isEmpty() )
1190  {
1191  if ( block.startsWith( '(' ) && !defaultType.isEmpty() )
1192  block.prepend( defaultType + ' ' );
1193  blocks.append( block );
1194  }
1195  block.clear();
1196  continue;
1197  }
1198  if ( wkt[i] == '(' )
1199  ++level;
1200  else if ( wkt[i] == ')' )
1201  --level;
1202  block += wkt[i];
1203  }
1204  if ( !block.isEmpty() )
1205  {
1206  if ( block.startsWith( '(' ) && !defaultType.isEmpty() )
1207  block.prepend( defaultType + ' ' );
1208  blocks.append( block );
1209  }
1210  return blocks;
1211 }
1212 
1214 {
1216 
1217 
1218  double x = ( pt1.x() + pt2.x() ) / 2.0;
1219  double y = ( pt1.y() + pt2.y() ) / 2.0;
1220  double z = std::numeric_limits<double>::quiet_NaN();
1221  double m = std::numeric_limits<double>::quiet_NaN();
1222 
1223  if ( pt1.is3D() || pt2.is3D() )
1224  {
1225  pType = QgsWkbTypes::addZ( pType );
1226  z = ( pt1.z() + pt2.z() ) / 2.0;
1227  }
1228 
1229  if ( pt1.isMeasure() || pt2.isMeasure() )
1230  {
1231  pType = QgsWkbTypes::addM( pType );
1232  m = ( pt1.m() + pt2.m() ) / 2.0;
1233  }
1234 
1235  return QgsPoint( pType, x, y, z, m );
1236 }
1237 
1238 QgsPoint QgsGeometryUtils::interpolatePointOnLine( const QgsPoint &p1, const QgsPoint &p2, const double fraction )
1239 {
1240  const double _fraction = 1 - fraction;
1241  return QgsPoint( p1.wkbType(),
1242  p1.x() * _fraction + p2.x() * fraction,
1243  p1.y() * _fraction + p2.y() * fraction,
1244  p1.is3D() ? p1.z() * _fraction + p2.z() * fraction : std::numeric_limits<double>::quiet_NaN(),
1245  p1.isMeasure() ? p1.m() * _fraction + p2.m() * fraction : std::numeric_limits<double>::quiet_NaN() );
1246 }
1247 
1248 QgsPointXY QgsGeometryUtils::interpolatePointOnLine( const double x1, const double y1, const double x2, const double y2, const double fraction )
1249 {
1250  const double deltaX = ( x2 - x1 ) * fraction;
1251  const double deltaY = ( y2 - y1 ) * fraction;
1252  return QgsPointXY( x1 + deltaX, y1 + deltaY );
1253 }
1254 
1255 QgsPointXY QgsGeometryUtils::interpolatePointOnLineByValue( const double x1, const double y1, const double v1, const double x2, const double y2, const double v2, const double value )
1256 {
1257  if ( qgsDoubleNear( v1, v2 ) )
1258  return QgsPointXY( x1, y1 );
1259 
1260  const double fraction = ( value - v1 ) / ( v2 - v1 );
1261  return interpolatePointOnLine( x1, y1, x2, y2, fraction );
1262 }
1263 
1264 double QgsGeometryUtils::gradient( const QgsPoint &pt1, const QgsPoint &pt2 )
1265 {
1266  double delta_x = pt2.x() - pt1.x();
1267  double delta_y = pt2.y() - pt1.y();
1268  if ( qgsDoubleNear( delta_x, 0.0 ) )
1269  {
1270  return INFINITY;
1271  }
1272 
1273  return delta_y / delta_x;
1274 }
1275 
1276 void QgsGeometryUtils::coefficients( const QgsPoint &pt1, const QgsPoint &pt2, double &a, double &b, double &c )
1277 {
1278  if ( qgsDoubleNear( pt1.x(), pt2.x() ) )
1279  {
1280  a = 1;
1281  b = 0;
1282  c = -pt1.x();
1283  }
1284  else if ( qgsDoubleNear( pt1.y(), pt2.y() ) )
1285  {
1286  a = 0;
1287  b = 1;
1288  c = -pt1.y();
1289  }
1290  else
1291  {
1292  a = pt1.y() - pt2.y();
1293  b = pt2.x() - pt1.x();
1294  c = pt1.x() * pt2.y() - pt1.y() * pt2.x();
1295  }
1296 
1297 }
1298 
1300 {
1301  QgsLineString line;
1302  QgsPoint p2;
1303 
1304  if ( ( p == s1 ) || ( p == s2 ) )
1305  {
1306  return line;
1307  }
1308 
1309  double a, b, c;
1310  coefficients( s1, s2, a, b, c );
1311 
1312  if ( qgsDoubleNear( a, 0 ) )
1313  {
1314  p2 = QgsPoint( p.x(), s1.y() );
1315  }
1316  else if ( qgsDoubleNear( b, 0 ) )
1317  {
1318  p2 = QgsPoint( s1.x(), p.y() );
1319  }
1320  else
1321  {
1322  double y = ( -c - a * p.x() ) / b;
1323  double m = gradient( s1, s2 );
1324  double d2 = 1 + m * m;
1325  double H = p.y() - y;
1326  double dx = m * H / d2;
1327  double dy = m * dx;
1328  p2 = QgsPoint( p.x() + dx, y + dy );
1329  }
1330 
1331  line.addVertex( p );
1332  line.addVertex( p2 );
1333 
1334  return line;
1335 }
1336 
1337 double QgsGeometryUtils::lineAngle( double x1, double y1, double x2, double y2 )
1338 {
1339  double at = std::atan2( y2 - y1, x2 - x1 );
1340  double a = -at + M_PI_2;
1341  return normalizedAngle( a );
1342 }
1343 
1344 double QgsGeometryUtils::angleBetweenThreePoints( double x1, double y1, double x2, double y2, double x3, double y3 )
1345 {
1346  double angle1 = std::atan2( y1 - y2, x1 - x2 );
1347  double angle2 = std::atan2( y3 - y2, x3 - x2 );
1348  return normalizedAngle( angle1 - angle2 );
1349 }
1350 
1351 double QgsGeometryUtils::linePerpendicularAngle( double x1, double y1, double x2, double y2 )
1352 {
1353  double a = lineAngle( x1, y1, x2, y2 );
1354  a += M_PI_2;
1355  return normalizedAngle( a );
1356 }
1357 
1358 double QgsGeometryUtils::averageAngle( double x1, double y1, double x2, double y2, double x3, double y3 )
1359 {
1360  // calc average angle between the previous and next point
1361  double a1 = lineAngle( x1, y1, x2, y2 );
1362  double a2 = lineAngle( x2, y2, x3, y3 );
1363  return averageAngle( a1, a2 );
1364 }
1365 
1366 double QgsGeometryUtils::averageAngle( double a1, double a2 )
1367 {
1368  a1 = normalizedAngle( a1 );
1369  a2 = normalizedAngle( a2 );
1370  double clockwiseDiff = 0.0;
1371  if ( a2 >= a1 )
1372  {
1373  clockwiseDiff = a2 - a1;
1374  }
1375  else
1376  {
1377  clockwiseDiff = a2 + ( 2 * M_PI - a1 );
1378  }
1379  double counterClockwiseDiff = 2 * M_PI - clockwiseDiff;
1380 
1381  double resultAngle = 0;
1382  if ( clockwiseDiff <= counterClockwiseDiff )
1383  {
1384  resultAngle = a1 + clockwiseDiff / 2.0;
1385  }
1386  else
1387  {
1388  resultAngle = a1 - counterClockwiseDiff / 2.0;
1389  }
1390  return normalizedAngle( resultAngle );
1391 }
1392 
1394  const QgsVector3D &P2, const QgsVector3D &P22 )
1395 {
1396  QgsVector3D u1 = P12 - P1;
1397  QgsVector3D u2 = P22 - P2;
1398  QgsVector3D u3 = QgsVector3D::crossProduct( u1, u2 );
1399  if ( u3.length() == 0 ) return 1;
1400  u3.normalize();
1401  QgsVector3D dir = P1 - P2;
1402  return std::fabs( ( QgsVector3D::dotProduct( dir, u3 ) ) ); // u3 is already normalized
1403 }
1404 
1406  const QgsVector3D &P2, const QgsVector3D &P22,
1407  QgsVector3D &X1, double epsilon )
1408 {
1409  QgsVector3D d = P2 - P1;
1410  QgsVector3D u1 = P12 - P1;
1411  u1.normalize();
1412  QgsVector3D u2 = P22 - P2;
1413  u2.normalize();
1414  QgsVector3D u3 = QgsVector3D::crossProduct( u1, u2 );
1415 
1416  if ( std::fabs( u3.x() ) <= epsilon &&
1417  std::fabs( u3.y() ) <= epsilon &&
1418  std::fabs( u3.z() ) <= epsilon )
1419  {
1420  // The rays are almost parallel.
1421  return false;
1422  }
1423 
1424  // X1 and X2 are the closest points on lines
1425  // we want to find X1 (lies on u1)
1426  // solving the linear equation in r1 and r2: Xi = Pi + ri*ui
1427  // we are only interested in X1 so we only solve for r1.
1428  float a1 = QgsVector3D::dotProduct( u1, u1 ), b1 = QgsVector3D::dotProduct( u1, u2 ), c1 = QgsVector3D::dotProduct( u1, d );
1429  float a2 = QgsVector3D::dotProduct( u1, u2 ), b2 = QgsVector3D::dotProduct( u2, u2 ), c2 = QgsVector3D::dotProduct( u2, d );
1430  if ( !( std::fabs( b1 ) > epsilon ) )
1431  {
1432  // Denominator is close to zero.
1433  return false;
1434  }
1435  if ( !( a2 != -1 && a2 != 1 ) )
1436  {
1437  // Lines are parallel
1438  return false;
1439  }
1440 
1441  double r1 = ( c2 - b2 * c1 / b1 ) / ( a2 - b2 * a1 / b1 );
1442  X1 = P1 + u1 * r1;
1443 
1444  return true;
1445 }
1446 
1448  const QgsVector3D &Lb1, const QgsVector3D &Lb2,
1449  QgsVector3D &intersection )
1450 {
1451 
1452  // if all Vector are on the same plane (have the same Z), use the 2D intersection
1453  // else return a false result
1454  if ( qgsDoubleNear( La1.z(), La2.z() ) && qgsDoubleNear( La1.z(), Lb1.z() ) && qgsDoubleNear( La1.z(), Lb2.z() ) )
1455  {
1456  QgsPoint ptInter;
1457  bool isIntersection;
1458  segmentIntersection( QgsPoint( La1.x(), La1.y() ),
1459  QgsPoint( La2.x(), La2.y() ),
1460  QgsPoint( Lb1.x(), Lb1.y() ),
1461  QgsPoint( Lb2.x(), Lb2.y() ),
1462  ptInter,
1463  isIntersection,
1464  1e-8,
1465  true );
1466  intersection.set( ptInter.x(), ptInter.y(), La1.z() );
1467  return true;
1468  }
1469 
1470  // first check if lines have an exact intersection point
1471  // do it by checking if the shortest distance is exactly 0
1472  float distance = skewLinesDistance( La1, La2, Lb1, Lb2 );
1473  if ( qgsDoubleNear( distance, 0.0 ) )
1474  {
1475  // 3d lines have exact intersection point.
1476  QgsVector3D C = La2;
1477  QgsVector3D D = Lb2;
1478  QgsVector3D e = La1 - La2;
1479  QgsVector3D f = Lb1 - Lb2;
1480  QgsVector3D g = D - C;
1481  if ( qgsDoubleNear( ( QgsVector3D::crossProduct( f, g ) ).length(), 0.0 ) || qgsDoubleNear( ( QgsVector3D::crossProduct( f, e ) ).length(), 0.0 ) )
1482  {
1483  // Lines have no intersection, are they parallel?
1484  return false;
1485  }
1486 
1487  QgsVector3D fgn = QgsVector3D::crossProduct( f, g );
1488  fgn.normalize();
1489 
1490  QgsVector3D fen = QgsVector3D::crossProduct( f, e );
1491  fen.normalize();
1492 
1493  int di = -1;
1494  if ( fgn == fen ) // same direction?
1495  di *= -1;
1496 
1497  intersection = C + e * di * ( QgsVector3D::crossProduct( f, g ).length() / QgsVector3D::crossProduct( f, e ).length() );
1498  return true;
1499  }
1500 
1501  // try to calculate the approximate intersection point
1502  QgsVector3D X1, X2;
1503  bool firstIsDone = skewLinesProjection( La1, La2, Lb1, Lb2, X1 );
1504  bool secondIsDone = skewLinesProjection( Lb1, Lb2, La1, La2, X2 );
1505 
1506  if ( !firstIsDone || !secondIsDone )
1507  {
1508  // Could not obtain projection point.
1509  return false;
1510  }
1511 
1512  intersection = ( X1 + X2 ) / 2.0;
1513  return true;
1514 }
1515 
1517 {
1518  bool rc = false;
1519 
1520  for ( const QgsPoint &pt : points )
1521  {
1522  if ( pt.is3D() )
1523  {
1524  point.convertTo( QgsWkbTypes::addZ( point.wkbType() ) );
1525  point.setZ( pt.z() );
1526  rc = true;
1527  break;
1528  }
1529  }
1530 
1531  return rc;
1532 }
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
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
Definition: qgspointxy.h:190
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...
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...
static double gradient(const QgsPoint &pt1, const QgsPoint &pt2)
Returns the gradient of a line defined by points pt1 and pt2.
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:278
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
double sqrDist(double x, double y) const
Returns the squared distance between this point a specified x, y coordinate.
Definition: qgspointxy.h:169
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.
double y() const
Returns the vector&#39;s y-component.
Definition: qgsvector.cpp:81
double length() const
Returns the length of the vector.
Definition: qgsvector3d.h:112
double z() const
Returns Z coordinate.
Definition: qgsvector3d.h:53
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.
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:906
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
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
static bool circleClockwise(double angle1, double angle2, double angle3)
Returns true if the circle defined by three angles is ordered clockwise.
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
bool isMeasure() const
Returns true if the geometry contains m values.
double x() const
Returns X coordinate.
Definition: qgsvector3d.h:49
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:1027
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:563
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:238
static Type addZ(Type type)
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1002
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.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
double y() const
Returns Y coordinate.
Definition: qgsvector3d.h:51
AxisOrder
Axis order for GML generation.
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:28
double length() const
Returns the length of the vector.
Definition: qgsvector.cpp:71
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.
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
Definition: qgspoint.h:276
virtual double length() const
Returns the length of the geometry.
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 int leftOfLine(double x, double y, double x1, double y1, double x2, double y2)
Returns a value < 0 if the point (x, y) is left of the line from (x1, y1) -> ( x2, y2).
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 is3D() const
Returns true if the geometry is 3D and contains a z-value.
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 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:956
bool isValid() const
Returns true if the vertex id is valid.
static QgsPoint closestPoint(const QgsAbstractGeometry &geometry, const QgsPoint &point)
Returns the nearest point on a segment of a geometry for the specified point.
double x() const
Returns the vector&#39;s x-component.
Definition: qgsvector.cpp:76
virtual QgsPoint vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
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
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).
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