QGIS API Documentation  2.99.0-Master (f1c3692)
qgsgeometry.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsgeometry.cpp - Geometry (stored as Open Geospatial Consortium WKB)
3  -------------------------------------------------------------------
4 Date : 02 May 2005
5 Copyright : (C) 2005 by Brendan Morley
6 email : morb at ozemail dot com dot au
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 <limits>
17 #include <cstdarg>
18 #include <cstdio>
19 #include <cmath>
20 
21 #include "qgis.h"
22 #include "qgsgeometry.h"
23 #include "qgsgeometryeditutils.h"
24 #include "qgsgeometryfactory.h"
25 #include "qgsgeometrymakevalid.h"
26 #include "qgsgeometryutils.h"
28 #include "qgsgeos.h"
29 #include "qgsapplication.h"
30 #include "qgslogger.h"
31 #include "qgsmaptopixel.h"
32 #include "qgsmessagelog.h"
33 #include "qgspointxy.h"
34 #include "qgsrectangle.h"
35 
36 #include "qgsvectorlayer.h"
37 #include "qgsgeometryvalidator.h"
38 
39 #include "qgsmulticurve.h"
40 #include "qgsmultilinestring.h"
41 #include "qgsmultipoint.h"
42 #include "qgsmultipolygon.h"
43 #include "qgsmultisurface.h"
44 #include "qgspoint.h"
45 #include "qgspolygon.h"
46 #include "qgslinestring.h"
47 #include "qgscircle.h"
48 
50 {
52  QAtomicInt ref;
53  std::unique_ptr< QgsAbstractGeometry > geometry;
54 };
55 
57  : d( new QgsGeometryPrivate() )
58 {
59 }
60 
62 {
63  if ( !d->ref.deref() )
64  delete d;
65 }
66 
68  : d( new QgsGeometryPrivate() )
69 {
70  d->geometry.reset( geom );
71  d->ref = QAtomicInt( 1 );
72 }
73 
74 QgsGeometry::QgsGeometry( std::unique_ptr<QgsAbstractGeometry> geom )
75  : d( new QgsGeometryPrivate() )
76 {
77  d->geometry = std::move( geom );
78  d->ref = QAtomicInt( 1 );
79 }
80 
82 {
83  d = other.d;
84  mLastError = other.mLastError;
85  d->ref.ref();
86 }
87 
89 {
90  if ( !d->ref.deref() )
91  {
92  delete d;
93  }
94 
95  mLastError = other.mLastError;
96  d = other.d;
97  d->ref.ref();
98  return *this;
99 }
100 
101 void QgsGeometry::detach()
102 {
103  if ( d->ref <= 1 )
104  return;
105 
106  std::unique_ptr< QgsAbstractGeometry > cGeom;
107  if ( d->geometry )
108  cGeom.reset( d->geometry->clone() );
109 
110  reset( std::move( cGeom ) );
111 }
112 
113 void QgsGeometry::reset( std::unique_ptr<QgsAbstractGeometry> newGeometry )
114 {
115  if ( d->ref > 1 )
116  {
117  ( void )d->ref.deref();
118  d = new QgsGeometryPrivate();
119  }
120  d->geometry = std::move( newGeometry );
121 }
122 
124 {
125  return d->geometry.get();
126 }
127 
129 {
130  detach();
131  return d->geometry.get();
132 }
133 
135 {
136  if ( d->geometry.get() == geometry )
137  {
138  return;
139  }
140 
141  reset( std::unique_ptr< QgsAbstractGeometry >( geometry ) );
142 }
143 
145 {
146  return !d->geometry;
147 }
148 
149 QgsGeometry QgsGeometry::fromWkt( const QString &wkt )
150 {
151  std::unique_ptr< QgsAbstractGeometry > geom = QgsGeometryFactory::geomFromWkt( wkt );
152  if ( !geom )
153  {
154  return QgsGeometry();
155  }
156  return QgsGeometry( std::move( geom ) );
157 }
158 
160 {
161  std::unique_ptr< QgsAbstractGeometry > geom( QgsGeometryFactory::fromPointXY( point ) );
162  if ( geom )
163  {
164  return QgsGeometry( geom.release() );
165  }
166  return QgsGeometry();
167 }
168 
170 {
171  std::unique_ptr< QgsAbstractGeometry > geom = QgsGeometryFactory::fromPolylineXY( polyline );
172  if ( geom )
173  {
174  return QgsGeometry( std::move( geom ) );
175  }
176  return QgsGeometry();
177 }
178 
180 {
181  return QgsGeometry( qgis::make_unique< QgsLineString >( polyline ) );
182 }
183 
185 {
186  std::unique_ptr< QgsPolygon > geom = QgsGeometryFactory::fromPolygonXY( polygon );
187  if ( geom )
188  {
189  return QgsGeometry( std::move( geom.release() ) );
190  }
191  return QgsGeometry();
192 }
193 
195 {
196  std::unique_ptr< QgsMultiPoint > geom = QgsGeometryFactory::fromMultiPointXY( multipoint );
197  if ( geom )
198  {
199  return QgsGeometry( std::move( geom ) );
200  }
201  return QgsGeometry();
202 }
203 
205 {
206  std::unique_ptr< QgsMultiLineString > geom = QgsGeometryFactory::fromMultiPolylineXY( multiline );
207  if ( geom )
208  {
209  return QgsGeometry( std::move( geom ) );
210  }
211  return QgsGeometry();
212 }
213 
215 {
216  std::unique_ptr< QgsMultiPolygon > geom = QgsGeometryFactory::fromMultiPolygonXY( multipoly );
217  if ( geom )
218  {
219  return QgsGeometry( std::move( geom ) );
220  }
221  return QgsGeometry();
222 }
223 
225 {
226  QgsPolylineXY ring;
227  ring.append( QgsPointXY( rect.xMinimum(), rect.yMinimum() ) );
228  ring.append( QgsPointXY( rect.xMaximum(), rect.yMinimum() ) );
229  ring.append( QgsPointXY( rect.xMaximum(), rect.yMaximum() ) );
230  ring.append( QgsPointXY( rect.xMinimum(), rect.yMaximum() ) );
231  ring.append( QgsPointXY( rect.xMinimum(), rect.yMinimum() ) );
232 
233  QgsPolygonXY polygon;
234  polygon.append( ring );
235 
236  return fromPolygonXY( polygon );
237 }
238 
239 QgsGeometry QgsGeometry::collectGeometry( const QVector< QgsGeometry > &geometries )
240 {
241  QgsGeometry collected;
242 
243  for ( const QgsGeometry &g : geometries )
244  {
245  if ( collected.isNull() )
246  {
247  collected = g;
248  collected.convertToMultiType();
249  }
250  else
251  {
252  collected.addPart( g );
253  }
254  }
255  return collected;
256 }
257 
258 void QgsGeometry::fromWkb( unsigned char *wkb, int length )
259 {
260  QgsConstWkbPtr ptr( wkb, length );
261  reset( QgsGeometryFactory::geomFromWkb( ptr ) );
262  delete [] wkb;
263 }
264 
265 void QgsGeometry::fromWkb( const QByteArray &wkb )
266 {
267  QgsConstWkbPtr ptr( wkb );
268  reset( QgsGeometryFactory::geomFromWkb( ptr ) );
269 }
270 
271 GEOSGeometry *QgsGeometry::exportToGeos( double precision ) const
272 {
273  if ( !d->geometry )
274  {
275  return nullptr;
276  }
277 
278  return QgsGeos::asGeos( d->geometry.get(), precision ).release();
279 }
280 
281 
283 {
284  if ( !d->geometry )
285  {
286  return QgsWkbTypes::Unknown;
287  }
288  else
289  {
290  return d->geometry->wkbType();
291  }
292 }
293 
294 
296 {
297  if ( !d->geometry )
298  {
300  }
301  return static_cast< QgsWkbTypes::GeometryType >( QgsWkbTypes::geometryType( d->geometry->wkbType() ) );
302 }
303 
305 {
306  if ( !d->geometry )
307  {
308  return true;
309  }
310 
311  return d->geometry->isEmpty();
312 }
313 
315 {
316  if ( !d->geometry )
317  {
318  return false;
319  }
320  return QgsWkbTypes::isMultiType( d->geometry->wkbType() );
321 }
322 
323 void QgsGeometry::fromGeos( GEOSGeometry *geos )
324 {
325  reset( QgsGeos::fromGeos( geos ) );
326  GEOSGeom_destroy_r( QgsGeos::getGEOSHandler(), geos );
327 }
328 
329 QgsPointXY QgsGeometry::closestVertex( const QgsPointXY &point, int &atVertex, int &beforeVertex, int &afterVertex, double &sqrDist ) const
330 {
331  if ( !d->geometry )
332  {
333  sqrDist = -1;
334  return QgsPointXY( 0, 0 );
335  }
336 
337  QgsPoint pt( point.x(), point.y() );
338  QgsVertexId id;
339 
340  QgsPoint vp = QgsGeometryUtils::closestVertex( *( d->geometry ), pt, id );
341  if ( !id.isValid() )
342  {
343  sqrDist = -1;
344  return QgsPointXY( 0, 0 );
345  }
346  sqrDist = QgsGeometryUtils::sqrDistance2D( pt, vp );
347 
348  QgsVertexId prevVertex;
349  QgsVertexId nextVertex;
350  d->geometry->adjacentVertices( id, prevVertex, nextVertex );
351  atVertex = vertexNrFromVertexId( id );
352  beforeVertex = vertexNrFromVertexId( prevVertex );
353  afterVertex = vertexNrFromVertexId( nextVertex );
354  return QgsPointXY( vp.x(), vp.y() );
355 }
356 
357 double QgsGeometry::distanceToVertex( int vertex ) const
358 {
359  if ( !d->geometry )
360  {
361  return -1;
362  }
363 
364  QgsVertexId id;
365  if ( !vertexIdFromVertexNr( vertex, id ) )
366  {
367  return -1;
368  }
369 
370  return QgsGeometryUtils::distanceToVertex( *( d->geometry ), id );
371 }
372 
373 double QgsGeometry::angleAtVertex( int vertex ) const
374 {
375  if ( !d->geometry )
376  {
377  return 0;
378  }
379 
380  QgsVertexId v2;
381  if ( !vertexIdFromVertexNr( vertex, v2 ) )
382  {
383  return 0;
384  }
385 
386  return d->geometry->vertexAngle( v2 );
387 }
388 
389 void QgsGeometry::adjacentVertices( int atVertex, int &beforeVertex, int &afterVertex ) const
390 {
391  if ( !d->geometry )
392  {
393  return;
394  }
395 
396  QgsVertexId id;
397  if ( !vertexIdFromVertexNr( atVertex, id ) )
398  {
399  beforeVertex = -1;
400  afterVertex = -1;
401  return;
402  }
403 
404  QgsVertexId beforeVertexId, afterVertexId;
405  d->geometry->adjacentVertices( id, beforeVertexId, afterVertexId );
406  beforeVertex = vertexNrFromVertexId( beforeVertexId );
407  afterVertex = vertexNrFromVertexId( afterVertexId );
408 }
409 
410 bool QgsGeometry::moveVertex( double x, double y, int atVertex )
411 {
412  if ( !d->geometry )
413  {
414  return false;
415  }
416 
417  QgsVertexId id;
418  if ( !vertexIdFromVertexNr( atVertex, id ) )
419  {
420  return false;
421  }
422 
423  detach();
424 
425  return d->geometry->moveVertex( id, QgsPoint( x, y ) );
426 }
427 
428 bool QgsGeometry::moveVertex( const QgsPoint &p, int atVertex )
429 {
430  if ( !d->geometry )
431  {
432  return false;
433  }
434 
435  QgsVertexId id;
436  if ( !vertexIdFromVertexNr( atVertex, id ) )
437  {
438  return false;
439  }
440 
441  detach();
442 
443  return d->geometry->moveVertex( id, p );
444 }
445 
446 bool QgsGeometry::deleteVertex( int atVertex )
447 {
448  if ( !d->geometry )
449  {
450  return false;
451  }
452 
453  //maintain compatibility with < 2.10 API
454  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::MultiPoint )
455  {
456  detach();
457  //delete geometry instead of point
458  return static_cast< QgsGeometryCollection * >( d->geometry.get() )->removeGeometry( atVertex );
459  }
460 
461  //if it is a point, set the geometry to nullptr
462  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::Point )
463  {
464  reset( nullptr );
465  return true;
466  }
467 
468  QgsVertexId id;
469  if ( !vertexIdFromVertexNr( atVertex, id ) )
470  {
471  return false;
472  }
473 
474  detach();
475 
476  return d->geometry->deleteVertex( id );
477 }
478 
479 bool QgsGeometry::insertVertex( double x, double y, int beforeVertex )
480 {
481  if ( !d->geometry )
482  {
483  return false;
484  }
485 
486  //maintain compatibility with < 2.10 API
487  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::MultiPoint )
488  {
489  detach();
490  //insert geometry instead of point
491  return static_cast< QgsGeometryCollection * >( d->geometry.get() )->insertGeometry( new QgsPoint( x, y ), beforeVertex );
492  }
493 
494  QgsVertexId id;
495  if ( !vertexIdFromVertexNr( beforeVertex, id ) )
496  {
497  return false;
498  }
499 
500  detach();
501 
502  return d->geometry->insertVertex( id, QgsPoint( x, y ) );
503 }
504 
505 bool QgsGeometry::insertVertex( const QgsPoint &point, int beforeVertex )
506 {
507  if ( !d->geometry )
508  {
509  return false;
510  }
511 
512  //maintain compatibility with < 2.10 API
513  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::MultiPoint )
514  {
515  detach();
516  //insert geometry instead of point
517  return static_cast< QgsGeometryCollection * >( d->geometry.get() )->insertGeometry( new QgsPoint( point ), beforeVertex );
518  }
519 
520  QgsVertexId id;
521  if ( !vertexIdFromVertexNr( beforeVertex, id ) )
522  {
523  return false;
524  }
525 
526  detach();
527 
528  return d->geometry->insertVertex( id, point );
529 }
530 
531 QgsPoint QgsGeometry::vertexAt( int atVertex ) const
532 {
533  if ( !d->geometry )
534  {
535  return QgsPoint();
536  }
537 
538  QgsVertexId vId;
539  ( void )vertexIdFromVertexNr( atVertex, vId );
540  if ( vId.vertex < 0 )
541  {
542  return QgsPoint();
543  }
544  return d->geometry->vertexAt( vId );
545 }
546 
547 double QgsGeometry::sqrDistToVertexAt( QgsPointXY &point, int atVertex ) const
548 {
549  QgsPointXY vertexPoint = vertexAt( atVertex );
550  return QgsGeometryUtils::sqrDistance2D( QgsPoint( vertexPoint.x(), vertexPoint.y() ), QgsPoint( point.x(), point.y() ) );
551 }
552 
554 {
555  QgsGeos geos( d->geometry.get() );
556  mLastError.clear();
557  QgsGeometry result = geos.closestPoint( other );
558  result.mLastError = mLastError;
559  return result;
560 }
561 
563 {
564  QgsGeos geos( d->geometry.get() );
565  mLastError.clear();
566  QgsGeometry result = geos.shortestLine( other, &mLastError );
567  result.mLastError = mLastError;
568  return result;
569 }
570 
571 double QgsGeometry::closestVertexWithContext( const QgsPointXY &point, int &atVertex ) const
572 {
573  if ( !d->geometry )
574  {
575  return -1;
576  }
577 
578  QgsVertexId vId;
579  QgsPoint pt( point.x(), point.y() );
580  QgsPoint closestPoint = QgsGeometryUtils::closestVertex( *( d->geometry ), pt, vId );
581  if ( !vId.isValid() )
582  return -1;
583  atVertex = vertexNrFromVertexId( vId );
584  return QgsGeometryUtils::sqrDistance2D( closestPoint, pt );
585 }
586 
588  const QgsPointXY &point,
589  QgsPointXY &minDistPoint,
590  int &afterVertex,
591  double *leftOf,
592  double epsilon ) const
593 {
594  if ( !d->geometry )
595  {
596  return -1;
597  }
598 
599  QgsPoint segmentPt;
600  QgsVertexId vertexAfter;
601  bool leftOfBool;
602 
603  double sqrDist = d->geometry->closestSegment( QgsPoint( point.x(), point.y() ), segmentPt, vertexAfter, &leftOfBool, epsilon );
604  if ( sqrDist < 0 )
605  return -1;
606 
607  minDistPoint.setX( segmentPt.x() );
608  minDistPoint.setY( segmentPt.y() );
609  afterVertex = vertexNrFromVertexId( vertexAfter );
610  if ( leftOf )
611  {
612  *leftOf = leftOfBool ? 1.0 : -1.0;
613  }
614  return sqrDist;
615 }
616 
617 QgsGeometry::OperationResult QgsGeometry::addRing( const QVector<QgsPointXY> &ring )
618 {
619  std::unique_ptr< QgsLineString > ringLine = qgis::make_unique< QgsLineString >( ring );
620  return addRing( ringLine.release() );
621 }
622 
624 {
625  std::unique_ptr< QgsCurve > r( ring );
626  if ( !d->geometry )
627  {
628  return InvalidInput;
629  }
630 
631  detach();
632 
633  return QgsGeometryEditUtils::addRing( d->geometry.get(), std::move( r ) );
634 }
635 
637 {
639  convertPointList( points, l );
640  return addPart( l, geomType );
641 }
642 
644 {
645  std::unique_ptr< QgsAbstractGeometry > partGeom;
646  if ( points.size() == 1 )
647  {
648  partGeom = qgis::make_unique< QgsPoint >( points[0] );
649  }
650  else if ( points.size() > 1 )
651  {
652  std::unique_ptr< QgsLineString > ringLine = qgis::make_unique< QgsLineString >();
653  ringLine->setPoints( points );
654  partGeom = std::move( ringLine );
655  }
656  return addPart( partGeom.release(), geomType );
657 }
658 
660 {
661  std::unique_ptr< QgsAbstractGeometry > p( part );
662  if ( !d->geometry )
663  {
664  switch ( geomType )
665  {
667  reset( qgis::make_unique< QgsMultiPoint >() );
668  break;
670  reset( qgis::make_unique< QgsMultiLineString >() );
671  break;
673  reset( qgis::make_unique< QgsMultiPolygon >() );
674  break;
675  default:
676  reset( nullptr );
678  }
679  }
680  else
681  {
682  detach();
683  }
684 
686  return QgsGeometryEditUtils::addPart( d->geometry.get(), std::move( p ) );
687 }
688 
690 {
691  if ( !d->geometry )
692  {
694  }
695  if ( !newPart || !newPart.d->geometry )
696  {
698  }
699 
700  return addPart( newPart.d->geometry->clone() );
701 }
702 
703 QgsGeometry QgsGeometry::removeInteriorRings( double minimumRingArea ) const
704 {
705  if ( !d->geometry || type() != QgsWkbTypes::PolygonGeometry )
706  {
707  return QgsGeometry();
708  }
709 
710  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
711  {
712  const QVector<QgsGeometry> parts = asGeometryCollection();
713  QVector<QgsGeometry> results;
714  for ( const QgsGeometry &part : parts )
715  {
716  QgsGeometry result = part.removeInteriorRings( minimumRingArea );
717  if ( result )
718  results << result;
719  }
720  if ( results.isEmpty() )
721  return QgsGeometry();
722 
723  QgsGeometry first = results.takeAt( 0 );
724  for ( const QgsGeometry &result : qgis::as_const( results ) )
725  {
726  first.addPart( result );
727  }
728  return first;
729  }
730  else
731  {
732  std::unique_ptr< QgsCurvePolygon > newPoly( static_cast< QgsCurvePolygon * >( d->geometry->clone() ) );
733  newPoly->removeInteriorRings( minimumRingArea );
734  return QgsGeometry( std::move( newPoly ) );
735  }
736 }
737 
739 {
740  if ( !d->geometry )
741  {
743  }
744  if ( !newPart )
745  {
747  }
748 
749  detach();
750 
751  std::unique_ptr< QgsAbstractGeometry > geom = QgsGeos::fromGeos( newPart );
752  return QgsGeometryEditUtils::addPart( d->geometry.get(), std::move( geom ) );
753 }
754 
756 {
757  if ( !d->geometry )
758  {
760  }
761 
762  detach();
763 
764  d->geometry->transform( QTransform::fromTranslate( dx, dy ) );
765  return QgsGeometry::Success;
766 }
767 
769 {
770  if ( !d->geometry )
771  {
773  }
774 
775  detach();
776 
777  QTransform t = QTransform::fromTranslate( center.x(), center.y() );
778  t.rotate( -rotation );
779  t.translate( -center.x(), -center.y() );
780  d->geometry->transform( t );
781  return QgsGeometry::Success;
782 }
783 
784 QgsGeometry::OperationResult QgsGeometry::splitGeometry( const QVector<QgsPointXY> &splitLine, QVector<QgsGeometry> &newGeometries, bool topological, QVector<QgsPointXY> &topologyTestPoints )
785 {
786  if ( !d->geometry )
787  {
788  return InvalidBaseGeometry;
789  }
790 
791  QVector<QgsGeometry > newGeoms;
792  QgsLineString splitLineString( splitLine );
793  QgsPointSequence tp;
794 
795  QgsGeos geos( d->geometry.get() );
796  mLastError.clear();
797  QgsGeometryEngine::EngineOperationResult result = geos.splitGeometry( splitLineString, newGeoms, topological, tp, &mLastError );
798 
799  if ( result == QgsGeometryEngine::Success )
800  {
801  *this = newGeoms.takeAt( 0 );
802 
803  newGeometries = newGeoms;
804  }
805 
806  convertPointList( tp, topologyTestPoints );
807 
808  switch ( result )
809  {
811  return QgsGeometry::Success;
824  //default: do not implement default to handle properly all cases
825  }
826 
827  // this should never be reached
828  Q_ASSERT( false );
830 }
831 
833 {
834  if ( !d->geometry )
835  {
836  return InvalidBaseGeometry;
837  }
838 
839  QgsGeos geos( d->geometry.get() );
841  mLastError.clear();
842  std::unique_ptr< QgsAbstractGeometry > geom( geos.reshapeGeometry( reshapeLineString, &errorCode, &mLastError ) );
843  if ( errorCode == QgsGeometryEngine::Success && geom )
844  {
845  reset( std::move( geom ) );
846  return Success;
847  }
848 
849  switch ( errorCode )
850  {
852  return Success;
856  return GeometryEngineError;
858  return InvalidBaseGeometry;
860  return InvalidInput;
861  case QgsGeometryEngine::SplitCannotSplitPoint: // should not happen
862  return GeometryEngineError;
864  return NothingHappened;
865  }
866 
867  // should not be reached
868  return GeometryEngineError;
869 }
870 
872 {
873  if ( !d->geometry || !other.d->geometry )
874  {
875  return 0;
876  }
877 
878  QgsGeos geos( d->geometry.get() );
879 
880  mLastError.clear();
881  std::unique_ptr< QgsAbstractGeometry > diffGeom( geos.intersection( other.constGet(), &mLastError ) );
882  if ( !diffGeom )
883  {
884  return 1;
885  }
886 
887  reset( std::move( diffGeom ) );
888  return 0;
889 }
890 
892 {
893  if ( !d->geometry || other.isNull() )
894  {
895  return QgsGeometry();
896  }
897 
898  QgsGeos geos( d->geometry.get() );
899 
900  mLastError.clear();
901  std::unique_ptr< QgsAbstractGeometry > diffGeom( geos.intersection( other.constGet(), &mLastError ) );
902  if ( !diffGeom )
903  {
904  QgsGeometry result;
905  result.mLastError = mLastError;
906  return result;
907  }
908 
909  return QgsGeometry( diffGeom.release() );
910 }
911 
913 {
914  if ( d->geometry )
915  {
916  return d->geometry->boundingBox();
917  }
918  return QgsRectangle();
919 }
920 
921 QgsGeometry QgsGeometry::orientedMinimumBoundingBox( double &area, double &angle, double &width, double &height ) const
922 {
923  QgsRectangle minRect;
924  area = DBL_MAX;
925  angle = 0;
926  width = DBL_MAX;
927  height = DBL_MAX;
928 
929  if ( !d->geometry || d->geometry->nCoordinates() < 2 )
930  return QgsGeometry();
931 
932  QgsGeometry hull = convexHull();
933  if ( hull.isNull() )
934  return QgsGeometry();
935 
936  QgsVertexId vertexId;
937  QgsPoint pt0;
938  QgsPoint pt1;
939  QgsPoint pt2;
940  // get first point
941  hull.constGet()->nextVertex( vertexId, pt0 );
942  pt1 = pt0;
943  double prevAngle = 0.0;
944  while ( hull.constGet()->nextVertex( vertexId, pt2 ) )
945  {
946  double currentAngle = QgsGeometryUtils::lineAngle( pt1.x(), pt1.y(), pt2.x(), pt2.y() );
947  double rotateAngle = 180.0 / M_PI * ( currentAngle - prevAngle );
948  prevAngle = currentAngle;
949 
950  QTransform t = QTransform::fromTranslate( pt0.x(), pt0.y() );
951  t.rotate( rotateAngle );
952  t.translate( -pt0.x(), -pt0.y() );
953 
954  hull.get()->transform( t );
955 
956  QgsRectangle bounds = hull.constGet()->boundingBox();
957  double currentArea = bounds.width() * bounds.height();
958  if ( currentArea < area )
959  {
960  minRect = bounds;
961  area = currentArea;
962  angle = 180.0 / M_PI * currentAngle;
963  width = bounds.width();
964  height = bounds.height();
965  }
966 
967  pt2 = pt1;
968  }
969 
970  QgsGeometry minBounds = QgsGeometry::fromRect( minRect );
971  minBounds.rotate( angle, QgsPointXY( pt0.x(), pt0.y() ) );
972 
973  // constrain angle to 0 - 180
974  if ( angle > 180.0 )
975  angle = std::fmod( angle, 180.0 );
976 
977  return minBounds;
978 }
979 
981 {
982  double area, angle, width, height;
983  return orientedMinimumBoundingBox( area, angle, width, height );
984 }
985 
986 static QgsCircle __recMinimalEnclosingCircle( QgsMultiPointXY points, QgsMultiPointXY boundary )
987 {
988  auto l_boundary = boundary.length();
989  QgsCircle circ_mec;
990  if ( ( points.length() == 0 ) || ( l_boundary == 3 ) )
991  {
992  switch ( l_boundary )
993  {
994  case 0:
995  circ_mec = QgsCircle();
996  break;
997  case 1:
998  circ_mec = QgsCircle( QgsPoint( boundary.last() ), 0 );
999  boundary.pop_back();
1000  break;
1001  case 2:
1002  {
1003  QgsPointXY p1 = boundary.last();
1004  boundary.pop_back();
1005  QgsPointXY p2 = boundary.last();
1006  boundary.pop_back();
1007  circ_mec = QgsCircle().from2Points( QgsPoint( p1 ), QgsPoint( p2 ) );
1008  }
1009  break;
1010  default:
1011  QgsPoint p1( boundary.at( 0 ) );
1012  QgsPoint p2( boundary.at( 1 ) );
1013  QgsPoint p3( boundary.at( 2 ) );
1014  circ_mec = QgsCircle().minimalCircleFrom3Points( p1, p2, p3 );
1015  break;
1016  }
1017  return circ_mec;
1018  }
1019  else
1020  {
1021  QgsPointXY pxy = points.last();
1022  points.pop_back();
1023  circ_mec = __recMinimalEnclosingCircle( points, boundary );
1024  QgsPoint p( pxy );
1025  if ( !circ_mec.contains( p ) )
1026  {
1027  boundary.append( pxy );
1028  circ_mec = __recMinimalEnclosingCircle( points, boundary );
1029  }
1030  }
1031  return circ_mec;
1032 }
1033 
1034 QgsGeometry QgsGeometry::minimalEnclosingCircle( QgsPointXY &center, double &radius, unsigned int segments ) const
1035 {
1036  center = QgsPointXY( );
1037  radius = 0;
1038 
1039  if ( !d->geometry )
1040  {
1041  return QgsGeometry();
1042  }
1043 
1044  /* optimization */
1045  QgsGeometry hull = convexHull();
1046  if ( hull.isNull() )
1047  return QgsGeometry();
1048 
1049  QgsMultiPointXY P = hull.convertToPoint( true ).asMultiPoint();
1050  QgsMultiPointXY R;
1051 
1052  QgsCircle circ = __recMinimalEnclosingCircle( P, R );
1053  center = QgsPointXY( circ.center() );
1054  radius = circ.radius();
1055  QgsGeometry geom;
1056  geom.set( circ.toPolygon( segments ) );
1057  return geom;
1058 
1059 }
1060 
1061 QgsGeometry QgsGeometry::minimalEnclosingCircle( unsigned int segments ) const
1062 {
1063  QgsPointXY center;
1064  double radius;
1065  return minimalEnclosingCircle( center, radius, segments );
1066 
1067 }
1068 
1069 QgsGeometry QgsGeometry::orthogonalize( double tolerance, int maxIterations, double angleThreshold ) const
1070 {
1071  QgsInternalGeometryEngine engine( *this );
1072 
1073  return engine.orthogonalize( tolerance, maxIterations, angleThreshold );
1074 }
1075 
1076 QgsGeometry QgsGeometry::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing ) const
1077 {
1078  if ( !d->geometry )
1079  {
1080  return QgsGeometry();
1081  }
1082  return QgsGeometry( d->geometry->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing ) );
1083 }
1084 
1086 {
1087  QgsGeometry g = fromRect( r );
1088  return intersects( g );
1089 }
1090 
1091 bool QgsGeometry::intersects( const QgsGeometry &geometry ) const
1092 {
1093  if ( !d->geometry || geometry.isNull() )
1094  {
1095  return false;
1096  }
1097 
1098  QgsGeos geos( d->geometry.get() );
1099  mLastError.clear();
1100  return geos.intersects( geometry.d->geometry.get(), &mLastError );
1101 }
1102 
1103 bool QgsGeometry::contains( const QgsPointXY *p ) const
1104 {
1105  if ( !d->geometry || !p )
1106  {
1107  return false;
1108  }
1109 
1110  QgsPoint pt( p->x(), p->y() );
1111  QgsGeos geos( d->geometry.get() );
1112  mLastError.clear();
1113  return geos.contains( &pt, &mLastError );
1114 }
1115 
1116 bool QgsGeometry::contains( const QgsGeometry &geometry ) const
1117 {
1118  if ( !d->geometry || geometry.isNull() )
1119  {
1120  return false;
1121  }
1122 
1123  QgsGeos geos( d->geometry.get() );
1124  mLastError.clear();
1125  return geos.contains( geometry.d->geometry.get(), &mLastError );
1126 }
1127 
1128 bool QgsGeometry::disjoint( const QgsGeometry &geometry ) const
1129 {
1130  if ( !d->geometry || geometry.isNull() )
1131  {
1132  return false;
1133  }
1134 
1135  QgsGeos geos( d->geometry.get() );
1136  mLastError.clear();
1137  return geos.disjoint( geometry.d->geometry.get(), &mLastError );
1138 }
1139 
1140 bool QgsGeometry::equals( const QgsGeometry &geometry ) const
1141 {
1142  if ( !d->geometry || geometry.isNull() )
1143  {
1144  return false;
1145  }
1146 
1147  QgsGeos geos( d->geometry.get() );
1148  mLastError.clear();
1149  return geos.isEqual( geometry.d->geometry.get(), &mLastError );
1150 }
1151 
1152 bool QgsGeometry::touches( const QgsGeometry &geometry ) const
1153 {
1154  if ( !d->geometry || geometry.isNull() )
1155  {
1156  return false;
1157  }
1158 
1159  QgsGeos geos( d->geometry.get() );
1160  mLastError.clear();
1161  return geos.touches( geometry.d->geometry.get(), &mLastError );
1162 }
1163 
1164 bool QgsGeometry::overlaps( const QgsGeometry &geometry ) const
1165 {
1166  if ( !d->geometry || geometry.isNull() )
1167  {
1168  return false;
1169  }
1170 
1171  QgsGeos geos( d->geometry.get() );
1172  mLastError.clear();
1173  return geos.overlaps( geometry.d->geometry.get(), &mLastError );
1174 }
1175 
1176 bool QgsGeometry::within( const QgsGeometry &geometry ) const
1177 {
1178  if ( !d->geometry || geometry.isNull() )
1179  {
1180  return false;
1181  }
1182 
1183  QgsGeos geos( d->geometry.get() );
1184  mLastError.clear();
1185  return geos.within( geometry.d->geometry.get(), &mLastError );
1186 }
1187 
1188 bool QgsGeometry::crosses( const QgsGeometry &geometry ) const
1189 {
1190  if ( !d->geometry || geometry.isNull() )
1191  {
1192  return false;
1193  }
1194 
1195  QgsGeos geos( d->geometry.get() );
1196  mLastError.clear();
1197  return geos.crosses( geometry.d->geometry.get(), &mLastError );
1198 }
1199 
1200 QString QgsGeometry::asWkt( int precision ) const
1201 {
1202  if ( !d->geometry )
1203  {
1204  return QString();
1205  }
1206  return d->geometry->asWkt( precision );
1207 }
1208 
1209 QString QgsGeometry::asJson( int precision ) const
1210 {
1211  if ( !d->geometry )
1212  {
1213  return QStringLiteral( "null" );
1214  }
1215  return d->geometry->asJson( precision );
1216 }
1217 
1219 {
1220  switch ( destType )
1221  {
1223  return convertToPoint( destMultipart );
1224 
1226  return convertToLine( destMultipart );
1227 
1229  return convertToPolygon( destMultipart );
1230 
1231  default:
1232  return QgsGeometry();
1233  }
1234 }
1235 
1237 {
1238  if ( !d->geometry )
1239  {
1240  return false;
1241  }
1242 
1243  if ( isMultipart() ) //already multitype, no need to convert
1244  {
1245  return true;
1246  }
1247 
1248  std::unique_ptr< QgsAbstractGeometry >geom = QgsGeometryFactory::geomFromWkbType( QgsWkbTypes::multiType( d->geometry->wkbType() ) );
1249  QgsGeometryCollection *multiGeom = qgsgeometry_cast<QgsGeometryCollection *>( geom.get() );
1250  if ( !multiGeom )
1251  {
1252  return false;
1253  }
1254 
1255  multiGeom->addGeometry( d->geometry->clone() );
1256  reset( std::move( geom ) );
1257  return true;
1258 }
1259 
1261 {
1262  if ( !d->geometry )
1263  {
1264  return false;
1265  }
1266 
1267  if ( !isMultipart() ) //already single part, no need to convert
1268  {
1269  return true;
1270  }
1271 
1273  if ( !multiGeom || multiGeom->partCount() < 1 )
1274  return false;
1275 
1276  std::unique_ptr< QgsAbstractGeometry > firstPart( multiGeom->geometryN( 0 )->clone() );
1277  reset( std::move( firstPart ) );
1278  return true;
1279 }
1280 
1282 {
1283  if ( !d->geometry || QgsWkbTypes::flatType( d->geometry->wkbType() ) != QgsWkbTypes::Point )
1284  {
1285  return QgsPointXY();
1286  }
1287  QgsPoint *pt = qgsgeometry_cast<QgsPoint *>( d->geometry.get() );
1288  if ( !pt )
1289  {
1290  return QgsPointXY();
1291  }
1292 
1293  return QgsPointXY( pt->x(), pt->y() );
1294 }
1295 
1297 {
1298  QgsPolylineXY polyLine;
1299  if ( !d->geometry )
1300  {
1301  return polyLine;
1302  }
1303 
1304  bool doSegmentation = ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::CompoundCurve
1306  std::unique_ptr< QgsLineString > segmentizedLine;
1307  QgsLineString *line = nullptr;
1308  if ( doSegmentation )
1309  {
1310  QgsCurve *curve = qgsgeometry_cast<QgsCurve *>( d->geometry.get() );
1311  if ( !curve )
1312  {
1313  return polyLine;
1314  }
1315  segmentizedLine.reset( curve->curveToLine() );
1316  line = segmentizedLine.get();
1317  }
1318  else
1319  {
1320  line = qgsgeometry_cast<QgsLineString *>( d->geometry.get() );
1321  if ( !line )
1322  {
1323  return polyLine;
1324  }
1325  }
1326 
1327  int nVertices = line->numPoints();
1328  polyLine.resize( nVertices );
1329  for ( int i = 0; i < nVertices; ++i )
1330  {
1331  polyLine[i].setX( line->xAt( i ) );
1332  polyLine[i].setY( line->yAt( i ) );
1333  }
1334 
1335  return polyLine;
1336 }
1337 
1339 {
1340  if ( !d->geometry )
1341  return QgsPolygonXY();
1342 
1343  bool doSegmentation = ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::CurvePolygon );
1344 
1345  QgsPolygon *p = nullptr;
1346  std::unique_ptr< QgsPolygon > segmentized;
1347  if ( doSegmentation )
1348  {
1349  QgsCurvePolygon *curvePoly = qgsgeometry_cast<QgsCurvePolygon *>( d->geometry.get() );
1350  if ( !curvePoly )
1351  {
1352  return QgsPolygonXY();
1353  }
1354  segmentized.reset( curvePoly->toPolygon() );
1355  p = segmentized.get();
1356  }
1357  else
1358  {
1359  p = qgsgeometry_cast<QgsPolygon *>( d->geometry.get() );
1360  }
1361 
1362  if ( !p )
1363  {
1364  return QgsPolygonXY();
1365  }
1366 
1367  QgsPolygonXY polygon;
1368  convertPolygon( *p, polygon );
1369 
1370  return polygon;
1371 }
1372 
1374 {
1375  if ( !d->geometry || QgsWkbTypes::flatType( d->geometry->wkbType() ) != QgsWkbTypes::MultiPoint )
1376  {
1377  return QgsMultiPointXY();
1378  }
1379 
1380  const QgsMultiPoint *mp = qgsgeometry_cast<QgsMultiPoint *>( d->geometry.get() );
1381  if ( !mp )
1382  {
1383  return QgsMultiPointXY();
1384  }
1385 
1386  int nPoints = mp->numGeometries();
1387  QgsMultiPointXY multiPoint( nPoints );
1388  for ( int i = 0; i < nPoints; ++i )
1389  {
1390  const QgsPoint *pt = static_cast<const QgsPoint *>( mp->geometryN( i ) );
1391  multiPoint[i].setX( pt->x() );
1392  multiPoint[i].setY( pt->y() );
1393  }
1394  return multiPoint;
1395 }
1396 
1398 {
1399  if ( !d->geometry )
1400  {
1401  return QgsMultiPolylineXY();
1402  }
1403 
1404  QgsGeometryCollection *geomCollection = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
1405  if ( !geomCollection )
1406  {
1407  return QgsMultiPolylineXY();
1408  }
1409 
1410  int nLines = geomCollection->numGeometries();
1411  if ( nLines < 1 )
1412  {
1413  return QgsMultiPolylineXY();
1414  }
1415 
1416  QgsMultiPolylineXY mpl;
1417  for ( int i = 0; i < nLines; ++i )
1418  {
1419  const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( geomCollection->geometryN( i ) );
1420  std::unique_ptr< QgsLineString > segmentized;
1421  if ( !line )
1422  {
1423  const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( geomCollection->geometryN( i ) );
1424  if ( !curve )
1425  {
1426  continue;
1427  }
1428  segmentized.reset( curve->curveToLine() );
1429  line = segmentized.get();
1430  }
1431 
1432  QgsPointSequence lineCoords;
1433  line->points( lineCoords );
1434  QgsPolylineXY polyLine;
1435  convertToPolyline( lineCoords, polyLine );
1436  mpl.append( polyLine );
1437  }
1438  return mpl;
1439 }
1440 
1442 {
1443  if ( !d->geometry )
1444  {
1445  return QgsMultiPolygonXY();
1446  }
1447 
1448  QgsGeometryCollection *geomCollection = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
1449  if ( !geomCollection )
1450  {
1451  return QgsMultiPolygonXY();
1452  }
1453 
1454  int nPolygons = geomCollection->numGeometries();
1455  if ( nPolygons < 1 )
1456  {
1457  return QgsMultiPolygonXY();
1458  }
1459 
1460  QgsMultiPolygonXY mp;
1461  for ( int i = 0; i < nPolygons; ++i )
1462  {
1463  const QgsPolygon *polygon = qgsgeometry_cast<const QgsPolygon *>( geomCollection->geometryN( i ) );
1464  if ( !polygon )
1465  {
1466  const QgsCurvePolygon *cPolygon = qgsgeometry_cast<const QgsCurvePolygon *>( geomCollection->geometryN( i ) );
1467  if ( cPolygon )
1468  {
1469  polygon = cPolygon->toPolygon();
1470  }
1471  else
1472  {
1473  continue;
1474  }
1475  }
1476 
1477  QgsPolygonXY poly;
1478  convertPolygon( *polygon, poly );
1479  mp.append( poly );
1480  }
1481  return mp;
1482 }
1483 
1484 double QgsGeometry::area() const
1485 {
1486  if ( !d->geometry )
1487  {
1488  return -1.0;
1489  }
1490  QgsGeos g( d->geometry.get() );
1491 
1492 #if 0
1493  //debug: compare geos area with calculation in QGIS
1494  double geosArea = g.area();
1495  double qgisArea = 0;
1496  QgsSurface *surface = qgsgeometry_cast<QgsSurface *>( d->geometry );
1497  if ( surface )
1498  {
1499  qgisArea = surface->area();
1500  }
1501 #endif
1502 
1503  mLastError.clear();
1504  return g.area( &mLastError );
1505 }
1506 
1507 double QgsGeometry::length() const
1508 {
1509  if ( !d->geometry )
1510  {
1511  return -1.0;
1512  }
1513  QgsGeos g( d->geometry.get() );
1514  mLastError.clear();
1515  return g.length( &mLastError );
1516 }
1517 
1518 double QgsGeometry::distance( const QgsGeometry &geom ) const
1519 {
1520  if ( !d->geometry || !geom.d->geometry )
1521  {
1522  return -1.0;
1523  }
1524 
1525  QgsGeos g( d->geometry.get() );
1526  mLastError.clear();
1527  return g.distance( geom.d->geometry.get(), &mLastError );
1528 }
1529 
1530 double QgsGeometry::hausdorffDistance( const QgsGeometry &geom ) const
1531 {
1532  if ( !d->geometry || !geom.d->geometry )
1533  {
1534  return -1.0;
1535  }
1536 
1537  QgsGeos g( d->geometry.get() );
1538  mLastError.clear();
1539  return g.hausdorffDistance( geom.d->geometry.get(), &mLastError );
1540 }
1541 
1542 double QgsGeometry::hausdorffDistanceDensify( const QgsGeometry &geom, double densifyFraction ) const
1543 {
1544  if ( !d->geometry || !geom.d->geometry )
1545  {
1546  return -1.0;
1547  }
1548 
1549  QgsGeos g( d->geometry.get() );
1550  mLastError.clear();
1551  return g.hausdorffDistanceDensify( geom.d->geometry.get(), densifyFraction, &mLastError );
1552 }
1553 
1555 {
1556  if ( !d->geometry )
1558  return d->geometry->vertices_begin();
1559 }
1560 
1562 {
1563  if ( !d->geometry )
1565  return d->geometry->vertices_end();
1566 }
1567 
1569 {
1570  if ( !d->geometry )
1571  return QgsVertexIterator();
1572  return QgsVertexIterator( d->geometry.get() );
1573 }
1574 
1575 QgsGeometry QgsGeometry::buffer( double distance, int segments ) const
1576 {
1577  if ( !d->geometry )
1578  {
1579  return QgsGeometry();
1580  }
1581 
1582  QgsGeos g( d->geometry.get() );
1583  mLastError.clear();
1584  std::unique_ptr<QgsAbstractGeometry> geom( g.buffer( distance, segments, &mLastError ) );
1585  if ( !geom )
1586  {
1587  QgsGeometry result;
1588  result.mLastError = mLastError;
1589  return result;
1590  }
1591  return QgsGeometry( std::move( geom ) );
1592 }
1593 
1594 QgsGeometry QgsGeometry::buffer( double distance, int segments, EndCapStyle endCapStyle, JoinStyle joinStyle, double miterLimit ) const
1595 {
1596  if ( !d->geometry )
1597  {
1598  return QgsGeometry();
1599  }
1600 
1601  QgsGeos g( d->geometry.get() );
1602  mLastError.clear();
1603  QgsAbstractGeometry *geom = g.buffer( distance, segments, endCapStyle, joinStyle, miterLimit, &mLastError );
1604  if ( !geom )
1605  {
1606  QgsGeometry result;
1607  result.mLastError = mLastError;
1608  return result;
1609  }
1610  return QgsGeometry( geom );
1611 }
1612 
1613 QgsGeometry QgsGeometry::offsetCurve( double distance, int segments, JoinStyle joinStyle, double miterLimit ) const
1614 {
1615  if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
1616  {
1617  return QgsGeometry();
1618  }
1619 
1620  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
1621  {
1622  const QVector<QgsGeometry> parts = asGeometryCollection();
1623  QVector<QgsGeometry> results;
1624  for ( const QgsGeometry &part : parts )
1625  {
1626  QgsGeometry result = part.offsetCurve( distance, segments, joinStyle, miterLimit );
1627  if ( result )
1628  results << result;
1629  }
1630  if ( results.isEmpty() )
1631  return QgsGeometry();
1632 
1633  QgsGeometry first = results.takeAt( 0 );
1634  for ( const QgsGeometry &result : qgis::as_const( results ) )
1635  {
1636  first.addPart( result );
1637  }
1638  return first;
1639  }
1640  else
1641  {
1642  QgsGeos geos( d->geometry.get() );
1643  mLastError.clear();
1644  QgsAbstractGeometry *offsetGeom = geos.offsetCurve( distance, segments, joinStyle, miterLimit, &mLastError );
1645  if ( !offsetGeom )
1646  {
1647  QgsGeometry result;
1648  result.mLastError = mLastError;
1649  return result;
1650  }
1651  return QgsGeometry( offsetGeom );
1652  }
1653 }
1654 
1655 QgsGeometry QgsGeometry::singleSidedBuffer( double distance, int segments, BufferSide side, JoinStyle joinStyle, double miterLimit ) const
1656 {
1657  if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
1658  {
1659  return QgsGeometry();
1660  }
1661 
1662  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
1663  {
1664  const QVector<QgsGeometry> parts = asGeometryCollection();
1665  QVector<QgsGeometry> results;
1666  for ( const QgsGeometry &part : parts )
1667  {
1668  QgsGeometry result = part.singleSidedBuffer( distance, segments, side, joinStyle, miterLimit );
1669  if ( result )
1670  results << result;
1671  }
1672  if ( results.isEmpty() )
1673  return QgsGeometry();
1674 
1675  QgsGeometry first = results.takeAt( 0 );
1676  for ( const QgsGeometry &result : qgis::as_const( results ) )
1677  {
1678  first.addPart( result );
1679  }
1680  return first;
1681  }
1682  else
1683  {
1684  QgsGeos geos( d->geometry.get() );
1685  mLastError.clear();
1686  std::unique_ptr< QgsAbstractGeometry > bufferGeom = geos.singleSidedBuffer( distance, segments, side,
1687  joinStyle, miterLimit, &mLastError );
1688  if ( !bufferGeom )
1689  {
1690  QgsGeometry result;
1691  result.mLastError = mLastError;
1692  return result;
1693  }
1694  return QgsGeometry( std::move( bufferGeom ) );
1695  }
1696 }
1697 
1698 QgsGeometry QgsGeometry::extendLine( double startDistance, double endDistance ) const
1699 {
1700  if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
1701  {
1702  return QgsGeometry();
1703  }
1704 
1705  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
1706  {
1707  const QVector<QgsGeometry> parts = asGeometryCollection();
1708  QVector<QgsGeometry> results;
1709  for ( const QgsGeometry &part : parts )
1710  {
1711  QgsGeometry result = part.extendLine( startDistance, endDistance );
1712  if ( result )
1713  results << result;
1714  }
1715  if ( results.isEmpty() )
1716  return QgsGeometry();
1717 
1718  QgsGeometry first = results.takeAt( 0 );
1719  for ( const QgsGeometry &result : qgis::as_const( results ) )
1720  {
1721  first.addPart( result );
1722  }
1723  return first;
1724  }
1725  else
1726  {
1727  QgsLineString *line = qgsgeometry_cast< QgsLineString * >( d->geometry.get() );
1728  if ( !line )
1729  return QgsGeometry();
1730 
1731  std::unique_ptr< QgsLineString > newLine( line->clone() );
1732  newLine->extend( startDistance, endDistance );
1733  return QgsGeometry( std::move( newLine ) );
1734  }
1735 }
1736 
1737 QgsGeometry QgsGeometry::simplify( double tolerance ) const
1738 {
1739  if ( !d->geometry )
1740  {
1741  return QgsGeometry();
1742  }
1743 
1744  QgsGeos geos( d->geometry.get() );
1745  mLastError.clear();
1746  std::unique_ptr< QgsAbstractGeometry > simplifiedGeom( geos.simplify( tolerance, &mLastError ) );
1747  if ( !simplifiedGeom )
1748  {
1749  QgsGeometry result;
1750  result.mLastError = mLastError;
1751  return result;
1752  }
1753  return QgsGeometry( std::move( simplifiedGeom ) );
1754 }
1755 
1756 QgsGeometry QgsGeometry::densifyByCount( int extraNodesPerSegment ) const
1757 {
1758  QgsInternalGeometryEngine engine( *this );
1759 
1760  return engine.densifyByCount( extraNodesPerSegment );
1761 }
1762 
1764 {
1765  QgsInternalGeometryEngine engine( *this );
1766 
1767  return engine.densifyByDistance( distance );
1768 }
1769 
1771 {
1772  if ( !d->geometry )
1773  {
1774  return QgsGeometry();
1775  }
1776 
1777  QgsGeos geos( d->geometry.get() );
1778 
1779  mLastError.clear();
1780  QgsGeometry result( geos.centroid( &mLastError ) );
1781  result.mLastError = mLastError;
1782  return result;
1783 }
1784 
1786 {
1787  if ( !d->geometry )
1788  {
1789  return QgsGeometry();
1790  }
1791 
1792  QgsGeos geos( d->geometry.get() );
1793 
1794  mLastError.clear();
1795  QgsGeometry result( geos.pointOnSurface( &mLastError ) );
1796  result.mLastError = mLastError;
1797  return result;
1798 }
1799 
1800 QgsGeometry QgsGeometry::poleOfInaccessibility( double precision, double *distanceToBoundary ) const
1801 {
1802  QgsInternalGeometryEngine engine( *this );
1803 
1804  return engine.poleOfInaccessibility( precision, distanceToBoundary );
1805 }
1806 
1808 {
1809  if ( !d->geometry )
1810  {
1811  return QgsGeometry();
1812  }
1813  QgsGeos geos( d->geometry.get() );
1814  mLastError.clear();
1815  std::unique_ptr< QgsAbstractGeometry > cHull( geos.convexHull( &mLastError ) );
1816  if ( !cHull )
1817  {
1818  QgsGeometry geom;
1819  geom.mLastError = mLastError;
1820  return geom;
1821  }
1822  return QgsGeometry( std::move( cHull ) );
1823 }
1824 
1825 QgsGeometry QgsGeometry::voronoiDiagram( const QgsGeometry &extent, double tolerance, bool edgesOnly ) const
1826 {
1827  if ( !d->geometry )
1828  {
1829  return QgsGeometry();
1830  }
1831 
1832  QgsGeos geos( d->geometry.get() );
1833  mLastError.clear();
1834  QgsGeometry result = geos.voronoiDiagram( extent.constGet(), tolerance, edgesOnly, &mLastError );
1835  result.mLastError = mLastError;
1836  return result;
1837 }
1838 
1839 QgsGeometry QgsGeometry::delaunayTriangulation( double tolerance, bool edgesOnly ) const
1840 {
1841  if ( !d->geometry )
1842  {
1843  return QgsGeometry();
1844  }
1845 
1846  QgsGeos geos( d->geometry.get() );
1847  mLastError.clear();
1848  QgsGeometry result = geos.delaunayTriangulation( tolerance, edgesOnly );
1849  result.mLastError = mLastError;
1850  return result;
1851 }
1852 
1854 {
1855  if ( !d->geometry )
1856  {
1857  return QgsGeometry();
1858  }
1859 
1860  const QgsAbstractGeometry *geom = d->geometry.get();
1861  std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
1862  if ( QgsWkbTypes::isCurvedType( d->geometry->wkbType() ) )
1863  {
1864  segmentizedCopy.reset( d->geometry->segmentize() );
1865  geom = segmentizedCopy.get();
1866  }
1867 
1868  QgsGeos geos( geom );
1869  mLastError.clear();
1870  std::unique_ptr< QgsAbstractGeometry > result( geos.subdivide( maxNodes, &mLastError ) );
1871  if ( !result )
1872  {
1873  QgsGeometry geom;
1874  geom.mLastError = mLastError;
1875  return geom;
1876  }
1877  return QgsGeometry( std::move( result ) );
1878 }
1879 
1881 {
1882  if ( !d->geometry )
1883  {
1884  return QgsGeometry();
1885  }
1886 
1887  QgsGeometry line = *this;
1889  line = QgsGeometry( d->geometry->boundary() );
1890 
1891  QgsGeos geos( line.constGet() );
1892  mLastError.clear();
1893  std::unique_ptr< QgsAbstractGeometry > result( geos.interpolate( distance, &mLastError ) );
1894  if ( !result )
1895  {
1896  QgsGeometry geom;
1897  geom.mLastError = mLastError;
1898  return geom;
1899  }
1900  return QgsGeometry( std::move( result ) );
1901 }
1902 
1903 double QgsGeometry::lineLocatePoint( const QgsGeometry &point ) const
1904 {
1905  if ( type() != QgsWkbTypes::LineGeometry )
1906  return -1;
1907 
1908  if ( QgsWkbTypes::flatType( point.wkbType() ) != QgsWkbTypes::Point )
1909  return -1;
1910 
1911  QgsGeometry segmentized = *this;
1913  {
1914  segmentized = QgsGeometry( static_cast< QgsCurve * >( d->geometry.get() )->segmentize() );
1915  }
1916 
1917  QgsGeos geos( d->geometry.get() );
1918  mLastError.clear();
1919  return geos.lineLocatePoint( *( static_cast< QgsPoint * >( point.d->geometry.get() ) ), &mLastError );
1920 }
1921 
1923 {
1924  if ( !d->geometry )
1925  return 0.0;
1926 
1927  // always operate on segmentized geometries
1928  QgsGeometry segmentized = *this;
1930  {
1931  segmentized = QgsGeometry( static_cast< QgsCurve * >( d->geometry.get() )->segmentize() );
1932  }
1933 
1934  QgsVertexId previous;
1935  QgsVertexId next;
1936  if ( !QgsGeometryUtils::verticesAtDistance( *segmentized.constGet(), distance, previous, next ) )
1937  return 0.0;
1938 
1939  if ( previous == next )
1940  {
1941  // distance coincided exactly with a vertex
1942  QgsVertexId v2 = previous;
1943  QgsVertexId v1;
1944  QgsVertexId v3;
1945  segmentized.constGet()->adjacentVertices( v2, v1, v3 );
1946  if ( v1.isValid() && v3.isValid() )
1947  {
1948  QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
1949  QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
1950  QgsPoint p3 = segmentized.constGet()->vertexAt( v3 );
1951  double angle1 = QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
1952  double angle2 = QgsGeometryUtils::lineAngle( p2.x(), p2.y(), p3.x(), p3.y() );
1953  return QgsGeometryUtils::averageAngle( angle1, angle2 );
1954  }
1955  else if ( v3.isValid() )
1956  {
1957  QgsPoint p1 = segmentized.constGet()->vertexAt( v2 );
1958  QgsPoint p2 = segmentized.constGet()->vertexAt( v3 );
1959  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
1960  }
1961  else
1962  {
1963  QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
1964  QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
1965  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
1966  }
1967  }
1968  else
1969  {
1970  QgsPoint p1 = segmentized.constGet()->vertexAt( previous );
1971  QgsPoint p2 = segmentized.constGet()->vertexAt( next );
1972  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
1973  }
1974 }
1975 
1977 {
1978  if ( !d->geometry || geometry.isNull() )
1979  {
1980  return QgsGeometry();
1981  }
1982 
1983  QgsGeos geos( d->geometry.get() );
1984 
1985  mLastError.clear();
1986  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.intersection( geometry.d->geometry.get(), &mLastError ) );
1987 
1988  if ( !resultGeom )
1989  {
1990  QgsGeometry geom;
1991  geom.mLastError = mLastError;
1992  return geom;
1993  }
1994 
1995  return QgsGeometry( std::move( resultGeom ) );
1996 }
1997 
1999 {
2000  if ( !d->geometry || geometry.isNull() )
2001  {
2002  return QgsGeometry();
2003  }
2004 
2005  QgsGeos geos( d->geometry.get() );
2006  mLastError.clear();
2007  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.combine( geometry.d->geometry.get(), &mLastError ) );
2008  if ( !resultGeom )
2009  {
2010  QgsGeometry geom;
2011  geom.mLastError = mLastError;
2012  return geom;
2013  }
2014  return QgsGeometry( std::move( resultGeom ) );
2015 }
2016 
2018 {
2019  if ( !d->geometry )
2020  {
2021  return QgsGeometry();
2022  }
2023 
2024  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::LineString )
2025  {
2026  // special case - a single linestring was passed
2027  return QgsGeometry( *this );
2028  }
2029 
2030  QgsGeos geos( d->geometry.get() );
2031  mLastError.clear();
2032  QgsGeometry result = geos.mergeLines( &mLastError );
2033  result.mLastError = mLastError;
2034  return result;
2035 }
2036 
2038 {
2039  if ( !d->geometry || geometry.isNull() )
2040  {
2041  return QgsGeometry();
2042  }
2043 
2044  QgsGeos geos( d->geometry.get() );
2045 
2046  mLastError.clear();
2047  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.difference( geometry.d->geometry.get(), &mLastError ) );
2048  if ( !resultGeom )
2049  {
2050  QgsGeometry geom;
2051  geom.mLastError = mLastError;
2052  return geom;
2053  }
2054  return QgsGeometry( std::move( resultGeom ) );
2055 }
2056 
2058 {
2059  if ( !d->geometry || geometry.isNull() )
2060  {
2061  return QgsGeometry();
2062  }
2063 
2064  QgsGeos geos( d->geometry.get() );
2065 
2066  mLastError.clear();
2067  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.symDifference( geometry.d->geometry.get(), &mLastError ) );
2068  if ( !resultGeom )
2069  {
2070  QgsGeometry geom;
2071  geom.mLastError = mLastError;
2072  return geom;
2073  }
2074  return QgsGeometry( std::move( resultGeom ) );
2075 }
2076 
2077 QgsGeometry QgsGeometry::extrude( double x, double y )
2078 {
2079  QgsInternalGeometryEngine engine( *this );
2080 
2081  return engine.extrude( x, y );
2082 }
2083 
2084 QByteArray QgsGeometry::asWkb() const
2085 {
2086  return d->geometry ? d->geometry->asWkb() : QByteArray();
2087 }
2088 
2089 QVector<QgsGeometry> QgsGeometry::asGeometryCollection() const
2090 {
2091  QVector<QgsGeometry> geometryList;
2092  if ( !d->geometry )
2093  {
2094  return geometryList;
2095  }
2096 
2098  if ( gc )
2099  {
2100  int numGeom = gc->numGeometries();
2101  geometryList.reserve( numGeom );
2102  for ( int i = 0; i < numGeom; ++i )
2103  {
2104  geometryList.append( QgsGeometry( gc->geometryN( i )->clone() ) );
2105  }
2106  }
2107  else //a singlepart geometry
2108  {
2109  geometryList.append( QgsGeometry( d->geometry->clone() ) );
2110  }
2111 
2112  return geometryList;
2113 }
2114 
2115 QPointF QgsGeometry::asQPointF() const
2116 {
2117  QgsPointXY point = asPoint();
2118  return point.toQPointF();
2119 }
2120 
2121 QPolygonF QgsGeometry::asQPolygonF() const
2122 {
2123  QPolygonF result;
2124  QgsPolylineXY polyline;
2126  if ( type == QgsWkbTypes::LineString || type == QgsWkbTypes::LineString25D )
2127  {
2128  polyline = asPolyline();
2129  }
2130  else if ( type == QgsWkbTypes::Polygon || type == QgsWkbTypes::Polygon25D )
2131  {
2132  QgsPolygonXY polygon = asPolygon();
2133  if ( polygon.empty() )
2134  return result;
2135  polyline = polygon.at( 0 );
2136  }
2137  else
2138  {
2139  return result;
2140  }
2141 
2142  for ( const QgsPointXY &p : qgis::as_const( polyline ) )
2143  {
2144  result << p.toQPointF();
2145  }
2146  return result;
2147 }
2148 
2149 bool QgsGeometry::deleteRing( int ringNum, int partNum )
2150 {
2151  if ( !d->geometry )
2152  {
2153  return false;
2154  }
2155 
2156  detach();
2157  bool ok = QgsGeometryEditUtils::deleteRing( d->geometry.get(), ringNum, partNum );
2158  return ok;
2159 }
2160 
2161 bool QgsGeometry::deletePart( int partNum )
2162 {
2163  if ( !d->geometry )
2164  {
2165  return false;
2166  }
2167 
2168  if ( !isMultipart() && partNum < 1 )
2169  {
2170  set( nullptr );
2171  return true;
2172  }
2173 
2174  detach();
2175  bool ok = QgsGeometryEditUtils::deletePart( d->geometry.get(), partNum );
2176  return ok;
2177 }
2178 
2179 int QgsGeometry::avoidIntersections( const QList<QgsVectorLayer *> &avoidIntersectionsLayers, const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures )
2180 {
2181  if ( !d->geometry )
2182  {
2183  return 1;
2184  }
2185 
2186  std::unique_ptr< QgsAbstractGeometry > diffGeom = QgsGeometryEditUtils::avoidIntersections( *( d->geometry ), avoidIntersectionsLayers, ignoreFeatures );
2187  if ( diffGeom )
2188  {
2189  reset( std::move( diffGeom ) );
2190  }
2191  return 0;
2192 }
2193 
2194 
2196 {
2197  if ( !d->geometry )
2198  return QgsGeometry();
2199 
2200  mLastError.clear();
2201  std::unique_ptr< QgsAbstractGeometry > g( _qgis_lwgeom_make_valid( d->geometry.get(), mLastError ) );
2202 
2203  QgsGeometry result = QgsGeometry( std::move( g ) );
2204  result.mLastError = mLastError;
2205  return result;
2206 }
2207 
2208 
2209 void QgsGeometry::validateGeometry( QVector<QgsGeometry::Error> &errors, ValidationMethod method ) const
2210 {
2211  QgsGeometryValidator::validateGeometry( *this, errors, method );
2212 }
2213 
2215 {
2216  if ( !d->geometry )
2217  {
2218  return false;
2219  }
2220 
2221  QgsGeos geos( d->geometry.get() );
2222  mLastError.clear();
2223  return geos.isValid( &mLastError );
2224 }
2225 
2227 {
2228  if ( !d->geometry )
2229  return false;
2230 
2231  QgsGeos geos( d->geometry.get() );
2232  mLastError.clear();
2233  return geos.isSimple( &mLastError );
2234 }
2235 
2237 {
2238  if ( !d->geometry || !g.d->geometry )
2239  {
2240  return false;
2241  }
2242 
2243  QgsGeos geos( d->geometry.get() );
2244  mLastError.clear();
2245  return geos.isEqual( g.d->geometry.get(), &mLastError );
2246 }
2247 
2248 QgsGeometry QgsGeometry::unaryUnion( const QVector<QgsGeometry> &geometries )
2249 {
2250  QgsGeos geos( nullptr );
2251 
2252  QString error;
2253  std::unique_ptr< QgsAbstractGeometry > geom( geos.combine( geometries, &error ) );
2254  QgsGeometry result( std::move( geom ) );
2255  result.mLastError = error;
2256  return result;
2257 }
2258 
2259 QgsGeometry QgsGeometry::polygonize( const QVector<QgsGeometry> &geometryList )
2260 {
2261  QgsGeos geos( nullptr );
2262 
2263  QVector<const QgsAbstractGeometry *> geomV2List;
2264  for ( const QgsGeometry &g : geometryList )
2265  {
2266  if ( !( g.isNull() ) )
2267  {
2268  geomV2List.append( g.constGet() );
2269  }
2270  }
2271 
2272  QString error;
2273  QgsGeometry result = geos.polygonize( geomV2List, &error );
2274  result.mLastError = error;
2275  return result;
2276 }
2277 
2279 {
2281  {
2282  return;
2283  }
2284 
2285  std::unique_ptr< QgsAbstractGeometry > straightGeom( d->geometry->segmentize() );
2286  reset( std::move( straightGeom ) );
2287 }
2288 
2290 {
2291  if ( !d->geometry )
2292  {
2293  return false;
2294  }
2295 
2296  return d->geometry->hasCurvedSegments();
2297 }
2298 
2300 {
2301  if ( !d->geometry )
2302  {
2304  }
2305 
2306  detach();
2307  d->geometry->transform( ct );
2308  return QgsGeometry::Success;
2309 }
2310 
2312 {
2313  if ( !d->geometry )
2314  {
2316  }
2317 
2318  detach();
2319  d->geometry->transform( ct );
2320  return QgsGeometry::Success;
2321 }
2322 
2324 {
2325  if ( d->geometry )
2326  {
2327  detach();
2328  d->geometry->transform( mtp.transform() );
2329  }
2330 }
2331 
2333 {
2334  if ( !d->geometry || rectangle.isNull() || rectangle.isEmpty() )
2335  {
2336  return QgsGeometry();
2337  }
2338 
2339  QgsGeos geos( d->geometry.get() );
2340  mLastError.clear();
2341  std::unique_ptr< QgsAbstractGeometry > resultGeom = geos.clip( rectangle, &mLastError );
2342  if ( !resultGeom )
2343  {
2344  QgsGeometry result;
2345  result.mLastError = mLastError;
2346  return result;
2347  }
2348  return QgsGeometry( std::move( resultGeom ) );
2349 }
2350 
2351 void QgsGeometry::draw( QPainter &p ) const
2352 {
2353  if ( d->geometry )
2354  {
2355  d->geometry->draw( p );
2356  }
2357 }
2358 
2359 static bool vertexIndexInfo( const QgsAbstractGeometry *g, int vertexIndex, int &partIndex, int &ringIndex, int &vertex )
2360 {
2361  if ( vertexIndex < 0 )
2362  return false; // clearly something wrong
2363 
2364  if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
2365  {
2366  partIndex = 0;
2367  int offset = 0;
2368  for ( int i = 0; i < geomCollection->numGeometries(); ++i )
2369  {
2370  const QgsAbstractGeometry *part = geomCollection->geometryN( i );
2371 
2372  // count total number of vertices in the part
2373  int numPoints = 0;
2374  for ( int k = 0; k < part->ringCount(); ++k )
2375  numPoints += part->vertexCount( 0, k );
2376 
2377  if ( vertexIndex < numPoints )
2378  {
2379  int nothing;
2380  return vertexIndexInfo( part, vertexIndex, nothing, ringIndex, vertex ); // set ring_index + index
2381  }
2382  vertexIndex -= numPoints;
2383  offset += numPoints;
2384  partIndex++;
2385  }
2386  }
2387  else if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
2388  {
2389  const QgsCurve *ring = curvePolygon->exteriorRing();
2390  if ( vertexIndex < ring->numPoints() )
2391  {
2392  partIndex = 0;
2393  ringIndex = 0;
2394  vertex = vertexIndex;
2395  return true;
2396  }
2397  vertexIndex -= ring->numPoints();
2398  ringIndex = 1;
2399  for ( int i = 0; i < curvePolygon->numInteriorRings(); ++i )
2400  {
2401  const QgsCurve *ring = curvePolygon->interiorRing( i );
2402  if ( vertexIndex < ring->numPoints() )
2403  {
2404  partIndex = 0;
2405  vertex = vertexIndex;
2406  return true;
2407  }
2408  vertexIndex -= ring->numPoints();
2409  ringIndex += 1;
2410  }
2411  }
2412  else if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
2413  {
2414  if ( vertexIndex < curve->numPoints() )
2415  {
2416  partIndex = 0;
2417  ringIndex = 0;
2418  vertex = vertexIndex;
2419  return true;
2420  }
2421  }
2422  else if ( qgsgeometry_cast<const QgsPoint *>( g ) )
2423  {
2424  if ( vertexIndex == 0 )
2425  {
2426  partIndex = 0;
2427  ringIndex = 0;
2428  vertex = 0;
2429  return true;
2430  }
2431  }
2432 
2433  return false;
2434 }
2435 
2437 {
2438  if ( !d->geometry )
2439  {
2440  return false;
2441  }
2442 
2443  id.type = QgsVertexId::SegmentVertex;
2444 
2445  bool res = vertexIndexInfo( d->geometry.get(), nr, id.part, id.ring, id.vertex );
2446  if ( !res )
2447  return false;
2448 
2449  // now let's find out if it is a straight or circular segment
2450  const QgsAbstractGeometry *g = d->geometry.get();
2451  if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
2452  {
2453  g = geomCollection->geometryN( id.part );
2454  }
2455 
2456  if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
2457  {
2458  g = id.ring == 0 ? curvePolygon->exteriorRing() : curvePolygon->interiorRing( id.ring - 1 );
2459  }
2460 
2461  if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
2462  {
2463  QgsPoint p;
2464  res = curve->pointAt( id.vertex, p, id.type );
2465  if ( !res )
2466  return false;
2467  }
2468 
2469  return true;
2470 }
2471 
2473 {
2474  if ( !d->geometry )
2475  {
2476  return -1;
2477  }
2478  return d->geometry->vertexNumberFromVertexId( id );
2479 }
2480 
2481 QString QgsGeometry::lastError() const
2482 {
2483  return mLastError;
2484 }
2485 
2486 void QgsGeometry::convertPointList( const QVector<QgsPointXY> &input, QgsPointSequence &output )
2487 {
2488  output.clear();
2489  for ( const QgsPointXY &p : input )
2490  {
2491  output.append( QgsPoint( p ) );
2492  }
2493 }
2494 
2495 void QgsGeometry::convertPointList( const QgsPointSequence &input, QVector<QgsPointXY> &output )
2496 {
2497  output.clear();
2498  for ( const QgsPoint &p : input )
2499  {
2500  output.append( QgsPointXY( p.x(), p.y() ) );
2501  }
2502 }
2503 
2504 QgsGeometry::operator bool() const
2505 {
2506  return d->geometry.get();
2507 }
2508 
2509 void QgsGeometry::convertToPolyline( const QgsPointSequence &input, QgsPolylineXY &output )
2510 {
2511  output.clear();
2512  output.resize( input.size() );
2513 
2514  for ( int i = 0; i < input.size(); ++i )
2515  {
2516  const QgsPoint &pt = input.at( i );
2517  output[i].setX( pt.x() );
2518  output[i].setY( pt.y() );
2519  }
2520 }
2521 
2522 void QgsGeometry::convertPolygon( const QgsPolygon &input, QgsPolygonXY &output )
2523 {
2524  output.clear();
2525  QgsCoordinateSequence coords = input.coordinateSequence();
2526  if ( coords.empty() )
2527  {
2528  return;
2529  }
2530  const QgsRingSequence &rings = coords[0];
2531  output.resize( rings.size() );
2532  for ( int i = 0; i < rings.size(); ++i )
2533  {
2534  convertToPolyline( rings[i], output[i] );
2535  }
2536 }
2537 
2538 GEOSContextHandle_t QgsGeometry::getGEOSHandler()
2539 {
2540  return QgsGeos::getGEOSHandler();
2541 }
2542 
2544 {
2545  return QgsGeometry( qgis::make_unique< QgsPoint >( point.x(), point.y() ) );
2546 }
2547 
2548 QgsGeometry QgsGeometry::fromQPolygonF( const QPolygonF &polygon )
2549 {
2550  if ( polygon.isClosed() )
2551  {
2553  }
2554  else
2555  {
2557  }
2558 }
2559 
2561 {
2562  QgsPolygonXY result;
2563  result << createPolylineFromQPolygonF( polygon );
2564  return result;
2565 }
2566 
2568 {
2569  QgsPolylineXY result;
2570  for ( const QPointF &p : polygon )
2571  {
2572  result.append( QgsPointXY( p ) );
2573  }
2574  return result;
2575 }
2576 
2577 bool QgsGeometry::compare( const QgsPolylineXY &p1, const QgsPolylineXY &p2, double epsilon )
2578 {
2579  if ( p1.count() != p2.count() )
2580  return false;
2581 
2582  for ( int i = 0; i < p1.count(); ++i )
2583  {
2584  if ( !p1.at( i ).compare( p2.at( i ), epsilon ) )
2585  return false;
2586  }
2587  return true;
2588 }
2589 
2590 bool QgsGeometry::compare( const QgsPolygonXY &p1, const QgsPolygonXY &p2, double epsilon )
2591 {
2592  if ( p1.count() != p2.count() )
2593  return false;
2594 
2595  for ( int i = 0; i < p1.count(); ++i )
2596  {
2597  if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
2598  return false;
2599  }
2600  return true;
2601 }
2602 
2603 
2604 bool QgsGeometry::compare( const QgsMultiPolygonXY &p1, const QgsMultiPolygonXY &p2, double epsilon )
2605 {
2606  if ( p1.count() != p2.count() )
2607  return false;
2608 
2609  for ( int i = 0; i < p1.count(); ++i )
2610  {
2611  if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
2612  return false;
2613  }
2614  return true;
2615 }
2616 
2617 QgsGeometry QgsGeometry::smooth( const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
2618 {
2619  if ( !d->geometry || d->geometry->isEmpty() )
2620  return QgsGeometry();
2621 
2622  QgsGeometry geom = *this;
2624  geom = QgsGeometry( d->geometry->segmentize() );
2625 
2626  switch ( QgsWkbTypes::flatType( geom.wkbType() ) )
2627  {
2628  case QgsWkbTypes::Point:
2630  //can't smooth a point based geometry
2631  return geom;
2632 
2634  {
2635  QgsLineString *lineString = static_cast< QgsLineString * >( d->geometry.get() );
2636  return QgsGeometry( smoothLine( *lineString, iterations, offset, minimumDistance, maxAngle ) );
2637  }
2638 
2640  {
2641  QgsMultiLineString *multiLine = static_cast< QgsMultiLineString * >( d->geometry.get() );
2642 
2643  std::unique_ptr< QgsMultiLineString > resultMultiline = qgis::make_unique< QgsMultiLineString> ();
2644  for ( int i = 0; i < multiLine->numGeometries(); ++i )
2645  {
2646  resultMultiline->addGeometry( smoothLine( *( static_cast< QgsLineString * >( multiLine->geometryN( i ) ) ), iterations, offset, minimumDistance, maxAngle ).release() );
2647  }
2648  return QgsGeometry( std::move( resultMultiline ) );
2649  }
2650 
2651  case QgsWkbTypes::Polygon:
2652  {
2653  QgsPolygon *poly = static_cast< QgsPolygon * >( d->geometry.get() );
2654  return QgsGeometry( smoothPolygon( *poly, iterations, offset, minimumDistance, maxAngle ) );
2655  }
2656 
2658  {
2659  QgsMultiPolygon *multiPoly = static_cast< QgsMultiPolygon * >( d->geometry.get() );
2660 
2661  std::unique_ptr< QgsMultiPolygon > resultMultiPoly = qgis::make_unique< QgsMultiPolygon >();
2662  for ( int i = 0; i < multiPoly->numGeometries(); ++i )
2663  {
2664  resultMultiPoly->addGeometry( smoothPolygon( *( static_cast< QgsPolygon * >( multiPoly->geometryN( i ) ) ), iterations, offset, minimumDistance, maxAngle ).release() );
2665  }
2666  return QgsGeometry( std::move( resultMultiPoly ) );
2667  }
2668 
2669  case QgsWkbTypes::Unknown:
2670  default:
2671  return QgsGeometry( *this );
2672  }
2673 }
2674 
2675 inline QgsPoint interpolatePointOnLine( const QgsPoint &p1, const QgsPoint &p2, const double offset )
2676 {
2677  double deltaX = p2.x() - p1.x();
2678  double deltaY = p2.y() - p1.y();
2679  return QgsPoint( p1.x() + deltaX * offset, p1.y() + deltaY * offset );
2680 }
2681 
2682 std::unique_ptr< QgsLineString > smoothCurve( const QgsLineString &line, const unsigned int iterations,
2683  const double offset, double squareDistThreshold, double maxAngleRads,
2684  bool isRing )
2685 {
2686  std::unique_ptr< QgsLineString > result = qgis::make_unique< QgsLineString >( line );
2687  for ( unsigned int iteration = 0; iteration < iterations; ++iteration )
2688  {
2689  QgsPointSequence outputLine;
2690  outputLine.reserve( 2 * ( result->numPoints() - 1 ) );
2691  bool skipFirst = false;
2692  bool skipLast = false;
2693  if ( isRing )
2694  {
2695  QgsPoint p1 = result->pointN( result->numPoints() - 2 );
2696  QgsPoint p2 = result->pointN( 0 );
2697  QgsPoint p3 = result->pointN( 1 );
2698  double angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
2699  p3.x(), p3.y() );
2700  angle = std::fabs( M_PI - angle );
2701  skipFirst = angle > maxAngleRads;
2702  }
2703  for ( int i = 0; i < result->numPoints() - 1; i++ )
2704  {
2705  QgsPoint p1 = result->pointN( i );
2706  QgsPoint p2 = result->pointN( i + 1 );
2707 
2708  double angle = M_PI;
2709  if ( i == 0 && isRing )
2710  {
2711  QgsPoint p3 = result->pointN( result->numPoints() - 2 );
2712  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
2713  p3.x(), p3.y() );
2714  }
2715  else if ( i < result->numPoints() - 2 )
2716  {
2717  QgsPoint p3 = result->pointN( i + 2 );
2718  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
2719  p3.x(), p3.y() );
2720  }
2721  else if ( i == result->numPoints() - 2 && isRing )
2722  {
2723  QgsPoint p3 = result->pointN( 1 );
2724  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
2725  p3.x(), p3.y() );
2726  }
2727 
2728  skipLast = angle < M_PI - maxAngleRads || angle > M_PI + maxAngleRads;
2729 
2730  // don't apply distance threshold to first or last segment
2731  if ( i == 0 || i >= result->numPoints() - 2
2732  || QgsGeometryUtils::sqrDistance2D( p1, p2 ) > squareDistThreshold )
2733  {
2734  if ( !isRing )
2735  {
2736  if ( !skipFirst )
2737  outputLine << ( i == 0 ? result->pointN( i ) : interpolatePointOnLine( p1, p2, offset ) );
2738  if ( !skipLast )
2739  outputLine << ( i == result->numPoints() - 2 ? result->pointN( i + 1 ) : interpolatePointOnLine( p1, p2, 1.0 - offset ) );
2740  else
2741  outputLine << p2;
2742  }
2743  else
2744  {
2745  // ring
2746  if ( !skipFirst )
2747  outputLine << interpolatePointOnLine( p1, p2, offset );
2748  else if ( i == 0 )
2749  outputLine << p1;
2750  if ( !skipLast )
2751  outputLine << interpolatePointOnLine( p1, p2, 1.0 - offset );
2752  else
2753  outputLine << p2;
2754  }
2755  }
2756  skipFirst = skipLast;
2757  }
2758 
2759  if ( isRing && outputLine.at( 0 ) != outputLine.at( outputLine.count() - 1 ) )
2760  outputLine << outputLine.at( 0 );
2761 
2762  result->setPoints( outputLine );
2763  }
2764  return result;
2765 }
2766 
2767 std::unique_ptr<QgsLineString> QgsGeometry::smoothLine( const QgsLineString &line, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
2768 {
2769  double maxAngleRads = maxAngle * M_PI / 180.0;
2770  double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
2771  return smoothCurve( line, iterations, offset, squareDistThreshold, maxAngleRads, false );
2772 }
2773 
2774 std::unique_ptr<QgsPolygon> QgsGeometry::smoothPolygon( const QgsPolygon &polygon, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
2775 {
2776  double maxAngleRads = maxAngle * M_PI / 180.0;
2777  double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
2778  std::unique_ptr< QgsPolygon > resultPoly = qgis::make_unique< QgsPolygon >();
2779 
2780  resultPoly->setExteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.exteriorRing() ) ), iterations, offset,
2781  squareDistThreshold, maxAngleRads, true ).release() );
2782 
2783  for ( int i = 0; i < polygon.numInteriorRings(); ++i )
2784  {
2785  resultPoly->addInteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.interiorRing( i ) ) ), iterations, offset,
2786  squareDistThreshold, maxAngleRads, true ).release() );
2787  }
2788  return resultPoly;
2789 }
2790 
2791 QgsGeometry QgsGeometry::convertToPoint( bool destMultipart ) const
2792 {
2793  switch ( type() )
2794  {
2796  {
2797  bool srcIsMultipart = isMultipart();
2798 
2799  if ( ( destMultipart && srcIsMultipart ) ||
2800  ( !destMultipart && !srcIsMultipart ) )
2801  {
2802  // return a copy of the same geom
2803  return QgsGeometry( *this );
2804  }
2805  if ( destMultipart )
2806  {
2807  // layer is multipart => make a multipoint with a single point
2808  return fromMultiPointXY( QgsMultiPointXY() << asPoint() );
2809  }
2810  else
2811  {
2812  // destination is singlepart => make a single part if possible
2813  QgsMultiPointXY multiPoint = asMultiPoint();
2814  if ( multiPoint.count() == 1 )
2815  {
2816  return fromPointXY( multiPoint[0] );
2817  }
2818  }
2819  return QgsGeometry();
2820  }
2821 
2823  {
2824  // only possible if destination is multipart
2825  if ( !destMultipart )
2826  return QgsGeometry();
2827 
2828  // input geometry is multipart
2829  if ( isMultipart() )
2830  {
2831  const QgsMultiPolylineXY multiLine = asMultiPolyline();
2832  QgsMultiPointXY multiPoint;
2833  for ( const QgsPolylineXY &l : multiLine )
2834  for ( const QgsPointXY &p : l )
2835  multiPoint << p;
2836  return fromMultiPointXY( multiPoint );
2837  }
2838  // input geometry is not multipart: copy directly the line into a multipoint
2839  else
2840  {
2841  QgsPolylineXY line = asPolyline();
2842  if ( !line.isEmpty() )
2843  return fromMultiPointXY( line );
2844  }
2845  return QgsGeometry();
2846  }
2847 
2849  {
2850  // can only transform if destination is multipoint
2851  if ( !destMultipart )
2852  return QgsGeometry();
2853 
2854  // input geometry is multipart: make a multipoint from multipolygon
2855  if ( isMultipart() )
2856  {
2857  const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
2858  QgsMultiPointXY multiPoint;
2859  for ( const QgsPolygonXY &poly : multiPolygon )
2860  for ( const QgsPolylineXY &line : poly )
2861  for ( const QgsPointXY &pt : line )
2862  multiPoint << pt;
2863  return fromMultiPointXY( multiPoint );
2864  }
2865  // input geometry is not multipart: make a multipoint from polygon
2866  else
2867  {
2868  const QgsPolygonXY polygon = asPolygon();
2869  QgsMultiPointXY multiPoint;
2870  for ( const QgsPolylineXY &line : polygon )
2871  for ( const QgsPointXY &pt : line )
2872  multiPoint << pt;
2873  return fromMultiPointXY( multiPoint );
2874  }
2875  }
2876 
2877  default:
2878  return QgsGeometry();
2879  }
2880 }
2881 
2882 QgsGeometry QgsGeometry::convertToLine( bool destMultipart ) const
2883 {
2884  switch ( type() )
2885  {
2887  {
2888  if ( !isMultipart() )
2889  return QgsGeometry();
2890 
2891  QgsMultiPointXY multiPoint = asMultiPoint();
2892  if ( multiPoint.count() < 2 )
2893  return QgsGeometry();
2894 
2895  if ( destMultipart )
2896  return fromMultiPolylineXY( QgsMultiPolylineXY() << multiPoint );
2897  else
2898  return fromPolylineXY( multiPoint );
2899  }
2900 
2902  {
2903  bool srcIsMultipart = isMultipart();
2904 
2905  if ( ( destMultipart && srcIsMultipart ) ||
2906  ( !destMultipart && ! srcIsMultipart ) )
2907  {
2908  // return a copy of the same geom
2909  return QgsGeometry( *this );
2910  }
2911  if ( destMultipart )
2912  {
2913  // destination is multipart => makes a multipoint with a single line
2914  QgsPolylineXY line = asPolyline();
2915  if ( !line.isEmpty() )
2916  return fromMultiPolylineXY( QgsMultiPolylineXY() << line );
2917  }
2918  else
2919  {
2920  // destination is singlepart => make a single part if possible
2921  QgsMultiPolylineXY multiLine = asMultiPolyline();
2922  if ( multiLine.count() == 1 )
2923  return fromPolylineXY( multiLine[0] );
2924  }
2925  return QgsGeometry();
2926  }
2927 
2929  {
2930  // input geometry is multipolygon
2931  if ( isMultipart() )
2932  {
2933  const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
2934  QgsMultiPolylineXY multiLine;
2935  for ( const QgsPolygonXY &poly : multiPolygon )
2936  for ( const QgsPolylineXY &line : poly )
2937  multiLine << line;
2938 
2939  if ( destMultipart )
2940  {
2941  // destination is multipart
2942  return fromMultiPolylineXY( multiLine );
2943  }
2944  else if ( multiLine.count() == 1 )
2945  {
2946  // destination is singlepart => make a single part if possible
2947  return fromPolylineXY( multiLine[0] );
2948  }
2949  }
2950  // input geometry is single polygon
2951  else
2952  {
2953  QgsPolygonXY polygon = asPolygon();
2954  // if polygon has rings
2955  if ( polygon.count() > 1 )
2956  {
2957  // cannot fit a polygon with rings in a single line layer
2958  // TODO: would it be better to remove rings?
2959  if ( destMultipart )
2960  {
2961  const QgsPolygonXY polygon = asPolygon();
2962  QgsMultiPolylineXY multiLine;
2963  for ( const QgsPolylineXY &line : polygon )
2964  multiLine << line;
2965  return fromMultiPolylineXY( multiLine );
2966  }
2967  }
2968  // no rings
2969  else if ( polygon.count() == 1 )
2970  {
2971  if ( destMultipart )
2972  {
2973  return fromMultiPolylineXY( polygon );
2974  }
2975  else
2976  {
2977  return fromPolylineXY( polygon[0] );
2978  }
2979  }
2980  }
2981  return QgsGeometry();
2982  }
2983 
2984  default:
2985  return QgsGeometry();
2986  }
2987 }
2988 
2989 QgsGeometry QgsGeometry::convertToPolygon( bool destMultipart ) const
2990 {
2991  switch ( type() )
2992  {
2994  {
2995  if ( !isMultipart() )
2996  return QgsGeometry();
2997 
2998  QgsMultiPointXY multiPoint = asMultiPoint();
2999  if ( multiPoint.count() < 3 )
3000  return QgsGeometry();
3001 
3002  if ( multiPoint.last() != multiPoint.first() )
3003  multiPoint << multiPoint.first();
3004 
3005  QgsPolygonXY polygon = QgsPolygonXY() << multiPoint;
3006  if ( destMultipart )
3007  return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3008  else
3009  return fromPolygonXY( polygon );
3010  }
3011 
3013  {
3014  // input geometry is multiline
3015  if ( isMultipart() )
3016  {
3017  QgsMultiPolylineXY multiLine = asMultiPolyline();
3018  QgsMultiPolygonXY multiPolygon;
3019  for ( QgsMultiPolylineXY::iterator multiLineIt = multiLine.begin(); multiLineIt != multiLine.end(); ++multiLineIt )
3020  {
3021  // do not create polygon for a 1 segment line
3022  if ( ( *multiLineIt ).count() < 3 )
3023  return QgsGeometry();
3024  if ( ( *multiLineIt ).count() == 3 && ( *multiLineIt ).first() == ( *multiLineIt ).last() )
3025  return QgsGeometry();
3026 
3027  // add closing node
3028  if ( ( *multiLineIt ).first() != ( *multiLineIt ).last() )
3029  *multiLineIt << ( *multiLineIt ).first();
3030  multiPolygon << ( QgsPolygonXY() << *multiLineIt );
3031  }
3032  // check that polygons were inserted
3033  if ( !multiPolygon.isEmpty() )
3034  {
3035  if ( destMultipart )
3036  {
3037  return fromMultiPolygonXY( multiPolygon );
3038  }
3039  else if ( multiPolygon.count() == 1 )
3040  {
3041  // destination is singlepart => make a single part if possible
3042  return fromPolygonXY( multiPolygon[0] );
3043  }
3044  }
3045  }
3046  // input geometry is single line
3047  else
3048  {
3049  QgsPolylineXY line = asPolyline();
3050 
3051  // do not create polygon for a 1 segment line
3052  if ( line.count() < 3 )
3053  return QgsGeometry();
3054  if ( line.count() == 3 && line.first() == line.last() )
3055  return QgsGeometry();
3056 
3057  // add closing node
3058  if ( line.first() != line.last() )
3059  line << line.first();
3060 
3061  // destination is multipart
3062  if ( destMultipart )
3063  {
3064  return fromMultiPolygonXY( QgsMultiPolygonXY() << ( QgsPolygonXY() << line ) );
3065  }
3066  else
3067  {
3068  return fromPolygonXY( QgsPolygonXY() << line );
3069  }
3070  }
3071  return QgsGeometry();
3072  }
3073 
3075  {
3076  bool srcIsMultipart = isMultipart();
3077 
3078  if ( ( destMultipart && srcIsMultipart ) ||
3079  ( !destMultipart && ! srcIsMultipart ) )
3080  {
3081  // return a copy of the same geom
3082  return QgsGeometry( *this );
3083  }
3084  if ( destMultipart )
3085  {
3086  // destination is multipart => makes a multipoint with a single polygon
3087  QgsPolygonXY polygon = asPolygon();
3088  if ( !polygon.isEmpty() )
3089  return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3090  }
3091  else
3092  {
3093  QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3094  if ( multiPolygon.count() == 1 )
3095  {
3096  // destination is singlepart => make a single part if possible
3097  return fromPolygonXY( multiPolygon[0] );
3098  }
3099  }
3100  return QgsGeometry();
3101  }
3102 
3103  default:
3104  return QgsGeometry();
3105  }
3106 }
3107 
3109 {
3110  return new QgsGeos( geometry );
3111 }
3112 
3113 QDataStream &operator<<( QDataStream &out, const QgsGeometry &geometry )
3114 {
3115  out << geometry.asWkb();
3116  return out;
3117 }
3118 
3119 QDataStream &operator>>( QDataStream &in, QgsGeometry &geometry )
3120 {
3121  QByteArray byteArray;
3122  in >> byteArray;
3123  if ( byteArray.isEmpty() )
3124  {
3125  geometry.set( nullptr );
3126  return in;
3127  }
3128 
3129  geometry.fromWkb( byteArray );
3130  return in;
3131 }
Geometry engine misses a method implemented or an error occurred in the geometry engine.
Definition: qgsgeometry.h:125
static std::unique_ptr< QgsAbstractGeometry > geomFromWkb(QgsConstWkbPtr &wkb)
Construct geometry from a WKB string.
const QgsCurve * interiorRing(int i) const
static QgsPolygonXY createPolygonFromQPolygonF(const QPolygonF &polygon)
Creates a QgsPolygonXYfrom a QPolygonF.
static QgsGeometry fromMultiPolygonXY(const QgsMultiPolygonXY &multipoly)
Creates a new geometry from a QgsMultiPolygon.
Circle geometry type.
Definition: qgscircle.h:42
static void validateGeometry(const QgsGeometry &geometry, QVector< QgsGeometry::Error > &errors, QgsGeometry::ValidationMethod method=QgsGeometry::ValidatorQgisInternal)
Validate geometry and produce a list of geometry errors.
QgsGeometry orientedMinimumBoundingBox() const
Returns the oriented minimum bounding box for the geometry, which is the smallest (by area) rotated r...
A rectangle specified with double values.
Definition: qgsrectangle.h:39
double y
Definition: qgspoint.h:42
QgsGeometry combine(const QgsGeometry &geometry) const
Returns a geometry representing all the points in this geometry and other (a union geometry operation...
static QgsGeometry fromPolylineXY(const QgsPolylineXY &polyline)
Creates a new LineString geometry from a list of QgsPointXY points.
static std::unique_ptr< QgsAbstractGeometry > geomFromWkbType(QgsWkbTypes::Type t)
Return empty geometry from wkb type.
void points(QgsPointSequence &pt) const override
Returns a list of points within the curve.
double hausdorffDistanceDensify(const QgsGeometry &geom, double densifyFraction) const
Returns the Hausdorff distance between this geometry and geom.
static Type multiType(Type type)
Returns the multi type for a WKB type.
Definition: qgswkbtypes.h:296
int makeDifferenceInPlace(const QgsGeometry &other)
Changes this geometry such that it does not intersect the other geometry.
static QgsGeometry fromPolyline(const QgsPolyline &polyline)
Creates a new LineString geometry from a list of QgsPoint points.
bool intersects(const QgsRectangle &r) const
Tests for intersection with a rectangle (uses GEOS)
QDataStream & operator<<(QDataStream &out, const QgsGeometry &geometry)
Writes the geometry to stream out. QGIS version compatibility is not guaranteed.
QgsGeometry removeInteriorRings(double minimumAllowedArea=-1) const
Removes the interior rings from a (multi)polygon geometry.
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
static bool verticesAtDistance(const QgsAbstractGeometry &geometry, double distance, QgsVertexId &previousVertex, QgsVertexId &nextVertex)
Retrieves the vertices which are before and after the interpolated point at a specified distance alon...
OperationResult addPart(const QVector< QgsPointXY > &points, QgsWkbTypes::GeometryType geomType=QgsWkbTypes::UnknownGeometry)
Adds a new part to a the geometry.
bool isNull() const
Returns true if the geometry is null (ie, contains no underlying geometry accessible via geometry() )...
double distance(const QgsGeometry &geom) const
Returns the minimum distance between this geometry and another geometry, using GEOS.
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...
Java-style iterator for traversal of vertices of a geometry.
Multi point geometry collection.
Definition: qgsmultipoint.h:29
bool isValid() const
Returns true if the vertex id is valid.
bool within(const QgsGeometry &geometry) const
Test for if geometry is within another (uses GEOS)
static bool isMultiType(Type type)
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:557
The source geometry is not multi.
Definition: qgsgeometry.h:128
Nothing happened, without any error.
Definition: qgsgeometry.h:122
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer&#39;s length...
double angleAtVertex(int vertex) const
Returns the bisector angle for this geometry at the specified vertex.
static double averageAngle(double x1, double y1, double x2, double y2, double x3, double y3)
Angle between two linear segments.
QVector< QgsRingSequence > QgsCoordinateSequence
QgsGeometry poleOfInaccessibility(double precision, double *distanceFromBoundary=nullptr) const
Calculates the approximate pole of inaccessibility for a surface, which is the most distant internal ...
static double angleBetweenThreePoints(double x1, double y1, double x2, double y2, double x3, double y3)
Calculates the angle between the lines AB and BC, where AB and BC described by points a...
static std::unique_ptr< QgsAbstractGeometry > fromPointXY(const QgsPointXY &point)
Construct geometry from a point.
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
QgsGeometry subdivide(int maxNodes=256) const
Subdivides the geometry.
double y
Definition: qgspointxy.h:48
static std::unique_ptr< QgsAbstractGeometry > fromPolylineXY(const QgsPolylineXY &polyline)
Construct geometry from a polyline.
double area(QString *errorMsg=nullptr) const override
Definition: qgsgeos.cpp:531
A class to represent a 2D point.
Definition: qgspointxy.h:43
QVector< QgsPoint > QgsPolyline
Polyline as represented as a vector of points.
Definition: qgsgeometry.h:69
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...
QString asJson(int precision=17) const
Exports the geometry to a GeoJSON string.
OperationResult rotate(double rotation, const QgsPointXY &center)
Rotate this geometry around the Z axis.
static QgsGeometry fromMultiPolylineXY(const QgsMultiPolylineXY &multiline)
Creates a new geometry from a QgsMultiPolylineXY object.
QVector< QgsPolylineXY > QgsPolygonXY
Polygon: first item of the list is outer ring, inner rings (if any) start from second item...
Definition: qgsgeometry.h:73
bool moveVertex(double x, double y, int atVertex)
Moves the vertex at the given position number and item (first number is index 0) to the given coordin...
Multi line string geometry collection.
QgsGeometry interpolate(double distance) const
Returns interpolated point on line at distance.
Curve polygon geometry type.
bool overlaps(const QgsGeometry &geometry) const
Test for if geometry overlaps another (uses GEOS)
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:111
QgsGeometry buffer(double distance, int segments) const
Returns a buffer region around this geometry having the given width and with a specified number of se...
QgsGeometry centroid() const
Returns the center of mass of a geometry.
QgsGeometry()
Constructor.
Definition: qgsgeometry.cpp:56
QVector< QgsPointXY > QgsMultiPointXY
A collection of QgsPoints that share a common collection of attributes.
Definition: qgsgeometry.h:79
OperationResult addRing(const QVector< QgsPointXY > &ring)
Adds a new ring to this geometry.
OperationResult reshapeGeometry(const QgsLineString &reshapeLineString)
Replaces a part of this geometry with another line.
double radius() const
Returns the radius of the circle.
Definition: qgscircle.h:159
QgsGeometry intersection(const QgsGeometry &geometry) const
Returns a geometry representing the points shared by this geometry and other.
QgsPoint center() const
Returns the center point.
Definition: qgsellipse.h:113
static QgsPoint closestVertex(const QgsAbstractGeometry &geom, const QgsPoint &pt, QgsVertexId &id)
Returns the closest vertex to a geometry for a specified point.
double distanceToVertex(int vertex) const
Returns the distance along this geometry from its first vertex to the specified vertex.
EndCapStyle
End cap styles for buffers.
Definition: qgsgeometry.h:805
virtual bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const =0
Returns next vertex id and coordinates.
double closestSegmentWithContext(const QgsPointXY &point, QgsPointXY &minDistPoint, int &afterVertex, double *leftOf=nullptr, double epsilon=DEFAULT_SEGMENT_EPSILON) const
Searches for the closest segment of geometry to the given point.
bool insertVertex(double x, double y, int beforeVertex)
Insert a new vertex before the given vertex index, ring and item (first number is index 0) If the req...
virtual QgsRectangle boundingBox() const =0
Returns the minimal bounding box for the geometry.
QgsGeometry minimalEnclosingCircle(QgsPointXY &center, double &radius, unsigned int segments=36) const
Returns the minimal enclosing circle for the geometry.
QgsGeometry nearestPoint(const QgsGeometry &other) const
Returns the nearest point on this geometry to another geometry.
virtual void transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d=QgsCoordinateTransform::ForwardTransform, bool transformZ=false)=0
Transforms the geometry using a coordinate transform.
QgsGeometry & operator=(QgsGeometry const &rhs)
Creates a deep copy of the object.
Definition: qgsgeometry.cpp:88
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
static std::unique_ptr< QgsPolygon > fromPolygonXY(const QgsPolygonXY &polygon)
Construct geometry from a polygon.
OperationResult
Success or failure of a geometry operation.
Definition: qgsgeometry.h:119
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:786
bool isGeosEqual(const QgsGeometry &) const
Compares the geometry with another geometry using GEOS.
QVector< QgsPolygonXY > QgsMultiPolygonXY
A collection of QgsPolygons that share a common collection of attributes.
Definition: qgsgeometry.h:90
bool deleteRing(int ringNum, int partNum=0)
Deletes a ring in polygon or multipolygon.
bool isGeosValid() const
Checks validity of the geometry using GEOS.
static GEOSContextHandle_t getGEOSHandler()
Definition: qgsgeos.cpp:2704
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
The input geometry (ring, part, split line, etc.) has not the correct geometry type.
Definition: qgsgeometry.h:124
int numPoints() const override
Returns the number of points in the curve.
QgsPointXY closestVertex(const QgsPointXY &point, int &atVertex, int &beforeVertex, int &afterVertex, double &sqrDist) const
Returns the vertex closest to the given point, the corresponding vertex index, squared distance snap ...
QgsGeometry poleOfInaccessibility(double precision, double *distanceToBoundary=nullptr) const
Calculates the approximate pole of inaccessibility for a surface, which is the most distant internal ...
static std::unique_ptr< QgsMultiPoint > fromMultiPointXY(const QgsMultiPointXY &multipoint)
Construct geometry from a multipoint.
bool deletePart(int partNum)
Deletes part identified by the part number.
QVector< QgsPolylineXY > QgsMultiPolylineXY
A collection of QgsPolylines that share a common collection of attributes.
Definition: qgsgeometry.h:83
QgsMultiPolylineXY asMultiPolyline() const
Returns contents of the geometry as a multi linestring if wkbType is WKBMultiLineString, otherwise an empty list.
QVector< QgsGeometry > asGeometryCollection() const
Return contents of the geometry as a list of geometries.
QgsGeometry mergeLines() const
Merges any connected lines in a LineString/MultiLineString geometry and converts them to single line ...
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:36
QgsPointXY transform(const QgsPointXY &p) const
Transform the point from map (world) coordinates to device coordinates.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
int numInteriorRings() const
Operation succeeded.
void validateGeometry(QVector< QgsGeometry::Error > &errors, ValidationMethod method=ValidatorQgisInternal) const
Validates geometry and produces a list of geometry errors.
Nothing happened, without any error.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:67
QPointF toQPointF() const
Converts a point to a QPointF.
Definition: qgspointxy.cpp:40
static QgsPolylineXY createPolylineFromQPolygonF(const QPolygonF &polygon)
Creates a QgsPolylineXY from a QPolygonF.
static bool deleteRing(QgsAbstractGeometry *geom, int ringNum, int partNum=0)
Deletes a ring from a geometry.
static std::unique_ptr< QgsAbstractGeometry > fromGeos(const GEOSGeometry *geos)
Create a geometry from a GEOSGeometry.
Definition: qgsgeos.cpp:1024
bool convertToSingleType()
Converts multi type geometry into single type geometry e.g.
bool equals(const QgsGeometry &geometry) const
Test for if geometry equals another (uses GEOS)
Utility class for identifying a unique vertex within a geometry.
bool isEmpty() const
Returns true if the rectangle is empty.
Geometry collection.
QgsPolygonXY asPolygon() const
Returns contents of the geometry as a polygon if wkbType is WKBPolygon, otherwise an empty list...
QgsPoint interpolatePointOnLine(const QgsPoint &p1, const QgsPoint &p2, const double offset)
static QgsGeometry fromQPointF(QPointF point)
Construct geometry from a QPointF.
virtual QgsPolygon * toPolygon(unsigned int segments=36) const
Returns a segmented polygon.
Definition: qgsellipse.cpp:213
QgsGeometry convexHull() const
Returns the smallest convex polygon that contains all the points in the geometry. ...
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:138
QgsGeometry densifyByCount(int extraNodesPerSegment) const
Returns a copy of the geometry which has been densified by adding the specified number of extra nodes...
bool deleteVertex(int atVertex)
Deletes the vertex at the given position number and item (first number is index 0) ...
OperationResult translate(double dx, double dy)
Translates this geometry by dx, dy.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
void setY(double y)
Sets the y value of the point.
Definition: qgspointxy.h:113
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
static std::unique_ptr< QgsAbstractGeometry > avoidIntersections(const QgsAbstractGeometry &geom, const QList< QgsVectorLayer *> &avoidIntersectionsLayers, const QHash< QgsVectorLayer *, QSet< QgsFeatureId > > &ignoreFeatures=(QHash< QgsVectorLayer *, QSet< QgsFeatureId > >()))
Alters a geometry so that it avoids intersections with features from all open vector layers...
static QgsGeometry fromMultiPointXY(const QgsMultiPointXY &multipoint)
Creates a new geometry from a QgsMultiPointXY object.
QgsGeometry extendLine(double startDistance, double endDistance) const
Extends a (multi)line geometry by extrapolating out the start or end of the line by a specified dista...
double sqrDistToVertexAt(QgsPointXY &point SIP_IN, int atVertex) const
Returns the squared Cartesian distance between the given point to the given vertex index (vertex at t...
T qgsgeometry_cast(const QgsAbstractGeometry *geom)
QgsGeometry offsetCurve(double distance, int segments, JoinStyle joinStyle, double miterLimit) const
Returns an offset line at a given distance and side from an input line.
void fromGeos(GEOSGeometry *geos)
Set the geometry, feeding in a geometry in GEOS format.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
static geos::unique_ptr asGeos(const QgsAbstractGeometry *geom, double precision=0)
Definition: qgsgeos.cpp:1237
bool contains(const QgsPoint &point, double epsilon=1E-8) const
Returns true if the circle contains the point.
Definition: qgscircle.cpp:276
bool crosses(const QgsGeometry &geometry) const
Test for if geometry crosses another (uses GEOS)
QgsGeometry clipped(const QgsRectangle &rectangle)
Clips the geometry using the specified rectangle.
static QgsGeometry polygonize(const QVector< const QgsAbstractGeometry *> &geometries, QString *errorMsg=nullptr)
Creates a GeometryCollection geometry containing possible polygons formed from the constituent linewo...
Definition: qgsgeos.cpp:2144
QgsGeometry densifyByDistance(double distance) const
Densifies the geometry by adding regularly placed extra nodes inside each segment so that the maximum...
Method not implemented in geometry engine.
virtual double area() const
Returns the area of the geometry.
virtual int ringCount(int part=0) const =0
Returns the number of rings of which this geometry is built.
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
virtual QgsPolygon * toPolygon(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a new polygon geometry corresponding to a segmentized approximation of the curve...
QgsGeometry pointOnSurface() const
Returns a point guaranteed to lie on the surface of a geometry.
bool touches(const QgsGeometry &geometry) const
Test for if geometry touch another (uses GEOS)
Abstract base class for all geometries.
QgsCoordinateSequence coordinateSequence() const override
Retrieves the sequence of geometries, rings and nodes.
The vertex_iterator class provides STL-style iterator for vertices.
void convertToStraightSegment()
Converts the geometry to straight line segments, if it is a curved geometry type. ...
const QgsCurve * exteriorRing() const
Does vector analysis using the geos library and handles import, export, exception handling*...
Definition: qgsgeos.h:98
static std::unique_ptr< QgsMultiLineString > fromMultiPolylineXY(const QgsMultiPolylineXY &multiline)
Construct geometry from a multipolyline.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
QgsGeometry densifyByDistance(double distance) const
Densifies the geometry by adding regularly placed extra nodes inside each segment so that the maximum...
QgsWkbTypes::GeometryType type() const
Returns type of the geometry as a QgsWkbTypes::GeometryType.
double length() const
Returns the length of geometry using GEOS.
This class offers geometry processing methods.
void setX(double x)
Sets the x value of the point.
Definition: qgspointxy.h:104
QByteArray asWkb() const
Export the geometry to WKB.
Error occurred while creating a noded geometry.
double x
Definition: qgspointxy.h:47
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
QgsGeometry extrude(double x, double y)
Returns an extruded version of this geometry.
Error occurred in the geometry engine.
void draw(QPainter &p) const
Draws the geometry onto a QPainter.
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
int numGeometries() const
Returns the number of geometries within the collection.
Contains geos related utilities and functions.
Definition: qgsgeos.h:36
void setX(double x)
Sets the point&#39;s x-coordinate.
Definition: qgspoint.h:192
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:126
QgsAbstractGeometry * combine(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the combination of this and geom.
Definition: qgsgeos.cpp:306
QString asWkt(int precision=17) const
Exports the geometry to WKT.
QPolygonF asQPolygonF() const
Returns contents of the geometry as a QPolygonF.
double interpolateAngle(double distance) const
Returns the angle parallel to the linestring or polygon boundary at the specified distance along the ...
static QgsGeometry fromPolygonXY(const QgsPolygonXY &polygon)
Creates a new geometry from a QgsPolygon.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:111
BufferSide
Side of line to buffer.
Definition: qgsgeometry.h:798
QVector< QgsPoint > QgsPointSequence
static void convertPointList(const QVector< QgsPointXY > &input, QgsPointSequence &output)
Upgrades a point list from QgsPointXY to QgsPoint.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:137
static QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
static QgsGeometry::OperationResult addPart(QgsAbstractGeometry *geometry, std::unique_ptr< QgsAbstractGeometry > part)
Add a part to multi type geometry.
virtual void adjacentVertices(QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex) const =0
Returns the vertices adjacent to a specified vertex within a geometry.
int partCount() const override
Returns count of parts contained in the geometry.
QVector< QgsPointSequence > QgsRingSequence
QString lastError() const
Returns an error string referring to the last error encountered either when this geometry was created...
QgsGeometry simplify(double tolerance) const
Returns a simplified version of this geometry using a specified tolerance value.
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
Definition: qgsgeometry.h:49
static double sqrDistance2D(const QgsPoint &pt1, const QgsPoint &pt2)
Returns the squared 2D distance between two points.
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
static std::unique_ptr< QgsAbstractGeometry > geomFromWkt(const QString &text)
Construct geometry from a WKT string.
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
double hausdorffDistance(const QgsGeometry &geom) const
Returns the Hausdorff distance between this geometry and geom.
OperationResult transform(const QgsCoordinateTransform &ct)
Transforms this geometry as described by CoordinateTransform ct.
QgsPointXY asPoint() const
Returns contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [0...
The base geometry on which the operation is done is invalid or empty.
Definition: qgsgeometry.h:123
Multi polygon geometry collection.
static GEOSContextHandle_t getGEOSHandler()
Return GEOS context handle.
int vertexNrFromVertexId(QgsVertexId id) const
Returns the vertex number corresponding to a vertex id.
OperationResult splitGeometry(const QVector< QgsPointXY > &splitLine, QVector< QgsGeometry > &newGeometries, bool topological, QVector< QgsPointXY > &topologyTestPoints)
Splits this geometry according to a given line.
static QgsGeometry polygonize(const QVector< QgsGeometry > &geometries)
Creates a GeometryCollection geometry containing possible polygons formed from the constituent linewo...
bool requiresConversionToStraightSegments() const
Returns true if the geometry is a curved geometry type which requires conversion to display as straig...
void mapToPixel(const QgsMapToPixel &mtp)
Transforms the geometry from map units to pixels in place.
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
static bool isCurvedType(Type type)
Returns true if the WKB type is a curved type or can contain curved geometries.
Definition: qgswkbtypes.h:606
GEOSGeometry * exportToGeos(double precision=0) const
Returns a geos geometry - caller takes ownership of the object (should be deleted with GEOSGeom_destr...
QgsGeometry makeValid() const
Attempts to make an invalid geometry valid without losing vertices.
bool isSimple() const
Determines whether the geometry is simple (according to OGC definition), i.e.
std::unique_ptr< QgsAbstractGeometry > subdivide(int maxNodes, QString *errorMsg=nullptr) const
Subdivides the geometry.
Definition: qgsgeos.cpp:286
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:41
QPointF asQPointF() const
Returns contents of the geometry as a QPointF if wkbType is WKBPoint, otherwise returns a null QPoint...
ValidationMethod
Available methods for validating geometries.
Definition: qgsgeometry.h:1293
virtual int vertexCount(int part=0, int ring=0) const =0
Returns the number of vertices of which this geometry is built.
virtual QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const =0
Returns a new line string geometry corresponding to a segmentized approximation of the curve...
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
QgsGeometry shortestLine(const QgsGeometry &other) const
Returns the shortest line joining this geometry to another geometry.
std::unique_ptr< QgsAbstractGeometry > _qgis_lwgeom_make_valid(const QgsAbstractGeometry *lwgeom_in, QString &errorMessage)
Implementation of QgsGeometry::makeValid(). Not a public API.
static QgsCircle minimalCircleFrom3Points(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double epsilon=1E-8)
Constructs the smallest circle from 3 points.
Definition: qgscircle.cpp:192
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
static QgsGeometry fromQPolygonF(const QPolygonF &polygon)
Construct geometry from a QPolygonF.
QgsGeometry snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0) const
Returns a new geometry with all points or vertices snapped to the closest point of the grid...
Class for doing transforms between two map coordinate systems.
QgsGeometry singleSidedBuffer(double distance, int segments, BufferSide side, JoinStyle joinStyle=JoinStyleRound, double miterLimit=2.0) const
Returns a single sided buffer for a (multi)line geometry.
The input is not valid.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:116
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
void adjacentVertices(int atVertex, int &beforeVertex, int &afterVertex) const
Returns the indexes of the vertices before and after the given vertex index.
QgsGeometry convertToType(QgsWkbTypes::GeometryType destType, bool destMultipart=false) const
Try to convert the geometry to the requested type.
double closestVertexWithContext(const QgsPointXY &point, int &atVertex) const
Searches for the closest vertex in this geometry to the given point.
Contains geometry relation and modification algorithms.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:121
QgsGeometry makeDifference(const QgsGeometry &other) const
Returns the geometry formed by modifying this geometry such that it does not intersect the other geom...
QgsPolylineXY asPolyline() const
Returns contents of the geometry as a polyline if wkbType is WKBLineString, otherwise an empty list...
QgsVertexIterator vertices() const
Returns Java-style iterator for traversal of vertices of the geometry.
static QgsCircle from2Points(const QgsPoint &pt1, const QgsPoint &pt2)
Constructs a circle by 2 points on the circle.
Definition: qgscircle.cpp:37
QgsGeometry voronoiDiagram(const QgsGeometry &extent=QgsGeometry(), double tolerance=0.0, bool edgesOnly=false) const
Creates a Voronoi diagram for the nodes contained within the geometry.
static bool deletePart(QgsAbstractGeometry *geom, int partNum)
Deletes a part from a geometry.
QgsMultiPointXY asMultiPoint() const
Returns contents of the geometry as a multi point if wkbType is WKBMultiPoint, otherwise an empty lis...
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...
double area() const
Returns the area of the geometry using GEOS.
EngineOperationResult
Success or failure of a geometry operation.
bool vertexIdFromVertexNr(int number, QgsVertexId &id) const
Calculates the vertex ID from a vertex number.
Polygon geometry type.
Definition: qgspolygon.h:31
Operation succeeded.
Definition: qgsgeometry.h:121
JoinStyle
Join styles for buffers.
Definition: qgsgeometry.h:813
void set(QgsAbstractGeometry *geometry)
Sets the underlying geometry store.
QgsGeometry densifyByCount(int extraNodesPerSegment) const
Densifies the geometry by adding the specified number of extra nodes within each segment of the geome...
bool contains(const QgsPointXY *p) const
Tests for containment of a point (uses GEOS)
QgsGeometry symDifference(const QgsGeometry &geometry) const
Returns a geometry representing the points making up this geometry that do not make up other...
virtual QgsPoint vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
Represents a vector layer which manages a vector based data sets.
QgsAbstractGeometry::vertex_iterator vertices_end() const
Returns STL-style iterator pointing to the imaginary vertex after the last vertex of the geometry...
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:427
QgsGeometry delaunayTriangulation(double tolerance=0.0, bool edgesOnly=false) const
Returns the Delaunay triangulation for the vertices of the geometry.
QgsGeometry smooth(const unsigned int iterations=1, const double offset=0.25, double minimumDistance=-1.0, double maxAngle=180.0) const
Smooths a geometry by rounding off corners using the Chaikin algorithm.
static QgsGeometry unaryUnion(const QVector< QgsGeometry > &geometries)
Compute the unary union on a list of geometries.
QgsMultiPolygonXY asMultiPolygon() const
Returns contents of the geometry as a multi polygon if wkbType is WKBMultiPolygon, otherwise an empty list.
static QgsGeometry collectGeometry(const QVector< QgsGeometry > &geometries)
Creates a new multipart geometry from a list of QgsGeometry objects.
The geometry on which the operation occurs is not valid.
virtual int numPoints() const =0
Returns the number of points in the curve.
static double distanceToVertex(const QgsAbstractGeometry &geom, QgsVertexId id)
Returns the distance along a geometry from its first vertex to the specified vertex.
QgsAbstractGeometry::vertex_iterator vertices_begin() const
Returns STL-style iterator pointing to the first vertex of the geometry.
double lineLocatePoint(const QgsGeometry &point) const
Returns a distance representing the location along this linestring of the closest point on this lines...
double ANALYSIS_EXPORT leftOf(const QgsPoint &thepoint, const QgsPoint *p1, const QgsPoint *p2)
Returns whether &#39;thepoint&#39; is left or right of the line from &#39;p1&#39; to &#39;p2&#39;. Negativ values mean left a...
Definition: MathUtils.cpp:292
bool disjoint(const QgsGeometry &geometry) const
Tests for if geometry is disjoint of another (uses GEOS)
static QgsGeometry fromPointXY(const QgsPointXY &point)
Creates a new geometry from a QgsPointXY object.
static QgsGeometry::OperationResult addRing(QgsAbstractGeometry *geometry, std::unique_ptr< QgsCurve > ring)
Add an interior ring to a geometry.
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...
std::unique_ptr< QgsAbstractGeometry > geometry
Definition: qgsgeometry.cpp:53
static bool compare(const QgsPolylineXY &p1, const QgsPolylineXY &p2, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compares two polylines for equality within a specified tolerance.
virtual bool addGeometry(QgsAbstractGeometry *g)
Adds a geometry and takes ownership. Returns true in case of success.
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:145
static std::unique_ptr< QgsMultiPolygon > fromMultiPolygonXY(const QgsMultiPolygonXY &multipoly)
Construct geometry from a multipolygon.
std::unique_ptr< QgsLineString > smoothCurve(const QgsLineString &line, const unsigned int iterations, const double offset, double squareDistThreshold, double maxAngleRads, bool isRing)
QDataStream & operator>>(QDataStream &in, QgsGeometry &geometry)
Reads a geometry from stream in into geometry. QGIS version compatibility is not guaranteed.
int avoidIntersections(const QList< QgsVectorLayer *> &avoidIntersectionsLayers, const QHash< QgsVectorLayer *, QSet< QgsFeatureId > > &ignoreFeatures=(QHash< QgsVectorLayer *, QSet< QgsFeatureId > >()))
Modifies geometry to avoid intersections with the layers specified in project properties.
double x
Definition: qgspoint.h:41
QgsGeometry difference(const QgsGeometry &geometry) const
Returns a geometry representing the points making up this geometry that do not make up other...