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