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