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