QGIS API Documentation  2.18.3-Las Palmas (77b8c3d)
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 "qgscurvev2.h"
19 #include "qgscurvepolygonv2.h"
21 #include "qgslinestringv2.h"
22 #include "qgswkbptr.h"
23 
24 #include <QStringList>
25 #include <QVector>
26 
28 {
29  QList< QgsLineStringV2* > linestrings;
30  if ( !geom )
31  return linestrings;
32 
34  geometries << geom;
35  while ( ! geometries.isEmpty() )
36  {
37  const QgsAbstractGeometryV2* g = geometries.takeFirst();
38  if ( const QgsCurveV2* curve = dynamic_cast< const QgsCurveV2* >( g ) )
39  {
40  linestrings << static_cast< QgsLineStringV2* >( curve->segmentize() );
41  }
42  else if ( const QgsGeometryCollectionV2* collection = dynamic_cast< const QgsGeometryCollectionV2* >( g ) )
43  {
44  for ( int i = 0; i < collection->numGeometries(); ++i )
45  {
46  geometries.append( collection->geometryN( i ) );
47  }
48  }
49  else if ( const QgsCurvePolygonV2* curvePolygon = dynamic_cast< const QgsCurvePolygonV2* >( g ) )
50  {
51  if ( curvePolygon->exteriorRing() )
52  linestrings << static_cast< QgsLineStringV2* >( curvePolygon->exteriorRing()->segmentize() );
53 
54  for ( int i = 0; i < curvePolygon->numInteriorRings(); ++i )
55  {
56  linestrings << static_cast< QgsLineStringV2* >( curvePolygon->interiorRing( i )->segmentize() );
57  }
58  }
59  }
60  return linestrings;
61 }
62 
64 {
65  double minDist = std::numeric_limits<double>::max();
66  double currentDist = 0;
67  QgsPointV2 minDistPoint;
68  id = QgsVertexId(); // set as invalid
69 
70  QgsVertexId vertexId;
71  QgsPointV2 vertex;
72  while ( geom.nextVertex( vertexId, vertex ) )
73  {
74  currentDist = QgsGeometryUtils::sqrDistance2D( pt, vertex );
75  // The <= is on purpose: for geometries with closing vertices, this ensures
76  // that the closing vertex is retuned. For the node tool, the rubberband
77  // of the closing vertex is above the opening vertex, hence with the <=
78  // situations where the covered opening vertex rubberband is selected are
79  // avoided.
80  if ( currentDist <= minDist )
81  {
82  minDist = currentDist;
83  minDistPoint = vertex;
84  id.part = vertexId.part;
85  id.ring = vertexId.ring;
86  id.vertex = vertexId.vertex;
87  id.type = vertexId.type;
88  }
89  }
90 
91  return minDistPoint;
92 }
93 
95 {
96  double currentDist = 0;
97  QgsVertexId vertexId;
98  QgsPointV2 vertex;
99  QgsPointV2 previousVertex;
100 
101  bool first = true;
102  while ( geom.nextVertex( vertexId, vertex ) )
103  {
104  if ( !first )
105  {
106  currentDist += sqrt( QgsGeometryUtils::sqrDistance2D( previousVertex, vertex ) );
107  }
108 
109  previousVertex = vertex;
110  first = false;
111 
112  if ( vertexId == id )
113  {
114  //found target vertex
115  return currentDist;
116  }
117  }
118 
119  //could not find target vertex
120  return -1;
121 }
122 
123 bool QgsGeometryUtils::verticesAtDistance( const QgsAbstractGeometryV2& geometry, double distance, QgsVertexId& previousVertex, QgsVertexId& nextVertex )
124 {
125  double currentDist = 0;
126  previousVertex = QgsVertexId();
127  nextVertex = QgsVertexId();
128 
129  QgsPointV2 point;
130  QgsPointV2 previousPoint;
131 
132  if ( qgsDoubleNear( distance, 0.0 ) )
133  {
134  geometry.nextVertex( previousVertex, point );
135  nextVertex = previousVertex;
136  return true;
137  }
138 
139  bool first = true;
140  while ( currentDist < distance && geometry.nextVertex( nextVertex, point ) )
141  {
142  if ( !first )
143  {
144  currentDist += sqrt( QgsGeometryUtils::sqrDistance2D( previousPoint, point ) );
145  }
146 
147  if ( qgsDoubleNear( currentDist, distance ) )
148  {
149  // exact hit!
150  previousVertex = nextVertex;
151  return true;
152  }
153 
154  if ( currentDist > distance )
155  {
156  return true;
157  }
158 
159  previousVertex = nextVertex;
160  previousPoint = point;
161  first = false;
162  }
163 
164  //could not find target distance
165  return false;
166 }
167 
168 void QgsGeometryUtils::adjacentVertices( const QgsAbstractGeometryV2& geom, QgsVertexId atVertex, QgsVertexId& beforeVertex, QgsVertexId& afterVertex )
169 {
170  bool polygonType = ( geom.dimension() == 2 );
171 
173 
174  //get feature
175  if ( coords.size() <= atVertex.part )
176  {
177  return; //error, no such feature
178  }
179 
180  const QgsRingSequenceV2 &part = coords.at( atVertex.part );
181 
182  //get ring
183  if ( part.size() <= atVertex.ring )
184  {
185  return; //error, no such ring
186  }
187  const QgsPointSequenceV2 &ring = part.at( atVertex.ring );
188  if ( ring.size() <= atVertex.vertex )
189  {
190  return;
191  }
192 
193  //vertex in the middle
194  if ( atVertex.vertex > 0 && atVertex.vertex < ring.size() - 1 )
195  {
196  beforeVertex.part = atVertex.part;
197  beforeVertex.ring = atVertex.ring;
198  beforeVertex.vertex = atVertex.vertex - 1;
199  afterVertex.part = atVertex.part;
200  afterVertex.ring = atVertex.ring;
201  afterVertex.vertex = atVertex.vertex + 1;
202  }
203  else if ( atVertex.vertex == 0 )
204  {
205  if ( ring.size() > 1 )
206  {
207  afterVertex.part = atVertex.part;
208  afterVertex.ring = atVertex.ring;
209  afterVertex.vertex = atVertex.vertex + 1;
210  }
211  else
212  {
213  afterVertex = QgsVertexId(); //after vertex invalid
214  }
215  if ( polygonType && ring.size() > 3 )
216  {
217  beforeVertex.part = atVertex.part;
218  beforeVertex.ring = atVertex.ring;
219  beforeVertex.vertex = ring.size() - 2;
220  }
221  else
222  {
223  beforeVertex = QgsVertexId(); //before vertex invalid
224  }
225  }
226  else if ( atVertex.vertex == ring.size() - 1 )
227  {
228  beforeVertex.part = atVertex.part;
229  beforeVertex.ring = atVertex.ring;
230  beforeVertex.vertex = atVertex.vertex - 1;
231  if ( polygonType )
232  {
233  afterVertex.part = atVertex.part;
234  afterVertex.ring = atVertex.ring;
235  afterVertex.vertex = 1;
236  }
237  else
238  {
239  afterVertex = QgsVertexId(); //after vertex invalid
240  }
241  }
242 }
243 
244 double QgsGeometryUtils::sqrDistance2D( const QgsPointV2& pt1, const QgsPointV2& pt2 )
245 {
246  return ( pt1.x() - pt2.x() ) * ( pt1.x() - pt2.x() ) + ( pt1.y() - pt2.y() ) * ( pt1.y() - pt2.y() );
247 }
248 
249 double QgsGeometryUtils::sqrDistToLine( double ptX, double ptY, double x1, double y1, double x2, double y2, double& minDistX, double& minDistY, double epsilon )
250 {
251  minDistX = x1;
252  minDistY = y1;
253 
254  double dx = x2 - x1;
255  double dy = y2 - y1;
256 
257  if ( !qgsDoubleNear( dx, 0.0 ) || !qgsDoubleNear( dy, 0.0 ) )
258  {
259  double t = (( ptX - x1 ) * dx + ( ptY - y1 ) * dy ) / ( dx * dx + dy * dy );
260  if ( t > 1 )
261  {
262  minDistX = x2;
263  minDistY = y2;
264  }
265  else if ( t > 0 )
266  {
267  minDistX += dx * t ;
268  minDistY += dy * t ;
269  }
270  }
271 
272  dx = ptX - minDistX;
273  dy = ptY - minDistY;
274 
275  double dist = dx * dx + dy * dy;
276 
277  //prevent rounding errors if the point is directly on the segment
278  if ( qgsDoubleNear( dist, 0.0, epsilon ) )
279  {
280  minDistX = ptX;
281  minDistY = ptY;
282  return 0.0;
283  }
284 
285  return dist;
286 }
287 
289 {
290  double d = v.y() * w.x() - v.x() * w.y();
291 
292  if ( qgsDoubleNear( d, 0 ) )
293  return false;
294 
295  double dx = q1.x() - p1.x();
296  double dy = q1.y() - p1.y();
297  double k = ( dy * w.x() - dx * w.y() ) / d;
298 
299  inter = QgsPointV2( p1.x() + v.x() * k, p1.y() + v.y() * k );
300 
301  return true;
302 }
303 
304 bool QgsGeometryUtils::segmentIntersection( const QgsPointV2 &p1, const QgsPointV2 &p2, const QgsPointV2 &q1, const QgsPointV2 &q2, QgsPointV2 &inter, double tolerance )
305 {
306  QgsVector v( p2.x() - p1.x(), p2.y() - p1.y() );
307  QgsVector w( q2.x() - q1.x(), q2.y() - q1.y() );
308  double vl = v.length();
309  double wl = w.length();
310 
311  if ( qFuzzyIsNull( vl ) || qFuzzyIsNull( wl ) )
312  {
313  return false;
314  }
315  v = v / vl;
316  w = w / wl;
317 
318  if ( !QgsGeometryUtils::lineIntersection( p1, v, q1, w, inter ) )
319  return false;
320 
321  double lambdav = QgsVector( inter.x() - p1.x(), inter.y() - p1.y() ) * v;
322  if ( lambdav < 0. + tolerance || lambdav > vl - tolerance )
323  return false;
324 
325  double lambdaw = QgsVector( inter.x() - q1.x(), inter.y() - q1.y() ) * w;
326  if ( lambdaw < 0. + tolerance || lambdaw >= wl - tolerance )
327  return false;
328 
329  return true;
330 }
331 
333 {
334  QList<SelfIntersection> intersections;
335 
336  int n = geom->vertexCount( part, ring );
337  bool isClosed = geom->vertexAt( QgsVertexId( part, ring, 0 ) ) == geom->vertexAt( QgsVertexId( part, ring, n - 1 ) );
338 
339  // Check every pair of segments for intersections
340  for ( int i = 0, j = 1; j < n; i = j++ )
341  {
342  QgsPointV2 pi = geom->vertexAt( QgsVertexId( part, ring, i ) );
343  QgsPointV2 pj = geom->vertexAt( QgsVertexId( part, ring, j ) );
344  if ( QgsGeometryUtils::sqrDistance2D( pi, pj ) < tolerance * tolerance ) continue;
345 
346  // Don't test neighboring edges
347  int start = j + 1;
348  int end = i == 0 && isClosed ? n - 1 : n;
349  for ( int k = start, l = start + 1; l < end; k = l++ )
350  {
351  QgsPointV2 pk = geom->vertexAt( QgsVertexId( part, ring, k ) );
352  QgsPointV2 pl = geom->vertexAt( QgsVertexId( part, ring, l ) );
353 
354  QgsPointV2 inter;
355  if ( !QgsGeometryUtils::segmentIntersection( pi, pj, pk, pl, inter, tolerance ) ) continue;
356 
358  s.segment1 = i;
359  s.segment2 = k;
360  if ( s.segment1 > s.segment2 )
361  {
362  qSwap( s.segment1, s.segment2 );
363  }
364  s.point = inter;
365  intersections.append( s );
366  }
367  }
368  return intersections;
369 }
370 
371 double QgsGeometryUtils::leftOfLine( double x, double y, double x1, double y1, double x2, double y2 )
372 {
373  double f1 = x - x1;
374  double f2 = y2 - y1;
375  double f3 = y - y1;
376  double f4 = x2 - x1;
377  return f1*f2 - f3*f4;
378 }
379 
380 QgsPointV2 QgsGeometryUtils::pointOnLineWithDistance( const QgsPointV2& startPoint, const QgsPointV2& directionPoint, double distance )
381 {
382  double dx = directionPoint.x() - startPoint.x();
383  double dy = directionPoint.y() - startPoint.y();
384  double length = sqrt( dx * dx + dy * dy );
385 
386  if ( qgsDoubleNear( length, 0.0 ) )
387  {
388  return startPoint;
389  }
390 
391  double scaleFactor = distance / length;
392  return QgsPointV2( startPoint.x() + dx * scaleFactor, startPoint.y() + dy * scaleFactor );
393 }
394 
395 double QgsGeometryUtils::ccwAngle( double dy, double dx )
396 {
397  double angle = atan2( dy, dx ) * 180 / M_PI;
398  if ( angle < 0 )
399  {
400  return 360 + angle;
401  }
402  else if ( angle > 360 )
403  {
404  return 360 - angle;
405  }
406  return angle;
407 }
408 
409 void QgsGeometryUtils::circleCenterRadius( const QgsPointV2& pt1, const QgsPointV2& pt2, const QgsPointV2& pt3, double& radius, double& centerX, double& centerY )
410 {
411  double dx21, dy21, dx31, dy31, h21, h31, d;
412 
413  //closed circle
414  if ( qgsDoubleNear( pt1.x(), pt3.x() ) && qgsDoubleNear( pt1.y(), pt3.y() ) )
415  {
416  centerX = ( pt1.x() + pt2.x() ) / 2.0;
417  centerY = ( pt1.y() + pt2.y() ) / 2.0;
418  radius = sqrt( pow( centerX - pt1.x(), 2.0 ) + pow( centerY - pt1.y(), 2.0 ) );
419  return;
420  }
421 
422  // Using cartesian circumcenter eguations from page https://en.wikipedia.org/wiki/Circumscribed_circle
423  dx21 = pt2.x() - pt1.x();
424  dy21 = pt2.y() - pt1.y();
425  dx31 = pt3.x() - pt1.x();
426  dy31 = pt3.y() - pt1.y();
427 
428  h21 = pow( dx21, 2.0 ) + pow( dy21, 2.0 );
429  h31 = pow( dx31, 2.0 ) + pow( dy31, 2.0 );
430 
431  // 2*Cross product, d<0 means clockwise and d>0 counterclockwise sweeping angle
432  d = 2 * ( dx21 * dy31 - dx31 * dy21 );
433 
434  // Check colinearity, Cross product = 0
435  if ( qgsDoubleNear( fabs( d ), 0.0, 0.00000000001 ) )
436  {
437  radius = -1.0;
438  return;
439  }
440 
441  // Calculate centroid coordinates and radius
442  centerX = pt1.x() + ( h21 * dy31 - h31 * dy21 ) / d;
443  centerY = pt1.y() - ( h21 * dx31 - h31 * dx21 ) / d;
444  radius = sqrt( pow( centerX - pt1.x(), 2.0 ) + pow( centerY - pt1.y(), 2.0 ) );
445 }
446 
447 bool QgsGeometryUtils::circleClockwise( double angle1, double angle2, double angle3 )
448 {
449  if ( angle3 >= angle1 )
450  {
451  if ( angle2 > angle1 && angle2 < angle3 )
452  {
453  return false;
454  }
455  else
456  {
457  return true;
458  }
459  }
460  else
461  {
462  if ( angle2 > angle1 || angle2 < angle3 )
463  {
464  return false;
465  }
466  else
467  {
468  return true;
469  }
470  }
471 }
472 
473 bool QgsGeometryUtils::circleAngleBetween( double angle, double angle1, double angle2, bool clockwise )
474 {
475  if ( clockwise )
476  {
477  if ( angle2 < angle1 )
478  {
479  return ( angle <= angle1 && angle >= angle2 );
480  }
481  else
482  {
483  return ( angle <= angle1 || angle >= angle2 );
484  }
485  }
486  else
487  {
488  if ( angle2 > angle1 )
489  {
490  return ( angle >= angle1 && angle <= angle2 );
491  }
492  else
493  {
494  return ( angle >= angle1 || angle <= angle2 );
495  }
496  }
497 }
498 
499 bool QgsGeometryUtils::angleOnCircle( double angle, double angle1, double angle2, double angle3 )
500 {
501  bool clockwise = circleClockwise( angle1, angle2, angle3 );
502  return circleAngleBetween( angle, angle1, angle3, clockwise );
503 }
504 
505 double QgsGeometryUtils::circleLength( double x1, double y1, double x2, double y2, double x3, double y3 )
506 {
507  double centerX, centerY, radius;
508  circleCenterRadius( QgsPointV2( x1, y1 ), QgsPointV2( x2, y2 ), QgsPointV2( x3, y3 ), radius, centerX, centerY );
509  double length = M_PI / 180.0 * radius * sweepAngle( centerX, centerY, x1, y1, x2, y2, x3, y3 );
510  if ( length < 0 )
511  {
512  length = -length;
513  }
514  return length;
515 }
516 
517 double QgsGeometryUtils::sweepAngle( double centerX, double centerY, double x1, double y1, double x2, double y2, double x3, double y3 )
518 {
519  double p1Angle = QgsGeometryUtils::ccwAngle( y1 - centerY, x1 - centerX );
520  double p2Angle = QgsGeometryUtils::ccwAngle( y2 - centerY, x2 - centerX );
521  double p3Angle = QgsGeometryUtils::ccwAngle( y3 - centerY, x3 - centerX );
522 
523  if ( p3Angle >= p1Angle )
524  {
525  if ( p2Angle > p1Angle && p2Angle < p3Angle )
526  {
527  return( p3Angle - p1Angle );
528  }
529  else
530  {
531  return ( - ( p1Angle + ( 360 - p3Angle ) ) );
532  }
533  }
534  else
535  {
536  if ( p2Angle < p1Angle && p2Angle > p3Angle )
537  {
538  return( -( p1Angle - p3Angle ) );
539  }
540  else
541  {
542  return( p3Angle + ( 360 - p1Angle ) );
543  }
544  }
545 }
546 
547 bool QgsGeometryUtils::segmentMidPoint( const QgsPointV2& p1, const QgsPointV2& p2, QgsPointV2& result, double radius, const QgsPointV2& mousePos )
548 {
549  QgsPointV2 midPoint(( p1.x() + p2.x() ) / 2.0, ( p1.y() + p2.y() ) / 2.0 );
550  double midDist = sqrt( sqrDistance2D( p1, midPoint ) );
551  if ( radius < midDist )
552  {
553  return false;
554  }
555  double centerMidDist = sqrt( radius * radius - midDist * midDist );
556  double dist = radius - centerMidDist;
557 
558  double midDx = midPoint.x() - p1.x();
559  double midDy = midPoint.y() - p1.y();
560 
561  //get the four possible midpoints
562  QVector<QgsPointV2> possibleMidPoints;
563  possibleMidPoints.append( pointOnLineWithDistance( midPoint, QgsPointV2( midPoint.x() - midDy, midPoint.y() + midDx ), dist ) );
564  possibleMidPoints.append( pointOnLineWithDistance( midPoint, QgsPointV2( midPoint.x() - midDy, midPoint.y() + midDx ), 2 * radius - dist ) );
565  possibleMidPoints.append( pointOnLineWithDistance( midPoint, QgsPointV2( midPoint.x() + midDy, midPoint.y() - midDx ), dist ) );
566  possibleMidPoints.append( pointOnLineWithDistance( midPoint, QgsPointV2( midPoint.x() + midDy, midPoint.y() - midDx ), 2 * radius - dist ) );
567 
568  //take the closest one
569  double minDist = std::numeric_limits<double>::max();
570  int minDistIndex = -1;
571  for ( int i = 0; i < possibleMidPoints.size(); ++i )
572  {
573  double currentDist = sqrDistance2D( mousePos, possibleMidPoints.at( i ) );
574  if ( currentDist < minDist )
575  {
576  minDistIndex = i;
577  minDist = currentDist;
578  }
579  }
580 
581  if ( minDistIndex == -1 )
582  {
583  return false;
584  }
585 
586  result = possibleMidPoints.at( minDistIndex );
587  return true;
588 }
589 
590 double QgsGeometryUtils::circleTangentDirection( const QgsPointV2& tangentPoint, const QgsPointV2& cp1,
591  const QgsPointV2& cp2, const QgsPointV2& cp3 )
592 {
593  //calculate circle midpoint
594  double mX, mY, radius;
595  circleCenterRadius( cp1, cp2, cp3, radius, mX, mY );
596 
597  double p1Angle = QgsGeometryUtils::ccwAngle( cp1.y() - mY, cp1.x() - mX );
598  double p2Angle = QgsGeometryUtils::ccwAngle( cp2.y() - mY, cp2.x() - mX );
599  double p3Angle = QgsGeometryUtils::ccwAngle( cp3.y() - mY, cp3.x() - mX );
600  if ( circleClockwise( p1Angle, p2Angle, p3Angle ) )
601  {
602  return lineAngle( tangentPoint.x(), tangentPoint.y(), mX, mY );
603  }
604  else
605  {
606  return lineAngle( mX, mY, tangentPoint.x(), tangentPoint.y() );
607  }
608 }
609 
610 QgsPointSequenceV2 QgsGeometryUtils::pointsFromWKT( const QString &wktCoordinateList, bool is3D, bool isMeasure )
611 {
612  int dim = 2 + is3D + isMeasure;
613  QgsPointSequenceV2 points;
614  QStringList coordList = wktCoordinateList.split( ',', QString::SkipEmptyParts );
615 
616  //first scan through for extra unexpected dimensions
617  bool foundZ = false;
618  bool foundM = false;
619  Q_FOREACH ( const QString& pointCoordinates, coordList )
620  {
621  QStringList coordinates = pointCoordinates.split( ' ', QString::SkipEmptyParts );
622  if ( coordinates.size() == 3 && !foundZ && !foundM && !is3D && !isMeasure )
623  {
624  // 3 dimensional coordinates, but not specifically marked as such. We allow this
625  // anyway and upgrade geometry to have Z dimension
626  foundZ = true;
627  }
628  else if ( coordinates.size() >= 4 && ( !( is3D || foundZ ) || !( isMeasure || foundM ) ) )
629  {
630  // 4 (or more) dimensional coordinates, but not specifically marked as such. We allow this
631  // anyway and upgrade geometry to have Z&M dimensions
632  foundZ = true;
633  foundM = true;
634  }
635  }
636 
637  Q_FOREACH ( const QString& pointCoordinates, coordList )
638  {
639  QStringList coordinates = pointCoordinates.split( ' ', QString::SkipEmptyParts );
640  if ( coordinates.size() < dim )
641  continue;
642 
643  int idx = 0;
644  double x = coordinates[idx++].toDouble();
645  double y = coordinates[idx++].toDouble();
646 
647  double z = 0;
648  if (( is3D || foundZ ) && coordinates.length() > idx )
649  z = coordinates[idx++].toDouble();
650 
651  double m = 0;
652  if (( isMeasure || foundM ) && coordinates.length() > idx )
653  m = coordinates[idx++].toDouble();
654 
656  if ( is3D || foundZ )
657  {
658  if ( isMeasure || foundM )
660  else
662  }
663  else
664  {
665  if ( isMeasure || foundM )
667  else
668  t = QgsWKBTypes::Point;
669  }
670 
671  points.append( QgsPointV2( t, x, y, z, m ) );
672  }
673 
674  return points;
675 }
676 
677 void QgsGeometryUtils::pointsToWKB( QgsWkbPtr& wkb, const QgsPointSequenceV2 &points, bool is3D, bool isMeasure )
678 {
679  wkb << static_cast<quint32>( points.size() );
680  Q_FOREACH ( const QgsPointV2& point, points )
681  {
682  wkb << point.x() << point.y();
683  if ( is3D )
684  {
685  wkb << point.z();
686  }
687  if ( isMeasure )
688  {
689  wkb << point.m();
690  }
691  }
692 }
693 
694 QString QgsGeometryUtils::pointsToWKT( const QgsPointSequenceV2 &points, int precision, bool is3D, bool isMeasure )
695 {
696  QString wkt = "(";
697  Q_FOREACH ( const QgsPointV2& p, points )
698  {
699  wkt += qgsDoubleToString( p.x(), precision );
700  wkt += ' ' + qgsDoubleToString( p.y(), precision );
701  if ( is3D )
702  wkt += ' ' + qgsDoubleToString( p.z(), precision );
703  if ( isMeasure )
704  wkt += ' ' + qgsDoubleToString( p.m(), precision );
705  wkt += ", ";
706  }
707  if ( wkt.endsWith( ", " ) )
708  wkt.chop( 2 ); // Remove last ", "
709  wkt += ')';
710  return wkt;
711 }
712 
713 QDomElement QgsGeometryUtils::pointsToGML2( const QgsPointSequenceV2 &points, QDomDocument& doc, int precision, const QString &ns )
714 {
715  QDomElement elemCoordinates = doc.createElementNS( ns, "coordinates" );
716 
717  QString strCoordinates;
718 
719  Q_FOREACH ( const QgsPointV2& p, points )
720  strCoordinates += qgsDoubleToString( p.x(), precision ) + ',' + qgsDoubleToString( p.y(), precision ) + ' ';
721 
722  if ( strCoordinates.endsWith( ' ' ) )
723  strCoordinates.chop( 1 ); // Remove trailing space
724 
725  elemCoordinates.appendChild( doc.createTextNode( strCoordinates ) );
726  return elemCoordinates;
727 }
728 
729 QDomElement QgsGeometryUtils::pointsToGML3( const QgsPointSequenceV2 &points, QDomDocument& doc, int precision, const QString &ns, bool is3D )
730 {
731  QDomElement elemPosList = doc.createElementNS( ns, "posList" );
732  elemPosList.setAttribute( "srsDimension", is3D ? 3 : 2 );
733 
734  QString strCoordinates;
735  Q_FOREACH ( const QgsPointV2& p, points )
736  {
737  strCoordinates += qgsDoubleToString( p.x(), precision ) + ' ' + qgsDoubleToString( p.y(), precision ) + ' ';
738  if ( is3D )
739  strCoordinates += qgsDoubleToString( p.z(), precision ) + ' ';
740  }
741  if ( strCoordinates.endsWith( ' ' ) )
742  strCoordinates.chop( 1 ); // Remove trailing space
743 
744  elemPosList.appendChild( doc.createTextNode( strCoordinates ) );
745  return elemPosList;
746 }
747 
749 {
750  QString json = "[ ";
751  Q_FOREACH ( const QgsPointV2& p, points )
752  {
753  json += '[' + qgsDoubleToString( p.x(), precision ) + ", " + qgsDoubleToString( p.y(), precision ) + "], ";
754  }
755  if ( json.endsWith( ", " ) )
756  {
757  json.chop( 2 ); // Remove last ", "
758  }
759  json += ']';
760  return json;
761 }
762 
764 {
765  double clippedAngle = angle;
766  if ( clippedAngle >= M_PI * 2 || clippedAngle <= -2 * M_PI )
767  {
768  clippedAngle = fmod( clippedAngle, 2 * M_PI );
769  }
770  if ( clippedAngle < 0.0 )
771  {
772  clippedAngle += 2 * M_PI;
773  }
774  return clippedAngle;
775 }
776 
778 {
779  QgsWKBTypes::Type wkbType = QgsWKBTypes::parseType( wkt );
780 
781  QRegExp cooRegEx( "^[^\\(]*\\((.*)\\)[^\\)]*$" );
782  QString contents = cooRegEx.indexIn( wkt ) >= 0 ? cooRegEx.cap( 1 ) : QString();
783  return qMakePair( wkbType, contents );
784 }
785 
787 {
788  int level = 0;
789  QString block;
790  QStringList blocks;
791  for ( int i = 0, n = wkt.length(); i < n; ++i )
792  {
793  if ( wkt[i].isSpace() && level == 0 )
794  continue;
795 
796  if ( wkt[i] == ',' && level == 0 )
797  {
798  if ( !block.isEmpty() )
799  {
800  if ( block.startsWith( '(' ) && !defaultType.isEmpty() )
801  block.prepend( defaultType + ' ' );
802  blocks.append( block );
803  }
804  block.clear();
805  continue;
806  }
807  if ( wkt[i] == '(' )
808  ++level;
809  else if ( wkt[i] == ')' )
810  --level;
811  block += wkt[i];
812  }
813  if ( !block.isEmpty() )
814  {
815  if ( block.startsWith( '(' ) && !defaultType.isEmpty() )
816  block.prepend( defaultType + ' ' );
817  blocks.append( block );
818  }
819  return blocks;
820 }
821 
822 double QgsGeometryUtils::lineAngle( double x1, double y1, double x2, double y2 )
823 {
824  double at = atan2( y2 - y1, x2 - x1 );
825  double a = -at + M_PI / 2.0;
826  return normalizedAngle( a );
827 }
828 
829 double QgsGeometryUtils::linePerpendicularAngle( double x1, double y1, double x2, double y2 )
830 {
831  double a = lineAngle( x1, y1, x2, y2 );
832  a += ( M_PI / 2.0 );
833  return normalizedAngle( a );
834 }
835 
836 double QgsGeometryUtils::averageAngle( double x1, double y1, double x2, double y2, double x3, double y3 )
837 {
838  // calc average angle between the previous and next point
839  double a1 = lineAngle( x1, y1, x2, y2 );
840  double a2 = lineAngle( x2, y2, x3, y3 );
841  return averageAngle( a1, a2 );
842 }
843 
844 double QgsGeometryUtils::averageAngle( double a1, double a2 )
845 {
846  a1 = normalizedAngle( a1 );
847  a2 = normalizedAngle( a2 );
848  double clockwiseDiff = 0.0;
849  if ( a2 >= a1 )
850  {
851  clockwiseDiff = a2 - a1;
852  }
853  else
854  {
855  clockwiseDiff = a2 + ( 2 * M_PI - a1 );
856  }
857  double counterClockwiseDiff = 2 * M_PI - clockwiseDiff;
858 
859  double resultAngle = 0;
860  if ( clockwiseDiff <= counterClockwiseDiff )
861  {
862  resultAngle = a1 + clockwiseDiff / 2.0;
863  }
864  else
865  {
866  resultAngle = a1 - counterClockwiseDiff / 2.0;
867  }
868  return normalizedAngle( resultAngle );
869 }
static QgsPointV2 pointOnLineWithDistance(const QgsPointV2 &startPoint, const QgsPointV2 &directionPoint, double distance)
Returns a point a specified distance toward a second point.
QString cap(int nth) const
static double circleTangentDirection(const QgsPointV2 &tangentPoint, const QgsPointV2 &cp1, const QgsPointV2 &cp2, const QgsPointV2 &cp3)
Calculates the direction angle of a circle tangent (clockwise from north in radians) ...
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 bool circleAngleBetween(double angle, double angle1, double angle2, bool clockwise)
Returns true if, in a circle, angle is between angle1 and angle2.
static bool verticesAtDistance(const QgsAbstractGeometryV2 &geometry, double distance, QgsVertexId &previousVertex, QgsVertexId &nextVertex)
Retrieves the vertices which are before and after the interpolated point at a specified distance alon...
virtual QgsCoordinateSequenceV2 coordinateSequence() const =0
Retrieves the sequence of geometries, rings and nodes.
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...
QDomNode appendChild(const QDomNode &newChild)
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 append(const T &value)
double x() const
Returns the point&#39;s x-coordinate.
Definition: qgspointv2.h:68
static double distanceToVertex(const QgsAbstractGeometryV2 &geom, const QgsVertexId &id)
Returns the distance along a geometry from its first vertex to the specified vertex.
int length() const
static double averageAngle(double x1, double y1, double x2, double y2, double x3, double y3)
Angle between two linear segments.
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequenceV2 &points, bool is3D, bool isMeasure)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
QString & prepend(QChar ch)
static bool lineIntersection(const QgsPointV2 &p1, QgsVector v, const QgsPointV2 &q1, QgsVector w, QgsPointV2 &inter)
Compute the intersection between two lines.
const T & at(int i) const
static void circleCenterRadius(const QgsPointV2 &pt1, const QgsPointV2 &pt2, const QgsPointV2 &pt3, double &radius, double &centerX, double &centerY)
Returns radius and center of the circle through pt1, pt2, pt3.
static QString pointsToJSON(const QgsPointSequenceV2 &points, int precision)
Returns a geoJSON coordinates string.
Abstract base class for all geometries.
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: qgspoint.cpp:73
static QStringList wktGetChildBlocks(const QString &wkt, const QString &defaultType="")
Parses a WKT string and returns of list of blocks contained in the WKT.
static QgsPointV2 closestVertex(const QgsAbstractGeometryV2 &geom, const QgsPointV2 &pt, QgsVertexId &id)
Returns the closest vertex to a geometry for a specified point.
static double leftOfLine(double x, double y, double x1, double y1, double x2, double y2)
Returns < 0 if point(x/y) is left of the line x1,y1 -> x2,y2.
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.
QDomElement createElementNS(const QString &nsURI, const QString &qName)
void chop(int n)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:353
int size() const
double y() const
Returns the point&#39;s y-coordinate.
Definition: qgspointv2.h:74
void clear()
double ANALYSIS_EXPORT max(double x, double y)
Returns the maximum of two doubles or the first argument if both are equal.
int indexIn(const QString &str, int offset, CaretMode caretMode) const
static bool circleClockwise(double angle1, double angle2, double angle3)
Returns true if circle is ordered clockwise.
void append(const T &value)
static double sqrDistance2D(const QgsPointV2 &pt1, const QgsPointV2 &pt2)
Returns the squared 2D distance between two points.
Utility class for identifying a unique vertex within a geometry.
double z() const
Returns the point&#39;s z-coordinate.
Definition: qgspointv2.h:80
static QString pointsToWKT(const QgsPointSequenceV2 &points, int precision, bool is3D, bool isMeasure)
Returns a WKT coordinate list.
static QList< SelfIntersection > getSelfIntersections(const QgsAbstractGeometryV2 *geom, int part, int ring, double tolerance)
Find self intersections in a polyline.
void setAttribute(const QString &name, const QString &value)
Point geometry type, with support for z-dimension and m-values.
Definition: qgspointv2.h:34
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:341
bool isEmpty() const
bool isEmpty() const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
#define M_PI
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
static void adjacentVertices(const QgsAbstractGeometryV2 &geom, QgsVertexId atVertex, QgsVertexId &beforeVertex, QgsVertexId &afterVertex)
Returns vertices adjacent to a specified vertex within a geometry.
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.
static bool segmentIntersection(const QgsPointV2 &p1, const QgsPointV2 &p2, const QgsPointV2 &q1, const QgsPointV2 &q2, QgsPointV2 &inter, double tolerance)
Compute the intersection between two segments.
virtual bool nextVertex(QgsVertexId &id, QgsPointV2 &vertex) const =0
Returns next vertex id and coordinates.
static double normalizedAngle(double angle)
Ensures that an angle is in the range 0 <= angle < 2 pi.
static QDomElement pointsToGML3(const QgsPointSequenceV2 &points, QDomDocument &doc, int precision, const QString &ns, bool is3D)
Returns a gml::posList DOM element.
QDomText createTextNode(const QString &value)
double ANALYSIS_EXPORT angle(Point3D *p1, Point3D *p2, Point3D *p3, Point3D *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
A class to represent a vector.
Definition: qgspoint.h:32
double length() const
Returns the length of the vector.
Definition: qgspoint.cpp:63
const T & at(int i) const
static bool segmentMidPoint(const QgsPointV2 &p1, const QgsPointV2 &p2, QgsPointV2 &result, double radius, const QgsPointV2 &mousePos)
Calculates midpoint on circle passing through p1 and p2, closest to given coordinate.
T takeFirst()
static QList< QgsLineStringV2 * > extractLineStrings(const QgsAbstractGeometryV2 *geom)
Returns list of linestrings extracted from the passed geometry.
static QgsPointSequenceV2 pointsFromWKT(const QString &wktCoordinateList, bool is3D, bool isMeasure)
Returns a list of points contained in a WKT string.
virtual int vertexCount(int part=0, int ring=0) const =0
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.
virtual int dimension() const =0
Returns the inherent dimension of the geometry.
int length() const
double m() const
Returns the point&#39;s m value.
Definition: qgspointv2.h:86
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.
static Type parseType(const QString &wktStr)
Attempts to extract the WKB type from a WKT string.
Definition: qgswkbtypes.cpp:32
Curve polygon geometry type.
double x() const
Returns the vector&#39;s x-component.
Definition: qgspoint.cpp:68
Abstract base class for curved geometry type.
Definition: qgscurvev2.h:32
int size() const
static QDomElement pointsToGML2(const QgsPointSequenceV2 &points, QDomDocument &doc, int precision, const QString &ns)
Returns a gml::coordinates DOM element.
virtual QgsPointV2 vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.