QGIS API Documentation  3.0.2-Girona (307d082)
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 bool QgsGeometryUtils::lineCircleIntersection( const QgsPointXY &center, const double radius,
317  const QgsPointXY &linePoint1, const QgsPointXY &linePoint2,
318  QgsPointXY &intersection )
319 {
320  // formula taken from http://mathworld.wolfram.com/Circle-LineIntersection.html
321 
322  const double x1 = linePoint1.x() - center.x();
323  const double y1 = linePoint1.y() - center.y();
324  const double x2 = linePoint2.x() - center.x();
325  const double y2 = linePoint2.y() - center.y();
326  const double dx = x2 - x1;
327  const double dy = y2 - y1;
328 
329  const double dr = std::sqrt( std::pow( dx, 2 ) + std::pow( dy, 2 ) );
330  const double d = x1 * y2 - x2 * y1;
331 
332  const double disc = std::pow( radius, 2 ) * std::pow( dr, 2 ) - std::pow( d, 2 );
333 
334  if ( disc < 0 )
335  {
336  //no intersection or tangent
337  return false;
338  }
339  else
340  {
341  // two solutions
342  const int sgnDy = dy < 0 ? -1 : 1;
343 
344  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 ) );
345  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 ) );
346  const QgsPointXY p1( ax, ay );
347 
348  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 ) );
349  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 ) );
350  const QgsPointXY p2( bx, by );
351 
352  // snap to nearest intersection
353 
354  if ( intersection.sqrDist( p1 ) < intersection.sqrDist( p2 ) )
355  {
356  intersection.set( p1.x(), p1.y() );
357  }
358  else
359  {
360  intersection.set( p2.x(), p2.y() );
361  }
362  return true;
363  }
364 }
365 
366 QVector<QgsGeometryUtils::SelfIntersection> QgsGeometryUtils::selfIntersections( const QgsAbstractGeometry *geom, int part, int ring, double tolerance )
367 {
368  QVector<SelfIntersection> intersections;
369 
370  int n = geom->vertexCount( part, ring );
371  bool isClosed = geom->vertexAt( QgsVertexId( part, ring, 0 ) ) == geom->vertexAt( QgsVertexId( part, ring, n - 1 ) );
372 
373  // Check every pair of segments for intersections
374  for ( int i = 0, j = 1; j < n; i = j++ )
375  {
376  QgsPoint pi = geom->vertexAt( QgsVertexId( part, ring, i ) );
377  QgsPoint pj = geom->vertexAt( QgsVertexId( part, ring, j ) );
378  if ( QgsGeometryUtils::sqrDistance2D( pi, pj ) < tolerance * tolerance ) continue;
379 
380  // Don't test neighboring edges
381  int start = j + 1;
382  int end = i == 0 && isClosed ? n - 1 : n;
383  for ( int k = start, l = start + 1; l < end; k = l++ )
384  {
385  QgsPoint pk = geom->vertexAt( QgsVertexId( part, ring, k ) );
386  QgsPoint pl = geom->vertexAt( QgsVertexId( part, ring, l ) );
387 
388  QgsPoint inter;
389  bool intersection = false;
390  if ( !QgsGeometryUtils::segmentIntersection( pi, pj, pk, pl, inter, intersection, tolerance ) ) continue;
391 
393  s.segment1 = i;
394  s.segment2 = k;
395  if ( s.segment1 > s.segment2 )
396  {
397  std::swap( s.segment1, s.segment2 );
398  }
399  s.point = inter;
400  intersections.append( s );
401  }
402  }
403  return intersections;
404 }
405 
406 int QgsGeometryUtils::leftOfLine( double x, double y, double x1, double y1, double x2, double y2 )
407 {
408  double f1 = x - x1;
409  double f2 = y2 - y1;
410  double f3 = y - y1;
411  double f4 = x2 - x1;
412  double test = ( f1 * f2 - f3 * f4 );
413  // return -1, 0, or 1
414  return qgsDoubleNear( test, 0.0 ) ? 0 : ( test < 0 ? -1 : 1 );
415 }
416 
417 QgsPoint QgsGeometryUtils::pointOnLineWithDistance( const QgsPoint &startPoint, const QgsPoint &directionPoint, double distance )
418 {
419  double dx = directionPoint.x() - startPoint.x();
420  double dy = directionPoint.y() - startPoint.y();
421  double length = std::sqrt( dx * dx + dy * dy );
422 
423  if ( qgsDoubleNear( length, 0.0 ) )
424  {
425  return startPoint;
426  }
427 
428  double scaleFactor = distance / length;
429  return QgsPoint( startPoint.x() + dx * scaleFactor, startPoint.y() + dy * scaleFactor );
430 }
431 
432 double QgsGeometryUtils::ccwAngle( double dy, double dx )
433 {
434  double angle = std::atan2( dy, dx ) * 180 / M_PI;
435  if ( angle < 0 )
436  {
437  return 360 + angle;
438  }
439  else if ( angle > 360 )
440  {
441  return 360 - angle;
442  }
443  return angle;
444 }
445 
446 void QgsGeometryUtils::circleCenterRadius( const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double &radius, double &centerX, double &centerY )
447 {
448  double dx21, dy21, dx31, dy31, h21, h31, d;
449 
450  //closed circle
451  if ( qgsDoubleNear( pt1.x(), pt3.x() ) && qgsDoubleNear( pt1.y(), pt3.y() ) )
452  {
453  centerX = ( pt1.x() + pt2.x() ) / 2.0;
454  centerY = ( pt1.y() + pt2.y() ) / 2.0;
455  radius = std::sqrt( std::pow( centerX - pt1.x(), 2.0 ) + std::pow( centerY - pt1.y(), 2.0 ) );
456  return;
457  }
458 
459  // Using Cartesian circumcenter eguations from page https://en.wikipedia.org/wiki/Circumscribed_circle
460  dx21 = pt2.x() - pt1.x();
461  dy21 = pt2.y() - pt1.y();
462  dx31 = pt3.x() - pt1.x();
463  dy31 = pt3.y() - pt1.y();
464 
465  h21 = std::pow( dx21, 2.0 ) + std::pow( dy21, 2.0 );
466  h31 = std::pow( dx31, 2.0 ) + std::pow( dy31, 2.0 );
467 
468  // 2*Cross product, d<0 means clockwise and d>0 counterclockwise sweeping angle
469  d = 2 * ( dx21 * dy31 - dx31 * dy21 );
470 
471  // Check colinearity, Cross product = 0
472  if ( qgsDoubleNear( std::fabs( d ), 0.0, 0.00000000001 ) )
473  {
474  radius = -1.0;
475  return;
476  }
477 
478  // Calculate centroid coordinates and radius
479  centerX = pt1.x() + ( h21 * dy31 - h31 * dy21 ) / d;
480  centerY = pt1.y() - ( h21 * dx31 - h31 * dx21 ) / d;
481  radius = std::sqrt( std::pow( centerX - pt1.x(), 2.0 ) + std::pow( centerY - pt1.y(), 2.0 ) );
482 }
483 
484 bool QgsGeometryUtils::circleClockwise( double angle1, double angle2, double angle3 )
485 {
486  if ( angle3 >= angle1 )
487  {
488  return !( angle2 > angle1 && angle2 < angle3 );
489  }
490  else
491  {
492  return !( angle2 > angle1 || angle2 < angle3 );
493  }
494 }
495 
496 bool QgsGeometryUtils::circleAngleBetween( double angle, double angle1, double angle2, bool clockwise )
497 {
498  if ( clockwise )
499  {
500  if ( angle2 < angle1 )
501  {
502  return ( angle <= angle1 && angle >= angle2 );
503  }
504  else
505  {
506  return ( angle <= angle1 || angle >= angle2 );
507  }
508  }
509  else
510  {
511  if ( angle2 > angle1 )
512  {
513  return ( angle >= angle1 && angle <= angle2 );
514  }
515  else
516  {
517  return ( angle >= angle1 || angle <= angle2 );
518  }
519  }
520 }
521 
522 bool QgsGeometryUtils::angleOnCircle( double angle, double angle1, double angle2, double angle3 )
523 {
524  bool clockwise = circleClockwise( angle1, angle2, angle3 );
525  return circleAngleBetween( angle, angle1, angle3, clockwise );
526 }
527 
528 double QgsGeometryUtils::circleLength( double x1, double y1, double x2, double y2, double x3, double y3 )
529 {
530  double centerX, centerY, radius;
531  circleCenterRadius( QgsPoint( x1, y1 ), QgsPoint( x2, y2 ), QgsPoint( x3, y3 ), radius, centerX, centerY );
532  double length = M_PI / 180.0 * radius * sweepAngle( centerX, centerY, x1, y1, x2, y2, x3, y3 );
533  if ( length < 0 )
534  {
535  length = -length;
536  }
537  return length;
538 }
539 
540 double QgsGeometryUtils::sweepAngle( double centerX, double centerY, double x1, double y1, double x2, double y2, double x3, double y3 )
541 {
542  double p1Angle = QgsGeometryUtils::ccwAngle( y1 - centerY, x1 - centerX );
543  double p2Angle = QgsGeometryUtils::ccwAngle( y2 - centerY, x2 - centerX );
544  double p3Angle = QgsGeometryUtils::ccwAngle( y3 - centerY, x3 - centerX );
545 
546  if ( p3Angle >= p1Angle )
547  {
548  if ( p2Angle > p1Angle && p2Angle < p3Angle )
549  {
550  return ( p3Angle - p1Angle );
551  }
552  else
553  {
554  return ( - ( p1Angle + ( 360 - p3Angle ) ) );
555  }
556  }
557  else
558  {
559  if ( p2Angle < p1Angle && p2Angle > p3Angle )
560  {
561  return ( -( p1Angle - p3Angle ) );
562  }
563  else
564  {
565  return ( p3Angle + ( 360 - p1Angle ) );
566  }
567  }
568 }
569 
570 bool QgsGeometryUtils::segmentMidPoint( const QgsPoint &p1, const QgsPoint &p2, QgsPoint &result, double radius, const QgsPoint &mousePos )
571 {
572  QgsPoint midPoint( ( p1.x() + p2.x() ) / 2.0, ( p1.y() + p2.y() ) / 2.0 );
573  double midDist = std::sqrt( sqrDistance2D( p1, midPoint ) );
574  if ( radius < midDist )
575  {
576  return false;
577  }
578  double centerMidDist = std::sqrt( radius * radius - midDist * midDist );
579  double dist = radius - centerMidDist;
580 
581  double midDx = midPoint.x() - p1.x();
582  double midDy = midPoint.y() - p1.y();
583 
584  //get the four possible midpoints
585  QVector<QgsPoint> possibleMidPoints;
586  possibleMidPoints.append( pointOnLineWithDistance( midPoint, QgsPoint( midPoint.x() - midDy, midPoint.y() + midDx ), dist ) );
587  possibleMidPoints.append( pointOnLineWithDistance( midPoint, QgsPoint( midPoint.x() - midDy, midPoint.y() + midDx ), 2 * radius - dist ) );
588  possibleMidPoints.append( pointOnLineWithDistance( midPoint, QgsPoint( midPoint.x() + midDy, midPoint.y() - midDx ), dist ) );
589  possibleMidPoints.append( pointOnLineWithDistance( midPoint, QgsPoint( midPoint.x() + midDy, midPoint.y() - midDx ), 2 * radius - dist ) );
590 
591  //take the closest one
592  double minDist = std::numeric_limits<double>::max();
593  int minDistIndex = -1;
594  for ( int i = 0; i < possibleMidPoints.size(); ++i )
595  {
596  double currentDist = sqrDistance2D( mousePos, possibleMidPoints.at( i ) );
597  if ( currentDist < minDist )
598  {
599  minDistIndex = i;
600  minDist = currentDist;
601  }
602  }
603 
604  if ( minDistIndex == -1 )
605  {
606  return false;
607  }
608 
609  result = possibleMidPoints.at( minDistIndex );
610 
611  // add z support if necessary
613 
614  return true;
615 }
616 
617 double QgsGeometryUtils::circleTangentDirection( const QgsPoint &tangentPoint, const QgsPoint &cp1,
618  const QgsPoint &cp2, const QgsPoint &cp3 )
619 {
620  //calculate circle midpoint
621  double mX, mY, radius;
622  circleCenterRadius( cp1, cp2, cp3, radius, mX, mY );
623 
624  double p1Angle = QgsGeometryUtils::ccwAngle( cp1.y() - mY, cp1.x() - mX );
625  double p2Angle = QgsGeometryUtils::ccwAngle( cp2.y() - mY, cp2.x() - mX );
626  double p3Angle = QgsGeometryUtils::ccwAngle( cp3.y() - mY, cp3.x() - mX );
627  double angle = 0;
628  if ( circleClockwise( p1Angle, p2Angle, p3Angle ) )
629  {
630  angle = lineAngle( tangentPoint.x(), tangentPoint.y(), mX, mY ) - M_PI_2;
631  }
632  else
633  {
634  angle = lineAngle( mX, mY, tangentPoint.x(), tangentPoint.y() ) - M_PI_2;
635  }
636  if ( angle < 0 )
637  angle += 2 * M_PI;
638  return angle;
639 }
640 
641 void QgsGeometryUtils::segmentizeArc( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3, QgsPointSequence &points, double tolerance, QgsAbstractGeometry::SegmentationToleranceType toleranceType, bool hasZ, bool hasM )
642 {
643  bool reversed = false;
644  int segSide = segmentSide( p1, p3, p2 );
645 
646  QgsPoint circlePoint1;
647  const QgsPoint circlePoint2 = p2;
648  QgsPoint circlePoint3;
649 
650  if ( segSide == -1 )
651  {
652  // Reverse !
653  circlePoint1 = p3;
654  circlePoint3 = p1;
655  reversed = true;
656  }
657  else
658  {
659  circlePoint1 = p1;
660  circlePoint3 = p3;
661  }
662 
663  //adapted code from PostGIS
664  double radius = 0;
665  double centerX = 0;
666  double centerY = 0;
667  circleCenterRadius( circlePoint1, circlePoint2, circlePoint3, radius, centerX, centerY );
668 
669  if ( circlePoint1 != circlePoint3 && ( radius < 0 || qgsDoubleNear( segSide, 0.0 ) ) ) //points are colinear
670  {
671  points.append( p1 );
672  points.append( p2 );
673  points.append( p3 );
674  return;
675  }
676 
677  double increment = tolerance; //one segment per degree
678  if ( toleranceType == QgsAbstractGeometry::MaximumDifference )
679  {
680  double halfAngle = std::acos( -tolerance / radius + 1 );
681  increment = 2 * halfAngle;
682  }
683 
684  //angles of pt1, pt2, pt3
685  double a1 = std::atan2( circlePoint1.y() - centerY, circlePoint1.x() - centerX );
686  double a2 = std::atan2( circlePoint2.y() - centerY, circlePoint2.x() - centerX );
687  double a3 = std::atan2( circlePoint3.y() - centerY, circlePoint3.x() - centerX );
688 
689  // Make segmentation symmetric
690  const bool symmetric = true;
691  if ( symmetric )
692  {
693  double angle = a3 - a1;
694  if ( angle < 0 ) angle += M_PI * 2;
695 
696  /* Number of segments in output */
697  int segs = ceil( angle / increment );
698  /* Tweak increment to be regular for all the arc */
699  increment = angle / segs;
700  }
701 
702  /* Adjust a3 up so we can increment from a1 to a3 cleanly */
703  if ( a3 < a1 )
704  a3 += 2.0 * M_PI;
705  if ( a2 < a1 )
706  a2 += 2.0 * M_PI;
707 
708  double x, y;
709  double z = 0;
710  double m = 0;
711 
712  QVector<QgsPoint> stringPoints;
713  stringPoints.insert( 0, circlePoint1 );
714  if ( circlePoint2 != circlePoint3 && circlePoint1 != circlePoint2 ) //draw straight line segment if two points have the same position
715  {
716  QgsWkbTypes::Type pointWkbType = QgsWkbTypes::Point;
717  if ( hasZ )
718  pointWkbType = QgsWkbTypes::addZ( pointWkbType );
719  if ( hasM )
720  pointWkbType = QgsWkbTypes::addM( pointWkbType );
721 
722  // As we're adding the last point in any case, we'll avoid
723  // including a point which is at less than 1% increment distance
724  // from it (may happen to find them due to numbers approximation).
725  // NOTE that this effectively allows in output some segments which
726  // are more distant than requested. This is at most 1% off
727  // from requested MaxAngle and less for MaxError.
728  double tolError = increment / 100;
729  double stopAngle = a3 - tolError;
730  for ( double angle = a1 + increment; angle < stopAngle; angle += increment )
731  {
732  x = centerX + radius * std::cos( angle );
733  y = centerY + radius * std::sin( angle );
734 
735  if ( hasZ )
736  {
737  z = interpolateArcValue( angle, a1, a2, a3, circlePoint1.z(), circlePoint2.z(), circlePoint3.z() );
738  }
739  if ( hasM )
740  {
741  m = interpolateArcValue( angle, a1, a2, a3, circlePoint1.m(), circlePoint2.m(), circlePoint3.m() );
742  }
743 
744  stringPoints.insert( stringPoints.size(), QgsPoint( pointWkbType, x, y, z, m ) );
745  }
746  }
747  stringPoints.insert( stringPoints.size(), circlePoint3 );
748 
749  // TODO: check if or implement QgsPointSequence directly taking an iterator to append
750  if ( reversed )
751  {
752  std::reverse( stringPoints.begin(), stringPoints.end() );
753  }
754  if ( ! points.empty() && stringPoints.front() == points.back() ) stringPoints.pop_front();
755  points.append( stringPoints );
756 }
757 
758 int QgsGeometryUtils::segmentSide( const QgsPoint &pt1, const QgsPoint &pt3, const QgsPoint &pt2 )
759 {
760  double side = ( ( pt2.x() - pt1.x() ) * ( pt3.y() - pt1.y() ) - ( pt3.x() - pt1.x() ) * ( pt2.y() - pt1.y() ) );
761  if ( side == 0.0 )
762  {
763  return 0;
764  }
765  else
766  {
767  if ( side < 0 )
768  {
769  return -1;
770  }
771  if ( side > 0 )
772  {
773  return 1;
774  }
775  return 0;
776  }
777 }
778 
779 double QgsGeometryUtils::interpolateArcValue( double angle, double a1, double a2, double a3, double zm1, double zm2, double zm3 )
780 {
781  /* Counter-clockwise sweep */
782  if ( a1 < a2 )
783  {
784  if ( angle <= a2 )
785  return zm1 + ( zm2 - zm1 ) * ( angle - a1 ) / ( a2 - a1 );
786  else
787  return zm2 + ( zm3 - zm2 ) * ( angle - a2 ) / ( a3 - a2 );
788  }
789  /* Clockwise sweep */
790  else
791  {
792  if ( angle >= a2 )
793  return zm1 + ( zm2 - zm1 ) * ( a1 - angle ) / ( a1 - a2 );
794  else
795  return zm2 + ( zm3 - zm2 ) * ( a2 - angle ) / ( a2 - a3 );
796  }
797 }
798 
799 QgsPointSequence QgsGeometryUtils::pointsFromWKT( const QString &wktCoordinateList, bool is3D, bool isMeasure )
800 {
801  int dim = 2 + is3D + isMeasure;
802  QgsPointSequence points;
803  const QStringList coordList = wktCoordinateList.split( ',', QString::SkipEmptyParts );
804 
805  //first scan through for extra unexpected dimensions
806  bool foundZ = false;
807  bool foundM = false;
808  QRegularExpression rx( QStringLiteral( "\\s" ) );
809  for ( const QString &pointCoordinates : coordList )
810  {
811  QStringList coordinates = pointCoordinates.split( rx, QString::SkipEmptyParts );
812  if ( coordinates.size() == 3 && !foundZ && !foundM && !is3D && !isMeasure )
813  {
814  // 3 dimensional coordinates, but not specifically marked as such. We allow this
815  // anyway and upgrade geometry to have Z dimension
816  foundZ = true;
817  }
818  else if ( coordinates.size() >= 4 && ( !( is3D || foundZ ) || !( isMeasure || foundM ) ) )
819  {
820  // 4 (or more) dimensional coordinates, but not specifically marked as such. We allow this
821  // anyway and upgrade geometry to have Z&M dimensions
822  foundZ = true;
823  foundM = true;
824  }
825  }
826 
827  for ( const QString &pointCoordinates : coordList )
828  {
829  QStringList coordinates = pointCoordinates.split( rx, QString::SkipEmptyParts );
830  if ( coordinates.size() < dim )
831  continue;
832 
833  int idx = 0;
834  double x = coordinates[idx++].toDouble();
835  double y = coordinates[idx++].toDouble();
836 
837  double z = 0;
838  if ( ( is3D || foundZ ) && coordinates.length() > idx )
839  z = coordinates[idx++].toDouble();
840 
841  double m = 0;
842  if ( ( isMeasure || foundM ) && coordinates.length() > idx )
843  m = coordinates[idx++].toDouble();
844 
846  if ( is3D || foundZ )
847  {
848  if ( isMeasure || foundM )
850  else
852  }
853  else
854  {
855  if ( isMeasure || foundM )
857  else
858  t = QgsWkbTypes::Point;
859  }
860 
861  points.append( QgsPoint( t, x, y, z, m ) );
862  }
863 
864  return points;
865 }
866 
868 {
869  wkb << static_cast<quint32>( points.size() );
870  for ( const QgsPoint &point : points )
871  {
872  wkb << point.x() << point.y();
873  if ( is3D )
874  {
875  wkb << point.z();
876  }
877  if ( isMeasure )
878  {
879  wkb << point.m();
880  }
881  }
882 }
883 
884 QString QgsGeometryUtils::pointsToWKT( const QgsPointSequence &points, int precision, bool is3D, bool isMeasure )
885 {
886  QString wkt = QStringLiteral( "(" );
887  for ( const QgsPoint &p : points )
888  {
889  wkt += qgsDoubleToString( p.x(), precision );
890  wkt += ' ' + qgsDoubleToString( p.y(), precision );
891  if ( is3D )
892  wkt += ' ' + qgsDoubleToString( p.z(), precision );
893  if ( isMeasure )
894  wkt += ' ' + qgsDoubleToString( p.m(), precision );
895  wkt += QLatin1String( ", " );
896  }
897  if ( wkt.endsWith( QLatin1String( ", " ) ) )
898  wkt.chop( 2 ); // Remove last ", "
899  wkt += ')';
900  return wkt;
901 }
902 
903 QDomElement QgsGeometryUtils::pointsToGML2( const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns )
904 {
905  QDomElement elemCoordinates = doc.createElementNS( ns, QStringLiteral( "coordinates" ) );
906 
907  // coordinate separator
908  QString cs = QStringLiteral( "," );
909  // tupel separator
910  QString ts = QStringLiteral( " " );
911 
912  elemCoordinates.setAttribute( QStringLiteral( "cs" ), cs );
913  elemCoordinates.setAttribute( QStringLiteral( "ts" ), ts );
914 
915  QString strCoordinates;
916 
917  for ( const QgsPoint &p : points )
918  strCoordinates += qgsDoubleToString( p.x(), precision ) + cs + qgsDoubleToString( p.y(), precision ) + ts;
919 
920  if ( strCoordinates.endsWith( ts ) )
921  strCoordinates.chop( 1 ); // Remove trailing space
922 
923  elemCoordinates.appendChild( doc.createTextNode( strCoordinates ) );
924  return elemCoordinates;
925 }
926 
927 QDomElement QgsGeometryUtils::pointsToGML3( const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, bool is3D )
928 {
929  QDomElement elemPosList = doc.createElementNS( ns, QStringLiteral( "posList" ) );
930  elemPosList.setAttribute( QStringLiteral( "srsDimension" ), is3D ? 3 : 2 );
931 
932  QString strCoordinates;
933  for ( const QgsPoint &p : points )
934  {
935  strCoordinates += qgsDoubleToString( p.x(), precision ) + ' ' + qgsDoubleToString( p.y(), precision ) + ' ';
936  if ( is3D )
937  strCoordinates += qgsDoubleToString( p.z(), precision ) + ' ';
938  }
939  if ( strCoordinates.endsWith( ' ' ) )
940  strCoordinates.chop( 1 ); // Remove trailing space
941 
942  elemPosList.appendChild( doc.createTextNode( strCoordinates ) );
943  return elemPosList;
944 }
945 
946 QString QgsGeometryUtils::pointsToJSON( const QgsPointSequence &points, int precision )
947 {
948  QString json = QStringLiteral( "[ " );
949  for ( const QgsPoint &p : points )
950  {
951  json += '[' + qgsDoubleToString( p.x(), precision ) + ", " + qgsDoubleToString( p.y(), precision ) + "], ";
952  }
953  if ( json.endsWith( QLatin1String( ", " ) ) )
954  {
955  json.chop( 2 ); // Remove last ", "
956  }
957  json += ']';
958  return json;
959 }
960 
962 {
963  double clippedAngle = angle;
964  if ( clippedAngle >= M_PI * 2 || clippedAngle <= -2 * M_PI )
965  {
966  clippedAngle = std::fmod( clippedAngle, 2 * M_PI );
967  }
968  if ( clippedAngle < 0.0 )
969  {
970  clippedAngle += 2 * M_PI;
971  }
972  return clippedAngle;
973 }
974 
975 QPair<QgsWkbTypes::Type, QString> QgsGeometryUtils::wktReadBlock( const QString &wkt )
976 {
978 
979  QRegularExpression cooRegEx( QStringLiteral( "^[^\\(]*\\((.*)\\)[^\\)]*$" ) );
980  cooRegEx.setPatternOptions( QRegularExpression::DotMatchesEverythingOption );
981  QRegularExpressionMatch match = cooRegEx.match( wkt );
982  QString contents = match.hasMatch() ? match.captured( 1 ) : QString();
983  return qMakePair( wkbType, contents );
984 }
985 
986 QStringList QgsGeometryUtils::wktGetChildBlocks( const QString &wkt, const QString &defaultType )
987 {
988  int level = 0;
989  QString block;
990  QStringList blocks;
991  for ( int i = 0, n = wkt.length(); i < n; ++i )
992  {
993  if ( ( wkt[i].isSpace() || wkt[i] == '\n' || wkt[i] == '\t' ) && level == 0 )
994  continue;
995 
996  if ( wkt[i] == ',' && level == 0 )
997  {
998  if ( !block.isEmpty() )
999  {
1000  if ( block.startsWith( '(' ) && !defaultType.isEmpty() )
1001  block.prepend( defaultType + ' ' );
1002  blocks.append( block );
1003  }
1004  block.clear();
1005  continue;
1006  }
1007  if ( wkt[i] == '(' )
1008  ++level;
1009  else if ( wkt[i] == ')' )
1010  --level;
1011  block += wkt[i];
1012  }
1013  if ( !block.isEmpty() )
1014  {
1015  if ( block.startsWith( '(' ) && !defaultType.isEmpty() )
1016  block.prepend( defaultType + ' ' );
1017  blocks.append( block );
1018  }
1019  return blocks;
1020 }
1021 
1023 {
1025 
1026 
1027  double x = ( pt1.x() + pt2.x() ) / 2.0;
1028  double y = ( pt1.y() + pt2.y() ) / 2.0;
1029  double z = std::numeric_limits<double>::quiet_NaN();
1030  double m = std::numeric_limits<double>::quiet_NaN();
1031 
1032  if ( pt1.is3D() || pt2.is3D() )
1033  {
1034  pType = QgsWkbTypes::addZ( pType );
1035  z = ( pt1.z() + pt2.z() ) / 2.0;
1036  }
1037 
1038  if ( pt1.isMeasure() || pt2.isMeasure() )
1039  {
1040  pType = QgsWkbTypes::addM( pType );
1041  m = ( pt1.m() + pt2.m() ) / 2.0;
1042  }
1043 
1044  return QgsPoint( pType, x, y, z, m );
1045 }
1046 
1047 QgsPoint QgsGeometryUtils::interpolatePointOnLine( const QgsPoint &p1, const QgsPoint &p2, const double fraction )
1048 {
1049  const double _fraction = 1 - fraction;
1050  return QgsPoint( p1.wkbType(),
1051  p1.x() * _fraction + p2.x() * fraction,
1052  p1.y() * _fraction + p2.y() * fraction,
1053  p1.is3D() ? p1.z() * _fraction + p2.z() * fraction : std::numeric_limits<double>::quiet_NaN(),
1054  p1.isMeasure() ? p1.m() * _fraction + p2.m() * fraction : std::numeric_limits<double>::quiet_NaN() );
1055 }
1056 
1057 QgsPointXY QgsGeometryUtils::interpolatePointOnLine( const double x1, const double y1, const double x2, const double y2, const double fraction )
1058 {
1059  const double deltaX = ( x2 - x1 ) * fraction;
1060  const double deltaY = ( y2 - y1 ) * fraction;
1061  return QgsPointXY( x1 + deltaX, y1 + deltaY );
1062 }
1063 
1064 QgsPointXY QgsGeometryUtils::interpolatePointOnLineByValue( const double x1, const double y1, const double v1, const double x2, const double y2, const double v2, const double value )
1065 {
1066  if ( qgsDoubleNear( v1, v2 ) )
1067  return QgsPointXY( x1, y1 );
1068 
1069  const double fraction = ( value - v1 ) / ( v2 - v1 );
1070  return interpolatePointOnLine( x1, y1, x2, y2, fraction );
1071 }
1072 
1073 double QgsGeometryUtils::gradient( const QgsPoint &pt1, const QgsPoint &pt2 )
1074 {
1075  double delta_x = pt2.x() - pt1.x();
1076  double delta_y = pt2.y() - pt1.y();
1077  if ( qgsDoubleNear( delta_x, 0.0 ) )
1078  {
1079  return INFINITY;
1080  }
1081 
1082  return delta_y / delta_x;
1083 }
1084 
1085 void QgsGeometryUtils::coefficients( const QgsPoint &pt1, const QgsPoint &pt2, double &a, double &b, double &c )
1086 {
1087  if ( qgsDoubleNear( pt1.x(), pt2.x() ) )
1088  {
1089  a = 1;
1090  b = 0;
1091  c = -pt1.x();
1092  }
1093  else if ( qgsDoubleNear( pt1.y(), pt2.y() ) )
1094  {
1095  a = 0;
1096  b = 1;
1097  c = -pt1.y();
1098  }
1099  else
1100  {
1101  a = pt1.y() - pt2.y();
1102  b = pt2.x() - pt1.x();
1103  c = pt1.x() * pt2.y() - pt1.y() * pt2.x();
1104  }
1105 
1106 }
1107 
1109 {
1110  QgsLineString line;
1111  QgsPoint p2;
1112 
1113  if ( ( p == s1 ) || ( p == s2 ) )
1114  {
1115  return line;
1116  }
1117 
1118  double a, b, c;
1119  coefficients( s1, s2, a, b, c );
1120 
1121  if ( qgsDoubleNear( a, 0 ) )
1122  {
1123  p2 = QgsPoint( p.x(), s1.y() );
1124  }
1125  else if ( qgsDoubleNear( b, 0 ) )
1126  {
1127  p2 = QgsPoint( s1.x(), p.y() );
1128  }
1129  else
1130  {
1131  double y = ( -c - a * p.x() ) / b;
1132  double m = gradient( s1, s2 );
1133  double d2 = 1 + m * m;
1134  double H = p.y() - y;
1135  double dx = m * H / d2;
1136  double dy = m * dx;
1137  p2 = QgsPoint( p.x() + dx, y + dy );
1138  }
1139 
1140  line.addVertex( p );
1141  line.addVertex( p2 );
1142 
1143  return line;
1144 }
1145 
1146 double QgsGeometryUtils::lineAngle( double x1, double y1, double x2, double y2 )
1147 {
1148  double at = std::atan2( y2 - y1, x2 - x1 );
1149  double a = -at + M_PI_2;
1150  return normalizedAngle( a );
1151 }
1152 
1153 double QgsGeometryUtils::angleBetweenThreePoints( double x1, double y1, double x2, double y2, double x3, double y3 )
1154 {
1155  double angle1 = std::atan2( y1 - y2, x1 - x2 );
1156  double angle2 = std::atan2( y3 - y2, x3 - x2 );
1157  return normalizedAngle( angle1 - angle2 );
1158 }
1159 
1160 double QgsGeometryUtils::linePerpendicularAngle( double x1, double y1, double x2, double y2 )
1161 {
1162  double a = lineAngle( x1, y1, x2, y2 );
1163  a += M_PI_2;
1164  return normalizedAngle( a );
1165 }
1166 
1167 double QgsGeometryUtils::averageAngle( double x1, double y1, double x2, double y2, double x3, double y3 )
1168 {
1169  // calc average angle between the previous and next point
1170  double a1 = lineAngle( x1, y1, x2, y2 );
1171  double a2 = lineAngle( x2, y2, x3, y3 );
1172  return averageAngle( a1, a2 );
1173 }
1174 
1175 double QgsGeometryUtils::averageAngle( double a1, double a2 )
1176 {
1177  a1 = normalizedAngle( a1 );
1178  a2 = normalizedAngle( a2 );
1179  double clockwiseDiff = 0.0;
1180  if ( a2 >= a1 )
1181  {
1182  clockwiseDiff = a2 - a1;
1183  }
1184  else
1185  {
1186  clockwiseDiff = a2 + ( 2 * M_PI - a1 );
1187  }
1188  double counterClockwiseDiff = 2 * M_PI - clockwiseDiff;
1189 
1190  double resultAngle = 0;
1191  if ( clockwiseDiff <= counterClockwiseDiff )
1192  {
1193  resultAngle = a1 + clockwiseDiff / 2.0;
1194  }
1195  else
1196  {
1197  resultAngle = a1 - counterClockwiseDiff / 2.0;
1198  }
1199  return normalizedAngle( resultAngle );
1200 }
1201 
1203 {
1204  bool rc = false;
1205 
1206  for ( const QgsPoint &pt : points )
1207  {
1208  if ( pt.is3D() )
1209  {
1210  point.convertTo( QgsWkbTypes::addZ( point.wkbType() ) );
1211  point.setZ( pt.z() );
1212  rc = true;
1213  break;
1214  }
1215  }
1216 
1217  return rc;
1218 }
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 QString pointsToJSON(const QgsPointSequence &points, int precision)
Returns a geoJSON coordinates string.
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 segmentIntersection(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q1, const QgsPoint &q2, QgsPoint &intersectionPoint, bool &isIntersection, const double tolerance=1e-8, bool acceptImproperIntersection=false)
Compute the intersection between two segments.
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 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:485
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:216
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)
Angle between two linear segments.
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.cpp:587
static double gradient(const QgsPoint &pt1, const QgsPoint &pt2)
Return 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
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.
virtual double closestSegment(const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf=nullptr, double epsilon=4 *DBL_EPSILON) const =0
Searches for the closest segment of the geometry to a given point.
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 given coordinate.
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:768
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:251
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.
double sqrDist(double x, double y) const
Returns the squared distance between this point a specified x, y coordinate.
Definition: qgspointxy.cpp:68
virtual double length() const
Returns the length of the geometry.
static bool circleClockwise(double angle1, double angle2, double angle3)
Returns true if circle 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:67
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:889
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
static QDomElement pointsToGML2(const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns)
Returns a gml::coordinates DOM element.
Utility class for identifying a unique vertex within a geometry.
const double DEFAULT_SEGMENT_EPSILON
Default snapping tolerance for segments.
Definition: qgis.h:465
Geometry collection.
static QgsPoint midpoint(const QgsPoint &pt1, const QgsPoint &pt2)
Returns a middle point between points pt1 and pt2.
static QDomElement pointsToGML3(const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, bool is3D)
Returns a gml::posList DOM element.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:237
static Type addZ(Type type)
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:864
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 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.
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
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:27
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 bool lineCircleIntersection(const QgsPointXY &center, const double radius, const QgsPointXY &linePoint1, const QgsPointXY &linePoint2, QgsPointXY &intersection)
Compute the intersection of a line and a circle.
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:41
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 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:548
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
Definition: qgspoint.cpp:496
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
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:818
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 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)
Return 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