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