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