QGIS API Documentation  3.9.0-Master (224899f119)
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  // fast case, check bounding boxes
1129  if ( !boundingBoxIntersects( r ) )
1130  return false;
1131 
1132  QgsGeometry g = fromRect( r );
1133  return intersects( g );
1134 }
1135 
1136 bool QgsGeometry::intersects( const QgsGeometry &geometry ) const
1137 {
1138  if ( !d->geometry || geometry.isNull() )
1139  {
1140  return false;
1141  }
1142 
1143  QgsGeos geos( d->geometry.get() );
1144  mLastError.clear();
1145  return geos.intersects( geometry.d->geometry.get(), &mLastError );
1146 }
1147 
1148 bool QgsGeometry::boundingBoxIntersects( const QgsRectangle &rectangle ) const
1149 {
1150  if ( !d->geometry )
1151  {
1152  return false;
1153  }
1154 
1155  return d->geometry->boundingBox().intersects( rectangle );
1156 }
1157 
1159 {
1160  if ( !d->geometry || geometry.isNull() )
1161  {
1162  return false;
1163  }
1164 
1165  return d->geometry->boundingBox().intersects( geometry.constGet()->boundingBox() );
1166 }
1167 
1168 bool QgsGeometry::contains( const QgsPointXY *p ) const
1169 {
1170  if ( !d->geometry || !p )
1171  {
1172  return false;
1173  }
1174 
1175  QgsPoint pt( p->x(), p->y() );
1176  QgsGeos geos( d->geometry.get() );
1177  mLastError.clear();
1178  return geos.contains( &pt, &mLastError );
1179 }
1180 
1181 bool QgsGeometry::contains( const QgsGeometry &geometry ) const
1182 {
1183  if ( !d->geometry || geometry.isNull() )
1184  {
1185  return false;
1186  }
1187 
1188  QgsGeos geos( d->geometry.get() );
1189  mLastError.clear();
1190  return geos.contains( geometry.d->geometry.get(), &mLastError );
1191 }
1192 
1193 bool QgsGeometry::disjoint( const QgsGeometry &geometry ) const
1194 {
1195  if ( !d->geometry || geometry.isNull() )
1196  {
1197  return false;
1198  }
1199 
1200  QgsGeos geos( d->geometry.get() );
1201  mLastError.clear();
1202  return geos.disjoint( geometry.d->geometry.get(), &mLastError );
1203 }
1204 
1205 bool QgsGeometry::equals( const QgsGeometry &geometry ) const
1206 {
1207  if ( !d->geometry || geometry.isNull() )
1208  {
1209  return false;
1210  }
1211 
1212  // fast check - are they shared copies of the same underlying geometry?
1213  if ( d == geometry.d )
1214  return true;
1215 
1216  // slower check - actually test the geometries
1217  return *d->geometry == *geometry.d->geometry;
1218 }
1219 
1220 bool QgsGeometry::touches( const QgsGeometry &geometry ) const
1221 {
1222  if ( !d->geometry || geometry.isNull() )
1223  {
1224  return false;
1225  }
1226 
1227  QgsGeos geos( d->geometry.get() );
1228  mLastError.clear();
1229  return geos.touches( geometry.d->geometry.get(), &mLastError );
1230 }
1231 
1232 bool QgsGeometry::overlaps( const QgsGeometry &geometry ) const
1233 {
1234  if ( !d->geometry || geometry.isNull() )
1235  {
1236  return false;
1237  }
1238 
1239  QgsGeos geos( d->geometry.get() );
1240  mLastError.clear();
1241  return geos.overlaps( geometry.d->geometry.get(), &mLastError );
1242 }
1243 
1244 bool QgsGeometry::within( const QgsGeometry &geometry ) const
1245 {
1246  if ( !d->geometry || geometry.isNull() )
1247  {
1248  return false;
1249  }
1250 
1251  QgsGeos geos( d->geometry.get() );
1252  mLastError.clear();
1253  return geos.within( geometry.d->geometry.get(), &mLastError );
1254 }
1255 
1256 bool QgsGeometry::crosses( const QgsGeometry &geometry ) const
1257 {
1258  if ( !d->geometry || geometry.isNull() )
1259  {
1260  return false;
1261  }
1262 
1263  QgsGeos geos( d->geometry.get() );
1264  mLastError.clear();
1265  return geos.crosses( geometry.d->geometry.get(), &mLastError );
1266 }
1267 
1268 QString QgsGeometry::asWkt( int precision ) const
1269 {
1270  if ( !d->geometry )
1271  {
1272  return QString();
1273  }
1274  return d->geometry->asWkt( precision );
1275 }
1276 
1277 QString QgsGeometry::asJson( int precision ) const
1278 {
1279  return QString::fromStdString( asJsonObject( precision ).dump() );
1280 }
1281 
1283 {
1284  if ( !d->geometry )
1285  {
1286  return nullptr;
1287  }
1288  return d->geometry->asJsonObject( precision );
1289 
1290 }
1291 
1293 {
1294  switch ( destType )
1295  {
1297  return convertToPoint( destMultipart );
1298 
1300  return convertToLine( destMultipart );
1301 
1303  return convertToPolygon( destMultipart );
1304 
1305  default:
1306  return QgsGeometry();
1307  }
1308 }
1309 
1311 {
1312  if ( !d->geometry )
1313  {
1314  return false;
1315  }
1316 
1317  if ( isMultipart() ) //already multitype, no need to convert
1318  {
1319  return true;
1320  }
1321 
1322  std::unique_ptr< QgsAbstractGeometry >geom = QgsGeometryFactory::geomFromWkbType( QgsWkbTypes::multiType( d->geometry->wkbType() ) );
1323  QgsGeometryCollection *multiGeom = qgsgeometry_cast<QgsGeometryCollection *>( geom.get() );
1324  if ( !multiGeom )
1325  {
1326  return false;
1327  }
1328 
1329  //try to avoid cloning existing geometry whenever we can
1330 
1331  //want to see a magic trick?... gather round kiddies...
1332  detach(); // maybe a clone, hopefully not if we're the only ref to the private data
1333  // now we cheat a bit and steal the private geometry and add it direct to the multigeom
1334  // we can do this because we're the only ref to this geometry, guaranteed by the detach call above
1335  multiGeom->addGeometry( d->geometry.release() );
1336  // and replace it with the multi geometry.
1337  // TADA! a clone free conversion in some cases
1338  d->geometry = std::move( geom );
1339  return true;
1340 }
1341 
1343 {
1344  if ( !d->geometry )
1345  {
1346  return false;
1347  }
1348 
1349  if ( !isMultipart() ) //already single part, no need to convert
1350  {
1351  return true;
1352  }
1353 
1355  if ( !multiGeom || multiGeom->partCount() < 1 )
1356  return false;
1357 
1358  std::unique_ptr< QgsAbstractGeometry > firstPart( multiGeom->geometryN( 0 )->clone() );
1359  reset( std::move( firstPart ) );
1360  return true;
1361 }
1362 
1363 
1365 {
1366  const QgsGeometryCollection *origGeom = qgsgeometry_cast<const QgsGeometryCollection *>( constGet() );
1367  if ( !origGeom )
1368  return false;
1369 
1370  std::unique_ptr<QgsGeometryCollection> resGeom;
1371  switch ( geomType )
1372  {
1374  resGeom = qgis::make_unique<QgsMultiPoint>();
1375  break;
1377  resGeom = qgis::make_unique<QgsMultiLineString>();
1378  break;
1380  resGeom = qgis::make_unique<QgsMultiPolygon>();
1381  break;
1382  default:
1383  break;
1384  }
1385  if ( !resGeom )
1386  return false;
1387 
1388  resGeom->reserve( origGeom->numGeometries() );
1389  for ( int i = 0; i < origGeom->numGeometries(); ++i )
1390  {
1391  const QgsAbstractGeometry *g = origGeom->geometryN( i );
1392  if ( QgsWkbTypes::geometryType( g->wkbType() ) == geomType )
1393  resGeom->addGeometry( g->clone() );
1394  }
1395 
1396  set( resGeom.release() );
1397  return true;
1398 }
1399 
1400 
1402 {
1403  if ( !d->geometry || QgsWkbTypes::flatType( d->geometry->wkbType() ) != QgsWkbTypes::Point )
1404  {
1405  return QgsPointXY();
1406  }
1407  QgsPoint *pt = qgsgeometry_cast<QgsPoint *>( d->geometry.get() );
1408  if ( !pt )
1409  {
1410  return QgsPointXY();
1411  }
1412 
1413  return QgsPointXY( pt->x(), pt->y() );
1414 }
1415 
1417 {
1418  QgsPolylineXY polyLine;
1419  if ( !d->geometry )
1420  {
1421  return polyLine;
1422  }
1423 
1424  bool doSegmentation = ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::CompoundCurve
1426  std::unique_ptr< QgsLineString > segmentizedLine;
1427  QgsLineString *line = nullptr;
1428  if ( doSegmentation )
1429  {
1430  QgsCurve *curve = qgsgeometry_cast<QgsCurve *>( d->geometry.get() );
1431  if ( !curve )
1432  {
1433  return polyLine;
1434  }
1435  segmentizedLine.reset( curve->curveToLine() );
1436  line = segmentizedLine.get();
1437  }
1438  else
1439  {
1440  line = qgsgeometry_cast<QgsLineString *>( d->geometry.get() );
1441  if ( !line )
1442  {
1443  return polyLine;
1444  }
1445  }
1446 
1447  int nVertices = line->numPoints();
1448  polyLine.resize( nVertices );
1449  QgsPointXY *data = polyLine.data();
1450  const double *xData = line->xData();
1451  const double *yData = line->yData();
1452  for ( int i = 0; i < nVertices; ++i )
1453  {
1454  data->setX( *xData++ );
1455  data->setY( *yData++ );
1456  data++;
1457  }
1458 
1459  return polyLine;
1460 }
1461 
1463 {
1464  if ( !d->geometry )
1465  return QgsPolygonXY();
1466 
1467  bool doSegmentation = ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::CurvePolygon );
1468 
1469  QgsPolygon *p = nullptr;
1470  std::unique_ptr< QgsPolygon > segmentized;
1471  if ( doSegmentation )
1472  {
1473  QgsCurvePolygon *curvePoly = qgsgeometry_cast<QgsCurvePolygon *>( d->geometry.get() );
1474  if ( !curvePoly )
1475  {
1476  return QgsPolygonXY();
1477  }
1478  segmentized.reset( curvePoly->toPolygon() );
1479  p = segmentized.get();
1480  }
1481  else
1482  {
1483  p = qgsgeometry_cast<QgsPolygon *>( d->geometry.get() );
1484  }
1485 
1486  if ( !p )
1487  {
1488  return QgsPolygonXY();
1489  }
1490 
1491  QgsPolygonXY polygon;
1492  convertPolygon( *p, polygon );
1493 
1494  return polygon;
1495 }
1496 
1498 {
1499  if ( !d->geometry || QgsWkbTypes::flatType( d->geometry->wkbType() ) != QgsWkbTypes::MultiPoint )
1500  {
1501  return QgsMultiPointXY();
1502  }
1503 
1504  const QgsMultiPoint *mp = qgsgeometry_cast<QgsMultiPoint *>( d->geometry.get() );
1505  if ( !mp )
1506  {
1507  return QgsMultiPointXY();
1508  }
1509 
1510  int nPoints = mp->numGeometries();
1511  QgsMultiPointXY multiPoint( nPoints );
1512  for ( int i = 0; i < nPoints; ++i )
1513  {
1514  const QgsPoint *pt = static_cast<const QgsPoint *>( mp->geometryN( i ) );
1515  multiPoint[i].setX( pt->x() );
1516  multiPoint[i].setY( pt->y() );
1517  }
1518  return multiPoint;
1519 }
1520 
1522 {
1523  if ( !d->geometry )
1524  {
1525  return QgsMultiPolylineXY();
1526  }
1527 
1528  QgsGeometryCollection *geomCollection = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
1529  if ( !geomCollection )
1530  {
1531  return QgsMultiPolylineXY();
1532  }
1533 
1534  int nLines = geomCollection->numGeometries();
1535  if ( nLines < 1 )
1536  {
1537  return QgsMultiPolylineXY();
1538  }
1539 
1540  QgsMultiPolylineXY mpl;
1541  mpl.reserve( nLines );
1542  for ( int i = 0; i < nLines; ++i )
1543  {
1544  const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( geomCollection->geometryN( i ) );
1545  std::unique_ptr< QgsLineString > segmentized;
1546  if ( !line )
1547  {
1548  const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( geomCollection->geometryN( i ) );
1549  if ( !curve )
1550  {
1551  continue;
1552  }
1553  segmentized.reset( curve->curveToLine() );
1554  line = segmentized.get();
1555  }
1556 
1557  QgsPolylineXY polyLine;
1558  int nVertices = line->numPoints();
1559  polyLine.resize( nVertices );
1560  QgsPointXY *data = polyLine.data();
1561  const double *xData = line->xData();
1562  const double *yData = line->yData();
1563  for ( int i = 0; i < nVertices; ++i )
1564  {
1565  data->setX( *xData++ );
1566  data->setY( *yData++ );
1567  data++;
1568  }
1569  mpl.append( polyLine );
1570  }
1571  return mpl;
1572 }
1573 
1575 {
1576  if ( !d->geometry )
1577  {
1578  return QgsMultiPolygonXY();
1579  }
1580 
1581  QgsGeometryCollection *geomCollection = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
1582  if ( !geomCollection )
1583  {
1584  return QgsMultiPolygonXY();
1585  }
1586 
1587  int nPolygons = geomCollection->numGeometries();
1588  if ( nPolygons < 1 )
1589  {
1590  return QgsMultiPolygonXY();
1591  }
1592 
1593  QgsMultiPolygonXY mp;
1594  for ( int i = 0; i < nPolygons; ++i )
1595  {
1596  const QgsPolygon *polygon = qgsgeometry_cast<const QgsPolygon *>( geomCollection->geometryN( i ) );
1597  if ( !polygon )
1598  {
1599  const QgsCurvePolygon *cPolygon = qgsgeometry_cast<const QgsCurvePolygon *>( geomCollection->geometryN( i ) );
1600  if ( cPolygon )
1601  {
1602  polygon = cPolygon->toPolygon();
1603  }
1604  else
1605  {
1606  continue;
1607  }
1608  }
1609 
1610  QgsPolygonXY poly;
1611  convertPolygon( *polygon, poly );
1612  mp.append( poly );
1613  }
1614  return mp;
1615 }
1616 
1617 double QgsGeometry::area() const
1618 {
1619  if ( !d->geometry )
1620  {
1621  return -1.0;
1622  }
1623  QgsGeos g( d->geometry.get() );
1624 
1625 #if 0
1626  //debug: compare geos area with calculation in QGIS
1627  double geosArea = g.area();
1628  double qgisArea = 0;
1629  QgsSurface *surface = qgsgeometry_cast<QgsSurface *>( d->geometry );
1630  if ( surface )
1631  {
1632  qgisArea = surface->area();
1633  }
1634 #endif
1635 
1636  mLastError.clear();
1637  return g.area( &mLastError );
1638 }
1639 
1640 double QgsGeometry::length() const
1641 {
1642  if ( !d->geometry )
1643  {
1644  return -1.0;
1645  }
1646  QgsGeos g( d->geometry.get() );
1647  mLastError.clear();
1648  return g.length( &mLastError );
1649 }
1650 
1651 double QgsGeometry::distance( const QgsGeometry &geom ) const
1652 {
1653  if ( !d->geometry || !geom.d->geometry )
1654  {
1655  return -1.0;
1656  }
1657 
1658  // avoid calling geos for trivial point-to-point distance calculations
1660  {
1661  return qgsgeometry_cast< const QgsPoint * >( d->geometry.get() )->distance( *qgsgeometry_cast< const QgsPoint * >( geom.constGet() ) );
1662  }
1663 
1664  QgsGeos g( d->geometry.get() );
1665  mLastError.clear();
1666  return g.distance( geom.d->geometry.get(), &mLastError );
1667 }
1668 
1669 double QgsGeometry::hausdorffDistance( const QgsGeometry &geom ) const
1670 {
1671  if ( !d->geometry || !geom.d->geometry )
1672  {
1673  return -1.0;
1674  }
1675 
1676  QgsGeos g( d->geometry.get() );
1677  mLastError.clear();
1678  return g.hausdorffDistance( geom.d->geometry.get(), &mLastError );
1679 }
1680 
1681 double QgsGeometry::hausdorffDistanceDensify( const QgsGeometry &geom, double densifyFraction ) const
1682 {
1683  if ( !d->geometry || !geom.d->geometry )
1684  {
1685  return -1.0;
1686  }
1687 
1688  QgsGeos g( d->geometry.get() );
1689  mLastError.clear();
1690  return g.hausdorffDistanceDensify( geom.d->geometry.get(), densifyFraction, &mLastError );
1691 }
1692 
1694 {
1695  if ( !d->geometry || d->geometry.get()->isEmpty() )
1697  return d->geometry->vertices_begin();
1698 }
1699 
1701 {
1702  if ( !d->geometry || d->geometry.get()->isEmpty() )
1704  return d->geometry->vertices_end();
1705 }
1706 
1708 {
1709  if ( !d->geometry || d->geometry.get()->isEmpty() )
1710  return QgsVertexIterator();
1711  return QgsVertexIterator( d->geometry.get() );
1712 }
1713 
1715 {
1716  if ( !d->geometry )
1718 
1719  detach();
1720  return d->geometry->parts_begin();
1721 }
1722 
1724 {
1725  if ( !d->geometry )
1727  return d->geometry->parts_end();
1728 }
1729 
1731 {
1732  if ( !d->geometry )
1734  return d->geometry->const_parts_begin();
1735 }
1736 
1738 {
1739  if ( !d->geometry )
1741  return d->geometry->const_parts_end();
1742 }
1743 
1745 {
1746  if ( !d->geometry )
1747  return QgsGeometryPartIterator();
1748 
1749  detach();
1750  return QgsGeometryPartIterator( d->geometry.get() );
1751 }
1752 
1754 {
1755  if ( !d->geometry )
1757 
1758  return QgsGeometryConstPartIterator( d->geometry.get() );
1759 }
1760 
1761 QgsGeometry QgsGeometry::buffer( double distance, int segments ) const
1762 {
1763  if ( !d->geometry )
1764  {
1765  return QgsGeometry();
1766  }
1767 
1768  QgsGeos g( d->geometry.get() );
1769  mLastError.clear();
1770  std::unique_ptr<QgsAbstractGeometry> geom( g.buffer( distance, segments, &mLastError ) );
1771  if ( !geom )
1772  {
1773  QgsGeometry result;
1774  result.mLastError = mLastError;
1775  return result;
1776  }
1777  return QgsGeometry( std::move( geom ) );
1778 }
1779 
1780 QgsGeometry QgsGeometry::buffer( double distance, int segments, EndCapStyle endCapStyle, JoinStyle joinStyle, double miterLimit ) const
1781 {
1782  if ( !d->geometry )
1783  {
1784  return QgsGeometry();
1785  }
1786 
1787  QgsGeos g( d->geometry.get() );
1788  mLastError.clear();
1789  QgsAbstractGeometry *geom = g.buffer( distance, segments, endCapStyle, joinStyle, miterLimit, &mLastError );
1790  if ( !geom )
1791  {
1792  QgsGeometry result;
1793  result.mLastError = mLastError;
1794  return result;
1795  }
1796  return QgsGeometry( geom );
1797 }
1798 
1799 QgsGeometry QgsGeometry::offsetCurve( double distance, int segments, JoinStyle joinStyle, double miterLimit ) const
1800 {
1801  if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
1802  {
1803  return QgsGeometry();
1804  }
1805 
1806  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
1807  {
1808  const QVector<QgsGeometry> parts = asGeometryCollection();
1809  QVector<QgsGeometry> results;
1810  results.reserve( parts.count() );
1811  for ( const QgsGeometry &part : parts )
1812  {
1813  QgsGeometry result = part.offsetCurve( distance, segments, joinStyle, miterLimit );
1814  if ( !result.isNull() )
1815  results << result;
1816  }
1817  if ( results.isEmpty() )
1818  return QgsGeometry();
1819 
1820  QgsGeometry first = results.takeAt( 0 );
1821  for ( const QgsGeometry &result : qgis::as_const( results ) )
1822  {
1823  first.addPart( result );
1824  }
1825  return first;
1826  }
1827  else
1828  {
1829  QgsGeos geos( d->geometry.get() );
1830  mLastError.clear();
1831 
1832  // GEOS can flip the curve orientation in some circumstances. So record previous orientation and correct if required
1833  const QgsCurve::Orientation prevOrientation = qgsgeometry_cast< const QgsCurve * >( d->geometry.get() )->orientation();
1834 
1835  std::unique_ptr< QgsAbstractGeometry > offsetGeom( geos.offsetCurve( distance, segments, joinStyle, miterLimit, &mLastError ) );
1836  if ( !offsetGeom )
1837  {
1838  QgsGeometry result;
1839  result.mLastError = mLastError;
1840  return result;
1841  }
1842 
1843  if ( const QgsCurve *offsetCurve = qgsgeometry_cast< const QgsCurve * >( offsetGeom.get() ) )
1844  {
1845  const QgsCurve::Orientation newOrientation = offsetCurve->orientation();
1846  if ( newOrientation != prevOrientation )
1847  {
1848  // GEOS has flipped line orientation, flip it back
1849  std::unique_ptr< QgsAbstractGeometry > flipped( offsetCurve->reversed() );
1850  offsetGeom = std::move( flipped );
1851  }
1852  }
1853  return QgsGeometry( std::move( offsetGeom ) );
1854  }
1855 }
1856 
1857 QgsGeometry QgsGeometry::singleSidedBuffer( double distance, int segments, BufferSide side, JoinStyle joinStyle, double miterLimit ) const
1858 {
1859  if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
1860  {
1861  return QgsGeometry();
1862  }
1863 
1864  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
1865  {
1866  const QVector<QgsGeometry> parts = asGeometryCollection();
1867  QVector<QgsGeometry> results;
1868  results.reserve( parts.count() );
1869  for ( const QgsGeometry &part : parts )
1870  {
1871  QgsGeometry result = part.singleSidedBuffer( distance, segments, side, joinStyle, miterLimit );
1872  if ( !result.isNull() )
1873  results << result;
1874  }
1875  if ( results.isEmpty() )
1876  return QgsGeometry();
1877 
1878  QgsGeometry first = results.takeAt( 0 );
1879  for ( const QgsGeometry &result : qgis::as_const( results ) )
1880  {
1881  first.addPart( result );
1882  }
1883  return first;
1884  }
1885  else
1886  {
1887  QgsGeos geos( d->geometry.get() );
1888  mLastError.clear();
1889  std::unique_ptr< QgsAbstractGeometry > bufferGeom = geos.singleSidedBuffer( distance, segments, side,
1890  joinStyle, miterLimit, &mLastError );
1891  if ( !bufferGeom )
1892  {
1893  QgsGeometry result;
1894  result.mLastError = mLastError;
1895  return result;
1896  }
1897  return QgsGeometry( std::move( bufferGeom ) );
1898  }
1899 }
1900 
1901 QgsGeometry QgsGeometry::taperedBuffer( double startWidth, double endWidth, int segments ) const
1902 {
1903  QgsInternalGeometryEngine engine( *this );
1904 
1905  return engine.taperedBuffer( startWidth, endWidth, segments );
1906 }
1907 
1909 {
1910  QgsInternalGeometryEngine engine( *this );
1911 
1912  return engine.variableWidthBufferByM( segments );
1913 }
1914 
1915 QgsGeometry QgsGeometry::extendLine( double startDistance, double endDistance ) const
1916 {
1917  if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
1918  {
1919  return QgsGeometry();
1920  }
1921 
1922  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
1923  {
1924  const QVector<QgsGeometry> parts = asGeometryCollection();
1925  QVector<QgsGeometry> results;
1926  results.reserve( parts.count() );
1927  for ( const QgsGeometry &part : parts )
1928  {
1929  QgsGeometry result = part.extendLine( startDistance, endDistance );
1930  if ( !result.isNull() )
1931  results << result;
1932  }
1933  if ( results.isEmpty() )
1934  return QgsGeometry();
1935 
1936  QgsGeometry first = results.takeAt( 0 );
1937  for ( const QgsGeometry &result : qgis::as_const( results ) )
1938  {
1939  first.addPart( result );
1940  }
1941  return first;
1942  }
1943  else
1944  {
1945  QgsLineString *line = qgsgeometry_cast< QgsLineString * >( d->geometry.get() );
1946  if ( !line )
1947  return QgsGeometry();
1948 
1949  std::unique_ptr< QgsLineString > newLine( line->clone() );
1950  newLine->extend( startDistance, endDistance );
1951  return QgsGeometry( std::move( newLine ) );
1952  }
1953 }
1954 
1955 QgsGeometry QgsGeometry::simplify( double tolerance ) const
1956 {
1957  if ( !d->geometry )
1958  {
1959  return QgsGeometry();
1960  }
1961 
1962  QgsGeos geos( d->geometry.get() );
1963  mLastError.clear();
1964  std::unique_ptr< QgsAbstractGeometry > simplifiedGeom( geos.simplify( tolerance, &mLastError ) );
1965  if ( !simplifiedGeom )
1966  {
1967  QgsGeometry result;
1968  result.mLastError = mLastError;
1969  return result;
1970  }
1971  return QgsGeometry( std::move( simplifiedGeom ) );
1972 }
1973 
1974 QgsGeometry QgsGeometry::densifyByCount( int extraNodesPerSegment ) const
1975 {
1976  QgsInternalGeometryEngine engine( *this );
1977 
1978  return engine.densifyByCount( extraNodesPerSegment );
1979 }
1980 
1982 {
1983  QgsInternalGeometryEngine engine( *this );
1984 
1985  return engine.densifyByDistance( distance );
1986 }
1987 
1989 {
1990  if ( !d->geometry )
1991  {
1992  return QgsGeometry();
1993  }
1994 
1995  // avoid calling geos for trivial point centroids
1996  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::Point )
1997  {
1998  QgsGeometry c = *this;
1999  c.get()->dropZValue();
2000  c.get()->dropMValue();
2001  return c;
2002  }
2003 
2004  QgsGeos geos( d->geometry.get() );
2005 
2006  mLastError.clear();
2007  QgsGeometry result( geos.centroid( &mLastError ) );
2008  result.mLastError = mLastError;
2009  return result;
2010 }
2011 
2013 {
2014  if ( !d->geometry )
2015  {
2016  return QgsGeometry();
2017  }
2018 
2019  QgsGeos geos( d->geometry.get() );
2020 
2021  mLastError.clear();
2022  QgsGeometry result( geos.pointOnSurface( &mLastError ) );
2023  result.mLastError = mLastError;
2024  return result;
2025 }
2026 
2027 QgsGeometry QgsGeometry::poleOfInaccessibility( double precision, double *distanceToBoundary ) const
2028 {
2029  QgsInternalGeometryEngine engine( *this );
2030 
2031  return engine.poleOfInaccessibility( precision, distanceToBoundary );
2032 }
2033 
2035 {
2036  if ( !d->geometry )
2037  {
2038  return QgsGeometry();
2039  }
2040  QgsGeos geos( d->geometry.get() );
2041  mLastError.clear();
2042  std::unique_ptr< QgsAbstractGeometry > cHull( geos.convexHull( &mLastError ) );
2043  if ( !cHull )
2044  {
2045  QgsGeometry geom;
2046  geom.mLastError = mLastError;
2047  return geom;
2048  }
2049  return QgsGeometry( std::move( cHull ) );
2050 }
2051 
2052 QgsGeometry QgsGeometry::voronoiDiagram( const QgsGeometry &extent, double tolerance, bool edgesOnly ) const
2053 {
2054  if ( !d->geometry )
2055  {
2056  return QgsGeometry();
2057  }
2058 
2059  QgsGeos geos( d->geometry.get() );
2060  mLastError.clear();
2061  QgsGeometry result = geos.voronoiDiagram( extent.constGet(), tolerance, edgesOnly, &mLastError );
2062  result.mLastError = mLastError;
2063  return result;
2064 }
2065 
2066 QgsGeometry QgsGeometry::delaunayTriangulation( double tolerance, bool edgesOnly ) const
2067 {
2068  if ( !d->geometry )
2069  {
2070  return QgsGeometry();
2071  }
2072 
2073  QgsGeos geos( d->geometry.get() );
2074  mLastError.clear();
2075  QgsGeometry result = geos.delaunayTriangulation( tolerance, edgesOnly );
2076  result.mLastError = mLastError;
2077  return result;
2078 }
2079 
2081 {
2082  if ( !d->geometry )
2083  {
2084  return QgsGeometry();
2085  }
2086 
2087  const QgsAbstractGeometry *geom = d->geometry.get();
2088  std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
2089  if ( QgsWkbTypes::isCurvedType( d->geometry->wkbType() ) )
2090  {
2091  segmentizedCopy.reset( d->geometry->segmentize() );
2092  geom = segmentizedCopy.get();
2093  }
2094 
2095  QgsGeos geos( geom );
2096  mLastError.clear();
2097  std::unique_ptr< QgsAbstractGeometry > result( geos.subdivide( maxNodes, &mLastError ) );
2098  if ( !result )
2099  {
2100  QgsGeometry geom;
2101  geom.mLastError = mLastError;
2102  return geom;
2103  }
2104  return QgsGeometry( std::move( result ) );
2105 }
2106 
2108 {
2109  if ( !d->geometry )
2110  {
2111  return QgsGeometry();
2112  }
2113 
2114  QgsGeometry line = *this;
2115  if ( type() == QgsWkbTypes::PointGeometry )
2116  return QgsGeometry();
2117  else if ( type() == QgsWkbTypes::PolygonGeometry )
2118  {
2119  line = QgsGeometry( d->geometry->boundary() );
2120  }
2121 
2122  const QgsCurve *curve = nullptr;
2123  if ( line.isMultipart() )
2124  {
2125  // if multi part, just use first part
2126  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( line.constGet() );
2127  if ( collection && collection->numGeometries() > 0 )
2128  {
2129  curve = qgsgeometry_cast< const QgsCurve * >( collection->geometryN( 0 ) );
2130  }
2131  }
2132  else
2133  {
2134  curve = qgsgeometry_cast< const QgsCurve * >( line.constGet() );
2135  }
2136  if ( !curve )
2137  return QgsGeometry();
2138 
2139  std::unique_ptr< QgsPoint > result( curve->interpolatePoint( distance ) );
2140  if ( !result )
2141  {
2142  return QgsGeometry();
2143  }
2144  return QgsGeometry( std::move( result ) );
2145 }
2146 
2147 double QgsGeometry::lineLocatePoint( const QgsGeometry &point ) const
2148 {
2149  if ( type() != QgsWkbTypes::LineGeometry )
2150  return -1;
2151 
2152  if ( QgsWkbTypes::flatType( point.wkbType() ) != QgsWkbTypes::Point )
2153  return -1;
2154 
2155  QgsGeometry segmentized = *this;
2157  {
2158  segmentized = QgsGeometry( static_cast< QgsCurve * >( d->geometry.get() )->segmentize() );
2159  }
2160 
2161  QgsGeos geos( d->geometry.get() );
2162  mLastError.clear();
2163  return geos.lineLocatePoint( *( static_cast< QgsPoint * >( point.d->geometry.get() ) ), &mLastError );
2164 }
2165 
2167 {
2168  if ( !d->geometry )
2169  return 0.0;
2170 
2171  // always operate on segmentized geometries
2172  QgsGeometry segmentized = *this;
2174  {
2175  segmentized = QgsGeometry( static_cast< QgsCurve * >( d->geometry.get() )->segmentize() );
2176  }
2177 
2178  QgsVertexId previous;
2179  QgsVertexId next;
2180  if ( !QgsGeometryUtils::verticesAtDistance( *segmentized.constGet(), distance, previous, next ) )
2181  return 0.0;
2182 
2183  if ( previous == next )
2184  {
2185  // distance coincided exactly with a vertex
2186  QgsVertexId v2 = previous;
2187  QgsVertexId v1;
2188  QgsVertexId v3;
2189  segmentized.constGet()->adjacentVertices( v2, v1, v3 );
2190  if ( v1.isValid() && v3.isValid() )
2191  {
2192  QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
2193  QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
2194  QgsPoint p3 = segmentized.constGet()->vertexAt( v3 );
2195  double angle1 = QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2196  double angle2 = QgsGeometryUtils::lineAngle( p2.x(), p2.y(), p3.x(), p3.y() );
2197  return QgsGeometryUtils::averageAngle( angle1, angle2 );
2198  }
2199  else if ( v3.isValid() )
2200  {
2201  QgsPoint p1 = segmentized.constGet()->vertexAt( v2 );
2202  QgsPoint p2 = segmentized.constGet()->vertexAt( v3 );
2203  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2204  }
2205  else
2206  {
2207  QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
2208  QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
2209  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2210  }
2211  }
2212  else
2213  {
2214  QgsPoint p1 = segmentized.constGet()->vertexAt( previous );
2215  QgsPoint p2 = segmentized.constGet()->vertexAt( next );
2216  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2217  }
2218 }
2219 
2221 {
2222  if ( !d->geometry || geometry.isNull() )
2223  {
2224  return QgsGeometry();
2225  }
2226 
2227  QgsGeos geos( d->geometry.get() );
2228 
2229  mLastError.clear();
2230  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.intersection( geometry.d->geometry.get(), &mLastError ) );
2231 
2232  if ( !resultGeom )
2233  {
2234  QgsGeometry geom;
2235  geom.mLastError = mLastError;
2236  return geom;
2237  }
2238 
2239  return QgsGeometry( std::move( resultGeom ) );
2240 }
2241 
2243 {
2244  if ( !d->geometry || geometry.isNull() )
2245  {
2246  return QgsGeometry();
2247  }
2248 
2249  QgsGeos geos( d->geometry.get() );
2250  mLastError.clear();
2251  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.combine( geometry.d->geometry.get(), &mLastError ) );
2252  if ( !resultGeom )
2253  {
2254  QgsGeometry geom;
2255  geom.mLastError = mLastError;
2256  return geom;
2257  }
2258  return QgsGeometry( std::move( resultGeom ) );
2259 }
2260 
2262 {
2263  if ( !d->geometry )
2264  {
2265  return QgsGeometry();
2266  }
2267 
2268  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::LineString )
2269  {
2270  // special case - a single linestring was passed
2271  return QgsGeometry( *this );
2272  }
2273 
2274  QgsGeos geos( d->geometry.get() );
2275  mLastError.clear();
2276  QgsGeometry result = geos.mergeLines( &mLastError );
2277  result.mLastError = mLastError;
2278  return result;
2279 }
2280 
2282 {
2283  if ( !d->geometry || geometry.isNull() )
2284  {
2285  return QgsGeometry();
2286  }
2287 
2288  QgsGeos geos( d->geometry.get() );
2289 
2290  mLastError.clear();
2291  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.difference( geometry.d->geometry.get(), &mLastError ) );
2292  if ( !resultGeom )
2293  {
2294  QgsGeometry geom;
2295  geom.mLastError = mLastError;
2296  return geom;
2297  }
2298  return QgsGeometry( std::move( resultGeom ) );
2299 }
2300 
2302 {
2303  if ( !d->geometry || geometry.isNull() )
2304  {
2305  return QgsGeometry();
2306  }
2307 
2308  QgsGeos geos( d->geometry.get() );
2309 
2310  mLastError.clear();
2311  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.symDifference( geometry.d->geometry.get(), &mLastError ) );
2312  if ( !resultGeom )
2313  {
2314  QgsGeometry geom;
2315  geom.mLastError = mLastError;
2316  return geom;
2317  }
2318  return QgsGeometry( std::move( resultGeom ) );
2319 }
2320 
2321 QgsGeometry QgsGeometry::extrude( double x, double y )
2322 {
2323  QgsInternalGeometryEngine engine( *this );
2324 
2325  return engine.extrude( x, y );
2326 }
2327 
2328 QByteArray QgsGeometry::asWkb() const
2329 {
2330  return d->geometry ? d->geometry->asWkb() : QByteArray();
2331 }
2332 
2333 QVector<QgsGeometry> QgsGeometry::asGeometryCollection() const
2334 {
2335  QVector<QgsGeometry> geometryList;
2336  if ( !d->geometry )
2337  {
2338  return geometryList;
2339  }
2340 
2342  if ( gc )
2343  {
2344  int numGeom = gc->numGeometries();
2345  geometryList.reserve( numGeom );
2346  for ( int i = 0; i < numGeom; ++i )
2347  {
2348  geometryList.append( QgsGeometry( gc->geometryN( i )->clone() ) );
2349  }
2350  }
2351  else //a singlepart geometry
2352  {
2353  geometryList.append( *this );
2354  }
2355 
2356  return geometryList;
2357 }
2358 
2359 QPointF QgsGeometry::asQPointF() const
2360 {
2361  QgsPointXY point = asPoint();
2362  return point.toQPointF();
2363 }
2364 
2365 QPolygonF QgsGeometry::asQPolygonF() const
2366 {
2367  QPolygonF result;
2368  QgsPolylineXY polyline;
2370  if ( type == QgsWkbTypes::LineString || type == QgsWkbTypes::LineString25D )
2371  {
2372  polyline = asPolyline();
2373  }
2374  else if ( type == QgsWkbTypes::Polygon || type == QgsWkbTypes::Polygon25D )
2375  {
2376  QgsPolygonXY polygon = asPolygon();
2377  if ( polygon.empty() )
2378  return result;
2379  polyline = polygon.at( 0 );
2380  }
2381  else
2382  {
2383  return result;
2384  }
2385 
2386  result.reserve( polyline.count() );
2387  for ( const QgsPointXY &p : qgis::as_const( polyline ) )
2388  {
2389  result << p.toQPointF();
2390  }
2391  return result;
2392 }
2393 
2394 bool QgsGeometry::deleteRing( int ringNum, int partNum )
2395 {
2396  if ( !d->geometry )
2397  {
2398  return false;
2399  }
2400 
2401  detach();
2402  bool ok = QgsGeometryEditUtils::deleteRing( d->geometry.get(), ringNum, partNum );
2403  return ok;
2404 }
2405 
2406 bool QgsGeometry::deletePart( int partNum )
2407 {
2408  if ( !d->geometry )
2409  {
2410  return false;
2411  }
2412 
2413  if ( !isMultipart() && partNum < 1 )
2414  {
2415  set( nullptr );
2416  return true;
2417  }
2418 
2419  detach();
2420  bool ok = QgsGeometryEditUtils::deletePart( d->geometry.get(), partNum );
2421  return ok;
2422 }
2423 
2424 int QgsGeometry::avoidIntersections( const QList<QgsVectorLayer *> &avoidIntersectionsLayers, const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures )
2425 {
2426  if ( !d->geometry )
2427  {
2428  return 1;
2429  }
2430 
2431  std::unique_ptr< QgsAbstractGeometry > diffGeom = QgsGeometryEditUtils::avoidIntersections( *( d->geometry ), avoidIntersectionsLayers, ignoreFeatures );
2432  if ( diffGeom )
2433  {
2434  reset( std::move( diffGeom ) );
2435  }
2436  return 0;
2437 }
2438 
2439 
2441 {
2442  if ( !d->geometry )
2443  return QgsGeometry();
2444 
2445  mLastError.clear();
2446  std::unique_ptr< QgsAbstractGeometry > g( _qgis_lwgeom_make_valid( d->geometry.get(), mLastError ) );
2447 
2448  QgsGeometry result = QgsGeometry( std::move( g ) );
2449  result.mLastError = mLastError;
2450  return result;
2451 }
2452 
2454 {
2455  if ( !d->geometry )
2456  return QgsGeometry();
2457 
2458  if ( isMultipart() )
2459  {
2460  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( d->geometry.get() );
2461  std::unique_ptr< QgsGeometryCollection > newCollection( collection->createEmptyWithSameType() );
2462  newCollection->reserve( collection->numGeometries() );
2463  for ( int i = 0; i < collection->numGeometries(); ++i )
2464  {
2465  const QgsAbstractGeometry *g = collection->geometryN( i );
2466  if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( g ) )
2467  {
2468  std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2469  corrected->forceRHR();
2470  newCollection->addGeometry( corrected.release() );
2471  }
2472  else
2473  {
2474  newCollection->addGeometry( g->clone() );
2475  }
2476  }
2477  return QgsGeometry( std::move( newCollection ) );
2478  }
2479  else
2480  {
2481  if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( d->geometry.get() ) )
2482  {
2483  std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2484  corrected->forceRHR();
2485  return QgsGeometry( std::move( corrected ) );
2486  }
2487  else
2488  {
2489  // not a curve polygon, so return unchanged
2490  return *this;
2491  }
2492  }
2493 }
2494 
2495 
2496 void QgsGeometry::validateGeometry( QVector<QgsGeometry::Error> &errors, const ValidationMethod method, const QgsGeometry::ValidityFlags flags ) const
2497 {
2498  errors.clear();
2499  if ( !d->geometry )
2500  return;
2501 
2502  // avoid expensive calcs for trivial point geometries
2504  {
2505  return;
2506  }
2507 
2508  switch ( method )
2509  {
2510  case ValidatorQgisInternal:
2511  QgsGeometryValidator::validateGeometry( *this, errors, method );
2512  return;
2513 
2514  case ValidatorGeos:
2515  {
2516  QgsGeos geos( d->geometry.get() );
2517  QString error;
2518  QgsGeometry errorLoc;
2519  if ( !geos.isValid( &error, flags & FlagAllowSelfTouchingHoles, &errorLoc ) )
2520  {
2521  if ( errorLoc.isNull() )
2522  {
2523  errors.append( QgsGeometry::Error( error ) );
2524  }
2525  else
2526  {
2527  const QgsPointXY point = errorLoc.asPoint();
2528  errors.append( QgsGeometry::Error( error, point ) );
2529  }
2530  return;
2531  }
2532  }
2533  }
2534 }
2535 
2536 bool QgsGeometry::isGeosValid( const QgsGeometry::ValidityFlags flags ) const
2537 {
2538  if ( !d->geometry )
2539  {
2540  return false;
2541  }
2542 
2543  return d->geometry->isValid( mLastError, static_cast< int >( flags ) );
2544 }
2545 
2547 {
2548  if ( !d->geometry )
2549  return false;
2550 
2551  QgsGeos geos( d->geometry.get() );
2552  mLastError.clear();
2553  return geos.isSimple( &mLastError );
2554 }
2555 
2557 {
2558  if ( !d->geometry || !g.d->geometry )
2559  {
2560  return false;
2561  }
2562 
2563  // fast check - are they shared copies of the same underlying geometry?
2564  if ( d == g.d )
2565  return true;
2566 
2567  // avoid calling geos for trivial point case
2568  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::Point
2569  && QgsWkbTypes::flatType( g.d->geometry->wkbType() ) == QgsWkbTypes::Point )
2570  {
2571  return equals( g );
2572  }
2573 
2574  // another nice fast check upfront -- if the bounding boxes aren't equal, the geometries themselves can't be equal!
2575  if ( d->geometry->boundingBox() != g.d->geometry->boundingBox() )
2576  return false;
2577 
2578  QgsGeos geos( d->geometry.get() );
2579  mLastError.clear();
2580  return geos.isEqual( g.d->geometry.get(), &mLastError );
2581 }
2582 
2583 QgsGeometry QgsGeometry::unaryUnion( const QVector<QgsGeometry> &geometries )
2584 {
2585  QgsGeos geos( nullptr );
2586 
2587  QString error;
2588  std::unique_ptr< QgsAbstractGeometry > geom( geos.combine( geometries, &error ) );
2589  QgsGeometry result( std::move( geom ) );
2590  result.mLastError = error;
2591  return result;
2592 }
2593 
2594 QgsGeometry QgsGeometry::polygonize( const QVector<QgsGeometry> &geometryList )
2595 {
2596  QgsGeos geos( nullptr );
2597 
2598  QVector<const QgsAbstractGeometry *> geomV2List;
2599  for ( const QgsGeometry &g : geometryList )
2600  {
2601  if ( !( g.isNull() ) )
2602  {
2603  geomV2List.append( g.constGet() );
2604  }
2605  }
2606 
2607  QString error;
2608  QgsGeometry result = geos.polygonize( geomV2List, &error );
2609  result.mLastError = error;
2610  return result;
2611 }
2612 
2614 {
2616  {
2617  return;
2618  }
2619 
2620  std::unique_ptr< QgsAbstractGeometry > straightGeom( d->geometry->segmentize( tolerance, toleranceType ) );
2621  reset( std::move( straightGeom ) );
2622 }
2623 
2625 {
2626  if ( !d->geometry )
2627  {
2628  return false;
2629  }
2630 
2631  return d->geometry->hasCurvedSegments();
2632 }
2633 
2635 {
2636  if ( !d->geometry )
2637  {
2639  }
2640 
2641  detach();
2642  d->geometry->transform( ct, direction, transformZ );
2643  return QgsGeometry::Success;
2644 }
2645 
2646 QgsGeometry::OperationResult QgsGeometry::transform( const QTransform &ct, double zTranslate, double zScale, double mTranslate, double mScale )
2647 {
2648  if ( !d->geometry )
2649  {
2651  }
2652 
2653  detach();
2654  d->geometry->transform( ct, zTranslate, zScale, mTranslate, mScale );
2655  return QgsGeometry::Success;
2656 }
2657 
2659 {
2660  if ( d->geometry )
2661  {
2662  detach();
2663  d->geometry->transform( mtp.transform() );
2664  }
2665 }
2666 
2668 {
2669  if ( !d->geometry || rectangle.isNull() || rectangle.isEmpty() )
2670  {
2671  return QgsGeometry();
2672  }
2673 
2674  QgsGeos geos( d->geometry.get() );
2675  mLastError.clear();
2676  std::unique_ptr< QgsAbstractGeometry > resultGeom = geos.clip( rectangle, &mLastError );
2677  if ( !resultGeom )
2678  {
2679  QgsGeometry result;
2680  result.mLastError = mLastError;
2681  return result;
2682  }
2683  return QgsGeometry( std::move( resultGeom ) );
2684 }
2685 
2686 void QgsGeometry::draw( QPainter &p ) const
2687 {
2688  if ( d->geometry )
2689  {
2690  d->geometry->draw( p );
2691  }
2692 }
2693 
2694 static bool vertexIndexInfo( const QgsAbstractGeometry *g, int vertexIndex, int &partIndex, int &ringIndex, int &vertex )
2695 {
2696  if ( vertexIndex < 0 )
2697  return false; // clearly something wrong
2698 
2699  if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
2700  {
2701  partIndex = 0;
2702  int offset = 0;
2703  for ( int i = 0; i < geomCollection->numGeometries(); ++i )
2704  {
2705  const QgsAbstractGeometry *part = geomCollection->geometryN( i );
2706 
2707  // count total number of vertices in the part
2708  int numPoints = 0;
2709  for ( int k = 0; k < part->ringCount(); ++k )
2710  numPoints += part->vertexCount( 0, k );
2711 
2712  if ( vertexIndex < numPoints )
2713  {
2714  int nothing;
2715  return vertexIndexInfo( part, vertexIndex, nothing, ringIndex, vertex ); // set ring_index + index
2716  }
2717  vertexIndex -= numPoints;
2718  offset += numPoints;
2719  partIndex++;
2720  }
2721  }
2722  else if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
2723  {
2724  const QgsCurve *ring = curvePolygon->exteriorRing();
2725  if ( vertexIndex < ring->numPoints() )
2726  {
2727  partIndex = 0;
2728  ringIndex = 0;
2729  vertex = vertexIndex;
2730  return true;
2731  }
2732  vertexIndex -= ring->numPoints();
2733  ringIndex = 1;
2734  for ( int i = 0; i < curvePolygon->numInteriorRings(); ++i )
2735  {
2736  const QgsCurve *ring = curvePolygon->interiorRing( i );
2737  if ( vertexIndex < ring->numPoints() )
2738  {
2739  partIndex = 0;
2740  vertex = vertexIndex;
2741  return true;
2742  }
2743  vertexIndex -= ring->numPoints();
2744  ringIndex += 1;
2745  }
2746  }
2747  else if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
2748  {
2749  if ( vertexIndex < curve->numPoints() )
2750  {
2751  partIndex = 0;
2752  ringIndex = 0;
2753  vertex = vertexIndex;
2754  return true;
2755  }
2756  }
2757  else if ( qgsgeometry_cast<const QgsPoint *>( g ) )
2758  {
2759  if ( vertexIndex == 0 )
2760  {
2761  partIndex = 0;
2762  ringIndex = 0;
2763  vertex = 0;
2764  return true;
2765  }
2766  }
2767 
2768  return false;
2769 }
2770 
2772 {
2773  if ( !d->geometry )
2774  {
2775  return false;
2776  }
2777 
2778  id.type = QgsVertexId::SegmentVertex;
2779 
2780  bool res = vertexIndexInfo( d->geometry.get(), nr, id.part, id.ring, id.vertex );
2781  if ( !res )
2782  return false;
2783 
2784  // now let's find out if it is a straight or circular segment
2785  const QgsAbstractGeometry *g = d->geometry.get();
2786  if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
2787  {
2788  g = geomCollection->geometryN( id.part );
2789  }
2790 
2791  if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
2792  {
2793  g = id.ring == 0 ? curvePolygon->exteriorRing() : curvePolygon->interiorRing( id.ring - 1 );
2794  }
2795 
2796  if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
2797  {
2798  QgsPoint p;
2799  res = curve->pointAt( id.vertex, p, id.type );
2800  if ( !res )
2801  return false;
2802  }
2803 
2804  return true;
2805 }
2806 
2808 {
2809  if ( !d->geometry )
2810  {
2811  return -1;
2812  }
2813  return d->geometry->vertexNumberFromVertexId( id );
2814 }
2815 
2816 QString QgsGeometry::lastError() const
2817 {
2818  return mLastError;
2819 }
2820 
2821 void QgsGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
2822 {
2823  if ( !d->geometry )
2824  return;
2825 
2826  detach();
2827 
2828  d->geometry->filterVertices( filter );
2829 }
2830 
2831 void QgsGeometry::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
2832 {
2833  if ( !d->geometry )
2834  return;
2835 
2836  detach();
2837 
2838  d->geometry->transformVertices( transform );
2839 }
2840 
2841 void QgsGeometry::convertPointList( const QVector<QgsPointXY> &input, QgsPointSequence &output )
2842 {
2843  output.clear();
2844  for ( const QgsPointXY &p : input )
2845  {
2846  output.append( QgsPoint( p ) );
2847  }
2848 }
2849 
2850 void QgsGeometry::convertPointList( const QgsPointSequence &input, QVector<QgsPointXY> &output )
2851 {
2852  output.clear();
2853  for ( const QgsPoint &p : input )
2854  {
2855  output.append( QgsPointXY( p.x(), p.y() ) );
2856  }
2857 }
2858 
2859 void QgsGeometry::convertToPolyline( const QgsPointSequence &input, QgsPolylineXY &output )
2860 {
2861  output.clear();
2862  output.resize( input.size() );
2863 
2864  for ( int i = 0; i < input.size(); ++i )
2865  {
2866  const QgsPoint &pt = input.at( i );
2867  output[i].setX( pt.x() );
2868  output[i].setY( pt.y() );
2869  }
2870 }
2871 
2872 void QgsGeometry::convertPolygon( const QgsPolygon &input, QgsPolygonXY &output )
2873 {
2874  output.clear();
2875  QgsCoordinateSequence coords = input.coordinateSequence();
2876  if ( coords.empty() )
2877  {
2878  return;
2879  }
2880  const QgsRingSequence &rings = coords[0];
2881  output.resize( rings.size() );
2882  for ( int i = 0; i < rings.size(); ++i )
2883  {
2884  convertToPolyline( rings[i], output[i] );
2885  }
2886 }
2887 
2889 {
2890  return QgsGeometry( qgis::make_unique< QgsPoint >( point.x(), point.y() ) );
2891 }
2892 
2893 QgsGeometry QgsGeometry::fromQPolygonF( const QPolygonF &polygon )
2894 {
2895  if ( polygon.isClosed() )
2896  {
2898  }
2899  else
2900  {
2902  }
2903 }
2904 
2906 {
2907  QgsPolygonXY result;
2908  result << createPolylineFromQPolygonF( polygon );
2909  return result;
2910 }
2911 
2913 {
2914  QgsPolylineXY result;
2915  result.reserve( polygon.count() );
2916  for ( const QPointF &p : polygon )
2917  {
2918  result.append( QgsPointXY( p ) );
2919  }
2920  return result;
2921 }
2922 
2923 bool QgsGeometry::compare( const QgsPolylineXY &p1, const QgsPolylineXY &p2, double epsilon )
2924 {
2925  if ( p1.count() != p2.count() )
2926  return false;
2927 
2928  for ( int i = 0; i < p1.count(); ++i )
2929  {
2930  if ( !p1.at( i ).compare( p2.at( i ), epsilon ) )
2931  return false;
2932  }
2933  return true;
2934 }
2935 
2936 bool QgsGeometry::compare( const QgsPolygonXY &p1, const QgsPolygonXY &p2, double epsilon )
2937 {
2938  if ( p1.count() != p2.count() )
2939  return false;
2940 
2941  for ( int i = 0; i < p1.count(); ++i )
2942  {
2943  if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
2944  return false;
2945  }
2946  return true;
2947 }
2948 
2949 
2950 bool QgsGeometry::compare( const QgsMultiPolygonXY &p1, const QgsMultiPolygonXY &p2, double epsilon )
2951 {
2952  if ( p1.count() != p2.count() )
2953  return false;
2954 
2955  for ( int i = 0; i < p1.count(); ++i )
2956  {
2957  if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
2958  return false;
2959  }
2960  return true;
2961 }
2962 
2963 QgsGeometry QgsGeometry::smooth( const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
2964 {
2965  if ( !d->geometry || d->geometry->isEmpty() )
2966  return QgsGeometry();
2967 
2968  QgsGeometry geom = *this;
2970  geom = QgsGeometry( d->geometry->segmentize() );
2971 
2972  switch ( QgsWkbTypes::flatType( geom.wkbType() ) )
2973  {
2974  case QgsWkbTypes::Point:
2976  //can't smooth a point based geometry
2977  return geom;
2978 
2980  {
2981  QgsLineString *lineString = static_cast< QgsLineString * >( d->geometry.get() );
2982  return QgsGeometry( smoothLine( *lineString, iterations, offset, minimumDistance, maxAngle ) );
2983  }
2984 
2986  {
2987  QgsMultiLineString *multiLine = static_cast< QgsMultiLineString * >( d->geometry.get() );
2988 
2989  std::unique_ptr< QgsMultiLineString > resultMultiline = qgis::make_unique< QgsMultiLineString> ();
2990  resultMultiline->reserve( multiLine->numGeometries() );
2991  for ( int i = 0; i < multiLine->numGeometries(); ++i )
2992  {
2993  resultMultiline->addGeometry( smoothLine( *( static_cast< QgsLineString * >( multiLine->geometryN( i ) ) ), iterations, offset, minimumDistance, maxAngle ).release() );
2994  }
2995  return QgsGeometry( std::move( resultMultiline ) );
2996  }
2997 
2998  case QgsWkbTypes::Polygon:
2999  {
3000  QgsPolygon *poly = static_cast< QgsPolygon * >( d->geometry.get() );
3001  return QgsGeometry( smoothPolygon( *poly, iterations, offset, minimumDistance, maxAngle ) );
3002  }
3003 
3005  {
3006  QgsMultiPolygon *multiPoly = static_cast< QgsMultiPolygon * >( d->geometry.get() );
3007 
3008  std::unique_ptr< QgsMultiPolygon > resultMultiPoly = qgis::make_unique< QgsMultiPolygon >();
3009  resultMultiPoly->reserve( multiPoly->numGeometries() );
3010  for ( int i = 0; i < multiPoly->numGeometries(); ++i )
3011  {
3012  resultMultiPoly->addGeometry( smoothPolygon( *( static_cast< QgsPolygon * >( multiPoly->geometryN( i ) ) ), iterations, offset, minimumDistance, maxAngle ).release() );
3013  }
3014  return QgsGeometry( std::move( resultMultiPoly ) );
3015  }
3016 
3017  case QgsWkbTypes::Unknown:
3018  default:
3019  return QgsGeometry( *this );
3020  }
3021 }
3022 
3023 std::unique_ptr< QgsLineString > smoothCurve( const QgsLineString &line, const unsigned int iterations,
3024  const double offset, double squareDistThreshold, double maxAngleRads,
3025  bool isRing )
3026 {
3027  std::unique_ptr< QgsLineString > result = qgis::make_unique< QgsLineString >( line );
3028  QgsPointSequence outputLine;
3029  for ( unsigned int iteration = 0; iteration < iterations; ++iteration )
3030  {
3031  outputLine.resize( 0 );
3032  outputLine.reserve( 2 * ( result->numPoints() - 1 ) );
3033  bool skipFirst = false;
3034  bool skipLast = false;
3035  if ( isRing )
3036  {
3037  QgsPoint p1 = result->pointN( result->numPoints() - 2 );
3038  QgsPoint p2 = result->pointN( 0 );
3039  QgsPoint p3 = result->pointN( 1 );
3040  double angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3041  p3.x(), p3.y() );
3042  angle = std::fabs( M_PI - angle );
3043  skipFirst = angle > maxAngleRads;
3044  }
3045  for ( int i = 0; i < result->numPoints() - 1; i++ )
3046  {
3047  QgsPoint p1 = result->pointN( i );
3048  QgsPoint p2 = result->pointN( i + 1 );
3049 
3050  double angle = M_PI;
3051  if ( i == 0 && isRing )
3052  {
3053  QgsPoint p3 = result->pointN( result->numPoints() - 2 );
3054  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3055  p3.x(), p3.y() );
3056  }
3057  else if ( i < result->numPoints() - 2 )
3058  {
3059  QgsPoint p3 = result->pointN( i + 2 );
3060  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3061  p3.x(), p3.y() );
3062  }
3063  else if ( i == result->numPoints() - 2 && isRing )
3064  {
3065  QgsPoint p3 = result->pointN( 1 );
3066  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3067  p3.x(), p3.y() );
3068  }
3069 
3070  skipLast = angle < M_PI - maxAngleRads || angle > M_PI + maxAngleRads;
3071 
3072  // don't apply distance threshold to first or last segment
3073  if ( i == 0 || i >= result->numPoints() - 2
3074  || QgsGeometryUtils::sqrDistance2D( p1, p2 ) > squareDistThreshold )
3075  {
3076  if ( !isRing )
3077  {
3078  if ( !skipFirst )
3079  outputLine << ( i == 0 ? result->pointN( i ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset ) );
3080  if ( !skipLast )
3081  outputLine << ( i == result->numPoints() - 2 ? result->pointN( i + 1 ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset ) );
3082  else
3083  outputLine << p2;
3084  }
3085  else
3086  {
3087  // ring
3088  if ( !skipFirst )
3089  outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset );
3090  else if ( i == 0 )
3091  outputLine << p1;
3092  if ( !skipLast )
3093  outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset );
3094  else
3095  outputLine << p2;
3096  }
3097  }
3098  skipFirst = skipLast;
3099  }
3100 
3101  if ( isRing && outputLine.at( 0 ) != outputLine.at( outputLine.count() - 1 ) )
3102  outputLine << outputLine.at( 0 );
3103 
3104  result->setPoints( outputLine );
3105  }
3106  return result;
3107 }
3108 
3109 std::unique_ptr<QgsLineString> QgsGeometry::smoothLine( const QgsLineString &line, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3110 {
3111  double maxAngleRads = maxAngle * M_PI / 180.0;
3112  double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
3113  return smoothCurve( line, iterations, offset, squareDistThreshold, maxAngleRads, false );
3114 }
3115 
3116 std::unique_ptr<QgsPolygon> QgsGeometry::smoothPolygon( const QgsPolygon &polygon, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3117 {
3118  double maxAngleRads = maxAngle * M_PI / 180.0;
3119  double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
3120  std::unique_ptr< QgsPolygon > resultPoly = qgis::make_unique< QgsPolygon >();
3121 
3122  resultPoly->setExteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.exteriorRing() ) ), iterations, offset,
3123  squareDistThreshold, maxAngleRads, true ).release() );
3124 
3125  for ( int i = 0; i < polygon.numInteriorRings(); ++i )
3126  {
3127  resultPoly->addInteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.interiorRing( i ) ) ), iterations, offset,
3128  squareDistThreshold, maxAngleRads, true ).release() );
3129  }
3130  return resultPoly;
3131 }
3132 
3133 QgsGeometry QgsGeometry::convertToPoint( bool destMultipart ) const
3134 {
3135  switch ( type() )
3136  {
3138  {
3139  bool srcIsMultipart = isMultipart();
3140 
3141  if ( ( destMultipart && srcIsMultipart ) ||
3142  ( !destMultipart && !srcIsMultipart ) )
3143  {
3144  // return a copy of the same geom
3145  return QgsGeometry( *this );
3146  }
3147  if ( destMultipart )
3148  {
3149  // layer is multipart => make a multipoint with a single point
3150  return fromMultiPointXY( QgsMultiPointXY() << asPoint() );
3151  }
3152  else
3153  {
3154  // destination is singlepart => make a single part if possible
3155  QgsMultiPointXY multiPoint = asMultiPoint();
3156  if ( multiPoint.count() == 1 )
3157  {
3158  return fromPointXY( multiPoint[0] );
3159  }
3160  }
3161  return QgsGeometry();
3162  }
3163 
3165  {
3166  // only possible if destination is multipart
3167  if ( !destMultipart )
3168  return QgsGeometry();
3169 
3170  // input geometry is multipart
3171  if ( isMultipart() )
3172  {
3173  const QgsMultiPolylineXY multiLine = asMultiPolyline();
3174  QgsMultiPointXY multiPoint;
3175  for ( const QgsPolylineXY &l : multiLine )
3176  for ( const QgsPointXY &p : l )
3177  multiPoint << p;
3178  return fromMultiPointXY( multiPoint );
3179  }
3180  // input geometry is not multipart: copy directly the line into a multipoint
3181  else
3182  {
3183  QgsPolylineXY line = asPolyline();
3184  if ( !line.isEmpty() )
3185  return fromMultiPointXY( line );
3186  }
3187  return QgsGeometry();
3188  }
3189 
3191  {
3192  // can only transform if destination is multipoint
3193  if ( !destMultipart )
3194  return QgsGeometry();
3195 
3196  // input geometry is multipart: make a multipoint from multipolygon
3197  if ( isMultipart() )
3198  {
3199  const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3200  QgsMultiPointXY multiPoint;
3201  for ( const QgsPolygonXY &poly : multiPolygon )
3202  for ( const QgsPolylineXY &line : poly )
3203  for ( const QgsPointXY &pt : line )
3204  multiPoint << pt;
3205  return fromMultiPointXY( multiPoint );
3206  }
3207  // input geometry is not multipart: make a multipoint from polygon
3208  else
3209  {
3210  const QgsPolygonXY polygon = asPolygon();
3211  QgsMultiPointXY multiPoint;
3212  for ( const QgsPolylineXY &line : polygon )
3213  for ( const QgsPointXY &pt : line )
3214  multiPoint << pt;
3215  return fromMultiPointXY( multiPoint );
3216  }
3217  }
3218 
3219  default:
3220  return QgsGeometry();
3221  }
3222 }
3223 
3224 QgsGeometry QgsGeometry::convertToLine( bool destMultipart ) const
3225 {
3226  switch ( type() )
3227  {
3229  {
3230  if ( !isMultipart() )
3231  return QgsGeometry();
3232 
3233  QgsMultiPointXY multiPoint = asMultiPoint();
3234  if ( multiPoint.count() < 2 )
3235  return QgsGeometry();
3236 
3237  if ( destMultipart )
3238  return fromMultiPolylineXY( QgsMultiPolylineXY() << multiPoint );
3239  else
3240  return fromPolylineXY( multiPoint );
3241  }
3242 
3244  {
3245  bool srcIsMultipart = isMultipart();
3246 
3247  if ( ( destMultipart && srcIsMultipart ) ||
3248  ( !destMultipart && ! srcIsMultipart ) )
3249  {
3250  // return a copy of the same geom
3251  return QgsGeometry( *this );
3252  }
3253  if ( destMultipart )
3254  {
3255  // destination is multipart => makes a multipoint with a single line
3256  QgsPolylineXY line = asPolyline();
3257  if ( !line.isEmpty() )
3258  return fromMultiPolylineXY( QgsMultiPolylineXY() << line );
3259  }
3260  else
3261  {
3262  // destination is singlepart => make a single part if possible
3263  QgsMultiPolylineXY multiLine = asMultiPolyline();
3264  if ( multiLine.count() == 1 )
3265  return fromPolylineXY( multiLine[0] );
3266  }
3267  return QgsGeometry();
3268  }
3269 
3271  {
3272  // input geometry is multipolygon
3273  if ( isMultipart() )
3274  {
3275  const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3276  QgsMultiPolylineXY multiLine;
3277  for ( const QgsPolygonXY &poly : multiPolygon )
3278  for ( const QgsPolylineXY &line : poly )
3279  multiLine << line;
3280 
3281  if ( destMultipart )
3282  {
3283  // destination is multipart
3284  return fromMultiPolylineXY( multiLine );
3285  }
3286  else if ( multiLine.count() == 1 )
3287  {
3288  // destination is singlepart => make a single part if possible
3289  return fromPolylineXY( multiLine[0] );
3290  }
3291  }
3292  // input geometry is single polygon
3293  else
3294  {
3295  QgsPolygonXY polygon = asPolygon();
3296  // if polygon has rings
3297  if ( polygon.count() > 1 )
3298  {
3299  // cannot fit a polygon with rings in a single line layer
3300  // TODO: would it be better to remove rings?
3301  if ( destMultipart )
3302  {
3303  const QgsPolygonXY polygon = asPolygon();
3304  QgsMultiPolylineXY multiLine;
3305  multiLine.reserve( polygon.count() );
3306  for ( const QgsPolylineXY &line : polygon )
3307  multiLine << line;
3308  return fromMultiPolylineXY( multiLine );
3309  }
3310  }
3311  // no rings
3312  else if ( polygon.count() == 1 )
3313  {
3314  if ( destMultipart )
3315  {
3316  return fromMultiPolylineXY( polygon );
3317  }
3318  else
3319  {
3320  return fromPolylineXY( polygon[0] );
3321  }
3322  }
3323  }
3324  return QgsGeometry();
3325  }
3326 
3327  default:
3328  return QgsGeometry();
3329  }
3330 }
3331 
3332 QgsGeometry QgsGeometry::convertToPolygon( bool destMultipart ) const
3333 {
3334  switch ( type() )
3335  {
3337  {
3338  if ( !isMultipart() )
3339  return QgsGeometry();
3340 
3341  QgsMultiPointXY multiPoint = asMultiPoint();
3342  if ( multiPoint.count() < 3 )
3343  return QgsGeometry();
3344 
3345  if ( multiPoint.last() != multiPoint.first() )
3346  multiPoint << multiPoint.first();
3347 
3348  QgsPolygonXY polygon = QgsPolygonXY() << multiPoint;
3349  if ( destMultipart )
3350  return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3351  else
3352  return fromPolygonXY( polygon );
3353  }
3354 
3356  {
3357  // input geometry is multiline
3358  if ( isMultipart() )
3359  {
3360  QgsMultiPolylineXY multiLine = asMultiPolyline();
3361  QgsMultiPolygonXY multiPolygon;
3362  for ( QgsMultiPolylineXY::iterator multiLineIt = multiLine.begin(); multiLineIt != multiLine.end(); ++multiLineIt )
3363  {
3364  // do not create polygon for a 1 segment line
3365  if ( ( *multiLineIt ).count() < 3 )
3366  return QgsGeometry();
3367  if ( ( *multiLineIt ).count() == 3 && ( *multiLineIt ).first() == ( *multiLineIt ).last() )
3368  return QgsGeometry();
3369 
3370  // add closing node
3371  if ( ( *multiLineIt ).first() != ( *multiLineIt ).last() )
3372  *multiLineIt << ( *multiLineIt ).first();
3373  multiPolygon << ( QgsPolygonXY() << *multiLineIt );
3374  }
3375  // check that polygons were inserted
3376  if ( !multiPolygon.isEmpty() )
3377  {
3378  if ( destMultipart )
3379  {
3380  return fromMultiPolygonXY( multiPolygon );
3381  }
3382  else if ( multiPolygon.count() == 1 )
3383  {
3384  // destination is singlepart => make a single part if possible
3385  return fromPolygonXY( multiPolygon[0] );
3386  }
3387  }
3388  }
3389  // input geometry is single line
3390  else
3391  {
3392  QgsPolylineXY line = asPolyline();
3393 
3394  // do not create polygon for a 1 segment line
3395  if ( line.count() < 3 )
3396  return QgsGeometry();
3397  if ( line.count() == 3 && line.first() == line.last() )
3398  return QgsGeometry();
3399 
3400  // add closing node
3401  if ( line.first() != line.last() )
3402  line << line.first();
3403 
3404  // destination is multipart
3405  if ( destMultipart )
3406  {
3407  return fromMultiPolygonXY( QgsMultiPolygonXY() << ( QgsPolygonXY() << line ) );
3408  }
3409  else
3410  {
3411  return fromPolygonXY( QgsPolygonXY() << line );
3412  }
3413  }
3414  return QgsGeometry();
3415  }
3416 
3418  {
3419  bool srcIsMultipart = isMultipart();
3420 
3421  if ( ( destMultipart && srcIsMultipart ) ||
3422  ( !destMultipart && ! srcIsMultipart ) )
3423  {
3424  // return a copy of the same geom
3425  return QgsGeometry( *this );
3426  }
3427  if ( destMultipart )
3428  {
3429  // destination is multipart => makes a multipoint with a single polygon
3430  QgsPolygonXY polygon = asPolygon();
3431  if ( !polygon.isEmpty() )
3432  return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3433  }
3434  else
3435  {
3436  QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3437  if ( multiPolygon.count() == 1 )
3438  {
3439  // destination is singlepart => make a single part if possible
3440  return fromPolygonXY( multiPolygon[0] );
3441  }
3442  }
3443  return QgsGeometry();
3444  }
3445 
3446  default:
3447  return QgsGeometry();
3448  }
3449 }
3450 
3452 {
3453  return new QgsGeos( geometry );
3454 }
3455 
3456 QDataStream &operator<<( QDataStream &out, const QgsGeometry &geometry )
3457 {
3458  out << geometry.asWkb();
3459  return out;
3460 }
3461 
3462 QDataStream &operator>>( QDataStream &in, QgsGeometry &geometry )
3463 {
3464  QByteArray byteArray;
3465  in >> byteArray;
3466  if ( byteArray.isEmpty() )
3467  {
3468  geometry.set( nullptr );
3469  return in;
3470  }
3471 
3472  geometry.fromWkb( byteArray );
3473  return in;
3474 }
3475 
3476 
3478 {
3479  return mMessage;
3480 }
3481 
3483 {
3484  return mLocation;
3485 }
3486 
3488 {
3489  return mHasLocation;
3490 }
Geometry engine misses a method implemented or an error occurred in the geometry engine.
Definition: qgsgeometry.h:141
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.
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:301
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.
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
Returns true if the geometry is completely within another geometry.
static bool isMultiType(Type type)
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:706
The source geometry is not multi.
Definition: qgsgeometry.h:145
Nothing happened, without any error.
Definition: qgsgeometry.h:136
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:1921
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
Returns true if the geometry overlaps another geometry.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:121
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:1088
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:133
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.
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:366
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
const double * xData() const
Returns a const pointer to the x vertex data.
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:154
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.
void setY(double y)
Sets the y value of the point.
Definition: qgspointxy.h:117
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:812
Use internal QgsGeometryValidator method.
Definition: qgsgeometry.h:1920
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
Returns true if the geometry crosses another geometry.
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:2267
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 planar, 2-dimensional 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
Returns true if the geometry touches another geometry.
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:675
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.
const double * yData() const
Returns a const pointer to the y vertex data.
double length() const
Returns the planar, 2-dimensional length of geometry.
This class offers geometry processing methods.
void setX(double x)
Sets the x value of the point.
Definition: qgspointxy.h:107
QByteArray asWkb() const
Export the geometry to WKB.
Error occurred while creating a noded geometry.
double x
Definition: qgspointxy.h:47
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
QgsGeometry extrude(double x, double y)
Returns an extruded version of this geometry.
Error occurred in the geometry engine.
void draw(QPainter &p) const
Draws the geometry onto a QPainter.
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:262
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:1080
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
void reserve(int size)
Attempts to allocate memory for at least size geometries.
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:137
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:138
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:755
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:1918
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
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 planar, 2-dimensional area of the geometry.
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:135
JoinStyle
Join styles for buffers.
Definition: qgsgeometry.h:1097
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
Returns true if the geometry contains the point p.
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:576
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
Returns true if the geometry is disjoint of another geometry.
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...