QGIS API Documentation  2.14.11-Essen
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  }
88  }
89 
90  return minDistPoint;
91 }
92 
93 void QgsGeometryUtils::adjacentVertices( const QgsAbstractGeometryV2& geom, QgsVertexId atVertex, QgsVertexId& beforeVertex, QgsVertexId& afterVertex )
94 {
95  bool polygonType = ( geom.dimension() == 2 );
96 
98 
99  //get feature
100  if ( coords.size() <= atVertex.part )
101  {
102  return; //error, no such feature
103  }
104 
105  const QgsRingSequenceV2 &part = coords.at( atVertex.part );
106 
107  //get ring
108  if ( part.size() <= atVertex.ring )
109  {
110  return; //error, no such ring
111  }
112  const QgsPointSequenceV2 &ring = part.at( atVertex.ring );
113  if ( ring.size() <= atVertex.vertex )
114  {
115  return;
116  }
117 
118  //vertex in the middle
119  if ( atVertex.vertex > 0 && atVertex.vertex < ring.size() - 1 )
120  {
121  beforeVertex.part = atVertex.part;
122  beforeVertex.ring = atVertex.ring;
123  beforeVertex.vertex = atVertex.vertex - 1;
124  afterVertex.part = atVertex.part;
125  afterVertex.ring = atVertex.ring;
126  afterVertex.vertex = atVertex.vertex + 1;
127  }
128  else if ( atVertex.vertex == 0 )
129  {
130  afterVertex.part = atVertex.part;
131  afterVertex.ring = atVertex.ring;
132  afterVertex.vertex = atVertex.vertex + 1;
133  if ( polygonType && ring.size() > 3 )
134  {
135  beforeVertex.part = atVertex.part;
136  beforeVertex.ring = atVertex.ring;
137  beforeVertex.vertex = ring.size() - 2;
138  }
139  else
140  {
141  beforeVertex = QgsVertexId(); //before vertex invalid
142  }
143  }
144  else if ( atVertex.vertex == ring.size() - 1 )
145  {
146  beforeVertex.part = atVertex.part;
147  beforeVertex.ring = atVertex.ring;
148  beforeVertex.vertex = atVertex.vertex - 1;
149  if ( polygonType )
150  {
151  afterVertex.part = atVertex.part;
152  afterVertex.ring = atVertex.ring;
153  afterVertex.vertex = 1;
154  }
155  else
156  {
157  afterVertex = QgsVertexId(); //after vertex invalid
158  }
159  }
160 }
161 
162 double QgsGeometryUtils::sqrDistance2D( const QgsPointV2& pt1, const QgsPointV2& pt2 )
163 {
164  return ( pt1.x() - pt2.x() ) * ( pt1.x() - pt2.x() ) + ( pt1.y() - pt2.y() ) * ( pt1.y() - pt2.y() );
165 }
166 
167 double QgsGeometryUtils::sqrDistToLine( double ptX, double ptY, double x1, double y1, double x2, double y2, double& minDistX, double& minDistY, double epsilon )
168 {
169  //normal vector
170  double nx = y2 - y1;
171  double ny = -( x2 - x1 );
172 
173  double t;
174  t = ( ptX * ny - ptY * nx - x1 * ny + y1 * nx ) / (( x2 - x1 ) * ny - ( y2 - y1 ) * nx );
175 
176  if ( t < 0.0 )
177  {
178  minDistX = x1;
179  minDistY = y1;
180  }
181  else if ( t > 1.0 )
182  {
183  minDistX = x2;
184  minDistY = y2;
185  }
186  else
187  {
188  minDistX = x1 + t * ( x2 - x1 );
189  minDistY = y1 + t * ( y2 - y1 );
190  }
191 
192  double dist = ( minDistX - ptX ) * ( minDistX - ptX ) + ( minDistY - ptY ) * ( minDistY - ptY );
193 
194  //prevent rounding errors if the point is directly on the segment
195  if ( qgsDoubleNear( dist, 0.0, epsilon ) )
196  {
197  minDistX = ptX;
198  minDistY = ptY;
199  return 0.0;
200  }
201 
202  return dist;
203 }
204 
206 {
207  double d = v.y() * w.x() - v.x() * w.y();
208 
209  if ( qgsDoubleNear( d, 0 ) )
210  return false;
211 
212  double dx = q1.x() - p1.x();
213  double dy = q1.y() - p1.y();
214  double k = ( dy * w.x() - dx * w.y() ) / d;
215 
216  inter = QgsPointV2( p1.x() + v.x() * k, p1.y() + v.y() * k );
217 
218  return true;
219 }
220 
221 bool QgsGeometryUtils::segmentIntersection( const QgsPointV2 &p1, const QgsPointV2 &p2, const QgsPointV2 &q1, const QgsPointV2 &q2, QgsPointV2 &inter, double tolerance )
222 {
223  QgsVector v( p2.x() - p1.x(), p2.y() - p1.y() );
224  QgsVector w( q2.x() - q1.x(), q2.y() - q1.y() );
225  double vl = v.length();
226  double wl = w.length();
227 
228  if ( qFuzzyIsNull( vl ) || qFuzzyIsNull( wl ) )
229  {
230  return false;
231  }
232  v = v / vl;
233  w = w / wl;
234 
235  if ( !QgsGeometryUtils::lineIntersection( p1, v, q1, w, inter ) )
236  return false;
237 
238  double lambdav = QgsVector( inter.x() - p1.x(), inter.y() - p1.y() ) * v;
239  if ( lambdav < 0. + tolerance || lambdav > vl - tolerance )
240  return false;
241 
242  double lambdaw = QgsVector( inter.x() - q1.x(), inter.y() - q1.y() ) * w;
243  if ( lambdaw < 0. + tolerance || lambdaw >= wl - tolerance )
244  return false;
245 
246  return true;
247 }
248 
250 {
251  QList<SelfIntersection> intersections;
252 
253  int n = geom->vertexCount( part, ring );
254  bool isClosed = geom->vertexAt( QgsVertexId( part, ring, 0 ) ) == geom->vertexAt( QgsVertexId( part, ring, n - 1 ) );
255 
256  // Check every pair of segments for intersections
257  for ( int i = 0, j = 1; j < n; i = j++ )
258  {
259  QgsPointV2 pi = geom->vertexAt( QgsVertexId( part, ring, i ) );
260  QgsPointV2 pj = geom->vertexAt( QgsVertexId( part, ring, j ) );
261  if ( QgsGeometryUtils::sqrDistance2D( pi, pj ) < tolerance * tolerance ) continue;
262 
263  // Don't test neighboring edges
264  int start = j + 1;
265  int end = i == 0 && isClosed ? n - 1 : n;
266  for ( int k = start, l = start + 1; l < end; k = l++ )
267  {
268  QgsPointV2 pk = geom->vertexAt( QgsVertexId( part, ring, k ) );
269  QgsPointV2 pl = geom->vertexAt( QgsVertexId( part, ring, l ) );
270 
271  QgsPointV2 inter;
272  if ( !QgsGeometryUtils::segmentIntersection( pi, pj, pk, pl, inter, tolerance ) ) continue;
273 
275  s.segment1 = i;
276  s.segment2 = k;
277  if ( s.segment1 > s.segment2 )
278  {
279  qSwap( s.segment1, s.segment2 );
280  }
281  s.point = inter;
282  intersections.append( s );
283  }
284  }
285  return intersections;
286 }
287 
288 double QgsGeometryUtils::leftOfLine( double x, double y, double x1, double y1, double x2, double y2 )
289 {
290  double f1 = x - x1;
291  double f2 = y2 - y1;
292  double f3 = y - y1;
293  double f4 = x2 - x1;
294  return f1*f2 - f3*f4;
295 }
296 
297 QgsPointV2 QgsGeometryUtils::pointOnLineWithDistance( const QgsPointV2& startPoint, const QgsPointV2& directionPoint, double distance )
298 {
299  double dx = directionPoint.x() - startPoint.x();
300  double dy = directionPoint.y() - startPoint.y();
301  double length = sqrt( dx * dx + dy * dy );
302 
303  if ( qgsDoubleNear( length, 0.0 ) )
304  {
305  return startPoint;
306  }
307 
308  double scaleFactor = distance / length;
309  return QgsPointV2( startPoint.x() + dx * scaleFactor, startPoint.y() + dy * scaleFactor );
310 }
311 
312 double QgsGeometryUtils::ccwAngle( double dy, double dx )
313 {
314  double angle = atan2( dy, dx ) * 180 / M_PI;
315  if ( angle < 0 )
316  {
317  return 360 + angle;
318  }
319  else if ( angle > 360 )
320  {
321  return 360 - angle;
322  }
323  return angle;
324 }
325 
326 void QgsGeometryUtils::circleCenterRadius( const QgsPointV2& pt1, const QgsPointV2& pt2, const QgsPointV2& pt3, double& radius, double& centerX, double& centerY )
327 {
328  double dx21, dy21, dx31, dy31, h21, h31, d;
329 
330  //closed circle
331  if ( qgsDoubleNear( pt1.x(), pt3.x() ) && qgsDoubleNear( pt1.y(), pt3.y() ) )
332  {
333  centerX = pt2.x();
334  centerY = pt2.y();
335  radius = sqrt( pow( pt2.x() - pt1.x(), 2.0 ) + pow( pt2.y() - pt1.y(), 2.0 ) );
336  return;
337  }
338 
339  // Using cartesian circumcenter eguations from page https://en.wikipedia.org/wiki/Circumscribed_circle
340  dx21 = pt2.x() - pt1.x();
341  dy21 = pt2.y() - pt1.y();
342  dx31 = pt3.x() - pt1.x();
343  dy31 = pt3.y() - pt1.y();
344 
345  h21 = pow( dx21, 2.0 ) + pow( dy21, 2.0 );
346  h31 = pow( dx31, 2.0 ) + pow( dy31, 2.0 );
347 
348  // 2*Cross product, d<0 means clockwise and d>0 counterclockwise sweeping angle
349  d = 2 * ( dx21 * dy31 - dx31 * dy21 );
350 
351  // Check colinearity, Cross product = 0
352  if ( qgsDoubleNear( fabs( d ), 0.0, 0.00000000001 ) )
353  {
354  radius = -1.0;
355  return;
356  }
357 
358  // Calculate centroid coordinates and radius
359  centerX = pt1.x() + ( h21 * dy31 - h31 * dy21 ) / d;
360  centerY = pt1.y() - ( h21 * dx31 - h31 * dx21 ) / d;
361  radius = sqrt( pow( centerX - pt1.x(), 2.0 ) + pow( centerY - pt1.y(), 2.0 ) );
362 }
363 
364 bool QgsGeometryUtils::circleClockwise( double angle1, double angle2, double angle3 )
365 {
366  if ( angle3 >= angle1 )
367  {
368  if ( angle2 > angle1 && angle2 < angle3 )
369  {
370  return false;
371  }
372  else
373  {
374  return true;
375  }
376  }
377  else
378  {
379  if ( angle2 > angle1 || angle2 < angle3 )
380  {
381  return false;
382  }
383  else
384  {
385  return true;
386  }
387  }
388 }
389 
390 bool QgsGeometryUtils::circleAngleBetween( double angle, double angle1, double angle2, bool clockwise )
391 {
392  if ( clockwise )
393  {
394  if ( angle2 < angle1 )
395  {
396  return ( angle <= angle1 && angle >= angle2 );
397  }
398  else
399  {
400  return ( angle <= angle1 || angle >= angle2 );
401  }
402  }
403  else
404  {
405  if ( angle2 > angle1 )
406  {
407  return ( angle >= angle1 && angle <= angle2 );
408  }
409  else
410  {
411  return ( angle >= angle1 || angle <= angle2 );
412  }
413  }
414 }
415 
416 bool QgsGeometryUtils::angleOnCircle( double angle, double angle1, double angle2, double angle3 )
417 {
418  bool clockwise = circleClockwise( angle1, angle2, angle3 );
419  return circleAngleBetween( angle, angle1, angle3, clockwise );
420 }
421 
422 double QgsGeometryUtils::circleLength( double x1, double y1, double x2, double y2, double x3, double y3 )
423 {
424  double centerX, centerY, radius;
425  circleCenterRadius( QgsPointV2( x1, y1 ), QgsPointV2( x2, y2 ), QgsPointV2( x3, y3 ), radius, centerX, centerY );
426  double length = M_PI / 180.0 * radius * sweepAngle( centerX, centerY, x1, y1, x2, y2, x3, y3 );
427  if ( length < 0 )
428  {
429  length = -length;
430  }
431  return length;
432 }
433 
434 double QgsGeometryUtils::sweepAngle( double centerX, double centerY, double x1, double y1, double x2, double y2, double x3, double y3 )
435 {
436  double p1Angle = QgsGeometryUtils::ccwAngle( y1 - centerY, x1 - centerX );
437  double p2Angle = QgsGeometryUtils::ccwAngle( y2 - centerY, x2 - centerX );
438  double p3Angle = QgsGeometryUtils::ccwAngle( y3 - centerY, x3 - centerX );
439 
440  if ( p3Angle >= p1Angle )
441  {
442  if ( p2Angle > p1Angle && p2Angle < p3Angle )
443  {
444  return( p3Angle - p1Angle );
445  }
446  else
447  {
448  return ( - ( p1Angle + ( 360 - p3Angle ) ) );
449  }
450  }
451  else
452  {
453  if ( p2Angle < p1Angle && p2Angle > p3Angle )
454  {
455  return( -( p1Angle - p3Angle ) );
456  }
457  else
458  {
459  return( p3Angle + ( 360 - p1Angle ) );
460  }
461  }
462 }
463 
464 bool QgsGeometryUtils::segmentMidPoint( const QgsPointV2& p1, const QgsPointV2& p2, QgsPointV2& result, double radius, const QgsPointV2& mousePos )
465 {
466  QgsPointV2 midPoint(( p1.x() + p2.x() ) / 2.0, ( p1.y() + p2.y() ) / 2.0 );
467  double midDist = sqrt( sqrDistance2D( p1, midPoint ) );
468  if ( radius < midDist )
469  {
470  return false;
471  }
472  double centerMidDist = sqrt( radius * radius - midDist * midDist );
473  double dist = radius - centerMidDist;
474 
475  double midDx = midPoint.x() - p1.x();
476  double midDy = midPoint.y() - p1.y();
477 
478  //get the four possible midpoints
479  QVector<QgsPointV2> possibleMidPoints;
480  possibleMidPoints.append( pointOnLineWithDistance( midPoint, QgsPointV2( midPoint.x() - midDy, midPoint.y() + midDx ), dist ) );
481  possibleMidPoints.append( pointOnLineWithDistance( midPoint, QgsPointV2( midPoint.x() - midDy, midPoint.y() + midDx ), 2 * radius - dist ) );
482  possibleMidPoints.append( pointOnLineWithDistance( midPoint, QgsPointV2( midPoint.x() + midDy, midPoint.y() - midDx ), dist ) );
483  possibleMidPoints.append( pointOnLineWithDistance( midPoint, QgsPointV2( midPoint.x() + midDy, midPoint.y() - midDx ), 2 * radius - dist ) );
484 
485  //take the closest one
486  double minDist = std::numeric_limits<double>::max();
487  int minDistIndex = -1;
488  for ( int i = 0; i < possibleMidPoints.size(); ++i )
489  {
490  double currentDist = sqrDistance2D( mousePos, possibleMidPoints.at( i ) );
491  if ( currentDist < minDist )
492  {
493  minDistIndex = i;
494  minDist = currentDist;
495  }
496  }
497 
498  if ( minDistIndex == -1 )
499  {
500  return false;
501  }
502 
503  result = possibleMidPoints.at( minDistIndex );
504  return true;
505 }
506 
507 double QgsGeometryUtils::circleTangentDirection( const QgsPointV2& tangentPoint, const QgsPointV2& cp1,
508  const QgsPointV2& cp2, const QgsPointV2& cp3 )
509 {
510  //calculate circle midpoint
511  double mX, mY, radius;
512  circleCenterRadius( cp1, cp2, cp3, radius, mX, mY );
513 
514  double p1Angle = QgsGeometryUtils::ccwAngle( cp1.y() - mY, cp1.x() - mX );
515  double p2Angle = QgsGeometryUtils::ccwAngle( cp2.y() - mY, cp2.x() - mX );
516  double p3Angle = QgsGeometryUtils::ccwAngle( cp3.y() - mY, cp3.x() - mX );
517  if ( circleClockwise( p1Angle, p2Angle, p3Angle ) )
518  {
519  return lineAngle( tangentPoint.x(), tangentPoint.y(), mX, mY );
520  }
521  else
522  {
523  return lineAngle( mX, mY, tangentPoint.x(), tangentPoint.y() );
524  }
525 }
526 
527 QgsPointSequenceV2 QgsGeometryUtils::pointsFromWKT( const QString &wktCoordinateList, bool is3D, bool isMeasure )
528 {
529  int dim = 2 + is3D + isMeasure;
530  QgsPointSequenceV2 points;
531  QStringList coordList = wktCoordinateList.split( ',', QString::SkipEmptyParts );
532 
533  //first scan through for extra unexpected dimensions
534  bool foundZ = false;
535  bool foundM = false;
536  Q_FOREACH ( const QString& pointCoordinates, coordList )
537  {
538  QStringList coordinates = pointCoordinates.split( ' ', QString::SkipEmptyParts );
539  if ( coordinates.size() == 3 && !foundZ && !foundM && !is3D && !isMeasure )
540  {
541  // 3 dimensional coordinates, but not specifically marked as such. We allow this
542  // anyway and upgrade geometry to have Z dimension
543  foundZ = true;
544  }
545  else if ( coordinates.size() >= 4 && ( !( is3D || foundZ ) || !( isMeasure || foundM ) ) )
546  {
547  // 4 (or more) dimensional coordinates, but not specifically marked as such. We allow this
548  // anyway and upgrade geometry to have Z&M dimensions
549  foundZ = true;
550  foundM = true;
551  }
552  }
553 
554  Q_FOREACH ( const QString& pointCoordinates, coordList )
555  {
556  QStringList coordinates = pointCoordinates.split( ' ', QString::SkipEmptyParts );
557  if ( coordinates.size() < dim )
558  continue;
559 
560  int idx = 0;
561  double x = coordinates[idx++].toDouble();
562  double y = coordinates[idx++].toDouble();
563 
564  double z = 0;
565  if (( is3D || foundZ ) && coordinates.length() > idx )
566  z = coordinates[idx++].toDouble();
567 
568  double m = 0;
569  if (( isMeasure || foundM ) && coordinates.length() > idx )
570  m = coordinates[idx++].toDouble();
571 
573  if ( is3D || foundZ )
574  {
575  if ( isMeasure || foundM )
577  else
579  }
580  else
581  {
582  if ( isMeasure || foundM )
584  else
585  t = QgsWKBTypes::Point;
586  }
587 
588  points.append( QgsPointV2( t, x, y, z, m ) );
589  }
590 
591  return points;
592 }
593 
594 void QgsGeometryUtils::pointsToWKB( QgsWkbPtr& wkb, const QgsPointSequenceV2 &points, bool is3D, bool isMeasure )
595 {
596  wkb << static_cast<quint32>( points.size() );
597  Q_FOREACH ( const QgsPointV2& point, points )
598  {
599  wkb << point.x() << point.y();
600  if ( is3D )
601  {
602  wkb << point.z();
603  }
604  if ( isMeasure )
605  {
606  wkb << point.m();
607  }
608  }
609 }
610 
611 QString QgsGeometryUtils::pointsToWKT( const QgsPointSequenceV2 &points, int precision, bool is3D, bool isMeasure )
612 {
613  QString wkt = "(";
614  Q_FOREACH ( const QgsPointV2& p, points )
615  {
616  wkt += qgsDoubleToString( p.x(), precision );
617  wkt += ' ' + qgsDoubleToString( p.y(), precision );
618  if ( is3D )
619  wkt += ' ' + qgsDoubleToString( p.z(), precision );
620  if ( isMeasure )
621  wkt += ' ' + qgsDoubleToString( p.m(), precision );
622  wkt += ", ";
623  }
624  if ( wkt.endsWith( ", " ) )
625  wkt.chop( 2 ); // Remove last ", "
626  wkt += ')';
627  return wkt;
628 }
629 
630 QDomElement QgsGeometryUtils::pointsToGML2( const QgsPointSequenceV2 &points, QDomDocument& doc, int precision, const QString &ns )
631 {
632  QDomElement elemCoordinates = doc.createElementNS( ns, "coordinates" );
633 
634  QString strCoordinates;
635 
636  Q_FOREACH ( const QgsPointV2& p, points )
637  strCoordinates += qgsDoubleToString( p.x(), precision ) + ',' + qgsDoubleToString( p.y(), precision ) + ' ';
638 
639  if ( strCoordinates.endsWith( ' ' ) )
640  strCoordinates.chop( 1 ); // Remove trailing space
641 
642  elemCoordinates.appendChild( doc.createTextNode( strCoordinates ) );
643  return elemCoordinates;
644 }
645 
646 QDomElement QgsGeometryUtils::pointsToGML3( const QgsPointSequenceV2 &points, QDomDocument& doc, int precision, const QString &ns, bool is3D )
647 {
648  QDomElement elemPosList = doc.createElementNS( ns, "posList" );
649  elemPosList.setAttribute( "srsDimension", is3D ? 3 : 2 );
650 
651  QString strCoordinates;
652  Q_FOREACH ( const QgsPointV2& p, points )
653  {
654  strCoordinates += qgsDoubleToString( p.x(), precision ) + ' ' + qgsDoubleToString( p.y(), precision ) + ' ';
655  if ( is3D )
656  strCoordinates += qgsDoubleToString( p.z(), precision ) + ' ';
657  }
658  if ( strCoordinates.endsWith( ' ' ) )
659  strCoordinates.chop( 1 ); // Remove trailing space
660 
661  elemPosList.appendChild( doc.createTextNode( strCoordinates ) );
662  return elemPosList;
663 }
664 
666 {
667  QString json = "[ ";
668  Q_FOREACH ( const QgsPointV2& p, points )
669  {
670  json += '[' + qgsDoubleToString( p.x(), precision ) + ", " + qgsDoubleToString( p.y(), precision ) + "], ";
671  }
672  if ( json.endsWith( ", " ) )
673  {
674  json.chop( 2 ); // Remove last ", "
675  }
676  json += ']';
677  return json;
678 }
679 
681 {
682  double clippedAngle = angle;
683  if ( clippedAngle >= M_PI * 2 || clippedAngle <= -2 * M_PI )
684  {
685  clippedAngle = fmod( clippedAngle, 2 * M_PI );
686  }
687  if ( clippedAngle < 0.0 )
688  {
689  clippedAngle += 2 * M_PI;
690  }
691  return clippedAngle;
692 }
693 
695 {
696  QgsWKBTypes::Type wkbType = QgsWKBTypes::parseType( wkt );
697 
698  QRegExp cooRegEx( "^[^\\(]*\\((.*)\\)[^\\)]*$" );
699  QString contents = cooRegEx.indexIn( wkt ) >= 0 ? cooRegEx.cap( 1 ) : QString();
700  return qMakePair( wkbType, contents );
701 }
702 
704 {
705  int level = 0;
706  QString block;
707  QStringList blocks;
708  for ( int i = 0, n = wkt.length(); i < n; ++i )
709  {
710  if ( wkt[i].isSpace() && level == 0 )
711  continue;
712 
713  if ( wkt[i] == ',' && level == 0 )
714  {
715  if ( !block.isEmpty() )
716  {
717  if ( block.startsWith( '(' ) && !defaultType.isEmpty() )
718  block.prepend( defaultType + ' ' );
719  blocks.append( block );
720  }
721  block.clear();
722  continue;
723  }
724  if ( wkt[i] == '(' )
725  ++level;
726  else if ( wkt[i] == ')' )
727  --level;
728  block += wkt[i];
729  }
730  if ( !block.isEmpty() )
731  {
732  if ( block.startsWith( '(' ) && !defaultType.isEmpty() )
733  block.prepend( defaultType + ' ' );
734  blocks.append( block );
735  }
736  return blocks;
737 }
738 
739 double QgsGeometryUtils::lineAngle( double x1, double y1, double x2, double y2 )
740 {
741  double at = atan2( y2 - y1, x2 - x1 );
742  double a = -at + M_PI / 2.0;
743  return normalizedAngle( a );
744 }
745 
746 double QgsGeometryUtils::linePerpendicularAngle( double x1, double y1, double x2, double y2 )
747 {
748  double a = lineAngle( x1, y1, x2, y2 );
749  a += ( M_PI / 2.0 );
750  return normalizedAngle( a );
751 }
752 
753 double QgsGeometryUtils::averageAngle( double x1, double y1, double x2, double y2, double x3, double y3 )
754 {
755  // calc average angle between the previous and next point
756  double a1 = lineAngle( x1, y1, x2, y2 );
757  double a2 = lineAngle( x2, y2, x3, y3 );
758  return averageAngle( a1, a2 );
759 }
760 
761 double QgsGeometryUtils::averageAngle( double a1, double a2 )
762 {
763  a1 = normalizedAngle( a1 );
764  a2 = normalizedAngle( a2 );
765  double clockwiseDiff = 0.0;
766  if ( a2 >= a1 )
767  {
768  clockwiseDiff = a2 - a1;
769  }
770  else
771  {
772  clockwiseDiff = a2 + ( 2 * M_PI - a1 );
773  }
774  double counterClockwiseDiff = 2 * M_PI - clockwiseDiff;
775 
776  double resultAngle = 0;
777  if ( clockwiseDiff <= counterClockwiseDiff )
778  {
779  resultAngle = a1 + clockwiseDiff / 2.0;
780  }
781  else
782  {
783  resultAngle = a1 - counterClockwiseDiff / 2.0;
784  }
785  return normalizedAngle( resultAngle );
786 }
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.
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)
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.
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)
double z() const
Returns the point&#39;s z-coordinate.
Definition: qgspointv2.h:80
double y() const
Returns the point&#39;s y-coordinate.
Definition: qgspointv2.h:74
void chop(int n)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:285
int size() const
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.
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)
Definition: qgis.h:274
bool isEmpty() const
bool isEmpty() const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
#define M_PI
double x() const
Returns the point&#39;s x-coordinate.
Definition: qgspointv2.h:68
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.
double length() const
Definition: qgspoint.cpp:59
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
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
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 x() const
Definition: qgspoint.cpp:64
static Type parseType(const QString &wktStr)
Attempts to extract the WKB type from a WKT string.
Definition: qgswkbtypes.cpp:32
Curve polygon geometry type.
Abstract base class for curved geometry type.
Definition: qgscurvev2.h:32
int size() const
double y() const
Definition: qgspoint.cpp:69
double m() const
Returns the point&#39;s m value.
Definition: qgspointv2.h:86
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.