QGIS API Documentation  3.20.0-Odense (decaadbb31)
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 #include <nlohmann/json.hpp>
21 
22 #include "qgis.h"
23 #include "qgsgeometry.h"
24 #include "qgsgeometryeditutils.h"
25 #include "qgsgeometryfactory.h"
26 
27 #include <geos_c.h>
28 
29 #if ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR<8 )
30 #include "qgsgeometrymakevalid.h"
31 #endif
32 
33 #include "qgsgeometryutils.h"
35 #include "qgsgeos.h"
36 #include "qgsapplication.h"
37 #include "qgslogger.h"
38 #include "qgsmaptopixel.h"
39 #include "qgsmessagelog.h"
40 #include "qgspointxy.h"
41 #include "qgsrectangle.h"
42 
43 #include "qgsvectorlayer.h"
44 #include "qgsgeometryvalidator.h"
45 
46 #include "qgsmulticurve.h"
47 #include "qgsmultilinestring.h"
48 #include "qgsmultipoint.h"
49 #include "qgsmultipolygon.h"
50 #include "qgsmultisurface.h"
51 #include "qgspoint.h"
52 #include "qgspolygon.h"
53 #include "qgslinestring.h"
54 #include "qgscircle.h"
55 #include "qgscurve.h"
56 
58 {
60  QAtomicInt ref;
61  std::unique_ptr< QgsAbstractGeometry > geometry;
62 };
63 
65  : d( new QgsGeometryPrivate() )
66 {
67 }
68 
70 {
71  if ( !d->ref.deref() )
72  delete d;
73 }
74 
76  : d( new QgsGeometryPrivate() )
77 {
78  d->geometry.reset( geom );
79  d->ref = QAtomicInt( 1 );
80 }
81 
82 QgsGeometry::QgsGeometry( std::unique_ptr<QgsAbstractGeometry> geom )
83  : d( new QgsGeometryPrivate() )
84 {
85  d->geometry = std::move( geom );
86  d->ref = QAtomicInt( 1 );
87 }
88 
90  : d( other.d )
91 {
92  mLastError = other.mLastError;
93  d->ref.ref();
94 }
95 
97 {
98  if ( this != &other )
99  {
100  if ( !d->ref.deref() )
101  {
102  delete d;
103  }
104 
105  mLastError = other.mLastError;
106  d = other.d;
107  d->ref.ref();
108  }
109  return *this;
110 }
111 
112 void QgsGeometry::detach()
113 {
114  if ( d->ref <= 1 )
115  return;
116 
117  std::unique_ptr< QgsAbstractGeometry > cGeom;
118  if ( d->geometry )
119  cGeom.reset( d->geometry->clone() );
120 
121  reset( std::move( cGeom ) );
122 }
123 
124 void QgsGeometry::reset( std::unique_ptr<QgsAbstractGeometry> newGeometry )
125 {
126  if ( d->ref > 1 )
127  {
128  ( void )d->ref.deref();
129  d = new QgsGeometryPrivate();
130  }
131  d->geometry = std::move( newGeometry );
132 }
133 
135 {
136  return d->geometry.get();
137 }
138 
140 {
141  detach();
142  return d->geometry.get();
143 }
144 
146 {
147  if ( d->geometry.get() == geometry )
148  {
149  return;
150  }
151 
152  reset( std::unique_ptr< QgsAbstractGeometry >( geometry ) );
153 }
154 
156 {
157  return !d->geometry;
158 }
159 
160 QgsGeometry QgsGeometry::fromWkt( const QString &wkt )
161 {
162  std::unique_ptr< QgsAbstractGeometry > geom = QgsGeometryFactory::geomFromWkt( wkt );
163  if ( !geom )
164  {
165  return QgsGeometry();
166  }
167  return QgsGeometry( std::move( geom ) );
168 }
169 
171 {
172  std::unique_ptr< QgsAbstractGeometry > geom( QgsGeometryFactory::fromPointXY( point ) );
173  if ( geom )
174  {
175  return QgsGeometry( geom.release() );
176  }
177  return QgsGeometry();
178 }
179 
181 {
182  std::unique_ptr< QgsAbstractGeometry > geom = QgsGeometryFactory::fromPolylineXY( polyline );
183  if ( geom )
184  {
185  return QgsGeometry( std::move( geom ) );
186  }
187  return QgsGeometry();
188 }
189 
191 {
192  return QgsGeometry( std::make_unique< QgsLineString >( polyline ) );
193 }
194 
196 {
197  std::unique_ptr< QgsPolygon > geom = QgsGeometryFactory::fromPolygonXY( polygon );
198  if ( geom )
199  {
200  return QgsGeometry( std::move( geom.release() ) );
201  }
202  return QgsGeometry();
203 }
204 
206 {
207  std::unique_ptr< QgsMultiPoint > geom = QgsGeometryFactory::fromMultiPointXY( multipoint );
208  if ( geom )
209  {
210  return QgsGeometry( std::move( geom ) );
211  }
212  return QgsGeometry();
213 }
214 
216 {
217  std::unique_ptr< QgsMultiLineString > geom = QgsGeometryFactory::fromMultiPolylineXY( multiline );
218  if ( geom )
219  {
220  return QgsGeometry( std::move( geom ) );
221  }
222  return QgsGeometry();
223 }
224 
226 {
227  std::unique_ptr< QgsMultiPolygon > geom = QgsGeometryFactory::fromMultiPolygonXY( multipoly );
228  if ( geom )
229  {
230  return QgsGeometry( std::move( geom ) );
231  }
232  return QgsGeometry();
233 }
234 
236 {
237  std::unique_ptr< QgsLineString > ext = std::make_unique< QgsLineString >(
238  QVector< double >() << rect.xMinimum()
239  << rect.xMaximum()
240  << rect.xMaximum()
241  << rect.xMinimum()
242  << rect.xMinimum(),
243  QVector< double >() << rect.yMinimum()
244  << rect.yMinimum()
245  << rect.yMaximum()
246  << rect.yMaximum()
247  << rect.yMinimum() );
248  std::unique_ptr< QgsPolygon > polygon = std::make_unique< QgsPolygon >();
249  polygon->setExteriorRing( ext.release() );
250  return QgsGeometry( std::move( polygon ) );
251 }
252 
253 QgsGeometry QgsGeometry::collectGeometry( const QVector< QgsGeometry > &geometries )
254 {
255  QgsGeometry collected;
256 
257  for ( const QgsGeometry &g : geometries )
258  {
259  if ( collected.isNull() )
260  {
261  collected = g;
262  collected.convertToMultiType();
263  }
264  else
265  {
266  if ( g.isMultipart() )
267  {
268  for ( auto p = g.const_parts_begin(); p != g.const_parts_end(); ++p )
269  {
270  collected.addPart( ( *p )->clone() );
271  }
272  }
273  else
274  {
275  collected.addPart( g );
276  }
277  }
278  }
279  return collected;
280 }
281 
282 QgsGeometry QgsGeometry::createWedgeBuffer( const QgsPoint &center, const double azimuth, const double angularWidth, const double outerRadius, const double innerRadius )
283 {
284  if ( std::abs( angularWidth ) >= 360.0 )
285  {
286  std::unique_ptr< QgsCompoundCurve > outerCc = std::make_unique< QgsCompoundCurve >();
287 
288  QgsCircle outerCircle = QgsCircle( center, outerRadius );
289  outerCc->addCurve( outerCircle.toCircularString() );
290 
291  std::unique_ptr< QgsCurvePolygon > cp = std::make_unique< QgsCurvePolygon >();
292  cp->setExteriorRing( outerCc.release() );
293 
294  if ( !qgsDoubleNear( innerRadius, 0.0 ) && innerRadius > 0 )
295  {
296  std::unique_ptr< QgsCompoundCurve > innerCc = std::make_unique< QgsCompoundCurve >();
297 
298  QgsCircle innerCircle = QgsCircle( center, innerRadius );
299  innerCc->addCurve( innerCircle.toCircularString() );
300 
301  cp->setInteriorRings( { innerCc.release() } );
302  }
303 
304  return QgsGeometry( std::move( cp ) );
305  }
306 
307  std::unique_ptr< QgsCompoundCurve > wedge = std::make_unique< QgsCompoundCurve >();
308 
309  const double startAngle = azimuth - angularWidth * 0.5;
310  const double endAngle = azimuth + angularWidth * 0.5;
311 
312  const QgsPoint outerP1 = center.project( outerRadius, startAngle );
313  const QgsPoint outerP2 = center.project( outerRadius, endAngle );
314 
315  const bool useShortestArc = angularWidth <= 180.0;
316 
317  wedge->addCurve( new QgsCircularString( QgsCircularString::fromTwoPointsAndCenter( outerP1, outerP2, center, useShortestArc ) ) );
318 
319  if ( !qgsDoubleNear( innerRadius, 0.0 ) && innerRadius > 0 )
320  {
321  const QgsPoint innerP1 = center.project( innerRadius, startAngle );
322  const QgsPoint innerP2 = center.project( innerRadius, endAngle );
323  wedge->addCurve( new QgsLineString( outerP2, innerP2 ) );
324  wedge->addCurve( new QgsCircularString( QgsCircularString::fromTwoPointsAndCenter( innerP2, innerP1, center, useShortestArc ) ) );
325  wedge->addCurve( new QgsLineString( innerP1, outerP1 ) );
326  }
327  else
328  {
329  wedge->addCurve( new QgsLineString( outerP2, center ) );
330  wedge->addCurve( new QgsLineString( center, outerP1 ) );
331  }
332 
333  std::unique_ptr< QgsCurvePolygon > cp = std::make_unique< QgsCurvePolygon >();
334  cp->setExteriorRing( wedge.release() );
335  return QgsGeometry( std::move( cp ) );
336 }
337 
338 void QgsGeometry::fromWkb( unsigned char *wkb, int length )
339 {
340  QgsConstWkbPtr ptr( wkb, length );
341  reset( QgsGeometryFactory::geomFromWkb( ptr ) );
342  delete [] wkb;
343 }
344 
345 void QgsGeometry::fromWkb( const QByteArray &wkb )
346 {
347  QgsConstWkbPtr ptr( wkb );
348  reset( QgsGeometryFactory::geomFromWkb( ptr ) );
349 }
350 
352 {
353  if ( !d->geometry )
354  {
355  return QgsWkbTypes::Unknown;
356  }
357  else
358  {
359  return d->geometry->wkbType();
360  }
361 }
362 
363 
365 {
366  if ( !d->geometry )
367  {
369  }
370  return static_cast< QgsWkbTypes::GeometryType >( QgsWkbTypes::geometryType( d->geometry->wkbType() ) );
371 }
372 
374 {
375  if ( !d->geometry )
376  {
377  return true;
378  }
379 
380  return d->geometry->isEmpty();
381 }
382 
384 {
385  if ( !d->geometry )
386  {
387  return false;
388  }
389  return QgsWkbTypes::isMultiType( d->geometry->wkbType() );
390 }
391 QgsPointXY QgsGeometry::closestVertex( const QgsPointXY &point, int &closestVertexIndex, int &previousVertexIndex, int &nextVertexIndex, double &sqrDist ) const
392 {
393  if ( !d->geometry )
394  {
395  sqrDist = -1;
396  return QgsPointXY();
397  }
398 
399  QgsPoint pt( point );
400  QgsVertexId id;
401 
402  QgsPoint vp = QgsGeometryUtils::closestVertex( *( d->geometry ), pt, id );
403  if ( !id.isValid() )
404  {
405  sqrDist = -1;
406  return QgsPointXY();
407  }
408  sqrDist = QgsGeometryUtils::sqrDistance2D( pt, vp );
409 
410  QgsVertexId prevVertex;
411  QgsVertexId nextVertex;
412  d->geometry->adjacentVertices( id, prevVertex, nextVertex );
413  closestVertexIndex = vertexNrFromVertexId( id );
414  previousVertexIndex = vertexNrFromVertexId( prevVertex );
415  nextVertexIndex = vertexNrFromVertexId( nextVertex );
416  return QgsPointXY( vp.x(), vp.y() );
417 }
418 
419 double QgsGeometry::distanceToVertex( int vertex ) const
420 {
421  if ( !d->geometry )
422  {
423  return -1;
424  }
425 
426  QgsVertexId id;
427  if ( !vertexIdFromVertexNr( vertex, id ) )
428  {
429  return -1;
430  }
431 
432  return QgsGeometryUtils::distanceToVertex( *( d->geometry ), id );
433 }
434 
435 double QgsGeometry::angleAtVertex( int vertex ) const
436 {
437  if ( !d->geometry )
438  {
439  return 0;
440  }
441 
442  QgsVertexId v2;
443  if ( !vertexIdFromVertexNr( vertex, v2 ) )
444  {
445  return 0;
446  }
447 
448  return d->geometry->vertexAngle( v2 );
449 }
450 
451 void QgsGeometry::adjacentVertices( int atVertex, int &beforeVertex, int &afterVertex ) const
452 {
453  if ( !d->geometry )
454  {
455  return;
456  }
457 
458  QgsVertexId id;
459  if ( !vertexIdFromVertexNr( atVertex, id ) )
460  {
461  beforeVertex = -1;
462  afterVertex = -1;
463  return;
464  }
465 
466  QgsVertexId beforeVertexId, afterVertexId;
467  d->geometry->adjacentVertices( id, beforeVertexId, afterVertexId );
468  beforeVertex = vertexNrFromVertexId( beforeVertexId );
469  afterVertex = vertexNrFromVertexId( afterVertexId );
470 }
471 
472 bool QgsGeometry::moveVertex( double x, double y, int atVertex )
473 {
474  if ( !d->geometry )
475  {
476  return false;
477  }
478 
479  QgsVertexId id;
480  if ( !vertexIdFromVertexNr( atVertex, id ) )
481  {
482  return false;
483  }
484 
485  detach();
486 
487  return d->geometry->moveVertex( id, QgsPoint( x, y ) );
488 }
489 
490 bool QgsGeometry::moveVertex( const QgsPoint &p, int atVertex )
491 {
492  if ( !d->geometry )
493  {
494  return false;
495  }
496 
497  QgsVertexId id;
498  if ( !vertexIdFromVertexNr( atVertex, id ) )
499  {
500  return false;
501  }
502 
503  detach();
504 
505  return d->geometry->moveVertex( id, p );
506 }
507 
508 bool QgsGeometry::deleteVertex( int atVertex )
509 {
510  if ( !d->geometry )
511  {
512  return false;
513  }
514 
515  //maintain compatibility with < 2.10 API
516  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::MultiPoint )
517  {
518  detach();
519  //delete geometry instead of point
520  return static_cast< QgsGeometryCollection * >( d->geometry.get() )->removeGeometry( atVertex );
521  }
522 
523  //if it is a point, set the geometry to nullptr
524  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::Point )
525  {
526  reset( nullptr );
527  return true;
528  }
529 
530  QgsVertexId id;
531  if ( !vertexIdFromVertexNr( atVertex, id ) )
532  {
533  return false;
534  }
535 
536  detach();
537 
538  return d->geometry->deleteVertex( id );
539 }
540 
541 bool QgsGeometry::insertVertex( double x, double y, int beforeVertex )
542 {
543  if ( !d->geometry )
544  {
545  return false;
546  }
547 
548  //maintain compatibility with < 2.10 API
549  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::MultiPoint )
550  {
551  detach();
552  //insert geometry instead of point
553  return static_cast< QgsGeometryCollection * >( d->geometry.get() )->insertGeometry( new QgsPoint( x, y ), beforeVertex );
554  }
555 
556  QgsVertexId id;
557  if ( !vertexIdFromVertexNr( beforeVertex, id ) )
558  {
559  return false;
560  }
561 
562  detach();
563 
564  return d->geometry->insertVertex( id, QgsPoint( x, y ) );
565 }
566 
567 bool QgsGeometry::insertVertex( const QgsPoint &point, int beforeVertex )
568 {
569  if ( !d->geometry )
570  {
571  return false;
572  }
573 
574  //maintain compatibility with < 2.10 API
575  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::MultiPoint )
576  {
577  detach();
578  //insert geometry instead of point
579  return static_cast< QgsGeometryCollection * >( d->geometry.get() )->insertGeometry( new QgsPoint( point ), beforeVertex );
580  }
581 
582  QgsVertexId id;
583  if ( !vertexIdFromVertexNr( beforeVertex, id ) )
584  {
585  return false;
586  }
587 
588  detach();
589 
590  return d->geometry->insertVertex( id, point );
591 }
592 
593 QgsPoint QgsGeometry::vertexAt( int atVertex ) const
594 {
595  if ( !d->geometry )
596  {
597  return QgsPoint();
598  }
599 
600  QgsVertexId vId;
601  ( void )vertexIdFromVertexNr( atVertex, vId );
602  if ( vId.vertex < 0 )
603  {
604  return QgsPoint();
605  }
606  return d->geometry->vertexAt( vId );
607 }
608 
609 double QgsGeometry::sqrDistToVertexAt( QgsPointXY &point, int atVertex ) const
610 {
611  QgsPointXY vertexPoint = vertexAt( atVertex );
612  return QgsGeometryUtils::sqrDistance2D( QgsPoint( vertexPoint ), QgsPoint( point ) );
613 }
614 
616 {
617  // avoid calling geos for trivial point calculations
618  if ( d->geometry && QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::Point )
619  {
620  return QgsGeometry( qgsgeometry_cast< const QgsPoint * >( d->geometry.get() )->clone() );
621  }
622 
623  QgsGeos geos( d->geometry.get() );
624  mLastError.clear();
625  QgsGeometry result = geos.closestPoint( other );
626  result.mLastError = mLastError;
627  return result;
628 }
629 
631 {
632  // avoid calling geos for trivial point-to-point line calculations
634  {
635  return QgsGeometry( std::make_unique< QgsLineString >( *qgsgeometry_cast< const QgsPoint * >( d->geometry.get() ), *qgsgeometry_cast< const QgsPoint * >( other.constGet() ) ) );
636  }
637 
638  QgsGeos geos( d->geometry.get() );
639  mLastError.clear();
640  QgsGeometry result = geos.shortestLine( other, &mLastError );
641  result.mLastError = mLastError;
642  return result;
643 }
644 
645 double QgsGeometry::closestVertexWithContext( const QgsPointXY &point, int &atVertex ) const
646 {
647  if ( !d->geometry )
648  {
649  return -1;
650  }
651 
652  QgsVertexId vId;
653  QgsPoint pt( point );
654  QgsPoint closestPoint = QgsGeometryUtils::closestVertex( *( d->geometry ), pt, vId );
655  if ( !vId.isValid() )
656  return -1;
657  atVertex = vertexNrFromVertexId( vId );
658  return QgsGeometryUtils::sqrDistance2D( closestPoint, pt );
659 }
660 
662  QgsPointXY &minDistPoint,
663  int &nextVertexIndex,
664  int *leftOrRightOfSegment,
665  double epsilon ) const
666 {
667  if ( !d->geometry )
668  {
669  return -1;
670  }
671 
672  QgsPoint segmentPt;
673  QgsVertexId vertexAfter;
674 
675  double sqrDist = d->geometry->closestSegment( QgsPoint( point ), segmentPt, vertexAfter, leftOrRightOfSegment, epsilon );
676  if ( sqrDist < 0 )
677  return -1;
678 
679  minDistPoint.setX( segmentPt.x() );
680  minDistPoint.setY( segmentPt.y() );
681  nextVertexIndex = vertexNrFromVertexId( vertexAfter );
682  return sqrDist;
683 }
684 
685 QgsGeometry::OperationResult QgsGeometry::addRing( const QVector<QgsPointXY> &ring )
686 {
687  std::unique_ptr< QgsLineString > ringLine = std::make_unique< QgsLineString >( ring );
688  return addRing( ringLine.release() );
689 }
690 
692 {
693  std::unique_ptr< QgsCurve > r( ring );
694  if ( !d->geometry )
695  {
697  }
698 
699  detach();
700 
701  return QgsGeometryEditUtils::addRing( d->geometry.get(), std::move( r ) );
702 }
703 
705 {
707  convertPointList( points, l );
708  return addPart( l, geomType );
709 }
710 
712 {
713  std::unique_ptr< QgsAbstractGeometry > partGeom;
714  if ( points.size() == 1 )
715  {
716  partGeom = std::make_unique< QgsPoint >( points[0] );
717  }
718  else if ( points.size() > 1 )
719  {
720  std::unique_ptr< QgsLineString > ringLine = std::make_unique< QgsLineString >();
721  ringLine->setPoints( points );
722  partGeom = std::move( ringLine );
723  }
724  return addPart( partGeom.release(), geomType );
725 }
726 
728 {
729  std::unique_ptr< QgsAbstractGeometry > p( part );
730  if ( !d->geometry )
731  {
732  switch ( geomType )
733  {
735  reset( std::make_unique< QgsMultiPoint >() );
736  break;
738  reset( std::make_unique< QgsMultiLineString >() );
739  break;
741  reset( std::make_unique< QgsMultiPolygon >() );
742  break;
743  default:
744  reset( nullptr );
745  return QgsGeometry::OperationResult::AddPartNotMultiGeometry;
746  }
747  }
748  else
749  {
750  detach();
751  }
752 
754  return QgsGeometryEditUtils::addPart( d->geometry.get(), std::move( p ) );
755 }
756 
758 {
759  if ( !d->geometry )
760  {
762  }
763  if ( newPart.isNull() || !newPart.d->geometry )
764  {
766  }
767 
768  return addPart( newPart.d->geometry->clone() );
769 }
770 
771 QgsGeometry QgsGeometry::removeInteriorRings( double minimumRingArea ) const
772 {
773  if ( !d->geometry || type() != QgsWkbTypes::PolygonGeometry )
774  {
775  return QgsGeometry();
776  }
777 
778  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
779  {
780  const QVector<QgsGeometry> parts = asGeometryCollection();
781  QVector<QgsGeometry> results;
782  results.reserve( parts.count() );
783  for ( const QgsGeometry &part : parts )
784  {
785  QgsGeometry result = part.removeInteriorRings( minimumRingArea );
786  if ( !result.isNull() )
787  results << result;
788  }
789  if ( results.isEmpty() )
790  return QgsGeometry();
791 
792  QgsGeometry first = results.takeAt( 0 );
793  for ( const QgsGeometry &result : std::as_const( results ) )
794  {
795  first.addPart( result );
796  }
797  return first;
798  }
799  else
800  {
801  std::unique_ptr< QgsCurvePolygon > newPoly( static_cast< QgsCurvePolygon * >( d->geometry->clone() ) );
802  newPoly->removeInteriorRings( minimumRingArea );
803  return QgsGeometry( std::move( newPoly ) );
804  }
805 }
806 
807 QgsGeometry::OperationResult QgsGeometry::translate( double dx, double dy, double dz, double dm )
808 {
809  if ( !d->geometry )
810  {
812  }
813 
814  detach();
815 
816  d->geometry->transform( QTransform::fromTranslate( dx, dy ), dz, 1.0, dm );
817  return QgsGeometry::Success;
818 }
819 
821 {
822  if ( !d->geometry )
823  {
825  }
826 
827  detach();
828 
829  QTransform t = QTransform::fromTranslate( center.x(), center.y() );
830  t.rotate( -rotation );
831  t.translate( -center.x(), -center.y() );
832  d->geometry->transform( t );
833  return QgsGeometry::Success;
834 }
835 
836 QgsGeometry::OperationResult QgsGeometry::splitGeometry( const QVector<QgsPointXY> &splitLine, QVector<QgsGeometry> &newGeometries, bool topological, QVector<QgsPointXY> &topologyTestPoints, bool splitFeature )
837 {
838  QgsPointSequence split, topology;
839  convertPointList( splitLine, split );
840  convertPointList( topologyTestPoints, topology );
841  QgsGeometry::OperationResult result = splitGeometry( split, newGeometries, topological, topology, splitFeature );
842  convertPointList( topology, topologyTestPoints );
843  return result;
844 }
845 QgsGeometry::OperationResult QgsGeometry::splitGeometry( const QgsPointSequence &splitLine, QVector<QgsGeometry> &newGeometries, bool topological, QgsPointSequence &topologyTestPoints, bool splitFeature, bool skipIntersectionTest )
846 {
847  if ( !d->geometry )
848  {
849  return QgsGeometry::OperationResult::InvalidBaseGeometry;
850  }
851 
852  QVector<QgsGeometry > newGeoms;
853  QgsLineString splitLineString( splitLine );
854 
863  splitLineString.dropZValue();
864  splitLineString.dropMValue();
865 
866  QgsGeos geos( d->geometry.get() );
867  mLastError.clear();
868  QgsGeometryEngine::EngineOperationResult result = geos.splitGeometry( splitLineString, newGeoms, topological, topologyTestPoints, &mLastError, skipIntersectionTest );
869 
870  if ( result == QgsGeometryEngine::Success )
871  {
872  if ( splitFeature )
873  *this = newGeoms.takeAt( 0 );
874  newGeometries = newGeoms;
875  }
876 
877  switch ( result )
878  {
880  return QgsGeometry::OperationResult::Success;
884  return QgsGeometry::OperationResult::GeometryEngineError;
886  return QgsGeometry::OperationResult::InvalidBaseGeometry;
888  return QgsGeometry::OperationResult::InvalidInputGeometryType;
890  return QgsGeometry::OperationResult::SplitCannotSplitPoint;
892  return QgsGeometry::OperationResult::NothingHappened;
893  //default: do not implement default to handle properly all cases
894  }
895 
896  // this should never be reached
897  Q_ASSERT( false );
899 }
900 
901 QgsGeometry::OperationResult QgsGeometry::splitGeometry( const QgsCurve *curve, QVector<QgsGeometry> &newGeometries, bool preserveCircular, bool topological, QgsPointSequence &topologyTestPoints, bool splitFeature )
902 {
903  std::unique_ptr<QgsLineString> segmentizedLine( curve->curveToLine() );
904  QgsPointSequence points;
905  segmentizedLine->points( points );
906  QgsGeometry::OperationResult result = splitGeometry( points, newGeometries, topological, topologyTestPoints, splitFeature );
907 
908  if ( result == QgsGeometry::Success )
909  {
910  if ( preserveCircular )
911  {
912  for ( int i = 0; i < newGeometries.count(); ++i )
913  newGeometries[i] = newGeometries[i].convertToCurves();
914  *this = convertToCurves();
915  }
916  }
917 
918  return result;
919 }
920 
922 {
923  if ( !d->geometry )
924  {
925  return InvalidBaseGeometry;
926  }
927 
928  QgsGeos geos( d->geometry.get() );
930  mLastError.clear();
931  std::unique_ptr< QgsAbstractGeometry > geom( geos.reshapeGeometry( reshapeLineString, &errorCode, &mLastError ) );
932  if ( errorCode == QgsGeometryEngine::Success && geom )
933  {
934  reset( std::move( geom ) );
935  return Success;
936  }
937 
938  switch ( errorCode )
939  {
941  return Success;
945  return GeometryEngineError;
947  return InvalidBaseGeometry;
950  case QgsGeometryEngine::SplitCannotSplitPoint: // should not happen
951  return GeometryEngineError;
953  return NothingHappened;
954  }
955 
956  // should not be reached
957  return GeometryEngineError;
958 }
959 
961 {
962  if ( !d->geometry || !other.d->geometry )
963  {
964  return 0;
965  }
966 
967  QgsGeos geos( d->geometry.get() );
968 
969  mLastError.clear();
970  std::unique_ptr< QgsAbstractGeometry > diffGeom( geos.intersection( other.constGet(), &mLastError ) );
971  if ( !diffGeom )
972  {
973  return 1;
974  }
975 
976  reset( std::move( diffGeom ) );
977  return 0;
978 }
979 
981 {
982  if ( !d->geometry || other.isNull() )
983  {
984  return QgsGeometry();
985  }
986 
987  QgsGeos geos( d->geometry.get() );
988 
989  mLastError.clear();
990  std::unique_ptr< QgsAbstractGeometry > diffGeom( geos.intersection( other.constGet(), &mLastError ) );
991  if ( !diffGeom )
992  {
993  QgsGeometry result;
994  result.mLastError = mLastError;
995  return result;
996  }
997 
998  return QgsGeometry( diffGeom.release() );
999 }
1000 
1002 {
1003  if ( d->geometry )
1004  {
1005  return d->geometry->boundingBox();
1006  }
1007  return QgsRectangle();
1008 }
1009 
1010 QgsGeometry QgsGeometry::orientedMinimumBoundingBox( double &area, double &angle, double &width, double &height ) const
1011 {
1012  mLastError.clear();
1013  QgsInternalGeometryEngine engine( *this );
1014  const QgsGeometry res = engine.orientedMinimumBoundingBox( area, angle, width, height );
1015  if ( res.isNull() )
1016  mLastError = engine.lastError();
1017  return res;
1018 }
1019 
1021 {
1022  double area, angle, width, height;
1023  return orientedMinimumBoundingBox( area, angle, width, height );
1024 }
1025 
1026 static QgsCircle __recMinimalEnclosingCircle( QgsMultiPointXY points, QgsMultiPointXY boundary )
1027 {
1028  auto l_boundary = boundary.length();
1029  QgsCircle circ_mec;
1030  if ( ( points.length() == 0 ) || ( l_boundary == 3 ) )
1031  {
1032  switch ( l_boundary )
1033  {
1034  case 0:
1035  circ_mec = QgsCircle();
1036  break;
1037  case 1:
1038  circ_mec = QgsCircle( QgsPoint( boundary.last() ), 0 );
1039  boundary.pop_back();
1040  break;
1041  case 2:
1042  {
1043  QgsPointXY p1 = boundary.last();
1044  boundary.pop_back();
1045  QgsPointXY p2 = boundary.last();
1046  boundary.pop_back();
1047  circ_mec = QgsCircle().from2Points( QgsPoint( p1 ), QgsPoint( p2 ) );
1048  }
1049  break;
1050  default:
1051  QgsPoint p1( boundary.at( 0 ) );
1052  QgsPoint p2( boundary.at( 1 ) );
1053  QgsPoint p3( boundary.at( 2 ) );
1054  circ_mec = QgsCircle().minimalCircleFrom3Points( p1, p2, p3 );
1055  break;
1056  }
1057  return circ_mec;
1058  }
1059  else
1060  {
1061  QgsPointXY pxy = points.last();
1062  points.pop_back();
1063  circ_mec = __recMinimalEnclosingCircle( points, boundary );
1064  QgsPoint p( pxy );
1065  if ( !circ_mec.contains( p ) )
1066  {
1067  boundary.append( pxy );
1068  circ_mec = __recMinimalEnclosingCircle( points, boundary );
1069  }
1070  }
1071  return circ_mec;
1072 }
1073 
1074 QgsGeometry QgsGeometry::minimalEnclosingCircle( QgsPointXY &center, double &radius, unsigned int segments ) const
1075 {
1076  center = QgsPointXY();
1077  radius = 0;
1078 
1079  if ( isEmpty() )
1080  {
1081  return QgsGeometry();
1082  }
1083 
1084  /* optimization */
1085  QgsGeometry hull = convexHull();
1086  if ( hull.isNull() )
1087  return QgsGeometry();
1088 
1089  QgsMultiPointXY P = hull.convertToPoint( true ).asMultiPoint();
1090  QgsMultiPointXY R;
1091 
1092  QgsCircle circ = __recMinimalEnclosingCircle( P, R );
1093  center = QgsPointXY( circ.center() );
1094  radius = circ.radius();
1095  QgsGeometry geom;
1096  geom.set( circ.toPolygon( segments ) );
1097  return geom;
1098 
1099 }
1100 
1101 QgsGeometry QgsGeometry::minimalEnclosingCircle( unsigned int segments ) const
1102 {
1103  QgsPointXY center;
1104  double radius;
1105  return minimalEnclosingCircle( center, radius, segments );
1106 
1107 }
1108 
1109 QgsGeometry QgsGeometry::orthogonalize( double tolerance, int maxIterations, double angleThreshold ) const
1110 {
1111  QgsInternalGeometryEngine engine( *this );
1112 
1113  return engine.orthogonalize( tolerance, maxIterations, angleThreshold );
1114 }
1115 
1116 QgsGeometry QgsGeometry::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing ) const
1117 {
1118  if ( !d->geometry )
1119  {
1120  return QgsGeometry();
1121  }
1122  return QgsGeometry( d->geometry->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing ) );
1123 }
1124 
1125 bool QgsGeometry::removeDuplicateNodes( double epsilon, bool useZValues )
1126 {
1127  if ( !d->geometry )
1128  return false;
1129 
1130  detach();
1131  return d->geometry->removeDuplicateNodes( epsilon, useZValues );
1132 }
1133 
1135 {
1136  // fast case, check bounding boxes
1137  if ( !boundingBoxIntersects( r ) )
1138  return false;
1139 
1140  // optimise trivial case for point intersections -- the bounding box test has already given us the answer
1141  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::Point )
1142  {
1143  return true;
1144  }
1145 
1146  QgsGeometry g = fromRect( r );
1147  return intersects( g );
1148 }
1149 
1150 bool QgsGeometry::intersects( const QgsGeometry &geometry ) const
1151 {
1152  if ( !d->geometry || geometry.isNull() )
1153  {
1154  return false;
1155  }
1156 
1157  QgsGeos geos( d->geometry.get() );
1158  mLastError.clear();
1159  return geos.intersects( geometry.d->geometry.get(), &mLastError );
1160 }
1161 
1162 bool QgsGeometry::boundingBoxIntersects( const QgsRectangle &rectangle ) const
1163 {
1164  if ( !d->geometry )
1165  {
1166  return false;
1167  }
1168 
1169  return d->geometry->boundingBoxIntersects( rectangle );
1170 }
1171 
1173 {
1174  if ( !d->geometry || geometry.isNull() )
1175  {
1176  return false;
1177  }
1178 
1179  return d->geometry->boundingBoxIntersects( geometry.constGet()->boundingBox() );
1180 }
1181 
1182 bool QgsGeometry::contains( const QgsPointXY *p ) const
1183 {
1184  if ( !d->geometry || !p )
1185  {
1186  return false;
1187  }
1188 
1189  QgsPoint pt( p->x(), p->y() );
1190  QgsGeos geos( d->geometry.get() );
1191  mLastError.clear();
1192  return geos.contains( &pt, &mLastError );
1193 }
1194 
1195 bool QgsGeometry::contains( const QgsGeometry &geometry ) const
1196 {
1197  if ( !d->geometry || geometry.isNull() )
1198  {
1199  return false;
1200  }
1201 
1202  QgsGeos geos( d->geometry.get() );
1203  mLastError.clear();
1204  return geos.contains( geometry.d->geometry.get(), &mLastError );
1205 }
1206 
1207 bool QgsGeometry::disjoint( const QgsGeometry &geometry ) const
1208 {
1209  if ( !d->geometry || geometry.isNull() )
1210  {
1211  return false;
1212  }
1213 
1214  QgsGeos geos( d->geometry.get() );
1215  mLastError.clear();
1216  return geos.disjoint( geometry.d->geometry.get(), &mLastError );
1217 }
1218 
1219 bool QgsGeometry::equals( const QgsGeometry &geometry ) const
1220 {
1221  if ( !d->geometry || geometry.isNull() )
1222  {
1223  return false;
1224  }
1225 
1226  // fast check - are they shared copies of the same underlying geometry?
1227  if ( d == geometry.d )
1228  return true;
1229 
1230  // fast check - distinct geometry types?
1231  if ( type() != geometry.type() )
1232  return false;
1233 
1234  // slower check - actually test the geometries
1235  return *d->geometry == *geometry.d->geometry;
1236 }
1237 
1238 bool QgsGeometry::touches( const QgsGeometry &geometry ) const
1239 {
1240  if ( !d->geometry || geometry.isNull() )
1241  {
1242  return false;
1243  }
1244 
1245  QgsGeos geos( d->geometry.get() );
1246  mLastError.clear();
1247  return geos.touches( geometry.d->geometry.get(), &mLastError );
1248 }
1249 
1250 bool QgsGeometry::overlaps( const QgsGeometry &geometry ) const
1251 {
1252  if ( !d->geometry || geometry.isNull() )
1253  {
1254  return false;
1255  }
1256 
1257  QgsGeos geos( d->geometry.get() );
1258  mLastError.clear();
1259  return geos.overlaps( geometry.d->geometry.get(), &mLastError );
1260 }
1261 
1262 bool QgsGeometry::within( const QgsGeometry &geometry ) const
1263 {
1264  if ( !d->geometry || geometry.isNull() )
1265  {
1266  return false;
1267  }
1268 
1269  QgsGeos geos( d->geometry.get() );
1270  mLastError.clear();
1271  return geos.within( geometry.d->geometry.get(), &mLastError );
1272 }
1273 
1274 bool QgsGeometry::crosses( const QgsGeometry &geometry ) const
1275 {
1276  if ( !d->geometry || geometry.isNull() )
1277  {
1278  return false;
1279  }
1280 
1281  QgsGeos geos( d->geometry.get() );
1282  mLastError.clear();
1283  return geos.crosses( geometry.d->geometry.get(), &mLastError );
1284 }
1285 
1286 QString QgsGeometry::asWkt( int precision ) const
1287 {
1288  if ( !d->geometry )
1289  {
1290  return QString();
1291  }
1292  return d->geometry->asWkt( precision );
1293 }
1294 
1295 QString QgsGeometry::asJson( int precision ) const
1296 {
1297  return QString::fromStdString( asJsonObject( precision ).dump() );
1298 }
1299 
1301 {
1302  if ( !d->geometry )
1303  {
1304  return nullptr;
1305  }
1306  return d->geometry->asJsonObject( precision );
1307 
1308 }
1309 
1310 QVector<QgsGeometry> QgsGeometry::coerceToType( const QgsWkbTypes::Type type ) const
1311 {
1312  QVector< QgsGeometry > res;
1313  if ( isNull() )
1314  return res;
1315 
1316  if ( wkbType() == type || type == QgsWkbTypes::Unknown )
1317  {
1318  res << *this;
1319  return res;
1320  }
1321 
1322  if ( type == QgsWkbTypes::NoGeometry )
1323  {
1324  return res;
1325  }
1326 
1327  QgsGeometry newGeom = *this;
1328 
1329  // Curved -> straight
1331  {
1332  newGeom = QgsGeometry( d->geometry.get()->segmentize() );
1333  }
1334 
1335  // polygon -> line
1337  newGeom.type() == QgsWkbTypes::PolygonGeometry )
1338  {
1339  // boundary gives us a (multi)line string of exterior + interior rings
1340  newGeom = QgsGeometry( newGeom.constGet()->boundary() );
1341  }
1342  // line -> polygon
1344  newGeom.type() == QgsWkbTypes::LineGeometry )
1345  {
1346  std::unique_ptr< QgsGeometryCollection > gc( QgsGeometryFactory::createCollectionOfType( type ) );
1347  const QgsGeometry source = newGeom;
1348  for ( auto part = source.const_parts_begin(); part != source.const_parts_end(); ++part )
1349  {
1350  std::unique_ptr< QgsAbstractGeometry > exterior( ( *part )->clone() );
1351  if ( QgsCurve *curve = qgsgeometry_cast< QgsCurve * >( exterior.get() ) )
1352  {
1354  {
1355  std::unique_ptr< QgsCurvePolygon > cp = std::make_unique< QgsCurvePolygon >();
1356  cp->setExteriorRing( curve );
1357  exterior.release();
1358  gc->addGeometry( cp.release() );
1359  }
1360  else
1361  {
1362  std::unique_ptr< QgsPolygon > p = std::make_unique< QgsPolygon >();
1363  p->setExteriorRing( qgsgeometry_cast< QgsLineString * >( curve ) );
1364  exterior.release();
1365  gc->addGeometry( p.release() );
1366  }
1367  }
1368  }
1369  newGeom = QgsGeometry( std::move( gc ) );
1370  }
1371 
1372  // line/polygon -> points
1374  ( newGeom.type() == QgsWkbTypes::LineGeometry ||
1375  newGeom.type() == QgsWkbTypes::PolygonGeometry ) )
1376  {
1377  // lines/polygons to a point layer, extract all vertices
1378  std::unique_ptr< QgsMultiPoint > mp = std::make_unique< QgsMultiPoint >();
1379  const QgsGeometry source = newGeom;
1380  QSet< QgsPoint > added;
1381  for ( auto vertex = source.vertices_begin(); vertex != source.vertices_end(); ++vertex )
1382  {
1383  if ( added.contains( *vertex ) )
1384  continue; // avoid duplicate points, e.g. start/end of rings
1385  mp->addGeometry( ( *vertex ).clone() );
1386  added.insert( *vertex );
1387  }
1388  newGeom = QgsGeometry( std::move( mp ) );
1389  }
1390 
1391  // Single -> multi
1392  if ( QgsWkbTypes::isMultiType( type ) && ! newGeom.isMultipart( ) )
1393  {
1394  newGeom.convertToMultiType();
1395  }
1396  // Drop Z/M
1397  if ( newGeom.constGet()->is3D() && ! QgsWkbTypes::hasZ( type ) )
1398  {
1399  newGeom.get()->dropZValue();
1400  }
1401  if ( newGeom.constGet()->isMeasure() && ! QgsWkbTypes::hasM( type ) )
1402  {
1403  newGeom.get()->dropMValue();
1404  }
1405  // Add Z/M back, set to 0
1406  if ( ! newGeom.constGet()->is3D() && QgsWkbTypes::hasZ( type ) )
1407  {
1408  newGeom.get()->addZValue( 0.0 );
1409  }
1410  if ( ! newGeom.constGet()->isMeasure() && QgsWkbTypes::hasM( type ) )
1411  {
1412  newGeom.get()->addMValue( 0.0 );
1413  }
1414 
1415  // Multi -> single
1416  if ( ! QgsWkbTypes::isMultiType( type ) && newGeom.isMultipart( ) )
1417  {
1418  const QgsGeometryCollection *parts( static_cast< const QgsGeometryCollection * >( newGeom.constGet() ) );
1419  QgsAttributeMap attrMap;
1420  res.reserve( parts->partCount() );
1421  for ( int i = 0; i < parts->partCount( ); i++ )
1422  {
1423  res << QgsGeometry( parts->geometryN( i )->clone() );
1424  }
1425  }
1426  else
1427  {
1428  res << newGeom;
1429  }
1430  return res;
1431 }
1432 
1434 {
1435  switch ( destType )
1436  {
1438  return convertToPoint( destMultipart );
1439 
1441  return convertToLine( destMultipart );
1442 
1444  return convertToPolygon( destMultipart );
1445 
1446  default:
1447  return QgsGeometry();
1448  }
1449 }
1450 
1452 {
1453  if ( !d->geometry )
1454  {
1455  return false;
1456  }
1457 
1458  if ( isMultipart() ) //already multitype, no need to convert
1459  {
1460  return true;
1461  }
1462 
1463  std::unique_ptr< QgsAbstractGeometry >geom = QgsGeometryFactory::geomFromWkbType( QgsWkbTypes::multiType( d->geometry->wkbType() ) );
1464  QgsGeometryCollection *multiGeom = qgsgeometry_cast<QgsGeometryCollection *>( geom.get() );
1465  if ( !multiGeom )
1466  {
1467  return false;
1468  }
1469 
1470  //try to avoid cloning existing geometry whenever we can
1471 
1472  //want to see a magic trick?... gather round kiddies...
1473  detach(); // maybe a clone, hopefully not if we're the only ref to the private data
1474  // now we cheat a bit and steal the private geometry and add it direct to the multigeom
1475  // we can do this because we're the only ref to this geometry, guaranteed by the detach call above
1476  multiGeom->addGeometry( d->geometry.release() );
1477  // and replace it with the multi geometry.
1478  // TADA! a clone free conversion in some cases
1479  d->geometry = std::move( geom );
1480  return true;
1481 }
1482 
1484 {
1485  if ( !d->geometry )
1486  {
1487  return false;
1488  }
1489 
1490  if ( !isMultipart() ) //already single part, no need to convert
1491  {
1492  return true;
1493  }
1494 
1495  QgsGeometryCollection *multiGeom = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
1496  if ( !multiGeom || multiGeom->partCount() < 1 )
1497  return false;
1498 
1499  std::unique_ptr< QgsAbstractGeometry > firstPart( multiGeom->geometryN( 0 )->clone() );
1500  reset( std::move( firstPart ) );
1501  return true;
1502 }
1503 
1504 
1506 {
1507  const QgsGeometryCollection *origGeom = qgsgeometry_cast<const QgsGeometryCollection *>( constGet() );
1508  if ( !origGeom )
1509  return false;
1510 
1511  std::unique_ptr<QgsGeometryCollection> resGeom;
1512  switch ( geomType )
1513  {
1515  resGeom = std::make_unique<QgsMultiPoint>();
1516  break;
1518  resGeom = std::make_unique<QgsMultiLineString>();
1519  break;
1521  resGeom = std::make_unique<QgsMultiPolygon>();
1522  break;
1523  default:
1524  break;
1525  }
1526  if ( !resGeom )
1527  return false;
1528 
1529  resGeom->reserve( origGeom->numGeometries() );
1530  for ( int i = 0; i < origGeom->numGeometries(); ++i )
1531  {
1532  const QgsAbstractGeometry *g = origGeom->geometryN( i );
1533  if ( QgsWkbTypes::geometryType( g->wkbType() ) == geomType )
1534  resGeom->addGeometry( g->clone() );
1535  }
1536 
1537  set( resGeom.release() );
1538  return true;
1539 }
1540 
1541 
1543 {
1544  if ( !d->geometry || QgsWkbTypes::flatType( d->geometry->wkbType() ) != QgsWkbTypes::Point )
1545  {
1546  return QgsPointXY();
1547  }
1548  QgsPoint *pt = qgsgeometry_cast<QgsPoint *>( d->geometry.get() );
1549  if ( !pt )
1550  {
1551  return QgsPointXY();
1552  }
1553 
1554  return QgsPointXY( pt->x(), pt->y() );
1555 }
1556 
1558 {
1559  QgsPolylineXY polyLine;
1560  if ( !d->geometry )
1561  {
1562  return polyLine;
1563  }
1564 
1565  bool doSegmentation = ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::CompoundCurve
1567  std::unique_ptr< QgsLineString > segmentizedLine;
1568  QgsLineString *line = nullptr;
1569  if ( doSegmentation )
1570  {
1571  QgsCurve *curve = qgsgeometry_cast<QgsCurve *>( d->geometry.get() );
1572  if ( !curve )
1573  {
1574  return polyLine;
1575  }
1576  segmentizedLine.reset( curve->curveToLine() );
1577  line = segmentizedLine.get();
1578  }
1579  else
1580  {
1581  line = qgsgeometry_cast<QgsLineString *>( d->geometry.get() );
1582  if ( !line )
1583  {
1584  return polyLine;
1585  }
1586  }
1587 
1588  int nVertices = line->numPoints();
1589  polyLine.resize( nVertices );
1590  QgsPointXY *data = polyLine.data();
1591  const double *xData = line->xData();
1592  const double *yData = line->yData();
1593  for ( int i = 0; i < nVertices; ++i )
1594  {
1595  data->setX( *xData++ );
1596  data->setY( *yData++ );
1597  data++;
1598  }
1599 
1600  return polyLine;
1601 }
1602 
1604 {
1605  if ( !d->geometry )
1606  return QgsPolygonXY();
1607 
1608  bool doSegmentation = ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::CurvePolygon );
1609 
1610  QgsPolygon *p = nullptr;
1611  std::unique_ptr< QgsPolygon > segmentized;
1612  if ( doSegmentation )
1613  {
1614  QgsCurvePolygon *curvePoly = qgsgeometry_cast<QgsCurvePolygon *>( d->geometry.get() );
1615  if ( !curvePoly )
1616  {
1617  return QgsPolygonXY();
1618  }
1619  segmentized.reset( curvePoly->toPolygon() );
1620  p = segmentized.get();
1621  }
1622  else
1623  {
1624  p = qgsgeometry_cast<QgsPolygon *>( d->geometry.get() );
1625  }
1626 
1627  if ( !p )
1628  {
1629  return QgsPolygonXY();
1630  }
1631 
1632  QgsPolygonXY polygon;
1633  convertPolygon( *p, polygon );
1634 
1635  return polygon;
1636 }
1637 
1639 {
1640  if ( !d->geometry || QgsWkbTypes::flatType( d->geometry->wkbType() ) != QgsWkbTypes::MultiPoint )
1641  {
1642  return QgsMultiPointXY();
1643  }
1644 
1645  const QgsMultiPoint *mp = qgsgeometry_cast<QgsMultiPoint *>( d->geometry.get() );
1646  if ( !mp )
1647  {
1648  return QgsMultiPointXY();
1649  }
1650 
1651  int nPoints = mp->numGeometries();
1652  QgsMultiPointXY multiPoint( nPoints );
1653  for ( int i = 0; i < nPoints; ++i )
1654  {
1655  const QgsPoint *pt = mp->pointN( i );
1656  multiPoint[i].setX( pt->x() );
1657  multiPoint[i].setY( pt->y() );
1658  }
1659  return multiPoint;
1660 }
1661 
1663 {
1664  if ( !d->geometry )
1665  {
1666  return QgsMultiPolylineXY();
1667  }
1668 
1669  QgsGeometryCollection *geomCollection = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
1670  if ( !geomCollection )
1671  {
1672  return QgsMultiPolylineXY();
1673  }
1674 
1675  int nLines = geomCollection->numGeometries();
1676  if ( nLines < 1 )
1677  {
1678  return QgsMultiPolylineXY();
1679  }
1680 
1681  QgsMultiPolylineXY mpl;
1682  mpl.reserve( nLines );
1683  for ( int i = 0; i < nLines; ++i )
1684  {
1685  const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( geomCollection->geometryN( i ) );
1686  std::unique_ptr< QgsLineString > segmentized;
1687  if ( !line )
1688  {
1689  const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( geomCollection->geometryN( i ) );
1690  if ( !curve )
1691  {
1692  continue;
1693  }
1694  segmentized.reset( curve->curveToLine() );
1695  line = segmentized.get();
1696  }
1697 
1698  QgsPolylineXY polyLine;
1699  int nVertices = line->numPoints();
1700  polyLine.resize( nVertices );
1701  QgsPointXY *data = polyLine.data();
1702  const double *xData = line->xData();
1703  const double *yData = line->yData();
1704  for ( int i = 0; i < nVertices; ++i )
1705  {
1706  data->setX( *xData++ );
1707  data->setY( *yData++ );
1708  data++;
1709  }
1710  mpl.append( polyLine );
1711  }
1712  return mpl;
1713 }
1714 
1716 {
1717  if ( !d->geometry )
1718  {
1719  return QgsMultiPolygonXY();
1720  }
1721 
1722  const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( d->geometry.get() );
1723  if ( !geomCollection )
1724  {
1725  return QgsMultiPolygonXY();
1726  }
1727 
1728  const int nPolygons = geomCollection->numGeometries();
1729  if ( nPolygons < 1 )
1730  {
1731  return QgsMultiPolygonXY();
1732  }
1733 
1734  QgsMultiPolygonXY mp;
1735  mp.reserve( nPolygons );
1736  for ( int i = 0; i < nPolygons; ++i )
1737  {
1738  const QgsPolygon *polygon = qgsgeometry_cast<const QgsPolygon *>( geomCollection->geometryN( i ) );
1739  if ( !polygon )
1740  {
1741  const QgsCurvePolygon *cPolygon = qgsgeometry_cast<const QgsCurvePolygon *>( geomCollection->geometryN( i ) );
1742  if ( cPolygon )
1743  {
1744  polygon = cPolygon->toPolygon();
1745  }
1746  else
1747  {
1748  continue;
1749  }
1750  }
1751 
1752  QgsPolygonXY poly;
1753  convertPolygon( *polygon, poly );
1754  mp.push_back( poly );
1755  }
1756  return mp;
1757 }
1758 
1759 double QgsGeometry::area() const
1760 {
1761  if ( !d->geometry )
1762  {
1763  return -1.0;
1764  }
1765  QgsGeos g( d->geometry.get() );
1766 
1767 #if 0
1768  //debug: compare geos area with calculation in QGIS
1769  double geosArea = g.area();
1770  double qgisArea = 0;
1771  QgsSurface *surface = qgsgeometry_cast<QgsSurface *>( d->geometry );
1772  if ( surface )
1773  {
1774  qgisArea = surface->area();
1775  }
1776 #endif
1777 
1778  mLastError.clear();
1779  return g.area( &mLastError );
1780 }
1781 
1782 double QgsGeometry::length() const
1783 {
1784  if ( !d->geometry )
1785  {
1786  return -1.0;
1787  }
1788 
1789  // avoid calling geos for trivial geometry calculations
1791  {
1792  return d->geometry->length();
1793  }
1794 
1795  QgsGeos g( d->geometry.get() );
1796  mLastError.clear();
1797  return g.length( &mLastError );
1798 }
1799 
1800 double QgsGeometry::distance( const QgsGeometry &geom ) const
1801 {
1802  if ( !d->geometry || !geom.d->geometry )
1803  {
1804  return -1.0;
1805  }
1806 
1807  // avoid calling geos for trivial point-to-point distance calculations
1809  {
1810  return qgsgeometry_cast< const QgsPoint * >( d->geometry.get() )->distance( *qgsgeometry_cast< const QgsPoint * >( geom.constGet() ) );
1811  }
1812 
1813  QgsGeos g( d->geometry.get() );
1814  mLastError.clear();
1815  return g.distance( geom.d->geometry.get(), &mLastError );
1816 }
1817 
1818 double QgsGeometry::hausdorffDistance( const QgsGeometry &geom ) const
1819 {
1820  if ( !d->geometry || !geom.d->geometry )
1821  {
1822  return -1.0;
1823  }
1824 
1825  QgsGeos g( d->geometry.get() );
1826  mLastError.clear();
1827  return g.hausdorffDistance( geom.d->geometry.get(), &mLastError );
1828 }
1829 
1830 double QgsGeometry::hausdorffDistanceDensify( const QgsGeometry &geom, double densifyFraction ) const
1831 {
1832  if ( !d->geometry || !geom.d->geometry )
1833  {
1834  return -1.0;
1835  }
1836 
1837  QgsGeos g( d->geometry.get() );
1838  mLastError.clear();
1839  return g.hausdorffDistanceDensify( geom.d->geometry.get(), densifyFraction, &mLastError );
1840 }
1841 
1842 
1843 double QgsGeometry::frechetDistance( const QgsGeometry &geom ) const
1844 {
1845  if ( !d->geometry || !geom.d->geometry )
1846  {
1847  return -1.0;
1848  }
1849 
1850  QgsGeos g( d->geometry.get() );
1851  mLastError.clear();
1852  return g.frechetDistance( geom.d->geometry.get(), &mLastError );
1853 }
1854 
1855 double QgsGeometry::frechetDistanceDensify( const QgsGeometry &geom, double densifyFraction ) const
1856 {
1857  if ( !d->geometry || !geom.d->geometry )
1858  {
1859  return -1.0;
1860  }
1861 
1862  QgsGeos g( d->geometry.get() );
1863  mLastError.clear();
1864  return g.frechetDistanceDensify( geom.d->geometry.get(), densifyFraction, &mLastError );
1865 }
1866 
1868 {
1869  if ( !d->geometry || d->geometry.get()->isEmpty() )
1871  return d->geometry->vertices_begin();
1872 }
1873 
1875 {
1876  if ( !d->geometry || d->geometry.get()->isEmpty() )
1878  return d->geometry->vertices_end();
1879 }
1880 
1882 {
1883  if ( !d->geometry || d->geometry.get()->isEmpty() )
1884  return QgsVertexIterator();
1885  return QgsVertexIterator( d->geometry.get() );
1886 }
1887 
1889 {
1890  if ( !d->geometry )
1892 
1893  detach();
1894  return d->geometry->parts_begin();
1895 }
1896 
1898 {
1899  if ( !d->geometry )
1901  return d->geometry->parts_end();
1902 }
1903 
1905 {
1906  if ( !d->geometry )
1908  return d->geometry->const_parts_begin();
1909 }
1910 
1912 {
1913  if ( !d->geometry )
1915  return d->geometry->const_parts_end();
1916 }
1917 
1919 {
1920  if ( !d->geometry )
1921  return QgsGeometryPartIterator();
1922 
1923  detach();
1924  return QgsGeometryPartIterator( d->geometry.get() );
1925 }
1926 
1928 {
1929  if ( !d->geometry )
1931 
1932  return QgsGeometryConstPartIterator( d->geometry.get() );
1933 }
1934 
1935 QgsGeometry QgsGeometry::buffer( double distance, int segments ) const
1936 {
1937  if ( !d->geometry )
1938  {
1939  return QgsGeometry();
1940  }
1941 
1942  QgsGeos g( d->geometry.get() );
1943  mLastError.clear();
1944  std::unique_ptr<QgsAbstractGeometry> geom( g.buffer( distance, segments, &mLastError ) );
1945  if ( !geom )
1946  {
1947  QgsGeometry result;
1948  result.mLastError = mLastError;
1949  return result;
1950  }
1951  return QgsGeometry( std::move( geom ) );
1952 }
1953 
1954 QgsGeometry QgsGeometry::buffer( double distance, int segments, EndCapStyle endCapStyle, JoinStyle joinStyle, double miterLimit ) const
1955 {
1956  if ( !d->geometry )
1957  {
1958  return QgsGeometry();
1959  }
1960 
1961  QgsGeos g( d->geometry.get() );
1962  mLastError.clear();
1963  QgsAbstractGeometry *geom = g.buffer( distance, segments, endCapStyle, joinStyle, miterLimit, &mLastError );
1964  if ( !geom )
1965  {
1966  QgsGeometry result;
1967  result.mLastError = mLastError;
1968  return result;
1969  }
1970  return QgsGeometry( geom );
1971 }
1972 
1973 QgsGeometry QgsGeometry::offsetCurve( double distance, int segments, JoinStyle joinStyle, double miterLimit ) const
1974 {
1975  if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
1976  {
1977  return QgsGeometry();
1978  }
1979 
1980  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
1981  {
1982  const QVector<QgsGeometry> parts = asGeometryCollection();
1983  QVector<QgsGeometry> results;
1984  results.reserve( parts.count() );
1985  for ( const QgsGeometry &part : parts )
1986  {
1987  QgsGeometry result = part.offsetCurve( distance, segments, joinStyle, miterLimit );
1988  if ( !result.isNull() )
1989  results << result;
1990  }
1991  if ( results.isEmpty() )
1992  return QgsGeometry();
1993 
1994  QgsGeometry first = results.takeAt( 0 );
1995  for ( const QgsGeometry &result : std::as_const( results ) )
1996  {
1997  first.addPart( result );
1998  }
1999  return first;
2000  }
2001  else
2002  {
2003  QgsGeos geos( d->geometry.get() );
2004  mLastError.clear();
2005 
2006  // GEOS can flip the curve orientation in some circumstances. So record previous orientation and correct if required
2007  const QgsCurve::Orientation prevOrientation = qgsgeometry_cast< const QgsCurve * >( d->geometry.get() )->orientation();
2008 
2009  std::unique_ptr< QgsAbstractGeometry > offsetGeom( geos.offsetCurve( distance, segments, joinStyle, miterLimit, &mLastError ) );
2010  if ( !offsetGeom )
2011  {
2012  QgsGeometry result;
2013  result.mLastError = mLastError;
2014  return result;
2015  }
2016 
2017  if ( const QgsCurve *offsetCurve = qgsgeometry_cast< const QgsCurve * >( offsetGeom.get() ) )
2018  {
2019  const QgsCurve::Orientation newOrientation = offsetCurve->orientation();
2020  if ( newOrientation != prevOrientation )
2021  {
2022  // GEOS has flipped line orientation, flip it back
2023  std::unique_ptr< QgsAbstractGeometry > flipped( offsetCurve->reversed() );
2024  offsetGeom = std::move( flipped );
2025  }
2026  }
2027  return QgsGeometry( std::move( offsetGeom ) );
2028  }
2029 }
2030 
2031 QgsGeometry QgsGeometry::singleSidedBuffer( double distance, int segments, BufferSide side, JoinStyle joinStyle, double miterLimit ) const
2032 {
2033  if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
2034  {
2035  return QgsGeometry();
2036  }
2037 
2038  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
2039  {
2040  const QVector<QgsGeometry> parts = asGeometryCollection();
2041  QVector<QgsGeometry> results;
2042  results.reserve( parts.count() );
2043  for ( const QgsGeometry &part : parts )
2044  {
2045  QgsGeometry result = part.singleSidedBuffer( distance, segments, side, joinStyle, miterLimit );
2046  if ( !result.isNull() )
2047  results << result;
2048  }
2049  if ( results.isEmpty() )
2050  return QgsGeometry();
2051 
2052  QgsGeometry first = results.takeAt( 0 );
2053  for ( const QgsGeometry &result : std::as_const( results ) )
2054  {
2055  first.addPart( result );
2056  }
2057  return first;
2058  }
2059  else
2060  {
2061  QgsGeos geos( d->geometry.get() );
2062  mLastError.clear();
2063  std::unique_ptr< QgsAbstractGeometry > bufferGeom = geos.singleSidedBuffer( distance, segments, side,
2064  joinStyle, miterLimit, &mLastError );
2065  if ( !bufferGeom )
2066  {
2067  QgsGeometry result;
2068  result.mLastError = mLastError;
2069  return result;
2070  }
2071  return QgsGeometry( std::move( bufferGeom ) );
2072  }
2073 }
2074 
2075 QgsGeometry QgsGeometry::taperedBuffer( double startWidth, double endWidth, int segments ) const
2076 {
2077  QgsInternalGeometryEngine engine( *this );
2078 
2079  return engine.taperedBuffer( startWidth, endWidth, segments );
2080 }
2081 
2083 {
2084  QgsInternalGeometryEngine engine( *this );
2085 
2086  return engine.variableWidthBufferByM( segments );
2087 }
2088 
2089 QgsGeometry QgsGeometry::extendLine( double startDistance, double endDistance ) const
2090 {
2091  if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
2092  {
2093  return QgsGeometry();
2094  }
2095 
2096  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
2097  {
2098  const QVector<QgsGeometry> parts = asGeometryCollection();
2099  QVector<QgsGeometry> results;
2100  results.reserve( parts.count() );
2101  for ( const QgsGeometry &part : parts )
2102  {
2103  QgsGeometry result = part.extendLine( startDistance, endDistance );
2104  if ( !result.isNull() )
2105  results << result;
2106  }
2107  if ( results.isEmpty() )
2108  return QgsGeometry();
2109 
2110  QgsGeometry first = results.takeAt( 0 );
2111  for ( const QgsGeometry &result : std::as_const( results ) )
2112  {
2113  first.addPart( result );
2114  }
2115  return first;
2116  }
2117  else
2118  {
2119  QgsLineString *line = qgsgeometry_cast< QgsLineString * >( d->geometry.get() );
2120  if ( !line )
2121  return QgsGeometry();
2122 
2123  std::unique_ptr< QgsLineString > newLine( line->clone() );
2124  newLine->extend( startDistance, endDistance );
2125  return QgsGeometry( std::move( newLine ) );
2126  }
2127 }
2128 
2129 QgsGeometry QgsGeometry::simplify( double tolerance ) const
2130 {
2131  if ( !d->geometry )
2132  {
2133  return QgsGeometry();
2134  }
2135 
2136  QgsGeos geos( d->geometry.get() );
2137  mLastError.clear();
2138  std::unique_ptr< QgsAbstractGeometry > simplifiedGeom( geos.simplify( tolerance, &mLastError ) );
2139  if ( !simplifiedGeom )
2140  {
2141  QgsGeometry result;
2142  result.mLastError = mLastError;
2143  return result;
2144  }
2145  return QgsGeometry( std::move( simplifiedGeom ) );
2146 }
2147 
2148 QgsGeometry QgsGeometry::densifyByCount( int extraNodesPerSegment ) const
2149 {
2150  QgsInternalGeometryEngine engine( *this );
2151 
2152  return engine.densifyByCount( extraNodesPerSegment );
2153 }
2154 
2156 {
2157  QgsInternalGeometryEngine engine( *this );
2158 
2159  return engine.densifyByDistance( distance );
2160 }
2161 
2162 QgsGeometry QgsGeometry::convertToCurves( double distanceTolerance, double angleTolerance ) const
2163 {
2164  QgsInternalGeometryEngine engine( *this );
2165 
2166  return engine.convertToCurves( distanceTolerance, angleTolerance );
2167 }
2168 
2170 {
2171  if ( !d->geometry )
2172  {
2173  return QgsGeometry();
2174  }
2175 
2176  // avoid calling geos for trivial point centroids
2177  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::Point )
2178  {
2179  QgsGeometry c = *this;
2180  c.get()->dropZValue();
2181  c.get()->dropMValue();
2182  return c;
2183  }
2184 
2185  QgsGeos geos( d->geometry.get() );
2186 
2187  mLastError.clear();
2188  QgsGeometry result( geos.centroid( &mLastError ) );
2189  result.mLastError = mLastError;
2190  return result;
2191 }
2192 
2194 {
2195  if ( !d->geometry )
2196  {
2197  return QgsGeometry();
2198  }
2199 
2200  QgsGeos geos( d->geometry.get() );
2201 
2202  mLastError.clear();
2203  QgsGeometry result( geos.pointOnSurface( &mLastError ) );
2204  result.mLastError = mLastError;
2205  return result;
2206 }
2207 
2208 QgsGeometry QgsGeometry::poleOfInaccessibility( double precision, double *distanceToBoundary ) const
2209 {
2210  QgsInternalGeometryEngine engine( *this );
2211 
2212  return engine.poleOfInaccessibility( precision, distanceToBoundary );
2213 }
2214 
2215 QgsGeometry QgsGeometry::largestEmptyCircle( double tolerance, const QgsGeometry &boundary ) const
2216 {
2217  if ( !d->geometry )
2218  {
2219  return QgsGeometry();
2220  }
2221 
2222  QgsGeos geos( d->geometry.get() );
2223 
2224  mLastError.clear();
2225  QgsGeometry result( geos.largestEmptyCircle( tolerance, boundary.constGet(), &mLastError ) );
2226  result.mLastError = mLastError;
2227  return result;
2228 }
2229 
2231 {
2232  if ( !d->geometry )
2233  {
2234  return QgsGeometry();
2235  }
2236 
2237  QgsGeos geos( d->geometry.get() );
2238 
2239  mLastError.clear();
2240  QgsGeometry result( geos.minimumWidth( &mLastError ) );
2241  result.mLastError = mLastError;
2242  return result;
2243 }
2244 
2246 {
2247  if ( !d->geometry )
2248  {
2249  return std::numeric_limits< double >::quiet_NaN();
2250  }
2251 
2252  QgsGeos geos( d->geometry.get() );
2253 
2254  mLastError.clear();
2255  return geos.minimumClearance( &mLastError );
2256 }
2257 
2259 {
2260  if ( !d->geometry )
2261  {
2262  return QgsGeometry();
2263  }
2264 
2265  QgsGeos geos( d->geometry.get() );
2266 
2267  mLastError.clear();
2268  QgsGeometry result( geos.minimumClearanceLine( &mLastError ) );
2269  result.mLastError = mLastError;
2270  return result;
2271 }
2272 
2274 {
2275  if ( !d->geometry )
2276  {
2277  return QgsGeometry();
2278  }
2279  QgsGeos geos( d->geometry.get() );
2280  mLastError.clear();
2281  std::unique_ptr< QgsAbstractGeometry > cHull( geos.convexHull( &mLastError ) );
2282  if ( !cHull )
2283  {
2284  QgsGeometry geom;
2285  geom.mLastError = mLastError;
2286  return geom;
2287  }
2288  return QgsGeometry( std::move( cHull ) );
2289 }
2290 
2291 QgsGeometry QgsGeometry::voronoiDiagram( const QgsGeometry &extent, double tolerance, bool edgesOnly ) const
2292 {
2293  if ( !d->geometry )
2294  {
2295  return QgsGeometry();
2296  }
2297 
2298  QgsGeos geos( d->geometry.get() );
2299  mLastError.clear();
2300  QgsGeometry result = geos.voronoiDiagram( extent.constGet(), tolerance, edgesOnly, &mLastError );
2301  result.mLastError = mLastError;
2302  return result;
2303 }
2304 
2305 QgsGeometry QgsGeometry::delaunayTriangulation( double tolerance, bool edgesOnly ) const
2306 {
2307  if ( !d->geometry )
2308  {
2309  return QgsGeometry();
2310  }
2311 
2312  QgsGeos geos( d->geometry.get() );
2313  mLastError.clear();
2314  QgsGeometry result = geos.delaunayTriangulation( tolerance, edgesOnly );
2315  result.mLastError = mLastError;
2316  return result;
2317 }
2318 
2320 {
2321  if ( !d->geometry )
2322  {
2323  return QgsGeometry();
2324  }
2325 
2326  QgsGeos geos( d->geometry.get() );
2327  mLastError.clear();
2328  QgsGeometry result( geos.node( &mLastError ) );
2329  result.mLastError = mLastError;
2330  return result;
2331 }
2332 
2334 {
2335  if ( !d->geometry )
2336  {
2337  return QgsGeometry();
2338  }
2339 
2340  QgsGeos geos( d->geometry.get() );
2341  mLastError.clear();
2342  QgsGeometry result( geos.sharedPaths( other.constGet(), &mLastError ) );
2343  result.mLastError = mLastError;
2344  return result;
2345 }
2346 
2348 {
2349  if ( !d->geometry )
2350  {
2351  return QgsGeometry();
2352  }
2353 
2354  const QgsAbstractGeometry *geom = d->geometry.get();
2355  std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
2356  if ( QgsWkbTypes::isCurvedType( d->geometry->wkbType() ) )
2357  {
2358  segmentizedCopy.reset( d->geometry->segmentize() );
2359  geom = segmentizedCopy.get();
2360  }
2361 
2362  QgsGeos geos( geom );
2363  mLastError.clear();
2364  std::unique_ptr< QgsAbstractGeometry > result( geos.subdivide( maxNodes, &mLastError ) );
2365  if ( !result )
2366  {
2367  QgsGeometry geom;
2368  geom.mLastError = mLastError;
2369  return geom;
2370  }
2371  return QgsGeometry( std::move( result ) );
2372 }
2373 
2374 QgsGeometry QgsGeometry::interpolate( double distance ) const
2375 {
2376  if ( !d->geometry )
2377  {
2378  return QgsGeometry();
2379  }
2380 
2381  QgsGeometry line = *this;
2382  if ( type() == QgsWkbTypes::PointGeometry )
2383  return QgsGeometry();
2384  else if ( type() == QgsWkbTypes::PolygonGeometry )
2385  {
2386  line = QgsGeometry( d->geometry->boundary() );
2387  }
2388 
2389  const QgsCurve *curve = nullptr;
2390  if ( line.isMultipart() )
2391  {
2392  // if multi part, iterate through parts to find target part
2393  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( line.constGet() );
2394  for ( int part = 0; part < collection->numGeometries(); ++part )
2395  {
2396  const QgsCurve *candidate = qgsgeometry_cast< const QgsCurve * >( collection->geometryN( part ) );
2397  if ( !candidate )
2398  continue;
2399  const double candidateLength = candidate->length();
2400  if ( candidateLength >= distance )
2401  {
2402  curve = candidate;
2403  break;
2404  }
2405 
2406  distance -= candidateLength;
2407  }
2408  }
2409  else
2410  {
2411  curve = qgsgeometry_cast< const QgsCurve * >( line.constGet() );
2412  }
2413  if ( !curve )
2414  return QgsGeometry();
2415 
2416  std::unique_ptr< QgsPoint > result( curve->interpolatePoint( distance ) );
2417  if ( !result )
2418  {
2419  return QgsGeometry();
2420  }
2421  return QgsGeometry( std::move( result ) );
2422 }
2423 
2424 double QgsGeometry::lineLocatePoint( const QgsGeometry &point ) const
2425 {
2426  if ( type() != QgsWkbTypes::LineGeometry )
2427  return -1;
2428 
2429  if ( QgsWkbTypes::flatType( point.wkbType() ) != QgsWkbTypes::Point )
2430  return -1;
2431 
2432  QgsGeometry segmentized = *this;
2434  {
2435  segmentized = QgsGeometry( static_cast< QgsCurve * >( d->geometry.get() )->segmentize() );
2436  }
2437 
2438  QgsGeos geos( d->geometry.get() );
2439  mLastError.clear();
2440  return geos.lineLocatePoint( *( static_cast< QgsPoint * >( point.d->geometry.get() ) ), &mLastError );
2441 }
2442 
2443 double QgsGeometry::interpolateAngle( double distance ) const
2444 {
2445  if ( !d->geometry )
2446  return 0.0;
2447 
2448  // always operate on segmentized geometries
2449  QgsGeometry segmentized = *this;
2451  {
2452  segmentized = QgsGeometry( static_cast< QgsCurve * >( d->geometry.get() )->segmentize() );
2453  }
2454 
2455  QgsVertexId previous;
2456  QgsVertexId next;
2457  if ( !QgsGeometryUtils::verticesAtDistance( *segmentized.constGet(), distance, previous, next ) )
2458  return 0.0;
2459 
2460  if ( previous == next )
2461  {
2462  // distance coincided exactly with a vertex
2463  QgsVertexId v2 = previous;
2464  QgsVertexId v1;
2465  QgsVertexId v3;
2466  segmentized.constGet()->adjacentVertices( v2, v1, v3 );
2467  if ( v1.isValid() && v3.isValid() )
2468  {
2469  QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
2470  QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
2471  QgsPoint p3 = segmentized.constGet()->vertexAt( v3 );
2472  double angle1 = QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2473  double angle2 = QgsGeometryUtils::lineAngle( p2.x(), p2.y(), p3.x(), p3.y() );
2474  return QgsGeometryUtils::averageAngle( angle1, angle2 );
2475  }
2476  else if ( v3.isValid() )
2477  {
2478  QgsPoint p1 = segmentized.constGet()->vertexAt( v2 );
2479  QgsPoint p2 = segmentized.constGet()->vertexAt( v3 );
2480  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2481  }
2482  else
2483  {
2484  QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
2485  QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
2486  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2487  }
2488  }
2489  else
2490  {
2491  QgsPoint p1 = segmentized.constGet()->vertexAt( previous );
2492  QgsPoint p2 = segmentized.constGet()->vertexAt( next );
2493  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2494  }
2495 }
2496 
2498 {
2499  if ( !d->geometry || geometry.isNull() )
2500  {
2501  return QgsGeometry();
2502  }
2503 
2504  QgsGeos geos( d->geometry.get() );
2505 
2506  mLastError.clear();
2507  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.intersection( geometry.d->geometry.get(), &mLastError ) );
2508 
2509  if ( !resultGeom )
2510  {
2511  QgsGeometry geom;
2512  geom.mLastError = mLastError;
2513  return geom;
2514  }
2515 
2516  return QgsGeometry( std::move( resultGeom ) );
2517 }
2518 
2520 {
2521  if ( !d->geometry || geometry.isNull() )
2522  {
2523  return QgsGeometry();
2524  }
2525 
2526  QgsGeos geos( d->geometry.get() );
2527  mLastError.clear();
2528  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.combine( geometry.d->geometry.get(), &mLastError ) );
2529  if ( !resultGeom )
2530  {
2531  QgsGeometry geom;
2532  geom.mLastError = mLastError;
2533  return geom;
2534  }
2535  return QgsGeometry( std::move( resultGeom ) );
2536 }
2537 
2539 {
2540  if ( !d->geometry )
2541  {
2542  return QgsGeometry();
2543  }
2544 
2545  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::LineString )
2546  {
2547  // special case - a single linestring was passed
2548  return QgsGeometry( *this );
2549  }
2550 
2551  QgsGeos geos( d->geometry.get() );
2552  mLastError.clear();
2553  QgsGeometry result = geos.mergeLines( &mLastError );
2554  result.mLastError = mLastError;
2555  return result;
2556 }
2557 
2559 {
2560  if ( !d->geometry || geometry.isNull() )
2561  {
2562  return QgsGeometry();
2563  }
2564 
2565  QgsGeos geos( d->geometry.get() );
2566 
2567  mLastError.clear();
2568  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.difference( geometry.d->geometry.get(), &mLastError ) );
2569  if ( !resultGeom )
2570  {
2571  QgsGeometry geom;
2572  geom.mLastError = mLastError;
2573  return geom;
2574  }
2575  return QgsGeometry( std::move( resultGeom ) );
2576 }
2577 
2579 {
2580  if ( !d->geometry || geometry.isNull() )
2581  {
2582  return QgsGeometry();
2583  }
2584 
2585  QgsGeos geos( d->geometry.get() );
2586 
2587  mLastError.clear();
2588  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.symDifference( geometry.d->geometry.get(), &mLastError ) );
2589  if ( !resultGeom )
2590  {
2591  QgsGeometry geom;
2592  geom.mLastError = mLastError;
2593  return geom;
2594  }
2595  return QgsGeometry( std::move( resultGeom ) );
2596 }
2597 
2598 QgsGeometry QgsGeometry::extrude( double x, double y )
2599 {
2600  QgsInternalGeometryEngine engine( *this );
2601 
2602  return engine.extrude( x, y );
2603 }
2604 
2606 
2607 QVector<QgsPointXY> QgsGeometry::randomPointsInPolygon( int count, const std::function< bool( const QgsPointXY & ) > &acceptPoint, unsigned long seed, QgsFeedback *feedback, int maxTriesPerPoint ) const
2608 {
2610  return QVector< QgsPointXY >();
2611 
2612  return QgsInternalGeometryEngine::randomPointsInPolygon( *this, count, acceptPoint, seed, feedback, maxTriesPerPoint );
2613 }
2614 
2615 QVector<QgsPointXY> QgsGeometry::randomPointsInPolygon( int count, unsigned long seed, QgsFeedback *feedback ) const
2616 {
2618  return QVector< QgsPointXY >();
2619 
2620  return QgsInternalGeometryEngine::randomPointsInPolygon( *this, count, []( const QgsPointXY & ) { return true; }, seed, feedback, 0 );
2621 }
2623 
2624 int QgsGeometry::wkbSize( QgsAbstractGeometry::WkbFlags flags ) const
2625 {
2626  return d->geometry ? d->geometry->wkbSize( flags ) : 0;
2627 }
2628 
2629 QByteArray QgsGeometry::asWkb( QgsAbstractGeometry::WkbFlags flags ) const
2630 {
2631  return d->geometry ? d->geometry->asWkb( flags ) : QByteArray();
2632 }
2633 
2634 QVector<QgsGeometry> QgsGeometry::asGeometryCollection() const
2635 {
2636  QVector<QgsGeometry> geometryList;
2637  if ( !d->geometry )
2638  {
2639  return geometryList;
2640  }
2641 
2642  QgsGeometryCollection *gc = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
2643  if ( gc )
2644  {
2645  int numGeom = gc->numGeometries();
2646  geometryList.reserve( numGeom );
2647  for ( int i = 0; i < numGeom; ++i )
2648  {
2649  geometryList.append( QgsGeometry( gc->geometryN( i )->clone() ) );
2650  }
2651  }
2652  else //a singlepart geometry
2653  {
2654  geometryList.append( *this );
2655  }
2656 
2657  return geometryList;
2658 }
2659 
2660 QPointF QgsGeometry::asQPointF() const
2661 {
2662  QgsPointXY point = asPoint();
2663  return point.toQPointF();
2664 }
2665 
2666 QPolygonF QgsGeometry::asQPolygonF() const
2667 {
2668  const QgsAbstractGeometry *part = constGet();
2669 
2670  // if a geometry collection, get first part only
2671  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection *>( part ) )
2672  {
2673  if ( collection->numGeometries() > 0 )
2674  part = collection->geometryN( 0 );
2675  else
2676  return QPolygonF();
2677  }
2678 
2679  if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( part ) )
2680  return curve->asQPolygonF();
2681  else if ( const QgsCurvePolygon *polygon = qgsgeometry_cast< const QgsCurvePolygon * >( part ) )
2682  return polygon->exteriorRing() ? polygon->exteriorRing()->asQPolygonF() : QPolygonF();
2683  return QPolygonF();
2684 }
2685 
2686 bool QgsGeometry::deleteRing( int ringNum, int partNum )
2687 {
2688  if ( !d->geometry )
2689  {
2690  return false;
2691  }
2692 
2693  detach();
2694  bool ok = QgsGeometryEditUtils::deleteRing( d->geometry.get(), ringNum, partNum );
2695  return ok;
2696 }
2697 
2698 bool QgsGeometry::deletePart( int partNum )
2699 {
2700  if ( !d->geometry )
2701  {
2702  return false;
2703  }
2704 
2705  if ( !isMultipart() && partNum < 1 )
2706  {
2707  set( nullptr );
2708  return true;
2709  }
2710 
2711  detach();
2712  bool ok = QgsGeometryEditUtils::deletePart( d->geometry.get(), partNum );
2713  return ok;
2714 }
2715 
2716 int QgsGeometry::avoidIntersections( const QList<QgsVectorLayer *> &avoidIntersectionsLayers, const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures )
2717 {
2718  if ( !d->geometry )
2719  {
2720  return 1;
2721  }
2722 
2723  QgsWkbTypes::Type geomTypeBeforeModification = wkbType();
2724 
2725  bool haveInvalidGeometry = false;
2726  std::unique_ptr< QgsAbstractGeometry > diffGeom = QgsGeometryEditUtils::avoidIntersections( *( d->geometry ), avoidIntersectionsLayers, haveInvalidGeometry, ignoreFeatures );
2727  if ( diffGeom )
2728  {
2729  reset( std::move( diffGeom ) );
2730  }
2731 
2732  if ( geomTypeBeforeModification != wkbType() )
2733  return 2;
2734  if ( haveInvalidGeometry )
2735  return 4;
2736 
2737  return 0;
2738 }
2739 
2740 
2742 {
2743  if ( !d->geometry )
2744  return QgsGeometry();
2745 
2746  mLastError.clear();
2747 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=8 )
2748  QgsGeos geos( d->geometry.get() );
2749  std::unique_ptr< QgsAbstractGeometry > g( geos.makeValid( &mLastError ) );
2750 #else
2751  std::unique_ptr< QgsAbstractGeometry > g( _qgis_lwgeom_make_valid( d->geometry.get(), mLastError ) );
2752 #endif
2753 
2754  QgsGeometry result = QgsGeometry( std::move( g ) );
2755  result.mLastError = mLastError;
2756  return result;
2757 }
2758 
2760 {
2761  if ( !d->geometry )
2762  return QgsGeometry();
2763 
2764  if ( isMultipart() )
2765  {
2766  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( d->geometry.get() );
2767  std::unique_ptr< QgsGeometryCollection > newCollection( collection->createEmptyWithSameType() );
2768  newCollection->reserve( collection->numGeometries() );
2769  for ( int i = 0; i < collection->numGeometries(); ++i )
2770  {
2771  const QgsAbstractGeometry *g = collection->geometryN( i );
2772  if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( g ) )
2773  {
2774  std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2775  corrected->forceRHR();
2776  newCollection->addGeometry( corrected.release() );
2777  }
2778  else
2779  {
2780  newCollection->addGeometry( g->clone() );
2781  }
2782  }
2783  return QgsGeometry( std::move( newCollection ) );
2784  }
2785  else
2786  {
2787  if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( d->geometry.get() ) )
2788  {
2789  std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2790  corrected->forceRHR();
2791  return QgsGeometry( std::move( corrected ) );
2792  }
2793  else
2794  {
2795  // not a curve polygon, so return unchanged
2796  return *this;
2797  }
2798  }
2799 }
2800 
2801 
2802 void QgsGeometry::validateGeometry( QVector<QgsGeometry::Error> &errors, const ValidationMethod method, const QgsGeometry::ValidityFlags flags ) const
2803 {
2804  errors.clear();
2805  if ( !d->geometry )
2806  return;
2807 
2808  // avoid expensive calcs for trivial point geometries
2810  {
2811  return;
2812  }
2813 
2814  switch ( method )
2815  {
2816  case ValidatorQgisInternal:
2817  QgsGeometryValidator::validateGeometry( *this, errors, method );
2818  return;
2819 
2820  case ValidatorGeos:
2821  {
2822  QgsGeos geos( d->geometry.get() );
2823  QString error;
2824  QgsGeometry errorLoc;
2825  if ( !geos.isValid( &error, flags & FlagAllowSelfTouchingHoles, &errorLoc ) )
2826  {
2827  if ( errorLoc.isNull() )
2828  {
2829  errors.append( QgsGeometry::Error( error ) );
2830  }
2831  else
2832  {
2833  const QgsPointXY point = errorLoc.asPoint();
2834  errors.append( QgsGeometry::Error( error, point ) );
2835  }
2836  return;
2837  }
2838  }
2839  }
2840 }
2841 
2843 {
2844  if ( !d->geometry )
2845  {
2846  return;
2847  }
2848 
2849  detach();
2850  d->geometry->normalize();
2851 }
2852 
2853 bool QgsGeometry::isGeosValid( const QgsGeometry::ValidityFlags flags ) const
2854 {
2855  if ( !d->geometry )
2856  {
2857  return false;
2858  }
2859 
2860  return d->geometry->isValid( mLastError, static_cast< int >( flags ) );
2861 }
2862 
2864 {
2865  if ( !d->geometry )
2866  return false;
2867 
2868  QgsGeos geos( d->geometry.get() );
2869  mLastError.clear();
2870  return geos.isSimple( &mLastError );
2871 }
2872 
2873 bool QgsGeometry::isAxisParallelRectangle( double maximumDeviation, bool simpleRectanglesOnly ) const
2874 {
2875  if ( !d->geometry )
2876  return false;
2877 
2878  QgsInternalGeometryEngine engine( *this );
2879  return engine.isAxisParallelRectangle( maximumDeviation, simpleRectanglesOnly );
2880 }
2881 
2883 {
2884  if ( !d->geometry || !g.d->geometry )
2885  {
2886  return false;
2887  }
2888 
2889  // fast check - are they shared copies of the same underlying geometry?
2890  if ( d == g.d )
2891  return true;
2892 
2893  // fast check - distinct geometry types?
2894  if ( type() != g.type() )
2895  return false;
2896 
2897  // avoid calling geos for trivial point case
2898  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::Point
2899  && QgsWkbTypes::flatType( g.d->geometry->wkbType() ) == QgsWkbTypes::Point )
2900  {
2901  return equals( g );
2902  }
2903 
2904  // another nice fast check upfront -- if the bounding boxes aren't equal, the geometries themselves can't be equal!
2905  if ( d->geometry->boundingBox() != g.d->geometry->boundingBox() )
2906  return false;
2907 
2908  QgsGeos geos( d->geometry.get() );
2909  mLastError.clear();
2910  return geos.isEqual( g.d->geometry.get(), &mLastError );
2911 }
2912 
2913 QgsGeometry QgsGeometry::unaryUnion( const QVector<QgsGeometry> &geometries )
2914 {
2915  QgsGeos geos( nullptr );
2916 
2917  QString error;
2918  std::unique_ptr< QgsAbstractGeometry > geom( geos.combine( geometries, &error ) );
2919  QgsGeometry result( std::move( geom ) );
2920  result.mLastError = error;
2921  return result;
2922 }
2923 
2924 QgsGeometry QgsGeometry::polygonize( const QVector<QgsGeometry> &geometryList )
2925 {
2926  QgsGeos geos( nullptr );
2927 
2928  QVector<const QgsAbstractGeometry *> geomV2List;
2929  for ( const QgsGeometry &g : geometryList )
2930  {
2931  if ( !( g.isNull() ) )
2932  {
2933  geomV2List.append( g.constGet() );
2934  }
2935  }
2936 
2937  QString error;
2938  QgsGeometry result = geos.polygonize( geomV2List, &error );
2939  result.mLastError = error;
2940  return result;
2941 }
2942 
2944 {
2946  {
2947  return;
2948  }
2949 
2950  std::unique_ptr< QgsAbstractGeometry > straightGeom( d->geometry->segmentize( tolerance, toleranceType ) );
2951  reset( std::move( straightGeom ) );
2952 }
2953 
2955 {
2956  if ( !d->geometry )
2957  {
2958  return false;
2959  }
2960 
2961  return d->geometry->hasCurvedSegments();
2962 }
2963 
2965 {
2966  if ( !d->geometry )
2967  {
2969  }
2970 
2971  detach();
2972  d->geometry->transform( ct, direction, transformZ );
2973  return QgsGeometry::Success;
2974 }
2975 
2976 QgsGeometry::OperationResult QgsGeometry::transform( const QTransform &ct, double zTranslate, double zScale, double mTranslate, double mScale )
2977 {
2978  if ( !d->geometry )
2979  {
2981  }
2982 
2983  detach();
2984  d->geometry->transform( ct, zTranslate, zScale, mTranslate, mScale );
2985  return QgsGeometry::Success;
2986 }
2987 
2989 {
2990  if ( d->geometry )
2991  {
2992  detach();
2993  d->geometry->transform( mtp.transform() );
2994  }
2995 }
2996 
2998 {
2999  if ( !d->geometry || rectangle.isNull() || rectangle.isEmpty() )
3000  {
3001  return QgsGeometry();
3002  }
3003 
3004  QgsGeos geos( d->geometry.get() );
3005  mLastError.clear();
3006  std::unique_ptr< QgsAbstractGeometry > resultGeom = geos.clip( rectangle, &mLastError );
3007  if ( !resultGeom )
3008  {
3009  QgsGeometry result;
3010  result.mLastError = mLastError;
3011  return result;
3012  }
3013  return QgsGeometry( std::move( resultGeom ) );
3014 }
3015 
3016 void QgsGeometry::draw( QPainter &p ) const
3017 {
3018  if ( d->geometry )
3019  {
3020  d->geometry->draw( p );
3021  }
3022 }
3023 
3024 static bool vertexIndexInfo( const QgsAbstractGeometry *g, int vertexIndex, int &partIndex, int &ringIndex, int &vertex )
3025 {
3026  if ( vertexIndex < 0 )
3027  return false; // clearly something wrong
3028 
3029  if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
3030  {
3031  partIndex = 0;
3032  int offset = 0;
3033  for ( int i = 0; i < geomCollection->numGeometries(); ++i )
3034  {
3035  const QgsAbstractGeometry *part = geomCollection->geometryN( i );
3036 
3037  // count total number of vertices in the part
3038  int numPoints = 0;
3039  for ( int k = 0; k < part->ringCount(); ++k )
3040  numPoints += part->vertexCount( 0, k );
3041 
3042  if ( vertexIndex < numPoints )
3043  {
3044  int nothing;
3045  return vertexIndexInfo( part, vertexIndex, nothing, ringIndex, vertex ); // set ring_index + index
3046  }
3047  vertexIndex -= numPoints;
3048  offset += numPoints;
3049  partIndex++;
3050  }
3051  }
3052  else if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
3053  {
3054  const QgsCurve *ring = curvePolygon->exteriorRing();
3055  if ( vertexIndex < ring->numPoints() )
3056  {
3057  partIndex = 0;
3058  ringIndex = 0;
3059  vertex = vertexIndex;
3060  return true;
3061  }
3062  vertexIndex -= ring->numPoints();
3063  ringIndex = 1;
3064  for ( int i = 0; i < curvePolygon->numInteriorRings(); ++i )
3065  {
3066  const QgsCurve *ring = curvePolygon->interiorRing( i );
3067  if ( vertexIndex < ring->numPoints() )
3068  {
3069  partIndex = 0;
3070  vertex = vertexIndex;
3071  return true;
3072  }
3073  vertexIndex -= ring->numPoints();
3074  ringIndex += 1;
3075  }
3076  }
3077  else if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
3078  {
3079  if ( vertexIndex < curve->numPoints() )
3080  {
3081  partIndex = 0;
3082  ringIndex = 0;
3083  vertex = vertexIndex;
3084  return true;
3085  }
3086  }
3087  else if ( qgsgeometry_cast<const QgsPoint *>( g ) )
3088  {
3089  if ( vertexIndex == 0 )
3090  {
3091  partIndex = 0;
3092  ringIndex = 0;
3093  vertex = 0;
3094  return true;
3095  }
3096  }
3097 
3098  return false;
3099 }
3100 
3102 {
3103  if ( !d->geometry )
3104  {
3105  return false;
3106  }
3107 
3108  id.type = QgsVertexId::SegmentVertex;
3109 
3110  bool res = vertexIndexInfo( d->geometry.get(), nr, id.part, id.ring, id.vertex );
3111  if ( !res )
3112  return false;
3113 
3114  // now let's find out if it is a straight or circular segment
3115  const QgsAbstractGeometry *g = d->geometry.get();
3116  if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
3117  {
3118  g = geomCollection->geometryN( id.part );
3119  }
3120 
3121  if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
3122  {
3123  g = id.ring == 0 ? curvePolygon->exteriorRing() : curvePolygon->interiorRing( id.ring - 1 );
3124  }
3125 
3126  if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
3127  {
3128  QgsPoint p;
3129  res = curve->pointAt( id.vertex, p, id.type );
3130  if ( !res )
3131  return false;
3132  }
3133 
3134  return true;
3135 }
3136 
3138 {
3139  if ( !d->geometry )
3140  {
3141  return -1;
3142  }
3143  return d->geometry->vertexNumberFromVertexId( id );
3144 }
3145 
3146 QString QgsGeometry::lastError() const
3147 {
3148  return mLastError;
3149 }
3150 
3151 void QgsGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
3152 {
3153  if ( !d->geometry )
3154  return;
3155 
3156  detach();
3157 
3158  d->geometry->filterVertices( filter );
3159 }
3160 
3161 void QgsGeometry::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
3162 {
3163  if ( !d->geometry )
3164  return;
3165 
3166  detach();
3167 
3168  d->geometry->transformVertices( transform );
3169 }
3170 
3171 void QgsGeometry::convertPointList( const QVector<QgsPointXY> &input, QgsPointSequence &output )
3172 {
3173  output.clear();
3174  for ( const QgsPointXY &p : input )
3175  {
3176  output.append( QgsPoint( p ) );
3177  }
3178 }
3179 
3180 void QgsGeometry::convertPointList( const QgsPointSequence &input, QVector<QgsPointXY> &output )
3181 {
3182  output.clear();
3183  for ( const QgsPoint &p : input )
3184  {
3185  output.append( QgsPointXY( p.x(), p.y() ) );
3186  }
3187 }
3188 
3189 void QgsGeometry::convertPolygon( const QgsPolygon &input, QgsPolygonXY &output )
3190 {
3191  output.clear();
3192 
3193  auto convertRing = []( const QgsCurve * ring ) -> QgsPolylineXY
3194  {
3195  QgsPolylineXY res;
3196  bool doSegmentation = ( QgsWkbTypes::flatType( ring->wkbType() ) == QgsWkbTypes::CompoundCurve
3198  std::unique_ptr< QgsLineString > segmentizedLine;
3199  const QgsLineString *line = nullptr;
3200  if ( doSegmentation )
3201  {
3202  segmentizedLine.reset( ring->curveToLine() );
3203  line = segmentizedLine.get();
3204  }
3205  else
3206  {
3207  line = qgsgeometry_cast<const QgsLineString *>( ring );
3208  if ( !line )
3209  {
3210  return res;
3211  }
3212  }
3213 
3214  int nVertices = line->numPoints();
3215  res.resize( nVertices );
3216  QgsPointXY *data = res.data();
3217  const double *xData = line->xData();
3218  const double *yData = line->yData();
3219  for ( int i = 0; i < nVertices; ++i )
3220  {
3221  data->setX( *xData++ );
3222  data->setY( *yData++ );
3223  data++;
3224  }
3225  return res;
3226  };
3227 
3228  if ( const QgsCurve *exterior = input.exteriorRing() )
3229  {
3230  output.push_back( convertRing( exterior ) );
3231  }
3232 
3233  const int interiorRingCount = input.numInteriorRings();
3234  output.reserve( output.size() + interiorRingCount );
3235  for ( int n = 0; n < interiorRingCount; ++n )
3236  {
3237  output.push_back( convertRing( input.interiorRing( n ) ) );
3238  }
3239 }
3240 
3242 {
3243  return QgsGeometry( std::make_unique< QgsPoint >( point.x(), point.y() ) );
3244 }
3245 
3246 QgsGeometry QgsGeometry::fromQPolygonF( const QPolygonF &polygon )
3247 {
3248  std::unique_ptr < QgsLineString > ring( QgsLineString::fromQPolygonF( polygon ) );
3249 
3250  if ( polygon.isClosed() )
3251  {
3252  std::unique_ptr< QgsPolygon > poly = std::make_unique< QgsPolygon >();
3253  poly->setExteriorRing( ring.release() );
3254  return QgsGeometry( std::move( poly ) );
3255  }
3256  else
3257  {
3258  return QgsGeometry( std::move( ring ) );
3259  }
3260 }
3261 
3263 {
3265  QgsPolygonXY result;
3266  result << createPolylineFromQPolygonF( polygon );
3267  return result;
3269 }
3270 
3272 {
3273  QgsPolylineXY result;
3274  result.reserve( polygon.count() );
3275  for ( const QPointF &p : polygon )
3276  {
3277  result.append( QgsPointXY( p ) );
3278  }
3279  return result;
3280 }
3281 
3282 bool QgsGeometry::compare( const QgsPolylineXY &p1, const QgsPolylineXY &p2, double epsilon )
3283 {
3284  if ( p1.count() != p2.count() )
3285  return false;
3286 
3287  for ( int i = 0; i < p1.count(); ++i )
3288  {
3289  if ( !p1.at( i ).compare( p2.at( i ), epsilon ) )
3290  return false;
3291  }
3292  return true;
3293 }
3294 
3295 bool QgsGeometry::compare( const QgsPolygonXY &p1, const QgsPolygonXY &p2, double epsilon )
3296 {
3297  if ( p1.count() != p2.count() )
3298  return false;
3299 
3300  for ( int i = 0; i < p1.count(); ++i )
3301  {
3302  if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
3303  return false;
3304  }
3305  return true;
3306 }
3307 
3308 
3309 bool QgsGeometry::compare( const QgsMultiPolygonXY &p1, const QgsMultiPolygonXY &p2, double epsilon )
3310 {
3311  if ( p1.count() != p2.count() )
3312  return false;
3313 
3314  for ( int i = 0; i < p1.count(); ++i )
3315  {
3316  if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
3317  return false;
3318  }
3319  return true;
3320 }
3321 
3322 QgsGeometry QgsGeometry::smooth( const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3323 {
3324  if ( !d->geometry || d->geometry->isEmpty() )
3325  return QgsGeometry();
3326 
3327  QgsGeometry geom = *this;
3329  geom = QgsGeometry( d->geometry->segmentize() );
3330 
3331  switch ( QgsWkbTypes::flatType( geom.wkbType() ) )
3332  {
3333  case QgsWkbTypes::Point:
3335  //can't smooth a point based geometry
3336  return geom;
3337 
3339  {
3340  const QgsLineString *lineString = qgsgeometry_cast< const QgsLineString * >( geom.constGet() );
3341  return QgsGeometry( smoothLine( *lineString, iterations, offset, minimumDistance, maxAngle ) );
3342  }
3343 
3345  {
3346  const QgsMultiLineString *multiLine = qgsgeometry_cast< const QgsMultiLineString * >( geom.constGet() );
3347 
3348  std::unique_ptr< QgsMultiLineString > resultMultiline = std::make_unique< QgsMultiLineString> ();
3349  resultMultiline->reserve( multiLine->numGeometries() );
3350  for ( int i = 0; i < multiLine->numGeometries(); ++i )
3351  {
3352  resultMultiline->addGeometry( smoothLine( *( multiLine->lineStringN( i ) ), iterations, offset, minimumDistance, maxAngle ).release() );
3353  }
3354  return QgsGeometry( std::move( resultMultiline ) );
3355  }
3356 
3357  case QgsWkbTypes::Polygon:
3358  {
3359  const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon * >( geom.constGet() );
3360  return QgsGeometry( smoothPolygon( *poly, iterations, offset, minimumDistance, maxAngle ) );
3361  }
3362 
3364  {
3365  const QgsMultiPolygon *multiPoly = qgsgeometry_cast< const QgsMultiPolygon * >( geom.constGet() );
3366 
3367  std::unique_ptr< QgsMultiPolygon > resultMultiPoly = std::make_unique< QgsMultiPolygon >();
3368  resultMultiPoly->reserve( multiPoly->numGeometries() );
3369  for ( int i = 0; i < multiPoly->numGeometries(); ++i )
3370  {
3371  resultMultiPoly->addGeometry( smoothPolygon( *( multiPoly->polygonN( i ) ), iterations, offset, minimumDistance, maxAngle ).release() );
3372  }
3373  return QgsGeometry( std::move( resultMultiPoly ) );
3374  }
3375 
3376  case QgsWkbTypes::Unknown:
3377  default:
3378  return QgsGeometry( *this );
3379  }
3380 }
3381 
3382 std::unique_ptr< QgsLineString > smoothCurve( const QgsLineString &line, const unsigned int iterations,
3383  const double offset, double squareDistThreshold, double maxAngleRads,
3384  bool isRing )
3385 {
3386  std::unique_ptr< QgsLineString > result = std::make_unique< QgsLineString >( line );
3387  QgsPointSequence outputLine;
3388  for ( unsigned int iteration = 0; iteration < iterations; ++iteration )
3389  {
3390  outputLine.resize( 0 );
3391  outputLine.reserve( 2 * ( result->numPoints() - 1 ) );
3392  bool skipFirst = false;
3393  bool skipLast = false;
3394  if ( isRing )
3395  {
3396  QgsPoint p1 = result->pointN( result->numPoints() - 2 );
3397  QgsPoint p2 = result->pointN( 0 );
3398  QgsPoint p3 = result->pointN( 1 );
3399  double angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3400  p3.x(), p3.y() );
3401  angle = std::fabs( M_PI - angle );
3402  skipFirst = angle > maxAngleRads;
3403  }
3404  for ( int i = 0; i < result->numPoints() - 1; i++ )
3405  {
3406  QgsPoint p1 = result->pointN( i );
3407  QgsPoint p2 = result->pointN( i + 1 );
3408 
3409  double angle = M_PI;
3410  if ( i == 0 && isRing )
3411  {
3412  QgsPoint p3 = result->pointN( result->numPoints() - 2 );
3413  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3414  p3.x(), p3.y() );
3415  }
3416  else if ( i < result->numPoints() - 2 )
3417  {
3418  QgsPoint p3 = result->pointN( i + 2 );
3419  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3420  p3.x(), p3.y() );
3421  }
3422  else if ( i == result->numPoints() - 2 && isRing )
3423  {
3424  QgsPoint p3 = result->pointN( 1 );
3425  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3426  p3.x(), p3.y() );
3427  }
3428 
3429  skipLast = angle < M_PI - maxAngleRads || angle > M_PI + maxAngleRads;
3430 
3431  // don't apply distance threshold to first or last segment
3432  if ( i == 0 || i >= result->numPoints() - 2
3433  || QgsGeometryUtils::sqrDistance2D( p1, p2 ) > squareDistThreshold )
3434  {
3435  if ( !isRing )
3436  {
3437  if ( !skipFirst )
3438  outputLine << ( i == 0 ? result->pointN( i ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset ) );
3439  if ( !skipLast )
3440  outputLine << ( i == result->numPoints() - 2 ? result->pointN( i + 1 ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset ) );
3441  else
3442  outputLine << p2;
3443  }
3444  else
3445  {
3446  // ring
3447  if ( !skipFirst )
3448  outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset );
3449  else if ( i == 0 )
3450  outputLine << p1;
3451  if ( !skipLast )
3452  outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset );
3453  else
3454  outputLine << p2;
3455  }
3456  }
3457  skipFirst = skipLast;
3458  }
3459 
3460  if ( isRing && outputLine.at( 0 ) != outputLine.at( outputLine.count() - 1 ) )
3461  outputLine << outputLine.at( 0 );
3462 
3463  result->setPoints( outputLine );
3464  }
3465  return result;
3466 }
3467 
3468 std::unique_ptr<QgsLineString> QgsGeometry::smoothLine( const QgsLineString &line, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3469 {
3470  double maxAngleRads = maxAngle * M_PI / 180.0;
3471  double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
3472  return smoothCurve( line, iterations, offset, squareDistThreshold, maxAngleRads, false );
3473 }
3474 
3475 std::unique_ptr<QgsPolygon> QgsGeometry::smoothPolygon( const QgsPolygon &polygon, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3476 {
3477  double maxAngleRads = maxAngle * M_PI / 180.0;
3478  double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
3479  std::unique_ptr< QgsPolygon > resultPoly = std::make_unique< QgsPolygon >();
3480 
3481  resultPoly->setExteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.exteriorRing() ) ), iterations, offset,
3482  squareDistThreshold, maxAngleRads, true ).release() );
3483 
3484  for ( int i = 0; i < polygon.numInteriorRings(); ++i )
3485  {
3486  resultPoly->addInteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.interiorRing( i ) ) ), iterations, offset,
3487  squareDistThreshold, maxAngleRads, true ).release() );
3488  }
3489  return resultPoly;
3490 }
3491 
3492 QgsGeometry QgsGeometry::convertToPoint( bool destMultipart ) const
3493 {
3494  switch ( type() )
3495  {
3497  {
3498  bool srcIsMultipart = isMultipart();
3499 
3500  if ( ( destMultipart && srcIsMultipart ) ||
3501  ( !destMultipart && !srcIsMultipart ) )
3502  {
3503  // return a copy of the same geom
3504  return QgsGeometry( *this );
3505  }
3506  if ( destMultipart )
3507  {
3508  // layer is multipart => make a multipoint with a single point
3509  return fromMultiPointXY( QgsMultiPointXY() << asPoint() );
3510  }
3511  else
3512  {
3513  // destination is singlepart => make a single part if possible
3514  QgsMultiPointXY multiPoint = asMultiPoint();
3515  if ( multiPoint.count() == 1 )
3516  {
3517  return fromPointXY( multiPoint[0] );
3518  }
3519  }
3520  return QgsGeometry();
3521  }
3522 
3524  {
3525  // only possible if destination is multipart
3526  if ( !destMultipart )
3527  return QgsGeometry();
3528 
3529  // input geometry is multipart
3530  if ( isMultipart() )
3531  {
3532  const QgsMultiPolylineXY multiLine = asMultiPolyline();
3533  QgsMultiPointXY multiPoint;
3534  for ( const QgsPolylineXY &l : multiLine )
3535  for ( const QgsPointXY &p : l )
3536  multiPoint << p;
3537  return fromMultiPointXY( multiPoint );
3538  }
3539  // input geometry is not multipart: copy directly the line into a multipoint
3540  else
3541  {
3542  QgsPolylineXY line = asPolyline();
3543  if ( !line.isEmpty() )
3544  return fromMultiPointXY( line );
3545  }
3546  return QgsGeometry();
3547  }
3548 
3550  {
3551  // can only transform if destination is multipoint
3552  if ( !destMultipart )
3553  return QgsGeometry();
3554 
3555  // input geometry is multipart: make a multipoint from multipolygon
3556  if ( isMultipart() )
3557  {
3558  const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3559  QgsMultiPointXY multiPoint;
3560  for ( const QgsPolygonXY &poly : multiPolygon )
3561  for ( const QgsPolylineXY &line : poly )
3562  for ( const QgsPointXY &pt : line )
3563  multiPoint << pt;
3564  return fromMultiPointXY( multiPoint );
3565  }
3566  // input geometry is not multipart: make a multipoint from polygon
3567  else
3568  {
3569  const QgsPolygonXY polygon = asPolygon();
3570  QgsMultiPointXY multiPoint;
3571  for ( const QgsPolylineXY &line : polygon )
3572  for ( const QgsPointXY &pt : line )
3573  multiPoint << pt;
3574  return fromMultiPointXY( multiPoint );
3575  }
3576  }
3577 
3578  default:
3579  return QgsGeometry();
3580  }
3581 }
3582 
3583 QgsGeometry QgsGeometry::convertToLine( bool destMultipart ) const
3584 {
3585  switch ( type() )
3586  {
3588  {
3589  if ( !isMultipart() )
3590  return QgsGeometry();
3591 
3592  QgsMultiPointXY multiPoint = asMultiPoint();
3593  if ( multiPoint.count() < 2 )
3594  return QgsGeometry();
3595 
3596  if ( destMultipart )
3597  return fromMultiPolylineXY( QgsMultiPolylineXY() << multiPoint );
3598  else
3599  return fromPolylineXY( multiPoint );
3600  }
3601 
3603  {
3604  bool srcIsMultipart = isMultipart();
3605 
3606  if ( ( destMultipart && srcIsMultipart ) ||
3607  ( !destMultipart && ! srcIsMultipart ) )
3608  {
3609  // return a copy of the same geom
3610  return QgsGeometry( *this );
3611  }
3612  if ( destMultipart )
3613  {
3614  // destination is multipart => makes a multipoint with a single line
3615  QgsPolylineXY line = asPolyline();
3616  if ( !line.isEmpty() )
3617  return fromMultiPolylineXY( QgsMultiPolylineXY() << line );
3618  }
3619  else
3620  {
3621  // destination is singlepart => make a single part if possible
3622  QgsMultiPolylineXY multiLine = asMultiPolyline();
3623  if ( multiLine.count() == 1 )
3624  return fromPolylineXY( multiLine[0] );
3625  }
3626  return QgsGeometry();
3627  }
3628 
3630  {
3631  // input geometry is multipolygon
3632  if ( isMultipart() )
3633  {
3634  const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3635  QgsMultiPolylineXY multiLine;
3636  for ( const QgsPolygonXY &poly : multiPolygon )
3637  for ( const QgsPolylineXY &line : poly )
3638  multiLine << line;
3639 
3640  if ( destMultipart )
3641  {
3642  // destination is multipart
3643  return fromMultiPolylineXY( multiLine );
3644  }
3645  else if ( multiLine.count() == 1 )
3646  {
3647  // destination is singlepart => make a single part if possible
3648  return fromPolylineXY( multiLine[0] );
3649  }
3650  }
3651  // input geometry is single polygon
3652  else
3653  {
3654  QgsPolygonXY polygon = asPolygon();
3655  // if polygon has rings
3656  if ( polygon.count() > 1 )
3657  {
3658  // cannot fit a polygon with rings in a single line layer
3659  // TODO: would it be better to remove rings?
3660  if ( destMultipart )
3661  {
3662  const QgsPolygonXY polygon = asPolygon();
3663  QgsMultiPolylineXY multiLine;
3664  multiLine.reserve( polygon.count() );
3665  for ( const QgsPolylineXY &line : polygon )
3666  multiLine << line;
3667  return fromMultiPolylineXY( multiLine );
3668  }
3669  }
3670  // no rings
3671  else if ( polygon.count() == 1 )
3672  {
3673  if ( destMultipart )
3674  {
3675  return fromMultiPolylineXY( polygon );
3676  }
3677  else
3678  {
3679  return fromPolylineXY( polygon[0] );
3680  }
3681  }
3682  }
3683  return QgsGeometry();
3684  }
3685 
3686  default:
3687  return QgsGeometry();
3688  }
3689 }
3690 
3691 QgsGeometry QgsGeometry::convertToPolygon( bool destMultipart ) const
3692 {
3693  switch ( type() )
3694  {
3696  {
3697  if ( !isMultipart() )
3698  return QgsGeometry();
3699 
3700  QgsMultiPointXY multiPoint = asMultiPoint();
3701  if ( multiPoint.count() < 3 )
3702  return QgsGeometry();
3703 
3704  if ( multiPoint.last() != multiPoint.first() )
3705  multiPoint << multiPoint.first();
3706 
3707  QgsPolygonXY polygon = QgsPolygonXY() << multiPoint;
3708  if ( destMultipart )
3709  return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3710  else
3711  return fromPolygonXY( polygon );
3712  }
3713 
3715  {
3716  // input geometry is multiline
3717  if ( isMultipart() )
3718  {
3719  QgsMultiPolylineXY multiLine = asMultiPolyline();
3720  QgsMultiPolygonXY multiPolygon;
3721  for ( QgsMultiPolylineXY::iterator multiLineIt = multiLine.begin(); multiLineIt != multiLine.end(); ++multiLineIt )
3722  {
3723  // do not create polygon for a 1 segment line
3724  if ( ( *multiLineIt ).count() < 3 )
3725  return QgsGeometry();
3726  if ( ( *multiLineIt ).count() == 3 && ( *multiLineIt ).first() == ( *multiLineIt ).last() )
3727  return QgsGeometry();
3728 
3729  // add closing node
3730  if ( ( *multiLineIt ).first() != ( *multiLineIt ).last() )
3731  *multiLineIt << ( *multiLineIt ).first();
3732  multiPolygon << ( QgsPolygonXY() << *multiLineIt );
3733  }
3734  // check that polygons were inserted
3735  if ( !multiPolygon.isEmpty() )
3736  {
3737  if ( destMultipart )
3738  {
3739  return fromMultiPolygonXY( multiPolygon );
3740  }
3741  else if ( multiPolygon.count() == 1 )
3742  {
3743  // destination is singlepart => make a single part if possible
3744  return fromPolygonXY( multiPolygon[0] );
3745  }
3746  }
3747  }
3748  // input geometry is single line
3749  else
3750  {
3751  QgsPolylineXY line = asPolyline();
3752 
3753  // do not create polygon for a 1 segment line
3754  if ( line.count() < 3 )
3755  return QgsGeometry();
3756  if ( line.count() == 3 && line.first() == line.last() )
3757  return QgsGeometry();
3758 
3759  // add closing node
3760  if ( line.first() != line.last() )
3761  line << line.first();
3762 
3763  // destination is multipart
3764  if ( destMultipart )
3765  {
3766  return fromMultiPolygonXY( QgsMultiPolygonXY() << ( QgsPolygonXY() << line ) );
3767  }
3768  else
3769  {
3770  return fromPolygonXY( QgsPolygonXY() << line );
3771  }
3772  }
3773  return QgsGeometry();
3774  }
3775 
3777  {
3778  bool srcIsMultipart = isMultipart();
3779 
3780  if ( ( destMultipart && srcIsMultipart ) ||
3781  ( !destMultipart && ! srcIsMultipart ) )
3782  {
3783  // return a copy of the same geom
3784  return QgsGeometry( *this );
3785  }
3786  if ( destMultipart )
3787  {
3788  // destination is multipart => makes a multipoint with a single polygon
3789  QgsPolygonXY polygon = asPolygon();
3790  if ( !polygon.isEmpty() )
3791  return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3792  }
3793  else
3794  {
3795  QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3796  if ( multiPolygon.count() == 1 )
3797  {
3798  // destination is singlepart => make a single part if possible
3799  return fromPolygonXY( multiPolygon[0] );
3800  }
3801  }
3802  return QgsGeometry();
3803  }
3804 
3805  default:
3806  return QgsGeometry();
3807  }
3808 }
3809 
3811 {
3812  return new QgsGeos( geometry );
3813 }
3814 
3815 QDataStream &operator<<( QDataStream &out, const QgsGeometry &geometry )
3816 {
3817  out << geometry.asWkb();
3818  return out;
3819 }
3820 
3821 QDataStream &operator>>( QDataStream &in, QgsGeometry &geometry )
3822 {
3823  QByteArray byteArray;
3824  in >> byteArray;
3825  if ( byteArray.isEmpty() )
3826  {
3827  geometry.set( nullptr );
3828  return in;
3829  }
3830 
3831  geometry.fromWkb( byteArray );
3832  return in;
3833 }
3834 
3835 
3837 {
3838  return mMessage;
3839 }
3840 
3842 {
3843  return mLocation;
3844 }
3845 
3847 {
3848  return mHasLocation;
3849 }
The part_iterator class provides STL-style iterator for const references to geometry parts.
The part_iterator class provides STL-style iterator for geometry parts.
The vertex_iterator class provides STL-style iterator for vertices.
Abstract base class for all geometries.
virtual int ringCount(int part=0) const =0
Returns the number of rings of which this geometry is built.
virtual bool addZValue(double zValue=0)=0
Adds a z-dimension to the geometry, initialized to a preset value.
virtual QgsAbstractGeometry * boundary() const =0
Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the...
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
virtual bool dropMValue()=0
Drops any measure values which exist in the geometry.
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
virtual int vertexCount(int part=0, int ring=0) const =0
Returns the number of vertices of which this geometry is built.
virtual QgsRectangle boundingBox() const =0
Returns the minimal bounding box for the geometry.
virtual QgsPoint vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
virtual void adjacentVertices(QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex) const =0
Returns the vertices adjacent to a specified vertex within a geometry.
virtual bool addMValue(double mValue=0)=0
Adds a measure to the geometry, initialized to a preset value.
virtual double length() const
Returns the planar, 2-dimensional length of the geometry.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
virtual bool dropZValue()=0
Drops any z-dimensions which exist in the geometry.
virtual double area() const
Returns the planar, 2-dimensional area of the geometry.
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
Circle geometry type.
Definition: qgscircle.h:44
double radius() const SIP_HOLDGIL
Returns the radius of the circle.
Definition: qgscircle.h:311
static QgsCircle from2Points(const QgsPoint &pt1, const QgsPoint &pt2) SIP_HOLDGIL
Constructs a circle by 2 points on the circle.
Definition: qgscircle.cpp:37
bool contains(const QgsPoint &point, double epsilon=1E-8) const
Returns true if the circle contains the point.
Definition: qgscircle.cpp:452
static QgsCircle minimalCircleFrom3Points(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double epsilon=1E-8) SIP_HOLDGIL
Constructs the smallest circle from 3 points.
Definition: qgscircle.cpp:325
QgsCircularString * toCircularString(bool oriented=false) const
Returns a circular string from the circle.
Definition: qgscircle.cpp:429
Circular string geometry type.
static QgsCircularString fromTwoPointsAndCenter(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &center, bool useShortestArc=true)
Creates a circular string with a single arc representing the curve from p1 to p2 with the specified c...
A const WKB pointer.
Definition: qgswkbptr.h:138
Class for doing transforms between two map coordinate systems.
TransformDirection
Enum used to indicate the direction (forward or inverse) of the transform.
Curve polygon geometry type.
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.
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
int numInteriorRings() const SIP_HOLDGIL
Returns the number of interior rings contained with the curve polygon.
Abstract base class for curved geometry type.
Definition: qgscurve.h:36
virtual int numPoints() const =0
Returns the number of points in the curve.
QgsCurve * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
Definition: qgscurve.cpp:174
virtual QgsPoint * interpolatePoint(double distance) const =0
Returns an interpolated point on the curve at the specified distance.
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.
Orientation
Curve orientation.
Definition: qgscurve.h:265
QgsPoint center() const SIP_HOLDGIL
Returns the center point.
Definition: qgsellipse.h:121
virtual QgsPolygon * toPolygon(unsigned int segments=36) const
Returns a segmented polygon.
Definition: qgsellipse.cpp:224
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:45
Geometry collection.
int numGeometries() const SIP_HOLDGIL
Returns the number of geometries within the collection.
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
QgsGeometryCollection * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
virtual bool addGeometry(QgsAbstractGeometry *g)
Adds a geometry and takes ownership. Returns true in case of success.
int partCount() const override
Returns count of parts contained in the geometry.
Java-style iterator for const traversal of parts of a geometry.
static std::unique_ptr< QgsAbstractGeometry > avoidIntersections(const QgsAbstractGeometry &geom, const QList< QgsVectorLayer * > &avoidIntersectionsLayers, bool &haveInvalidGeometry, 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 bool deletePart(QgsAbstractGeometry *geom, int partNum)
Deletes a part from a geometry.
static QgsGeometry::OperationResult addRing(QgsAbstractGeometry *geometry, std::unique_ptr< QgsCurve > ring)
Add an interior ring to a geometry.
static QgsGeometry::OperationResult addPart(QgsAbstractGeometry *geometry, std::unique_ptr< QgsAbstractGeometry > part)
Add a part to multi type geometry.
static bool deleteRing(QgsAbstractGeometry *geom, int ringNum, int partNum=0)
Deletes a ring from a geometry.
A geometry engine is a low-level representation of a QgsAbstractGeometry object, optimised for use wi...
EngineOperationResult
Success or failure of a geometry operation.
@ NothingHappened
Nothing happened, without any error.
@ InvalidBaseGeometry
The geometry on which the operation occurs is not valid.
@ InvalidInput
The input is not valid.
@ NodedGeometryError
Error occurred while creating a noded geometry.
@ EngineError
Error occurred in the geometry engine.
@ SplitCannotSplitPoint
Points cannot be split.
@ Success
Operation succeeded.
@ MethodNotImplemented
Method not implemented in geometry engine.
static std::unique_ptr< QgsMultiPolygon > fromMultiPolygonXY(const QgsMultiPolygonXY &multipoly)
Construct geometry from a multipolygon.
static std::unique_ptr< QgsAbstractGeometry > geomFromWkb(QgsConstWkbPtr &wkb)
Construct geometry from a WKB string.
static std::unique_ptr< QgsAbstractGeometry > fromPolylineXY(const QgsPolylineXY &polyline)
Construct geometry from a polyline.
static std::unique_ptr< QgsMultiPoint > fromMultiPointXY(const QgsMultiPointXY &multipoint)
Construct geometry from a multipoint.
static std::unique_ptr< QgsAbstractGeometry > geomFromWkt(const QString &text)
Construct geometry from a WKT string.
static std::unique_ptr< QgsAbstractGeometry > geomFromWkbType(QgsWkbTypes::Type t)
Returns empty geometry from wkb type.
static std::unique_ptr< QgsMultiLineString > fromMultiPolylineXY(const QgsMultiPolylineXY &multiline)
Construct geometry from a multipolyline.
static std::unique_ptr< QgsGeometryCollection > createCollectionOfType(QgsWkbTypes::Type type)
Returns a new geometry collection matching a specified WKB type.
static std::unique_ptr< QgsAbstractGeometry > fromPointXY(const QgsPointXY &point)
Construct geometry from a point.
static std::unique_ptr< QgsPolygon > fromPolygonXY(const QgsPolygonXY &polygon)
Construct geometry from a polygon.
Java-style iterator for traversal of parts of a geometry.
static double sqrDistance2D(const QgsPoint &pt1, const QgsPoint &pt2) SIP_HOLDGIL
Returns the squared 2D distance between two points.
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...
static double distanceToVertex(const QgsAbstractGeometry &geom, QgsVertexId id)
Returns the distance along a geometry from its first vertex to the specified vertex.
static double averageAngle(double x1, double y1, double x2, double y2, double x3, double y3) SIP_HOLDGIL
Calculates the average angle (in radians) between the two linear segments from (x1,...
static double lineAngle(double x1, double y1, double x2, double y2) SIP_HOLDGIL
Calculates the direction of line joining two points in radians, clockwise from the north direction.
static double angleBetweenThreePoints(double x1, double y1, double x2, double y2, double x3, double y3) SIP_HOLDGIL
Calculates the angle between the lines AB and BC, where AB and BC described by points a,...
static QgsPoint closestVertex(const QgsAbstractGeometry &geom, const QgsPoint &pt, QgsVertexId &id)
Returns the closest vertex to a geometry for a specified point.
static QgsPointXY interpolatePointOnLine(double x1, double y1, double x2, double y2, double fraction) SIP_HOLDGIL
Interpolates the position of a point a fraction of the way along the line from (x1,...
static void validateGeometry(const QgsGeometry &geometry, QVector< QgsGeometry::Error > &errors, QgsGeometry::ValidationMethod method=QgsGeometry::ValidatorQgisInternal)
Validate geometry and produce a list of geometry errors.
A geometry error.
Definition: qgsgeometry.h:2268
bool hasWhere() const
true if the location available from
QgsPointXY where() const
The coordinates at which the error is located and should be visualized.
QString what() const
A human readable error message containing details about the error.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsGeometry() SIP_HOLDGIL
Constructor.
Definition: qgsgeometry.cpp:64
OperationResult addPart(const QVector< QgsPointXY > &points, QgsWkbTypes::GeometryType geomType=QgsWkbTypes::UnknownGeometry)
Adds a new part to a the geometry.
bool deleteRing(int ringNum, int partNum=0)
Deletes a ring in polygon or multipolygon.
QVector< QgsPointXY > randomPointsInPolygon(int count, const std::function< bool(const QgsPointXY &) > &acceptPoint, unsigned long seed=0, QgsFeedback *feedback=nullptr, int maxTriesPerPoint=0) const
Returns a list of count random points generated inside a (multi)polygon geometry (if acceptPoint is s...
double hausdorffDistanceDensify(const QgsGeometry &geom, double densifyFraction) const
Returns the Hausdorff distance between this geometry and geom.
QgsGeometry densifyByCount(int extraNodesPerSegment) const
Returns a copy of the geometry which has been densified by adding the specified number of extra nodes...
QgsGeometry clipped(const QgsRectangle &rectangle)
Clips the geometry using the specified rectangle.
JoinStyle
Join styles for buffers.
Definition: qgsgeometry.h:1244
double lineLocatePoint(const QgsGeometry &point) const
Returns a distance representing the location along this linestring of the closest point on this lines...
int makeDifferenceInPlace(const QgsGeometry &other)
Changes this geometry such that it does not intersect the other geometry.
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
void adjacentVertices(int atVertex, int &beforeVertex, int &afterVertex) const
Returns the indexes of the vertices before and after the given vertex index.
QgsMultiPolygonXY asMultiPolygon() const
Returns the contents of the geometry as a multi-polygon.
bool deleteVertex(int atVertex)
Deletes the vertex at the given position number and item (first number is index 0)
double length() const
Returns the planar, 2-dimensional length of geometry.
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.
QgsVertexIterator vertices() const
Returns a read-only, Java-style iterator for traversal of vertices of all the geometry,...
QgsGeometry densifyByDistance(double distance) const
Densifies the geometry by adding regularly placed extra nodes inside each segment so that the maximum...
QgsGeometry poleOfInaccessibility(double precision, double *distanceToBoundary=nullptr) const
Calculates the approximate pole of inaccessibility for a surface, which is the most distant internal ...
QgsGeometry largestEmptyCircle(double tolerance, const QgsGeometry &boundary=QgsGeometry()) const SIP_THROW(QgsNotSupportedException)
Constructs the Largest Empty Circle for a set of obstacle geometries, up to a specified tolerance.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
QgsAbstractGeometry::const_part_iterator const_parts_begin() const
Returns STL-style const iterator pointing to the first part of the geometry.
QgsGeometry difference(const QgsGeometry &geometry) const
Returns a geometry representing the points making up this geometry that do not make up other.
static QgsGeometry polygonize(const QVector< QgsGeometry > &geometries)
Creates a GeometryCollection geometry containing possible polygons formed from the constituent linewo...
bool boundingBoxIntersects(const QgsRectangle &rectangle) const
Returns true if the bounding box of this geometry intersects with a rectangle.
bool vertexIdFromVertexNr(int number, QgsVertexId &id) const
Calculates the vertex ID from a vertex number.
QgsGeometry pointOnSurface() const
Returns a point guaranteed to lie on the surface of a geometry.
OperationResult rotate(double rotation, const QgsPointXY &center)
Rotate this geometry around the Z axis.
bool touches(const QgsGeometry &geometry) const
Returns true if the geometry touches another geometry.
static QgsGeometry fromQPointF(QPointF point) SIP_HOLDGIL
Construct geometry from a QPointF.
void transformVertices(const std::function< QgsPoint(const QgsPoint &) > &transform)
Transforms the vertices from the geometry in place, applying the transform function to every vertex.
QgsGeometry nearestPoint(const QgsGeometry &other) const
Returns the nearest (closest) point on this geometry to another geometry.
QgsGeometry makeDifference(const QgsGeometry &other) const
Returns the geometry formed by modifying this geometry such that it does not intersect the other geom...
static QgsGeometry collectGeometry(const QVector< QgsGeometry > &geometries)
Creates a new multipart geometry from a list of QgsGeometry objects.
QVector< QgsGeometry > coerceToType(QgsWkbTypes::Type type) const
Attempts to coerce this geometry into the specified destination type.
static QgsGeometry fromMultiPolylineXY(const QgsMultiPolylineXY &multiline)
Creates a new geometry from a QgsMultiPolylineXY object.
OperationResult translate(double dx, double dy, double dz=0.0, double dm=0.0)
Translates this geometry by dx, dy, dz and dm.
bool isAxisParallelRectangle(double maximumDeviation, bool simpleRectanglesOnly=false) const
Returns true if the geometry is a polygon that is almost an axis-parallel rectangle.
static QgsGeometry fromQPolygonF(const QPolygonF &polygon)
Construct geometry from a QPolygonF.
static QgsGeometry unaryUnion(const QVector< QgsGeometry > &geometries)
Compute the unary union on a list of geometries.
QgsGeometry variableWidthBufferByM(int segments) const
Calculates a variable width buffer for a (multi)linestring geometry, where the width at each node is ...
static QgsGeometry fromPolylineXY(const QgsPolylineXY &polyline)
Creates a new LineString geometry from a list of QgsPointXY points.
QgsMultiPointXY asMultiPoint() const
Returns the contents of the geometry as a multi-point.
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
QgsPointXY closestVertex(const QgsPointXY &point, int &closestVertexIndex, int &previousVertexIndex, int &nextVertexIndex, double &sqrDist) const
Returns the vertex closest to the given point, the corresponding vertex index, squared distance snap ...
void normalize()
Reorganizes the geometry into a normalized form (or "canonical" form).
BufferSide
Side of line to buffer.
Definition: qgsgeometry.h:1227
int wkbSize(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const
Returns the length of the QByteArray returned by asWkb()
QgsGeometry minimumWidth() const SIP_THROW(QgsNotSupportedException)
Returns a linestring geometry which represents the minimum diameter of the geometry.
QgsPolygonXY asPolygon() const
Returns the contents of the geometry as a polygon.
OperationResult reshapeGeometry(const QgsLineString &reshapeLineString)
Replaces a part of this geometry with another line.
bool disjoint(const QgsGeometry &geometry) const
Returns true if the geometry is disjoint of another geometry.
QgsGeometry combine(const QgsGeometry &geometry) const
Returns a geometry representing all the points in this geometry and other (a union geometry operation...
QVector< QgsGeometry > asGeometryCollection() const
Returns contents of the geometry as a list of geometries.
double distance(const QgsGeometry &geom) const
Returns the minimum distance between this geometry and another geometry.
QgsGeometry interpolate(double distance) const
Returns an interpolated point on the geometry at the specified distance.
QgsGeometry extrude(double x, double y)
Returns an extruded version of this geometry.
static Q_DECL_DEPRECATED QgsPolylineXY createPolylineFromQPolygonF(const QPolygonF &polygon)
Creates a QgsPolylineXY from a QPolygonF.
Q_GADGET bool isNull
Definition: qgsgeometry.h:126
void mapToPixel(const QgsMapToPixel &mtp)
Transforms the geometry from map units to pixels in place.
static QgsGeometry fromMultiPointXY(const QgsMultiPointXY &multipoint)
Creates a new geometry from a QgsMultiPointXY object.
OperationResult addRing(const QVector< QgsPointXY > &ring)
Adds a new ring to this geometry.
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
Q_DECL_DEPRECATED OperationResult splitGeometry(const QVector< QgsPointXY > &splitLine, QVector< QgsGeometry > &newGeometries, bool topological, QVector< QgsPointXY > &topologyTestPoints, bool splitFeature=true)
Splits this geometry according to a given line.
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
double minimumClearance() const SIP_THROW(QgsNotSupportedException)
Computes the minimum clearance of a geometry.
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...
bool isMultipart() const SIP_HOLDGIL
Returns true if WKB of the geometry is of WKBMulti* type.
QgsGeometry intersection(const QgsGeometry &geometry) const
Returns a geometry representing the points shared by this geometry and other.
static QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
bool contains(const QgsPointXY *p) const
Returns true if the geometry contains the point p.
QgsGeometry convertToType(QgsWkbTypes::GeometryType destType, bool destMultipart=false) const
Try to convert the geometry to the requested type.
QgsPolylineXY asPolyline() const
Returns the contents of the geometry as a polyline.
QgsAbstractGeometry::part_iterator parts_begin()
Returns STL-style iterator pointing to the first part of the geometry.
bool isGeosValid(QgsGeometry::ValidityFlags flags=QgsGeometry::ValidityFlags()) const
Checks validity of the geometry using GEOS.
QgsGeometry forceRHR() const
Forces geometries to respect the Right-Hand-Rule, in which the area that is bounded by a polygon is t...
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
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.
QgsGeometry minimumClearanceLine() const SIP_THROW(QgsNotSupportedException)
Returns a LineString whose endpoints define the minimum clearance of a geometry.
virtual json asJsonObject(int precision=17) const
Exports the geometry to a json object.
void filterVertices(const std::function< bool(const QgsPoint &) > &filter)
Filters the vertices from the geometry in place, removing any which do not return true for the filter...
bool equals(const QgsGeometry &geometry) const
Test if this geometry is exactly equal to another geometry.
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...
static Q_DECL_DEPRECATED QgsPolygonXY createPolygonFromQPolygonF(const QPolygonF &polygon)
Creates a QgsPolygonXYfrom a QPolygonF.
bool convertToSingleType()
Converts multi type geometry into single type geometry e.g.
QPointF asQPointF() const SIP_HOLDGIL
Returns contents of the geometry as a QPointF if wkbType is WKBPoint, otherwise returns a null QPoint...
EndCapStyle
End cap styles for buffers.
Definition: qgsgeometry.h:1235
static QgsGeometry fromPointXY(const QgsPointXY &point) SIP_HOLDGIL
Creates a new geometry from a QgsPointXY object.
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:127
bool requiresConversionToStraightSegments() const
Returns true if the geometry is a curved geometry type which requires conversion to display as straig...
OperationResult
Success or failure of a geometry operation.
Definition: qgsgeometry.h:136
@ InvalidBaseGeometry
The base geometry on which the operation is done is invalid or empty.
Definition: qgsgeometry.h:139
@ GeometryEngineError
Geometry engine misses a method implemented or an error occurred in the geometry engine.
Definition: qgsgeometry.h:143
@ AddPartNotMultiGeometry
The source geometry is not multi.
Definition: qgsgeometry.h:147
@ InvalidInputGeometryType
The input geometry (ring, part, split line, etc.) has not the correct geometry type.
Definition: qgsgeometry.h:140
@ Success
Operation succeeded.
Definition: qgsgeometry.h:137
@ NothingHappened
Nothing happened, without any error.
Definition: qgsgeometry.h:138
bool isSimple() const
Determines whether the geometry is simple (according to OGC definition), i.e.
static QgsGeometry fromPolyline(const QgsPolyline &polyline)
Creates a new LineString geometry from a list of QgsPoint points.
@ FlagAllowSelfTouchingHoles
Indicates that self-touching holes are permitted. OGC validity states that self-touching holes are NO...
Definition: qgsgeometry.h:369
QgsMultiPolylineXY asMultiPolyline() const
Returns the contents of the geometry as a multi-linestring.
QgsGeometry taperedBuffer(double startWidth, double endWidth, int segments) const
Calculates a variable width buffer ("tapered buffer") for a (multi)curve geometry.
bool within(const QgsGeometry &geometry) const
Returns true if the geometry is completely within another geometry.
double frechetDistanceDensify(const QgsGeometry &geom, double densifyFraction) const SIP_THROW(QgsNotSupportedException)
Returns the Fréchet distance between this geometry and geom, restricted to discrete points for both g...
void convertToStraightSegment(double tolerance=M_PI/180., QgsAbstractGeometry::SegmentationToleranceType toleranceType=QgsAbstractGeometry::MaximumAngle)
Converts the geometry to straight line segments, if it is a curved geometry type.
double area() const
Returns the planar, 2-dimensional area of the geometry.
QgsGeometry centroid() const
Returns the center of mass of a geometry.
bool crosses(const QgsGeometry &geometry) const
Returns true if the geometry crosses another geometry.
QgsGeometry & operator=(QgsGeometry const &rhs)
Creates a deep copy of the object.
Definition: qgsgeometry.cpp:96
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...
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine representing the specified geometry.
QgsGeometry makeValid() const
Attempts to make an invalid geometry valid without losing vertices.
double hausdorffDistance(const QgsGeometry &geom) const
Returns the Hausdorff distance between this geometry and geom.
QString lastError() const SIP_HOLDGIL
Returns an error string referring to the last error encountered either when this geometry was created...
QgsGeometryPartIterator parts()
Returns Java-style iterator for traversal of parts of the geometry.
QPolygonF asQPolygonF() const SIP_HOLDGIL
Returns contents of the geometry as a QPolygonF.
QgsGeometry convertToCurves(double distanceTolerance=1e-8, double angleTolerance=1e-8) const
Attempts to convert a non-curved geometry into a curved geometry type (e.g.
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.
void set(QgsAbstractGeometry *geometry)
Sets the underlying geometry store.
QgsGeometry convexHull() const
Returns the smallest convex polygon that contains all the points in the geometry.
QgsGeometry sharedPaths(const QgsGeometry &other) const
Find paths shared between the two given lineal geometries (this and other).
virtual ~QgsGeometry()
Definition: qgsgeometry.cpp:69
static QgsGeometry fromPolygonXY(const QgsPolygonXY &polygon)
Creates a new geometry from a QgsPolygon.
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer's length.
QgsGeometry minimalEnclosingCircle(QgsPointXY &center, double &radius, unsigned int segments=36) const
Returns the minimal enclosing circle for the geometry.
QgsGeometry mergeLines() const
Merges any connected lines in a LineString/MultiLineString geometry and converts them to single line ...
static QgsGeometry fromMultiPolygonXY(const QgsMultiPolygonXY &multipoly)
Creates a new geometry from a QgsMultiPolygon.
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...
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
QgsGeometry symDifference(const QgsGeometry &geometry) const
Returns a geometry representing the points making up this geometry that do not make up other.
QgsGeometry node() const
Returns a (Multi)LineString representing the fully noded version of a collection of linestrings.
double distanceToVertex(int vertex) const
Returns the distance along this geometry from its first vertex to the specified vertex.
int vertexNrFromVertexId(QgsVertexId id) const
Returns the vertex number corresponding to a vertex id.
QgsAbstractGeometry::const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry.
bool removeDuplicateNodes(double epsilon=4 *std::numeric_limits< double >::epsilon(), bool useZValues=false)
Removes duplicate nodes from the geometry, wherever removing the nodes does not result in a degenerat...
QgsAbstractGeometry::part_iterator parts_end()
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry.
QgsAbstractGeometry::vertex_iterator vertices_begin() const
Returns STL-style iterator pointing to the first vertex of the geometry.
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.
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
void validateGeometry(QVector< QgsGeometry::Error > &errors, ValidationMethod method=ValidatorQgisInternal, QgsGeometry::ValidityFlags flags=QgsGeometry::ValidityFlags()) const
Validates geometry and produces a list of geometry errors.
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
QString asJson(int precision=17) const
Exports the geometry to a GeoJSON string.
static QgsGeometry createWedgeBuffer(const QgsPoint &center, double azimuth, double angularWidth, double outerRadius, double innerRadius=0)
Creates a wedge shaped buffer from a center point.
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const
Export the geometry to WKB.
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...
static void convertPointList(const QVector< QgsPointXY > &input, QgsPointSequence &output)
Upgrades a point list from QgsPointXY to QgsPoint.
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.
QgsGeometry orientedMinimumBoundingBox() const
Returns the oriented minimum bounding box for the geometry, which is the smallest (by area) rotated r...
QgsGeometryConstPartIterator constParts() const
Returns Java-style iterator for traversal of parts of the geometry.
QgsGeometry simplify(double tolerance) const
Returns a simplified version of this geometry using a specified tolerance value.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
double interpolateAngle(double distance) const
Returns the angle parallel to the linestring or polygon boundary at the specified distance along the ...
double angleAtVertex(int vertex) const
Returns the bisector angle for this geometry at the specified vertex.
double closestVertexWithContext(const QgsPointXY &point, int &atVertex) const
Searches for the closest vertex in this geometry to the given point.
QgsGeometry delaunayTriangulation(double tolerance=0.0, bool edgesOnly=false) const
Returns the Delaunay triangulation for the vertices of the geometry.
void draw(QPainter &p) const
Draws the geometry onto a QPainter.
bool convertGeometryCollectionToSubclass(QgsWkbTypes::GeometryType geomType)
Converts geometry collection to a the desired geometry type subclass (multi-point,...
double frechetDistance(const QgsGeometry &geom) const SIP_THROW(QgsNotSupportedException)
Returns the Fréchet distance between this geometry and geom, restricted to discrete points for both g...
QgsGeometry smooth(unsigned int iterations=1, double offset=0.25, double minimumDistance=-1.0, double maxAngle=180.0) const
Smooths a geometry by rounding off corners using the Chaikin algorithm.
QString asWkt(int precision=17) const
Exports the geometry to WKT.
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...
bool isGeosEqual(const QgsGeometry &) const
Compares the geometry with another geometry using GEOS.
double closestSegmentWithContext(const QgsPointXY &point, QgsPointXY &minDistPoint, int &nextVertexIndex, int *leftOrRightOfSegment=nullptr, double epsilon=DEFAULT_SEGMENT_EPSILON) const
Searches for the closest segment of geometry to the given point.
QgsGeometry subdivide(int maxNodes=256) const
Subdivides the geometry.
bool intersects(const QgsRectangle &rectangle) const
Returns true if this geometry exactly intersects with a rectangle.
QgsAbstractGeometry::vertex_iterator vertices_end() const
Returns STL-style iterator pointing to the imaginary vertex after the last vertex of the geometry.
bool deletePart(int partNum)
Deletes part identified by the part number.
QgsGeometry removeInteriorRings(double minimumAllowedArea=-1) const
Removes the interior rings from a (multi)polygon geometry.
bool overlaps(const QgsGeometry &geometry) const
Returns true if the geometry overlaps another geometry.
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.
ValidationMethod
Available methods for validating geometries.
Definition: qgsgeometry.h:2322
@ ValidatorQgisInternal
Use internal QgsGeometryValidator method.
Definition: qgsgeometry.h:2323
@ ValidatorGeos
Use GEOS validation methods.
Definition: qgsgeometry.h:2324
QgsGeometry shortestLine(const QgsGeometry &other) const
Returns the shortest line joining this geometry to another geometry.
Does vector analysis using the geos library and handles import, export, exception handling*.
Definition: qgsgeos.h:104
double hausdorffDistanceDensify(const QgsAbstractGeometry *geom, double densifyFraction, QString *errorMsg=nullptr) const
Returns the Hausdorff distance between this geometry and geom.
Definition: qgsgeos.cpp:492
double hausdorffDistance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const
Returns the Hausdorff distance between this geometry and geom.
Definition: qgsgeos.cpp:469
QgsAbstractGeometry * buffer(double distance, int segments, QString *errorMsg=nullptr) const override
Definition: qgsgeos.cpp:1628
double distance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculates the distance between this and geom.
Definition: qgsgeos.cpp:435
double frechetDistance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const
Returns the Fréchet distance between this geometry and geom, restricted to discrete points for both g...
Definition: qgsgeos.cpp:515
double area(QString *errorMsg=nullptr) const override
Definition: qgsgeos.cpp:674
double length(QString *errorMsg=nullptr) const override
Definition: qgsgeos.cpp:691
double frechetDistanceDensify(const QgsAbstractGeometry *geom, double densifyFraction, QString *errorMsg=nullptr) const
Returns the Fréchet distance between this geometry and geom, restricted to discrete points for both g...
Definition: qgsgeos.cpp:544
This class offers geometry processing methods.
QgsGeometry poleOfInaccessibility(double precision, double *distanceFromBoundary=nullptr) const
Calculates the approximate pole of inaccessibility for a surface, which is the most distant internal ...
QgsGeometry variableWidthBufferByM(int segments) const
Calculates a variable width buffer using the m-values from a (multi)line 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...
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 lastError() const
Returns an error string referring to the last error encountered.
QgsGeometry orientedMinimumBoundingBox(double &area, double &angle, double &width, double &height) const
Returns the oriented minimum bounding box for the geometry, which is the smallest (by area) rotated r...
QgsGeometry densifyByDistance(double distance) const
Densifies the geometry by adding regularly placed extra nodes inside each segment so that the maximum...
QgsGeometry taperedBuffer(double startWidth, double endWidth, int segments) const
Calculates a tapered width buffer for a (multi)curve geometry.
QgsGeometry densifyByCount(int extraNodesPerSegment) const
Densifies the geometry by adding the specified number of extra nodes within each segment of the geome...
static QVector< QgsPointXY > randomPointsInPolygon(const QgsGeometry &polygon, int count, const std::function< bool(const QgsPointXY &) > &acceptPoint, unsigned long seed=0, QgsFeedback *feedback=nullptr, int maxTriesPerPoint=0)
Returns a list of count random points generated inside a polygon geometry (if acceptPoint is specifie...
QgsGeometry convertToCurves(double distanceTolerance, double angleTolerance) const
Attempts to convert a non-curved geometry into a curved geometry type (e.g.
bool isAxisParallelRectangle(double maximumDeviation, bool simpleRectanglesOnly=false) const
Returns true if the geometry is a polygon that is almost an axis-parallel rectangle.
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:44
const double * yData() const
Returns a const pointer to the y vertex data.
int numPoints() const override SIP_HOLDGIL
Returns the number of points in the curve.
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
static QgsLineString * fromQPolygonF(const QPolygonF &polygon)
Returns a new linestring from a QPolygonF polygon input.
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
bool dropMValue() override
Drops any measure values which exist in the geometry.
const double * xData() const
Returns a const pointer to the x vertex data.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:39
QgsPointXY transform(const QgsPointXY &p) const
Transform the point p from map (world) coordinates to device coordinates.
Definition: qgsmaptopixel.h:82
Multi line string geometry collection.
QgsLineString * lineStringN(int index)
Returns the line string with the specified index.
Multi point geometry collection.
Definition: qgsmultipoint.h:30
QgsPoint * pointN(int index)
Returns the point with the specified index.
Multi polygon geometry collection.
QgsPolygon * polygonN(int index)
Returns the polygon with the specified index.
A class to represent a 2D point.
Definition: qgspointxy.h:59
void setX(double x) SIP_HOLDGIL
Sets the x value of the point.
Definition: qgspointxy.h:122
double y
Definition: qgspointxy.h:63
Q_GADGET double x
Definition: qgspointxy.h:62
void setY(double y) SIP_HOLDGIL
Sets the y value of the point.
Definition: qgspointxy.h:132
QPointF toQPointF() const
Converts a point to a QPointF.
Definition: qgspointxy.h:169
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
void setX(double x) SIP_HOLDGIL
Sets the point's x-coordinate.
Definition: qgspoint.h:280
QgsPoint project(double distance, double azimuth, double inclination=90.0) const SIP_HOLDGIL
Returns a new point which corresponds to this point projected by a specified distance with specified ...
Definition: qgspoint.cpp:735
Q_GADGET double x
Definition: qgspoint.h:52
double y
Definition: qgspoint.h:53
Polygon geometry type.
Definition: qgspolygon.h:34
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:183
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:479
bool isEmpty() const
Returns true if the rectangle is empty.
Definition: qgsrectangle.h:469
Surface geometry type.
Definition: qgssurface.h:34
Represents a vector layer which manages a vector based data sets.
Java-style iterator for traversal of vertices of a geometry.
static GeometryType geometryType(Type type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:938
static bool isMultiType(Type type) SIP_HOLDGIL
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:832
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:141
static bool hasM(Type type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1100
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
static bool isCurvedType(Type type) SIP_HOLDGIL
Returns true if the WKB type is a curved type or can contain curved geometries.
Definition: qgswkbtypes.h:881
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:702
static Type multiType(Type type) SIP_HOLDGIL
Returns the multi type for a WKB type.
Definition: qgswkbtypes.h:302
static bool hasZ(Type type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:1050
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
Contains geos related utilities and functions.
Definition: qgsgeos.h:42
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:1080
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:1079
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:598
QVector< QgsPoint > QgsPointSequence
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
QDataStream & operator>>(QDataStream &in, QgsGeometry &geometry)
Reads a geometry from stream in into geometry. QGIS version compatibility is not guaranteed.
QDataStream & operator<<(QDataStream &out, const QgsGeometry &geometry)
Writes the geometry to stream out. QGIS version compatibility is not guaranteed.
std::unique_ptr< QgsLineString > smoothCurve(const QgsLineString &line, const unsigned int iterations, const double offset, double squareDistThreshold, double maxAngleRads, bool isRing)
QVector< QgsPolylineXY > QgsPolygonXY
Polygon: first item of the list is outer ring, inner rings (if any) start from second item.
Definition: qgsgeometry.h:75
QVector< QgsPolylineXY > QgsMultiPolylineXY
A collection of QgsPolylines that share a common collection of attributes.
Definition: qgsgeometry.h:85
QVector< QgsPointXY > QgsMultiPointXY
A collection of QgsPoints that share a common collection of attributes.
Definition: qgsgeometry.h:81
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
Definition: qgsgeometry.h:51
QVector< QgsPolygonXY > QgsMultiPolygonXY
A collection of QgsPolygons that share a common collection of attributes.
Definition: qgsgeometry.h:92
QgsPointSequence QgsPolyline
Polyline as represented as a vector of points.
Definition: qgsgeometry.h:71
int precision
std::unique_ptr< QgsAbstractGeometry > geometry
Definition: qgsgeometry.cpp:61
Utility class for identifying a unique vertex within a geometry.
int vertex
Vertex number.
bool isValid() const SIP_HOLDGIL
Returns true if the vertex id is valid.
@ SegmentVertex
The actual start or end point of a segment.