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