QGIS API Documentation  3.0.2-Girona (307d082)
qgsinternalgeometryengine.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsinternalgeometryengine.cpp - QgsInternalGeometryEngine
3 
4  ---------------------
5  begin : 13.1.2016
6  copyright : (C) 2016 by Matthias Kuhn
7  email : [email protected]
8  ***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
18 
19 #include "qgslinestring.h"
20 #include "qgsmultipolygon.h"
21 #include "qgspolygon.h"
22 #include "qgsmulticurve.h"
23 #include "qgsgeometry.h"
24 #include "qgsgeometryutils.h"
25 
26 
27 #include <QTransform>
28 #include <memory>
29 #include <queue>
30 
32  : mGeometry( geometry.constGet() )
33 {
34 
35 }
36 
37 /***************************************************************************
38  * This class is considered CRITICAL and any change MUST be accompanied with
39  * full unit tests.
40  * See details in QEP #17
41  ****************************************************************************/
42 
44 {
45  QVector<QgsLineString *> linesToProcess;
46 
47  const QgsMultiCurve *multiCurve = qgsgeometry_cast< const QgsMultiCurve * >( mGeometry );
48  if ( multiCurve )
49  {
50  for ( int i = 0; i < multiCurve->partCount(); ++i )
51  {
52  linesToProcess << static_cast<QgsLineString *>( multiCurve->geometryN( i )->clone() );
53  }
54  }
55 
56  const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( mGeometry );
57  if ( curve )
58  {
59  linesToProcess << static_cast<QgsLineString *>( curve->segmentize() );
60  }
61 
62  std::unique_ptr<QgsMultiPolygon> multipolygon( linesToProcess.size() > 1 ? new QgsMultiPolygon() : nullptr );
63  QgsPolygon *polygon = nullptr;
64 
65  if ( !linesToProcess.empty() )
66  {
67  std::unique_ptr< QgsLineString > secondline;
68  for ( QgsLineString *line : qgis::as_const( linesToProcess ) )
69  {
70  QTransform transform = QTransform::fromTranslate( x, y );
71 
72  secondline.reset( line->reversed() );
73  secondline->transform( transform );
74 
75  line->append( secondline.get() );
76  line->addVertex( line->pointN( 0 ) );
77 
78  polygon = new QgsPolygon();
79  polygon->setExteriorRing( line );
80 
81  if ( multipolygon )
82  multipolygon->addGeometry( polygon );
83  }
84 
85  if ( multipolygon )
86  return QgsGeometry( multipolygon.release() );
87  else
88  return QgsGeometry( polygon );
89  }
90 
91  return QgsGeometry();
92 }
93 
94 
95 
96 // polylabel implementation
97 // ported from the original JavaScript implementation developed by Vladimir Agafonkin
98 // originally licensed under the ISC License
99 
101 class Cell
102 {
103  public:
104  Cell( double x, double y, double h, const QgsPolygon *polygon )
105  : x( x )
106  , y( y )
107  , h( h )
108  , d( polygon->pointDistanceToBoundary( x, y ) )
109  , max( d + h * M_SQRT2 )
110  {}
111 
113  double x;
115  double y;
117  double h;
119  double d;
121  double max;
122 };
123 
124 struct GreaterThanByMax
125 {
126  bool operator()( const Cell *lhs, const Cell *rhs )
127  {
128  return rhs->max > lhs->max;
129  }
130 };
131 
132 Cell *getCentroidCell( const QgsPolygon *polygon )
133 {
134  double area = 0;
135  double x = 0;
136  double y = 0;
137 
138  const QgsLineString *exterior = static_cast< const QgsLineString *>( polygon->exteriorRing() );
139  int len = exterior->numPoints() - 1; //assume closed
140  for ( int i = 0, j = len - 1; i < len; j = i++ )
141  {
142  double aX = exterior->xAt( i );
143  double aY = exterior->yAt( i );
144  double bX = exterior->xAt( j );
145  double bY = exterior->yAt( j );
146  double f = aX * bY - bX * aY;
147  x += ( aX + bX ) * f;
148  y += ( aY + bY ) * f;
149  area += f * 3;
150  }
151  if ( area == 0 )
152  return new Cell( exterior->xAt( 0 ), exterior->yAt( 0 ), 0, polygon );
153  else
154  return new Cell( x / area, y / area, 0.0, polygon );
155 }
156 
157 QgsPoint surfacePoleOfInaccessibility( const QgsSurface *surface, double precision, double &distanceFromBoundary )
158 {
159  std::unique_ptr< QgsPolygon > segmentizedPoly;
160  const QgsPolygon *polygon = qgsgeometry_cast< const QgsPolygon * >( surface );
161  if ( !polygon )
162  {
163  segmentizedPoly.reset( static_cast< QgsPolygon *>( surface->segmentize() ) );
164  polygon = segmentizedPoly.get();
165  }
166 
167  // start with the bounding box
168  QgsRectangle bounds = polygon->boundingBox();
169 
170  // initial parameters
171  double cellSize = std::min( bounds.width(), bounds.height() );
172 
173  if ( qgsDoubleNear( cellSize, 0.0 ) )
174  return QgsPoint( bounds.xMinimum(), bounds.yMinimum() );
175 
176  double h = cellSize / 2.0;
177  std::priority_queue< Cell *, std::vector<Cell *>, GreaterThanByMax > cellQueue;
178 
179  // cover polygon with initial cells
180  for ( double x = bounds.xMinimum(); x < bounds.xMaximum(); x += cellSize )
181  {
182  for ( double y = bounds.yMinimum(); y < bounds.yMaximum(); y += cellSize )
183  {
184  cellQueue.push( new Cell( x + h, y + h, h, polygon ) );
185  }
186  }
187 
188  // take centroid as the first best guess
189  std::unique_ptr< Cell > bestCell( getCentroidCell( polygon ) );
190 
191  // special case for rectangular polygons
192  std::unique_ptr< Cell > bboxCell( new Cell( bounds.xMinimum() + bounds.width() / 2.0,
193  bounds.yMinimum() + bounds.height() / 2.0,
194  0, polygon ) );
195  if ( bboxCell->d > bestCell->d )
196  {
197  bestCell = std::move( bboxCell );
198  }
199 
200  while ( !cellQueue.empty() )
201  {
202  // pick the most promising cell from the queue
203  std::unique_ptr< Cell > cell( cellQueue.top() );
204  cellQueue.pop();
205  Cell *currentCell = cell.get();
206 
207  // update the best cell if we found a better one
208  if ( currentCell->d > bestCell->d )
209  {
210  bestCell = std::move( cell );
211  }
212 
213  // do not drill down further if there's no chance of a better solution
214  if ( currentCell->max - bestCell->d <= precision )
215  continue;
216 
217  // split the cell into four cells
218  h = currentCell->h / 2.0;
219  cellQueue.push( new Cell( currentCell->x - h, currentCell->y - h, h, polygon ) );
220  cellQueue.push( new Cell( currentCell->x + h, currentCell->y - h, h, polygon ) );
221  cellQueue.push( new Cell( currentCell->x - h, currentCell->y + h, h, polygon ) );
222  cellQueue.push( new Cell( currentCell->x + h, currentCell->y + h, h, polygon ) );
223  }
224 
225  distanceFromBoundary = bestCell->d;
226 
227  return QgsPoint( bestCell->x, bestCell->y );
228 }
229 
231 
232 QgsGeometry QgsInternalGeometryEngine::poleOfInaccessibility( double precision, double *distanceFromBoundary ) const
233 {
234  if ( distanceFromBoundary )
235  *distanceFromBoundary = DBL_MAX;
236 
237  if ( !mGeometry || mGeometry->isEmpty() )
238  return QgsGeometry();
239 
240  if ( precision <= 0 )
241  return QgsGeometry();
242 
243  if ( const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
244  {
245  int numGeom = gc->numGeometries();
246  double maxDist = 0;
247  QgsPoint bestPoint;
248  bool found = false;
249  for ( int i = 0; i < numGeom; ++i )
250  {
251  const QgsSurface *surface = qgsgeometry_cast< const QgsSurface * >( gc->geometryN( i ) );
252  if ( !surface )
253  continue;
254 
255  found = true;
256  double dist = DBL_MAX;
257  QgsPoint p = surfacePoleOfInaccessibility( surface, precision, dist );
258  if ( dist > maxDist )
259  {
260  maxDist = dist;
261  bestPoint = p;
262  }
263  }
264 
265  if ( !found )
266  return QgsGeometry();
267 
268  if ( distanceFromBoundary )
269  *distanceFromBoundary = maxDist;
270  return QgsGeometry( new QgsPoint( bestPoint ) );
271  }
272  else
273  {
274  const QgsSurface *surface = qgsgeometry_cast< const QgsSurface * >( mGeometry );
275  if ( !surface )
276  return QgsGeometry();
277 
278  double dist = DBL_MAX;
279  QgsPoint p = surfacePoleOfInaccessibility( surface, precision, dist );
280  if ( distanceFromBoundary )
281  *distanceFromBoundary = dist;
282  return QgsGeometry( new QgsPoint( p ) );
283  }
284 }
285 
286 
287 // helpers for orthogonalize
288 // adapted from original code in potlatch/id osm editor
289 
290 bool dotProductWithinAngleTolerance( double dotProduct, double lowerThreshold, double upperThreshold )
291 {
292  return lowerThreshold > std::fabs( dotProduct ) || std::fabs( dotProduct ) > upperThreshold;
293 }
294 
295 double normalizedDotProduct( const QgsPoint &a, const QgsPoint &b, const QgsPoint &c )
296 {
297  QgsVector p = a - b;
298  QgsVector q = c - b;
299 
300  if ( p.length() > 0 )
301  p = p.normalized();
302  if ( q.length() > 0 )
303  q = q.normalized();
304 
305  return p * q;
306 }
307 
308 double squareness( QgsLineString *ring, double lowerThreshold, double upperThreshold )
309 {
310  double sum = 0.0;
311 
312  bool isClosed = ring->isClosed();
313  int numPoints = ring->numPoints();
314  QgsPoint a;
315  QgsPoint b;
316  QgsPoint c;
317 
318  for ( int i = 0; i < numPoints; ++i )
319  {
320  if ( !isClosed && i == numPoints - 1 )
321  break;
322  else if ( !isClosed && i == 0 )
323  {
324  b = ring->pointN( 0 );
325  c = ring->pointN( 1 );
326  }
327  else
328  {
329  if ( i == 0 )
330  {
331  a = ring->pointN( numPoints - 1 );
332  b = ring->pointN( 0 );
333  }
334  if ( i == numPoints - 1 )
335  c = ring->pointN( 0 );
336  else
337  c = ring->pointN( i + 1 );
338 
339  double dotProduct = normalizedDotProduct( a, b, c );
340  if ( !dotProductWithinAngleTolerance( dotProduct, lowerThreshold, upperThreshold ) )
341  continue;
342 
343  sum += 2.0 * std::min( std::fabs( dotProduct - 1.0 ), std::min( std::fabs( dotProduct ), std::fabs( dotProduct + 1 ) ) );
344  }
345  a = b;
346  b = c;
347  }
348 
349  return sum;
350 }
351 
352 QgsVector calcMotion( const QgsPoint &a, const QgsPoint &b, const QgsPoint &c,
353  double lowerThreshold, double upperThreshold )
354 {
355  QgsVector p = a - b;
356  QgsVector q = c - b;
357 
358  if ( qgsDoubleNear( p.length(), 0.0 ) || qgsDoubleNear( q.length(), 0.0 ) )
359  return QgsVector( 0, 0 );
360 
361  // 2.0 is a magic number from the original JOSM source code
362  double scale = 2.0 * std::min( p.length(), q.length() );
363 
364  p = p.normalized();
365  q = q.normalized();
366  double dotProduct = p * q;
367 
368  if ( !dotProductWithinAngleTolerance( dotProduct, lowerThreshold, upperThreshold ) )
369  {
370  return QgsVector( 0, 0 );
371  }
372 
373  // wonderful nasty hack which has survived through JOSM -> id -> QGIS
374  // to deal with almost-straight segments (angle is closer to 180 than to 90/270).
375  if ( dotProduct < -M_SQRT1_2 )
376  dotProduct += 1.0;
377 
378  QgsVector new_v = p + q;
379  // 0.1 magic number from JOSM implementation - think this is to limit each iterative step
380  return new_v.normalized() * ( 0.1 * dotProduct * scale );
381 }
382 
383 QgsLineString *doOrthogonalize( QgsLineString *ring, int iterations, double tolerance, double lowerThreshold, double upperThreshold )
384 {
385  double minScore = DBL_MAX;
386 
387  bool isClosed = ring->isClosed();
388  int numPoints = ring->numPoints();
389 
390  std::unique_ptr< QgsLineString > best( ring->clone() );
391 
392  for ( int it = 0; it < iterations; ++it )
393  {
394  QVector< QgsVector > /* yep */ motions;
395  motions.reserve( numPoints );
396 
397  // first loop through an calculate all motions
398  QgsPoint a;
399  QgsPoint b;
400  QgsPoint c;
401  for ( int i = 0; i < numPoints; ++i )
402  {
403  if ( isClosed && i == numPoints - 1 )
404  motions << motions.at( 0 ); //closed ring, so last point follows first point motion
405  else if ( !isClosed && ( i == 0 || i == numPoints - 1 ) )
406  {
407  b = ring->pointN( 0 );
408  c = ring->pointN( 1 );
409  motions << QgsVector( 0, 0 ); //non closed line, leave first/last vertex untouched
410  }
411  else
412  {
413  if ( i == 0 )
414  {
415  a = ring->pointN( numPoints - 1 );
416  b = ring->pointN( 0 );
417  }
418  if ( i == numPoints - 1 )
419  c = ring->pointN( 0 );
420  else
421  c = ring->pointN( i + 1 );
422 
423  motions << calcMotion( a, b, c, lowerThreshold, upperThreshold );
424  }
425  a = b;
426  b = c;
427  }
428 
429  // then apply them
430  for ( int i = 0; i < numPoints; ++i )
431  {
432  ring->setXAt( i, ring->xAt( i ) + motions.at( i ).x() );
433  ring->setYAt( i, ring->yAt( i ) + motions.at( i ).y() );
434  }
435 
436  double newScore = squareness( ring, lowerThreshold, upperThreshold );
437  if ( newScore < minScore )
438  {
439  best.reset( ring->clone() );
440  minScore = newScore;
441  }
442 
443  if ( minScore < tolerance )
444  break;
445  }
446 
447  delete ring;
448 
449  return best.release();
450 }
451 
452 
453 QgsAbstractGeometry *orthogonalizeGeom( const QgsAbstractGeometry *geom, int maxIterations, double tolerance, double lowerThreshold, double upperThreshold )
454 {
455  std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
456  if ( QgsWkbTypes::isCurvedType( geom->wkbType() ) )
457  {
458  segmentizedCopy.reset( geom->segmentize() );
459  geom = segmentizedCopy.get();
460  }
461 
463  {
464  return doOrthogonalize( static_cast< QgsLineString * >( geom->clone() ),
465  maxIterations, tolerance, lowerThreshold, upperThreshold );
466  }
467  else
468  {
469  // polygon
470  const QgsPolygon *polygon = static_cast< const QgsPolygon * >( geom );
471  QgsPolygon *result = new QgsPolygon();
472 
473  result->setExteriorRing( doOrthogonalize( static_cast< QgsLineString * >( polygon->exteriorRing()->clone() ),
474  maxIterations, tolerance, lowerThreshold, upperThreshold ) );
475  for ( int i = 0; i < polygon->numInteriorRings(); ++i )
476  {
477  result->addInteriorRing( doOrthogonalize( static_cast< QgsLineString * >( polygon->interiorRing( i )->clone() ),
478  maxIterations, tolerance, lowerThreshold, upperThreshold ) );
479  }
480 
481  return result;
482  }
483 }
484 
485 QgsGeometry QgsInternalGeometryEngine::orthogonalize( double tolerance, int maxIterations, double angleThreshold ) const
486 {
487  if ( !mGeometry || ( QgsWkbTypes::geometryType( mGeometry->wkbType() ) != QgsWkbTypes::LineGeometry
488  && QgsWkbTypes::geometryType( mGeometry->wkbType() ) != QgsWkbTypes::PolygonGeometry ) )
489  {
490  return QgsGeometry();
491  }
492 
493  double lowerThreshold = std::cos( ( 90 - angleThreshold ) * M_PI / 180.00 );
494  double upperThreshold = std::cos( angleThreshold * M_PI / 180.0 );
495 
496  if ( const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
497  {
498  int numGeom = gc->numGeometries();
499  QVector< QgsAbstractGeometry * > geometryList;
500  geometryList.reserve( numGeom );
501  for ( int i = 0; i < numGeom; ++i )
502  {
503  geometryList << orthogonalizeGeom( gc->geometryN( i ), maxIterations, tolerance, lowerThreshold, upperThreshold );
504  }
505 
506  QgsGeometry first = QgsGeometry( geometryList.takeAt( 0 ) );
507  for ( QgsAbstractGeometry *g : qgis::as_const( geometryList ) )
508  {
509  first.addPart( g );
510  }
511  return first;
512  }
513  else
514  {
515  return QgsGeometry( orthogonalizeGeom( mGeometry, maxIterations, tolerance, lowerThreshold, upperThreshold ) );
516  }
517 }
518 
519 // if extraNodesPerSegment < 0, then use distance based mode
520 QgsLineString *doDensify( const QgsLineString *ring, int extraNodesPerSegment = -1, double distance = 1 )
521 {
522  QVector< double > outX;
523  QVector< double > outY;
524  QVector< double > outZ;
525  QVector< double > outM;
526  double multiplier = 1.0 / double( extraNodesPerSegment + 1 );
527 
528  int nPoints = ring->numPoints();
529  outX.reserve( ( extraNodesPerSegment + 1 ) * nPoints );
530  outY.reserve( ( extraNodesPerSegment + 1 ) * nPoints );
531  bool withZ = ring->is3D();
532  if ( withZ )
533  outZ.reserve( ( extraNodesPerSegment + 1 ) * nPoints );
534  bool withM = ring->isMeasure();
535  if ( withM )
536  outM.reserve( ( extraNodesPerSegment + 1 ) * nPoints );
537  double x1 = 0;
538  double x2 = 0;
539  double y1 = 0;
540  double y2 = 0;
541  double z1 = 0;
542  double z2 = 0;
543  double m1 = 0;
544  double m2 = 0;
545  double xOut = 0;
546  double yOut = 0;
547  double zOut = 0;
548  double mOut = 0;
549  int extraNodesThisSegment = extraNodesPerSegment;
550  for ( int i = 0; i < nPoints - 1; ++i )
551  {
552  x1 = ring->xAt( i );
553  x2 = ring->xAt( i + 1 );
554  y1 = ring->yAt( i );
555  y2 = ring->yAt( i + 1 );
556  if ( withZ )
557  {
558  z1 = ring->zAt( i );
559  z2 = ring->zAt( i + 1 );
560  }
561  if ( withM )
562  {
563  m1 = ring->mAt( i );
564  m2 = ring->mAt( i + 1 );
565  }
566 
567  outX << x1;
568  outY << y1;
569  if ( withZ )
570  outZ << z1;
571  if ( withM )
572  outM << m1;
573 
574  if ( extraNodesPerSegment < 0 )
575  {
576  // distance mode
577  extraNodesThisSegment = std::floor( std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) + ( y2 - y1 ) * ( y2 - y1 ) ) / distance );
578  if ( extraNodesThisSegment >= 1 )
579  multiplier = 1.0 / ( extraNodesThisSegment + 1 );
580  }
581 
582  for ( int j = 0; j < extraNodesThisSegment; ++j )
583  {
584  double delta = multiplier * ( j + 1 );
585  xOut = x1 + delta * ( x2 - x1 );
586  yOut = y1 + delta * ( y2 - y1 );
587  if ( withZ )
588  zOut = z1 + delta * ( z2 - z1 );
589  if ( withM )
590  mOut = m1 + delta * ( m2 - m1 );
591 
592  outX << xOut;
593  outY << yOut;
594  if ( withZ )
595  outZ << zOut;
596  if ( withM )
597  outM << mOut;
598  }
599  }
600  outX << ring->xAt( nPoints - 1 );
601  outY << ring->yAt( nPoints - 1 );
602  if ( withZ )
603  outZ << ring->zAt( nPoints - 1 );
604  if ( withM )
605  outM << ring->mAt( nPoints - 1 );
606 
607  QgsLineString *result = new QgsLineString( outX, outY, outZ, outM );
608  return result;
609 }
610 
611 QgsAbstractGeometry *densifyGeometry( const QgsAbstractGeometry *geom, int extraNodesPerSegment = 1, double distance = 1 )
612 {
613  std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
614  if ( QgsWkbTypes::isCurvedType( geom->wkbType() ) )
615  {
616  segmentizedCopy.reset( geom->segmentize() );
617  geom = segmentizedCopy.get();
618  }
619 
621  {
622  return doDensify( static_cast< const QgsLineString * >( geom ), extraNodesPerSegment, distance );
623  }
624  else
625  {
626  // polygon
627  const QgsPolygon *polygon = static_cast< const QgsPolygon * >( geom );
628  QgsPolygon *result = new QgsPolygon();
629 
630  result->setExteriorRing( doDensify( static_cast< const QgsLineString * >( polygon->exteriorRing() ),
631  extraNodesPerSegment, distance ) );
632  for ( int i = 0; i < polygon->numInteriorRings(); ++i )
633  {
634  result->addInteriorRing( doDensify( static_cast< const QgsLineString * >( polygon->interiorRing( i ) ),
635  extraNodesPerSegment, distance ) );
636  }
637 
638  return result;
639  }
640 }
641 
643 {
644  if ( !mGeometry )
645  {
646  return QgsGeometry();
647  }
648 
649  if ( QgsWkbTypes::geometryType( mGeometry->wkbType() ) == QgsWkbTypes::PointGeometry )
650  {
651  return QgsGeometry( mGeometry->clone() ); // point geometry, nothing to do
652  }
653 
654  if ( const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
655  {
656  int numGeom = gc->numGeometries();
657  QVector< QgsAbstractGeometry * > geometryList;
658  geometryList.reserve( numGeom );
659  for ( int i = 0; i < numGeom; ++i )
660  {
661  geometryList << densifyGeometry( gc->geometryN( i ), extraNodesPerSegment );
662  }
663 
664  QgsGeometry first = QgsGeometry( geometryList.takeAt( 0 ) );
665  for ( QgsAbstractGeometry *g : qgis::as_const( geometryList ) )
666  {
667  first.addPart( g );
668  }
669  return first;
670  }
671  else
672  {
673  return QgsGeometry( densifyGeometry( mGeometry, extraNodesPerSegment ) );
674  }
675 }
676 
678 {
679  if ( !mGeometry )
680  {
681  return QgsGeometry();
682  }
683 
684  if ( QgsWkbTypes::geometryType( mGeometry->wkbType() ) == QgsWkbTypes::PointGeometry )
685  {
686  return QgsGeometry( mGeometry->clone() ); // point geometry, nothing to do
687  }
688 
689  if ( const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
690  {
691  int numGeom = gc->numGeometries();
692  QVector< QgsAbstractGeometry * > geometryList;
693  geometryList.reserve( numGeom );
694  for ( int i = 0; i < numGeom; ++i )
695  {
696  geometryList << densifyGeometry( gc->geometryN( i ), -1, distance );
697  }
698 
699  QgsGeometry first = QgsGeometry( geometryList.takeAt( 0 ) );
700  for ( QgsAbstractGeometry *g : qgis::as_const( geometryList ) )
701  {
702  first.addPart( g );
703  }
704  return first;
705  }
706  else
707  {
708  return QgsGeometry( densifyGeometry( mGeometry, -1, distance ) );
709  }
710 }
bool isMeasure() const
Returns true if the geometry contains m values.
const QgsCurve * interiorRing(int i) const
QgsAbstractGeometry * orthogonalizeGeom(const QgsAbstractGeometry *geom, int maxIterations, double tolerance, double lowerThreshold, double upperThreshold)
QgsLineString * doDensify(const QgsLineString *ring, int extraNodesPerSegment=-1, double distance=1)
QgsVector calcMotion(const QgsPoint &a, const QgsPoint &b, const QgsPoint &c, double lowerThreshold, double upperThreshold)
A rectangle specified with double values.
Definition: qgsrectangle.h:39
QgsInternalGeometryEngine(const QgsGeometry &geometry)
The caller is responsible that the geometry is available and unchanged for the whole lifetime of this...
double zAt(int index) const
Returns the z-coordinate of the specified node in the line string.
OperationResult addPart(const QVector< QgsPointXY > &points, QgsWkbTypes::GeometryType geomType=QgsWkbTypes::UnknownGeometry)
Adds a new part to a the geometry.
double normalizedDotProduct(const QgsPoint &a, const QgsPoint &b, const QgsPoint &c)
QgsGeometry poleOfInaccessibility(double precision, double *distanceFromBoundary=nullptr) const
Calculates the approximate pole of inaccessibility for a surface, which is the most distant internal ...
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:111
void setYAt(int index, double y)
Sets the y-coordinate of the specified node in the line string.
double squareness(QgsLineString *ring, double lowerThreshold, double upperThreshold)
double pointDistanceToBoundary(double x, double y) const
Returns the distance from a point to the boundary of the polygon (either the exterior ring or any clo...
Definition: qgspolygon.cpp:236
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:251
void setXAt(int index, double x)
Sets the x-coordinate of the specified node in the line string.
int numPoints() const override
Returns the number of points in the curve.
void addInteriorRing(QgsCurve *ring) override
Adds an interior ring to the geometry (takes ownership)
Definition: qgspolygon.cpp:148
int numInteriorRings() const
Geometry collection.
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:142
double mAt(int index) const
Returns the m value of the specified node in the line string.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
static GeometryType geometryType(Type type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:663
T qgsgeometry_cast(const QgsAbstractGeometry *geom)
Multi curve geometry collection.
Definition: qgsmulticurve.h:29
QgsRectangle boundingBox() const override
Returns the minimal bounding box for the geometry.
Definition: qgssurface.h:45
QgsGeometry densifyByDistance(double distance) const
Densifies the geometry by adding regularly placed extra nodes inside each segment so that the maximum...
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
Abstract base class for all geometries.
const QgsCurve * exteriorRing() const
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
double length() const
Returns the length of the vector.
Definition: qgsvector.cpp:71
QgsAbstractGeometry * densifyGeometry(const QgsAbstractGeometry *geom, int extraNodesPerSegment=1, double distance=1)
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
A class to represent a vector.
Definition: qgsvector.h:27
virtual bool isClosed() const
Returns true if the curve is closed.
Definition: qgscurve.cpp:39
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:130
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:115
bool dotProductWithinAngleTolerance(double dotProduct, double lowerThreshold, double upperThreshold)
int partCount() const override
Returns count of parts contained in the geometry.
void setExteriorRing(QgsCurve *ring) override
Sets the exterior ring of the polygon.
Definition: qgspolygon.cpp:179
Multi polygon geometry collection.
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
QgsCurve * clone() const override=0
Clones the geometry by performing a deep copy.
static bool isCurvedType(Type type)
Returns true if the WKB type is a curved type or can contain curved geometries.
Definition: qgswkbtypes.h:606
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:41
QgsPoint pointN(int i) const
Returns the specified point from inside the line string.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:120
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:125
QgsGeometry orthogonalize(double tolerance=1.0E-8, int maxIterations=1000, double angleThreshold=15.0) const
Attempts to orthogonalize a line or polygon geometry by shifting vertices to make the geometries angl...
Polygon geometry type.
Definition: qgspolygon.h:31
QgsGeometry densifyByCount(int extraNodesPerSegment) const
Densifies the geometry by adding the specified number of extra nodes within each segment of the geome...
virtual QgsAbstractGeometry * segmentize(double tolerance=M_PI/180., SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a version of the geometry without curves.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
QgsGeometry extrude(double x, double y) const
Will extrude a line or (segmentized) curve by a given offset and return a polygon representation of i...
QgsVector normalized() const
Returns the vector&#39;s normalized (or "unit") vector (ie same angle but length of 1.0).
Definition: qgsvector.cpp:109
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:149
QgsLineString * doOrthogonalize(QgsLineString *ring, int iterations, double tolerance, double lowerThreshold, double upperThreshold)