QGIS API Documentation  3.7.0-Master (1205fbf)
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 
145 bool QgsGeometry::isNull() const
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, const ValidationMethod method, const QgsGeometry::ValidityFlags flags ) const
2461 {
2462  errors.clear();
2463  if ( !d->geometry )
2464  return;
2465 
2466  // avoid expensive calcs for trivial point geometries
2468  {
2469  return;
2470  }
2471 
2472  switch ( method )
2473  {
2474  case ValidatorQgisInternal:
2475  QgsGeometryValidator::validateGeometry( *this, errors, method );
2476  return;
2477 
2478  case ValidatorGeos:
2479  {
2480  QgsGeos geos( d->geometry.get() );
2481  QString error;
2482  QgsGeometry errorLoc;
2483  if ( !geos.isValid( &error, flags & FlagAllowSelfTouchingHoles, &errorLoc ) )
2484  {
2485  if ( errorLoc.isNull() )
2486  {
2487  errors.append( QgsGeometry::Error( error ) );
2488  }
2489  else
2490  {
2491  const QgsPointXY point = errorLoc.asPoint();
2492  errors.append( QgsGeometry::Error( error, point ) );
2493  }
2494  return;
2495  }
2496  }
2497  }
2498 }
2499 
2500 bool QgsGeometry::isGeosValid( const QgsGeometry::ValidityFlags flags ) const
2501 {
2502  if ( !d->geometry )
2503  {
2504  return false;
2505  }
2506 
2507  return d->geometry->isValid( mLastError, static_cast< int >( flags ) );
2508 }
2509 
2511 {
2512  if ( !d->geometry )
2513  return false;
2514 
2515  QgsGeos geos( d->geometry.get() );
2516  mLastError.clear();
2517  return geos.isSimple( &mLastError );
2518 }
2519 
2521 {
2522  if ( !d->geometry || !g.d->geometry )
2523  {
2524  return false;
2525  }
2526 
2527  QgsGeos geos( d->geometry.get() );
2528  mLastError.clear();
2529  return geos.isEqual( g.d->geometry.get(), &mLastError );
2530 }
2531 
2532 QgsGeometry QgsGeometry::unaryUnion( const QVector<QgsGeometry> &geometries )
2533 {
2534  QgsGeos geos( nullptr );
2535 
2536  QString error;
2537  std::unique_ptr< QgsAbstractGeometry > geom( geos.combine( geometries, &error ) );
2538  QgsGeometry result( std::move( geom ) );
2539  result.mLastError = error;
2540  return result;
2541 }
2542 
2543 QgsGeometry QgsGeometry::polygonize( const QVector<QgsGeometry> &geometryList )
2544 {
2545  QgsGeos geos( nullptr );
2546 
2547  QVector<const QgsAbstractGeometry *> geomV2List;
2548  for ( const QgsGeometry &g : geometryList )
2549  {
2550  if ( !( g.isNull() ) )
2551  {
2552  geomV2List.append( g.constGet() );
2553  }
2554  }
2555 
2556  QString error;
2557  QgsGeometry result = geos.polygonize( geomV2List, &error );
2558  result.mLastError = error;
2559  return result;
2560 }
2561 
2563 {
2565  {
2566  return;
2567  }
2568 
2569  std::unique_ptr< QgsAbstractGeometry > straightGeom( d->geometry->segmentize( tolerance, toleranceType ) );
2570  reset( std::move( straightGeom ) );
2571 }
2572 
2574 {
2575  if ( !d->geometry )
2576  {
2577  return false;
2578  }
2579 
2580  return d->geometry->hasCurvedSegments();
2581 }
2582 
2584 {
2585  if ( !d->geometry )
2586  {
2588  }
2589 
2590  detach();
2591  d->geometry->transform( ct, direction, transformZ );
2592  return QgsGeometry::Success;
2593 }
2594 
2595 QgsGeometry::OperationResult QgsGeometry::transform( const QTransform &ct, double zTranslate, double zScale, double mTranslate, double mScale )
2596 {
2597  if ( !d->geometry )
2598  {
2600  }
2601 
2602  detach();
2603  d->geometry->transform( ct, zTranslate, zScale, mTranslate, mScale );
2604  return QgsGeometry::Success;
2605 }
2606 
2608 {
2609  if ( d->geometry )
2610  {
2611  detach();
2612  d->geometry->transform( mtp.transform() );
2613  }
2614 }
2615 
2617 {
2618  if ( !d->geometry || rectangle.isNull() || rectangle.isEmpty() )
2619  {
2620  return QgsGeometry();
2621  }
2622 
2623  QgsGeos geos( d->geometry.get() );
2624  mLastError.clear();
2625  std::unique_ptr< QgsAbstractGeometry > resultGeom = geos.clip( rectangle, &mLastError );
2626  if ( !resultGeom )
2627  {
2628  QgsGeometry result;
2629  result.mLastError = mLastError;
2630  return result;
2631  }
2632  return QgsGeometry( std::move( resultGeom ) );
2633 }
2634 
2635 void QgsGeometry::draw( QPainter &p ) const
2636 {
2637  if ( d->geometry )
2638  {
2639  d->geometry->draw( p );
2640  }
2641 }
2642 
2643 static bool vertexIndexInfo( const QgsAbstractGeometry *g, int vertexIndex, int &partIndex, int &ringIndex, int &vertex )
2644 {
2645  if ( vertexIndex < 0 )
2646  return false; // clearly something wrong
2647 
2648  if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
2649  {
2650  partIndex = 0;
2651  int offset = 0;
2652  for ( int i = 0; i < geomCollection->numGeometries(); ++i )
2653  {
2654  const QgsAbstractGeometry *part = geomCollection->geometryN( i );
2655 
2656  // count total number of vertices in the part
2657  int numPoints = 0;
2658  for ( int k = 0; k < part->ringCount(); ++k )
2659  numPoints += part->vertexCount( 0, k );
2660 
2661  if ( vertexIndex < numPoints )
2662  {
2663  int nothing;
2664  return vertexIndexInfo( part, vertexIndex, nothing, ringIndex, vertex ); // set ring_index + index
2665  }
2666  vertexIndex -= numPoints;
2667  offset += numPoints;
2668  partIndex++;
2669  }
2670  }
2671  else if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
2672  {
2673  const QgsCurve *ring = curvePolygon->exteriorRing();
2674  if ( vertexIndex < ring->numPoints() )
2675  {
2676  partIndex = 0;
2677  ringIndex = 0;
2678  vertex = vertexIndex;
2679  return true;
2680  }
2681  vertexIndex -= ring->numPoints();
2682  ringIndex = 1;
2683  for ( int i = 0; i < curvePolygon->numInteriorRings(); ++i )
2684  {
2685  const QgsCurve *ring = curvePolygon->interiorRing( i );
2686  if ( vertexIndex < ring->numPoints() )
2687  {
2688  partIndex = 0;
2689  vertex = vertexIndex;
2690  return true;
2691  }
2692  vertexIndex -= ring->numPoints();
2693  ringIndex += 1;
2694  }
2695  }
2696  else if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
2697  {
2698  if ( vertexIndex < curve->numPoints() )
2699  {
2700  partIndex = 0;
2701  ringIndex = 0;
2702  vertex = vertexIndex;
2703  return true;
2704  }
2705  }
2706  else if ( qgsgeometry_cast<const QgsPoint *>( g ) )
2707  {
2708  if ( vertexIndex == 0 )
2709  {
2710  partIndex = 0;
2711  ringIndex = 0;
2712  vertex = 0;
2713  return true;
2714  }
2715  }
2716 
2717  return false;
2718 }
2719 
2721 {
2722  if ( !d->geometry )
2723  {
2724  return false;
2725  }
2726 
2727  id.type = QgsVertexId::SegmentVertex;
2728 
2729  bool res = vertexIndexInfo( d->geometry.get(), nr, id.part, id.ring, id.vertex );
2730  if ( !res )
2731  return false;
2732 
2733  // now let's find out if it is a straight or circular segment
2734  const QgsAbstractGeometry *g = d->geometry.get();
2735  if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
2736  {
2737  g = geomCollection->geometryN( id.part );
2738  }
2739 
2740  if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
2741  {
2742  g = id.ring == 0 ? curvePolygon->exteriorRing() : curvePolygon->interiorRing( id.ring - 1 );
2743  }
2744 
2745  if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
2746  {
2747  QgsPoint p;
2748  res = curve->pointAt( id.vertex, p, id.type );
2749  if ( !res )
2750  return false;
2751  }
2752 
2753  return true;
2754 }
2755 
2757 {
2758  if ( !d->geometry )
2759  {
2760  return -1;
2761  }
2762  return d->geometry->vertexNumberFromVertexId( id );
2763 }
2764 
2765 QString QgsGeometry::lastError() const
2766 {
2767  return mLastError;
2768 }
2769 
2770 void QgsGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
2771 {
2772  if ( !d->geometry )
2773  return;
2774 
2775  detach();
2776 
2777  d->geometry->filterVertices( filter );
2778 }
2779 
2780 void QgsGeometry::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
2781 {
2782  if ( !d->geometry )
2783  return;
2784 
2785  detach();
2786 
2787  d->geometry->transformVertices( transform );
2788 }
2789 
2790 void QgsGeometry::convertPointList( const QVector<QgsPointXY> &input, QgsPointSequence &output )
2791 {
2792  output.clear();
2793  for ( const QgsPointXY &p : input )
2794  {
2795  output.append( QgsPoint( p ) );
2796  }
2797 }
2798 
2799 void QgsGeometry::convertPointList( const QgsPointSequence &input, QVector<QgsPointXY> &output )
2800 {
2801  output.clear();
2802  for ( const QgsPoint &p : input )
2803  {
2804  output.append( QgsPointXY( p.x(), p.y() ) );
2805  }
2806 }
2807 
2808 void QgsGeometry::convertToPolyline( const QgsPointSequence &input, QgsPolylineXY &output )
2809 {
2810  output.clear();
2811  output.resize( input.size() );
2812 
2813  for ( int i = 0; i < input.size(); ++i )
2814  {
2815  const QgsPoint &pt = input.at( i );
2816  output[i].setX( pt.x() );
2817  output[i].setY( pt.y() );
2818  }
2819 }
2820 
2821 void QgsGeometry::convertPolygon( const QgsPolygon &input, QgsPolygonXY &output )
2822 {
2823  output.clear();
2824  QgsCoordinateSequence coords = input.coordinateSequence();
2825  if ( coords.empty() )
2826  {
2827  return;
2828  }
2829  const QgsRingSequence &rings = coords[0];
2830  output.resize( rings.size() );
2831  for ( int i = 0; i < rings.size(); ++i )
2832  {
2833  convertToPolyline( rings[i], output[i] );
2834  }
2835 }
2836 
2838 {
2839  return QgsGeometry( qgis::make_unique< QgsPoint >( point.x(), point.y() ) );
2840 }
2841 
2842 QgsGeometry QgsGeometry::fromQPolygonF( const QPolygonF &polygon )
2843 {
2844  if ( polygon.isClosed() )
2845  {
2847  }
2848  else
2849  {
2851  }
2852 }
2853 
2855 {
2856  QgsPolygonXY result;
2857  result << createPolylineFromQPolygonF( polygon );
2858  return result;
2859 }
2860 
2862 {
2863  QgsPolylineXY result;
2864  result.reserve( polygon.count() );
2865  for ( const QPointF &p : polygon )
2866  {
2867  result.append( QgsPointXY( p ) );
2868  }
2869  return result;
2870 }
2871 
2872 bool QgsGeometry::compare( const QgsPolylineXY &p1, const QgsPolylineXY &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 ( !p1.at( i ).compare( p2.at( i ), epsilon ) )
2880  return false;
2881  }
2882  return true;
2883 }
2884 
2885 bool QgsGeometry::compare( const QgsPolygonXY &p1, const QgsPolygonXY &p2, double epsilon )
2886 {
2887  if ( p1.count() != p2.count() )
2888  return false;
2889 
2890  for ( int i = 0; i < p1.count(); ++i )
2891  {
2892  if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
2893  return false;
2894  }
2895  return true;
2896 }
2897 
2898 
2899 bool QgsGeometry::compare( const QgsMultiPolygonXY &p1, const QgsMultiPolygonXY &p2, double epsilon )
2900 {
2901  if ( p1.count() != p2.count() )
2902  return false;
2903 
2904  for ( int i = 0; i < p1.count(); ++i )
2905  {
2906  if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
2907  return false;
2908  }
2909  return true;
2910 }
2911 
2912 QgsGeometry QgsGeometry::smooth( const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
2913 {
2914  if ( !d->geometry || d->geometry->isEmpty() )
2915  return QgsGeometry();
2916 
2917  QgsGeometry geom = *this;
2919  geom = QgsGeometry( d->geometry->segmentize() );
2920 
2921  switch ( QgsWkbTypes::flatType( geom.wkbType() ) )
2922  {
2923  case QgsWkbTypes::Point:
2925  //can't smooth a point based geometry
2926  return geom;
2927 
2929  {
2930  QgsLineString *lineString = static_cast< QgsLineString * >( d->geometry.get() );
2931  return QgsGeometry( smoothLine( *lineString, iterations, offset, minimumDistance, maxAngle ) );
2932  }
2933 
2935  {
2936  QgsMultiLineString *multiLine = static_cast< QgsMultiLineString * >( d->geometry.get() );
2937 
2938  std::unique_ptr< QgsMultiLineString > resultMultiline = qgis::make_unique< QgsMultiLineString> ();
2939  for ( int i = 0; i < multiLine->numGeometries(); ++i )
2940  {
2941  resultMultiline->addGeometry( smoothLine( *( static_cast< QgsLineString * >( multiLine->geometryN( i ) ) ), iterations, offset, minimumDistance, maxAngle ).release() );
2942  }
2943  return QgsGeometry( std::move( resultMultiline ) );
2944  }
2945 
2946  case QgsWkbTypes::Polygon:
2947  {
2948  QgsPolygon *poly = static_cast< QgsPolygon * >( d->geometry.get() );
2949  return QgsGeometry( smoothPolygon( *poly, iterations, offset, minimumDistance, maxAngle ) );
2950  }
2951 
2953  {
2954  QgsMultiPolygon *multiPoly = static_cast< QgsMultiPolygon * >( d->geometry.get() );
2955 
2956  std::unique_ptr< QgsMultiPolygon > resultMultiPoly = qgis::make_unique< QgsMultiPolygon >();
2957  for ( int i = 0; i < multiPoly->numGeometries(); ++i )
2958  {
2959  resultMultiPoly->addGeometry( smoothPolygon( *( static_cast< QgsPolygon * >( multiPoly->geometryN( i ) ) ), iterations, offset, minimumDistance, maxAngle ).release() );
2960  }
2961  return QgsGeometry( std::move( resultMultiPoly ) );
2962  }
2963 
2964  case QgsWkbTypes::Unknown:
2965  default:
2966  return QgsGeometry( *this );
2967  }
2968 }
2969 
2970 std::unique_ptr< QgsLineString > smoothCurve( const QgsLineString &line, const unsigned int iterations,
2971  const double offset, double squareDistThreshold, double maxAngleRads,
2972  bool isRing )
2973 {
2974  std::unique_ptr< QgsLineString > result = qgis::make_unique< QgsLineString >( line );
2975  QgsPointSequence outputLine;
2976  for ( unsigned int iteration = 0; iteration < iterations; ++iteration )
2977  {
2978  outputLine.resize( 0 );
2979  outputLine.reserve( 2 * ( result->numPoints() - 1 ) );
2980  bool skipFirst = false;
2981  bool skipLast = false;
2982  if ( isRing )
2983  {
2984  QgsPoint p1 = result->pointN( result->numPoints() - 2 );
2985  QgsPoint p2 = result->pointN( 0 );
2986  QgsPoint p3 = result->pointN( 1 );
2987  double angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
2988  p3.x(), p3.y() );
2989  angle = std::fabs( M_PI - angle );
2990  skipFirst = angle > maxAngleRads;
2991  }
2992  for ( int i = 0; i < result->numPoints() - 1; i++ )
2993  {
2994  QgsPoint p1 = result->pointN( i );
2995  QgsPoint p2 = result->pointN( i + 1 );
2996 
2997  double angle = M_PI;
2998  if ( i == 0 && isRing )
2999  {
3000  QgsPoint p3 = result->pointN( result->numPoints() - 2 );
3001  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3002  p3.x(), p3.y() );
3003  }
3004  else if ( i < result->numPoints() - 2 )
3005  {
3006  QgsPoint p3 = result->pointN( i + 2 );
3007  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3008  p3.x(), p3.y() );
3009  }
3010  else if ( i == result->numPoints() - 2 && isRing )
3011  {
3012  QgsPoint p3 = result->pointN( 1 );
3013  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3014  p3.x(), p3.y() );
3015  }
3016 
3017  skipLast = angle < M_PI - maxAngleRads || angle > M_PI + maxAngleRads;
3018 
3019  // don't apply distance threshold to first or last segment
3020  if ( i == 0 || i >= result->numPoints() - 2
3021  || QgsGeometryUtils::sqrDistance2D( p1, p2 ) > squareDistThreshold )
3022  {
3023  if ( !isRing )
3024  {
3025  if ( !skipFirst )
3026  outputLine << ( i == 0 ? result->pointN( i ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset ) );
3027  if ( !skipLast )
3028  outputLine << ( i == result->numPoints() - 2 ? result->pointN( i + 1 ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset ) );
3029  else
3030  outputLine << p2;
3031  }
3032  else
3033  {
3034  // ring
3035  if ( !skipFirst )
3036  outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset );
3037  else if ( i == 0 )
3038  outputLine << p1;
3039  if ( !skipLast )
3040  outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset );
3041  else
3042  outputLine << p2;
3043  }
3044  }
3045  skipFirst = skipLast;
3046  }
3047 
3048  if ( isRing && outputLine.at( 0 ) != outputLine.at( outputLine.count() - 1 ) )
3049  outputLine << outputLine.at( 0 );
3050 
3051  result->setPoints( outputLine );
3052  }
3053  return result;
3054 }
3055 
3056 std::unique_ptr<QgsLineString> QgsGeometry::smoothLine( const QgsLineString &line, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3057 {
3058  double maxAngleRads = maxAngle * M_PI / 180.0;
3059  double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
3060  return smoothCurve( line, iterations, offset, squareDistThreshold, maxAngleRads, false );
3061 }
3062 
3063 std::unique_ptr<QgsPolygon> QgsGeometry::smoothPolygon( const QgsPolygon &polygon, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3064 {
3065  double maxAngleRads = maxAngle * M_PI / 180.0;
3066  double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
3067  std::unique_ptr< QgsPolygon > resultPoly = qgis::make_unique< QgsPolygon >();
3068 
3069  resultPoly->setExteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.exteriorRing() ) ), iterations, offset,
3070  squareDistThreshold, maxAngleRads, true ).release() );
3071 
3072  for ( int i = 0; i < polygon.numInteriorRings(); ++i )
3073  {
3074  resultPoly->addInteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.interiorRing( i ) ) ), iterations, offset,
3075  squareDistThreshold, maxAngleRads, true ).release() );
3076  }
3077  return resultPoly;
3078 }
3079 
3080 QgsGeometry QgsGeometry::convertToPoint( bool destMultipart ) const
3081 {
3082  switch ( type() )
3083  {
3085  {
3086  bool srcIsMultipart = isMultipart();
3087 
3088  if ( ( destMultipart && srcIsMultipart ) ||
3089  ( !destMultipart && !srcIsMultipart ) )
3090  {
3091  // return a copy of the same geom
3092  return QgsGeometry( *this );
3093  }
3094  if ( destMultipart )
3095  {
3096  // layer is multipart => make a multipoint with a single point
3097  return fromMultiPointXY( QgsMultiPointXY() << asPoint() );
3098  }
3099  else
3100  {
3101  // destination is singlepart => make a single part if possible
3102  QgsMultiPointXY multiPoint = asMultiPoint();
3103  if ( multiPoint.count() == 1 )
3104  {
3105  return fromPointXY( multiPoint[0] );
3106  }
3107  }
3108  return QgsGeometry();
3109  }
3110 
3112  {
3113  // only possible if destination is multipart
3114  if ( !destMultipart )
3115  return QgsGeometry();
3116 
3117  // input geometry is multipart
3118  if ( isMultipart() )
3119  {
3120  const QgsMultiPolylineXY multiLine = asMultiPolyline();
3121  QgsMultiPointXY multiPoint;
3122  for ( const QgsPolylineXY &l : multiLine )
3123  for ( const QgsPointXY &p : l )
3124  multiPoint << p;
3125  return fromMultiPointXY( multiPoint );
3126  }
3127  // input geometry is not multipart: copy directly the line into a multipoint
3128  else
3129  {
3130  QgsPolylineXY line = asPolyline();
3131  if ( !line.isEmpty() )
3132  return fromMultiPointXY( line );
3133  }
3134  return QgsGeometry();
3135  }
3136 
3138  {
3139  // can only transform if destination is multipoint
3140  if ( !destMultipart )
3141  return QgsGeometry();
3142 
3143  // input geometry is multipart: make a multipoint from multipolygon
3144  if ( isMultipart() )
3145  {
3146  const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3147  QgsMultiPointXY multiPoint;
3148  for ( const QgsPolygonXY &poly : multiPolygon )
3149  for ( const QgsPolylineXY &line : poly )
3150  for ( const QgsPointXY &pt : line )
3151  multiPoint << pt;
3152  return fromMultiPointXY( multiPoint );
3153  }
3154  // input geometry is not multipart: make a multipoint from polygon
3155  else
3156  {
3157  const QgsPolygonXY polygon = asPolygon();
3158  QgsMultiPointXY multiPoint;
3159  for ( const QgsPolylineXY &line : polygon )
3160  for ( const QgsPointXY &pt : line )
3161  multiPoint << pt;
3162  return fromMultiPointXY( multiPoint );
3163  }
3164  }
3165 
3166  default:
3167  return QgsGeometry();
3168  }
3169 }
3170 
3171 QgsGeometry QgsGeometry::convertToLine( bool destMultipart ) const
3172 {
3173  switch ( type() )
3174  {
3176  {
3177  if ( !isMultipart() )
3178  return QgsGeometry();
3179 
3180  QgsMultiPointXY multiPoint = asMultiPoint();
3181  if ( multiPoint.count() < 2 )
3182  return QgsGeometry();
3183 
3184  if ( destMultipart )
3185  return fromMultiPolylineXY( QgsMultiPolylineXY() << multiPoint );
3186  else
3187  return fromPolylineXY( multiPoint );
3188  }
3189 
3191  {
3192  bool srcIsMultipart = isMultipart();
3193 
3194  if ( ( destMultipart && srcIsMultipart ) ||
3195  ( !destMultipart && ! srcIsMultipart ) )
3196  {
3197  // return a copy of the same geom
3198  return QgsGeometry( *this );
3199  }
3200  if ( destMultipart )
3201  {
3202  // destination is multipart => makes a multipoint with a single line
3203  QgsPolylineXY line = asPolyline();
3204  if ( !line.isEmpty() )
3205  return fromMultiPolylineXY( QgsMultiPolylineXY() << line );
3206  }
3207  else
3208  {
3209  // destination is singlepart => make a single part if possible
3210  QgsMultiPolylineXY multiLine = asMultiPolyline();
3211  if ( multiLine.count() == 1 )
3212  return fromPolylineXY( multiLine[0] );
3213  }
3214  return QgsGeometry();
3215  }
3216 
3218  {
3219  // input geometry is multipolygon
3220  if ( isMultipart() )
3221  {
3222  const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3223  QgsMultiPolylineXY multiLine;
3224  for ( const QgsPolygonXY &poly : multiPolygon )
3225  for ( const QgsPolylineXY &line : poly )
3226  multiLine << line;
3227 
3228  if ( destMultipart )
3229  {
3230  // destination is multipart
3231  return fromMultiPolylineXY( multiLine );
3232  }
3233  else if ( multiLine.count() == 1 )
3234  {
3235  // destination is singlepart => make a single part if possible
3236  return fromPolylineXY( multiLine[0] );
3237  }
3238  }
3239  // input geometry is single polygon
3240  else
3241  {
3242  QgsPolygonXY polygon = asPolygon();
3243  // if polygon has rings
3244  if ( polygon.count() > 1 )
3245  {
3246  // cannot fit a polygon with rings in a single line layer
3247  // TODO: would it be better to remove rings?
3248  if ( destMultipart )
3249  {
3250  const QgsPolygonXY polygon = asPolygon();
3251  QgsMultiPolylineXY multiLine;
3252  multiLine.reserve( polygon.count() );
3253  for ( const QgsPolylineXY &line : polygon )
3254  multiLine << line;
3255  return fromMultiPolylineXY( multiLine );
3256  }
3257  }
3258  // no rings
3259  else if ( polygon.count() == 1 )
3260  {
3261  if ( destMultipart )
3262  {
3263  return fromMultiPolylineXY( polygon );
3264  }
3265  else
3266  {
3267  return fromPolylineXY( polygon[0] );
3268  }
3269  }
3270  }
3271  return QgsGeometry();
3272  }
3273 
3274  default:
3275  return QgsGeometry();
3276  }
3277 }
3278 
3279 QgsGeometry QgsGeometry::convertToPolygon( bool destMultipart ) const
3280 {
3281  switch ( type() )
3282  {
3284  {
3285  if ( !isMultipart() )
3286  return QgsGeometry();
3287 
3288  QgsMultiPointXY multiPoint = asMultiPoint();
3289  if ( multiPoint.count() < 3 )
3290  return QgsGeometry();
3291 
3292  if ( multiPoint.last() != multiPoint.first() )
3293  multiPoint << multiPoint.first();
3294 
3295  QgsPolygonXY polygon = QgsPolygonXY() << multiPoint;
3296  if ( destMultipart )
3297  return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3298  else
3299  return fromPolygonXY( polygon );
3300  }
3301 
3303  {
3304  // input geometry is multiline
3305  if ( isMultipart() )
3306  {
3307  QgsMultiPolylineXY multiLine = asMultiPolyline();
3308  QgsMultiPolygonXY multiPolygon;
3309  for ( QgsMultiPolylineXY::iterator multiLineIt = multiLine.begin(); multiLineIt != multiLine.end(); ++multiLineIt )
3310  {
3311  // do not create polygon for a 1 segment line
3312  if ( ( *multiLineIt ).count() < 3 )
3313  return QgsGeometry();
3314  if ( ( *multiLineIt ).count() == 3 && ( *multiLineIt ).first() == ( *multiLineIt ).last() )
3315  return QgsGeometry();
3316 
3317  // add closing node
3318  if ( ( *multiLineIt ).first() != ( *multiLineIt ).last() )
3319  *multiLineIt << ( *multiLineIt ).first();
3320  multiPolygon << ( QgsPolygonXY() << *multiLineIt );
3321  }
3322  // check that polygons were inserted
3323  if ( !multiPolygon.isEmpty() )
3324  {
3325  if ( destMultipart )
3326  {
3327  return fromMultiPolygonXY( multiPolygon );
3328  }
3329  else if ( multiPolygon.count() == 1 )
3330  {
3331  // destination is singlepart => make a single part if possible
3332  return fromPolygonXY( multiPolygon[0] );
3333  }
3334  }
3335  }
3336  // input geometry is single line
3337  else
3338  {
3339  QgsPolylineXY line = asPolyline();
3340 
3341  // do not create polygon for a 1 segment line
3342  if ( line.count() < 3 )
3343  return QgsGeometry();
3344  if ( line.count() == 3 && line.first() == line.last() )
3345  return QgsGeometry();
3346 
3347  // add closing node
3348  if ( line.first() != line.last() )
3349  line << line.first();
3350 
3351  // destination is multipart
3352  if ( destMultipart )
3353  {
3354  return fromMultiPolygonXY( QgsMultiPolygonXY() << ( QgsPolygonXY() << line ) );
3355  }
3356  else
3357  {
3358  return fromPolygonXY( QgsPolygonXY() << line );
3359  }
3360  }
3361  return QgsGeometry();
3362  }
3363 
3365  {
3366  bool srcIsMultipart = isMultipart();
3367 
3368  if ( ( destMultipart && srcIsMultipart ) ||
3369  ( !destMultipart && ! srcIsMultipart ) )
3370  {
3371  // return a copy of the same geom
3372  return QgsGeometry( *this );
3373  }
3374  if ( destMultipart )
3375  {
3376  // destination is multipart => makes a multipoint with a single polygon
3377  QgsPolygonXY polygon = asPolygon();
3378  if ( !polygon.isEmpty() )
3379  return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3380  }
3381  else
3382  {
3383  QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3384  if ( multiPolygon.count() == 1 )
3385  {
3386  // destination is singlepart => make a single part if possible
3387  return fromPolygonXY( multiPolygon[0] );
3388  }
3389  }
3390  return QgsGeometry();
3391  }
3392 
3393  default:
3394  return QgsGeometry();
3395  }
3396 }
3397 
3399 {
3400  return new QgsGeos( geometry );
3401 }
3402 
3403 QDataStream &operator<<( QDataStream &out, const QgsGeometry &geometry )
3404 {
3405  out << geometry.asWkb();
3406  return out;
3407 }
3408 
3409 QDataStream &operator>>( QDataStream &in, QgsGeometry &geometry )
3410 {
3411  QByteArray byteArray;
3412  in >> byteArray;
3413  if ( byteArray.isEmpty() )
3414  {
3415  geometry.set( nullptr );
3416  return in;
3417  }
3418 
3419  geometry.fromWkb( byteArray );
3420  return in;
3421 }
3422 
3423 
3425 {
3426  return mMessage;
3427 }
3428 
3430 {
3431  return mLocation;
3432 }
3433 
3435 {
3436  return mHasLocation;
3437 }
Geometry engine misses a method implemented or an error occurred in the geometry engine.
Definition: qgsgeometry.h:126
static std::unique_ptr< QgsAbstractGeometry > geomFromWkb(QgsConstWkbPtr &wkb)
Construct geometry from a WKB string.
bool boundingBoxIntersects(const QgsRectangle &rectangle) const
Returns true if the bounding box of this geometry intersects with a rectangle.
bool convertGeometryCollectionToSubclass(QgsWkbTypes::GeometryType geomType)
Converts geometry collection to a the desired geometry type subclass (multi-point, multi-linestring or multi-polygon).
QgsGeometry taperedBuffer(double startWidth, double endWidth, int segments) const
Calculates a tapered width buffer for a (multi)curve geometry.
static QgsPolygonXY createPolygonFromQPolygonF(const QPolygonF &polygon)
Creates a QgsPolygonXYfrom a QPolygonF.
static QgsGeometry fromMultiPolygonXY(const QgsMultiPolygonXY &multipoly)
Creates a new geometry from a QgsMultiPolygon.
Circle geometry type.
Definition: qgscircle.h:43
static void validateGeometry(const QgsGeometry &geometry, QVector< QgsGeometry::Error > &errors, QgsGeometry::ValidationMethod method=QgsGeometry::ValidatorQgisInternal)
Validate geometry and produce a list of geometry errors.
QgsGeometry orientedMinimumBoundingBox() const
Returns the oriented minimum bounding box for the geometry, which is the smallest (by area) rotated r...
double closestSegmentWithContext(const QgsPointXY &point, QgsPointXY &minDistPoint, int &afterVertex, int *leftOf=nullptr, double epsilon=DEFAULT_SEGMENT_EPSILON) const
Searches for the closest segment of geometry to the given point.
QgsGeometryConstPartIterator constParts() const
Returns Java-style iterator for traversal of parts of the geometry.
int precision
A rectangle specified with double values.
Definition: qgsrectangle.h:41
Java-style iterator for traversal of parts of a geometry.
double y
Definition: qgspoint.h:42
QgsGeometry combine(const QgsGeometry &geometry) const
Returns a geometry representing all the points in this geometry and other (a union geometry operation...
static QgsGeometry fromPolylineXY(const QgsPolylineXY &polyline)
Creates a new LineString geometry from a list of QgsPointXY points.
static std::unique_ptr< QgsAbstractGeometry > geomFromWkbType(QgsWkbTypes::Type t)
Returns empty geometry from wkb type.
void points(QgsPointSequence &pt) const override
Returns a list of points within the curve.
double hausdorffDistanceDensify(const QgsGeometry &geom, double densifyFraction) const
Returns the Hausdorff distance between this geometry and geom.
static Type multiType(Type type)
Returns the multi type for a WKB type.
Definition: qgswkbtypes.h: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:130
Nothing happened, without any error.
Definition: qgsgeometry.h:121
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer&#39;s length...
Use GEOS validation methods.
Definition: qgsgeometry.h:1872
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:265
QString asJson(int precision=17) const
Exports the geometry to a GeoJSON string.
OperationResult rotate(double rotation, const QgsPointXY &center)
Rotate this geometry around the Z axis.
static QgsGeometry fromMultiPolylineXY(const QgsMultiPolylineXY &multiline)
Creates a new geometry from a QgsMultiPolylineXY object.
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon.
QgsAbstractGeometry::const_part_iterator const_parts_begin() const
Returns STL-style const iterator pointing to the first part of the geometry.
TransformDirection
Enum used to indicate the direction (forward or inverse) of the transform.
QgsGeometryPartIterator parts()
Returns Java-style iterator for traversal of parts of the geometry.
QVector< QgsPolylineXY > QgsPolygonXY
Polygon: first item of the list is outer ring, inner rings (if any) start from second item...
Definition: qgsgeometry.h: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:247
QgsGeometry intersection(const QgsGeometry &geometry) const
Returns a geometry representing the points shared by this geometry and other.
QgsPoint center() const
Returns the center point.
Definition: qgsellipse.h:121
static QgsPoint closestVertex(const QgsAbstractGeometry &geom, const QgsPoint &pt, QgsVertexId &id)
Returns the closest vertex to a geometry for a specified point.
double distanceToVertex(int vertex) const
Returns the distance along this geometry from its first vertex to the specified vertex.
EndCapStyle
End cap styles for buffers.
Definition: qgsgeometry.h:1046
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:118
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 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 the contents of the geometry as a multi-linestring.
QVector< QgsGeometry > asGeometryCollection() const
Returns contents of the geometry as a list of geometries.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Indicates that self-touching holes are permitted. OGC validity states that self-touching holes are NO...
Definition: qgsgeometry.h:351
bool hasWhere() const
true if the location available from
QgsGeometry mergeLines() const
Merges any connected lines in a LineString/MultiLineString geometry and converts them to single line ...
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:37
QgsPointXY transform(const QgsPointXY &p) const
Transform the point from map (world) coordinates to device coordinates.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
int numInteriorRings() const
Returns the number of interior rings contained with the curve polygon.
Operation succeeded.
Nothing happened, without any error.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
QPointF toQPointF() const
Converts a point to a QPointF.
Definition: qgspointxy.h:148
static QgsPolylineXY createPolylineFromQPolygonF(const QPolygonF &polygon)
Creates a QgsPolylineXY from a QPolygonF.
bool isGeosValid(QgsGeometry::ValidityFlags flags=nullptr) const
Checks validity of the geometry using GEOS.
static bool deleteRing(QgsAbstractGeometry *geom, int ringNum, int partNum=0)
Deletes a ring from a geometry.
bool convertToSingleType()
Converts multi type geometry into single type geometry e.g.
bool equals(const QgsGeometry &geometry) const
Test if this geometry is exactly equal to another geometry.
QgsGeometry variableWidthBufferByM(int segments) const
Calculates a variable width buffer for a (multi)linestring geometry, where the width at each node is ...
Utility class for identifying a unique vertex within a geometry.
bool isEmpty() const
Returns true if the rectangle is empty.
Definition: qgsrectangle.h:426
QgsGeometry taperedBuffer(double startWidth, double endWidth, int segments) const
Calculates a variable width buffer ("tapered buffer") for a (multi)curve geometry.
Geometry collection.
QgsPolygonXY asPolygon() const
Returns the contents of the geometry as a polygon.
static QgsGeometry fromQPointF(QPointF point)
Construct geometry from a QPointF.
virtual QgsPolygon * toPolygon(unsigned int segments=36) const
Returns a segmented polygon.
Definition: qgsellipse.cpp:224
QgsGeometry convexHull() const
Returns the smallest convex polygon that contains all the points in the geometry. ...
The part_iterator class provides STL-style iterator for geometry parts.
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:202
QgsGeometry densifyByCount(int extraNodesPerSegment) const
Returns a copy of the geometry which has been densified by adding the specified number of extra nodes...
bool deleteVertex(int atVertex)
Deletes the vertex at the given position number and item (first number is index 0) ...
QString what() const
A human readable error message containing details about the error.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
void setY(double y)
Sets the y value of the point.
Definition: qgspointxy.h:113
QgsGeometryCollection * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership...
static GeometryType geometryType(Type type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:665
Use internal QgsGeometryValidator method.
Definition: qgsgeometry.h:1871
static std::unique_ptr< QgsAbstractGeometry > avoidIntersections(const QgsAbstractGeometry &geom, const QList< QgsVectorLayer *> &avoidIntersectionsLayers, const QHash< QgsVectorLayer *, QSet< QgsFeatureId > > &ignoreFeatures=(QHash< QgsVectorLayer *, QSet< QgsFeatureId > >()))
Alters a geometry so that it avoids intersections with features from all open vector layers...
static QgsGeometry fromMultiPointXY(const QgsMultiPointXY &multipoint)
Creates a new geometry from a QgsMultiPointXY object.
QgsGeometry extendLine(double startDistance, double endDistance) const
Extends a (multi)line geometry by extrapolating out the start or end of the line by a specified dista...
double sqrDistToVertexAt(QgsPointXY &point SIP_IN, int atVertex) const
Returns the squared Cartesian distance between the given point to the given vertex index (vertex at t...
T qgsgeometry_cast(const QgsAbstractGeometry *geom)
QgsGeometry offsetCurve(double distance, int segments, JoinStyle joinStyle, double miterLimit) const
Returns an offset line at a given distance and side from an input line.
QgsGeometry smooth(unsigned int iterations=1, double offset=0.25, double minimumDistance=-1.0, double maxAngle=180.0) const
Smooths a geometry by rounding off corners using the Chaikin algorithm.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
bool contains(const QgsPoint &point, double epsilon=1E-8) const
Returns true if the circle contains the point.
Definition: qgscircle.cpp:350
bool crosses(const QgsGeometry &geometry) const
Test for if geometry crosses another (uses GEOS)
QgsGeometry clipped(const QgsRectangle &rectangle)
Clips the geometry using the specified rectangle.
void transformVertices(const std::function< QgsPoint(const QgsPoint &) > &transform)
Transforms the vertices from the geometry in place, applying the transform function to every vertex...
static QgsGeometry polygonize(const QVector< const QgsAbstractGeometry *> &geometries, QString *errorMsg=nullptr)
Creates a GeometryCollection geometry containing possible polygons formed from the constituent linewo...
Definition: qgsgeos.cpp:2257
QgsGeometry densifyByDistance(double distance) const
Densifies the geometry by adding regularly placed extra nodes inside each segment so that the maximum...
Method not implemented in geometry engine.
virtual double area() const
Returns the area of the geometry.
virtual int ringCount(int part=0) const =0
Returns the number of rings of which this geometry is built.
Orientation
Curve orientation.
Definition: qgscurve.h:234
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
virtual QgsPolygon * toPolygon(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a new polygon geometry corresponding to a segmentized approximation of the curve...
static QgsPointXY interpolatePointOnLine(double x1, double y1, double x2, double y2, double fraction)
Interpolates the position of a point a fraction of the way along the line from (x1, y1) to (x2, y2).
QgsGeometry pointOnSurface() const
Returns a point guaranteed to lie on the surface of a geometry.
bool touches(const QgsGeometry &geometry) const
Test for if geometry touch another (uses GEOS)
Abstract base class for all geometries.
QgsCoordinateSequence coordinateSequence() const override
Retrieves the sequence of geometries, rings and nodes.
The vertex_iterator class provides STL-style iterator for vertices.
Does vector analysis using the geos library and handles import, export, exception handling*...
Definition: qgsgeos.h:103
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
static std::unique_ptr< QgsMultiLineString > fromMultiPolylineXY(const QgsMultiPolylineXY &multiline)
Construct geometry from a multipolyline.
QgsPoint project(double distance, double azimuth, double inclination=90.0) const
Returns a new point which correspond to this point projected by a specified distance with specified a...
Definition: qgspoint.cpp:648
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:177
QgsAbstractGeometry * combine(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the combination of this and geom.
Definition: qgsgeos.cpp:361
QString asWkt(int precision=17) const
Exports the geometry to WKT.
QPolygonF asQPolygonF() const
Returns contents of the geometry as a QPolygonF.
double interpolateAngle(double distance) const
Returns the angle parallel to the linestring or polygon boundary at the specified distance along the ...
static QgsGeometry fromPolygonXY(const QgsPolygonXY &polygon)
Creates a new geometry from a QgsPolygon.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
BufferSide
Side of line to buffer.
Definition: qgsgeometry.h:1038
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 the contents of the geometry as a 2-dimensional point.
The base geometry on which the operation is done is invalid or empty.
Definition: qgsgeometry.h:122
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:123
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:1869
virtual int vertexCount(int part=0, int ring=0) const =0
Returns the number of vertices of which this geometry is built.
virtual QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const =0
Returns a new line string geometry corresponding to a segmentized approximation of the curve...
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
QgsGeometry shortestLine(const QgsGeometry &other) const
Returns the shortest line joining this geometry to another geometry.
std::unique_ptr< QgsAbstractGeometry > _qgis_lwgeom_make_valid(const QgsAbstractGeometry *lwgeom_in, QString &errorMessage)
Implementation of QgsGeometry::makeValid(). Not a public API.
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
static QgsCircle minimalCircleFrom3Points(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double epsilon=1E-8)
Constructs the smallest circle from 3 points.
Definition: qgscircle.cpp:223
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:436
static QgsGeometry fromQPolygonF(const QPolygonF &polygon)
Construct geometry from a QPolygonF.
QgsGeometry snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0) const
Returns a new geometry with all points or vertices snapped to the closest point of the grid...
Class for doing transforms between two map coordinate systems.
QgsGeometry singleSidedBuffer(double distance, int segments, BufferSide side, JoinStyle joinStyle=JoinStyleRound, double miterLimit=2.0) const
Returns a single sided buffer for a (multi)line geometry.
The input is not valid.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
OperationResult translate(double dx, double dy, double dz=0.0, double dm=0.0)
Translates this geometry by dx, dy, dz and dm.
void adjacentVertices(int atVertex, int &beforeVertex, int &afterVertex) const
Returns the indexes of the vertices before and after the given vertex index.
QgsGeometry convertToType(QgsWkbTypes::GeometryType destType, bool destMultipart=false) const
Try to convert the geometry to the requested type.
QgsGeometry forceRHR() const
Forces geometries to respect the Right-Hand-Rule, in which the area that is bounded by a polygon is t...
double closestVertexWithContext(const QgsPointXY &point, int &atVertex) const
Searches for the closest vertex in this geometry to the given point.
Contains geometry relation and modification algorithms.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
QgsGeometry makeDifference(const QgsGeometry &other) const
Returns the geometry formed by modifying this geometry such that it does not intersect the other geom...
QgsPolylineXY asPolyline() const
Returns the contents of the geometry as a polyline.
Circular string geometry type.
QgsVertexIterator vertices() const
Returns a read-only, Java-style iterator for traversal of vertices of all the geometry, including all geometry parts and rings.
static QgsCircle from2Points(const QgsPoint &pt1, const QgsPoint &pt2)
Constructs a circle by 2 points on the circle.
Definition: qgscircle.cpp:37
QgsGeometry voronoiDiagram(const QgsGeometry &extent=QgsGeometry(), double tolerance=0.0, bool edgesOnly=false) const
Creates a Voronoi diagram for the nodes contained within the geometry.
static bool deletePart(QgsAbstractGeometry *geom, int partNum)
Deletes a part from a geometry.
QgsMultiPointXY asMultiPoint() const
Returns the contents of the geometry as a multi-point.
virtual bool dropMValue()=0
Drops any measure values which exist in the geometry.
QgsGeometry orthogonalize(double tolerance=1.0E-8, int maxIterations=1000, double angleThreshold=15.0) const
Attempts to orthogonalize a line or polygon geometry by shifting vertices to make the geometries angl...
double area() const
Returns the area of the geometry using GEOS.
EngineOperationResult
Success or failure of a geometry operation.
bool vertexIdFromVertexNr(int number, QgsVertexId &id) const
Calculates the vertex ID from a vertex number.
Polygon geometry type.
Definition: qgspolygon.h:31
Operation succeeded.
Definition: qgsgeometry.h:120
JoinStyle
Join styles for buffers.
Definition: qgsgeometry.h:1055
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 the contents of the geometry as a multi-polygon.
static QgsGeometry collectGeometry(const QVector< QgsGeometry > &geometries)
Creates a new multipart geometry from a list of QgsGeometry objects.
The geometry on which the operation occurs is not valid.
virtual int numPoints() const =0
Returns the number of points in the curve.
static double distanceToVertex(const QgsAbstractGeometry &geom, QgsVertexId id)
Returns the distance along a geometry from its first vertex to the specified vertex.
QgsAbstractGeometry::vertex_iterator vertices_begin() const
Returns STL-style iterator pointing to the first vertex of the geometry.
QgsAbstractGeometry::part_iterator parts_end()
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry...
double lineLocatePoint(const QgsGeometry &point) const
Returns a distance representing the location along this linestring of the closest point on this lines...
double ANALYSIS_EXPORT leftOf(const QgsPoint &thepoint, const QgsPoint *p1, const QgsPoint *p2)
Returns whether &#39;thepoint&#39; is left or right of the line from &#39;p1&#39; to &#39;p2&#39;. Negativ values mean left a...
Definition: MathUtils.cpp:292
bool disjoint(const QgsGeometry &geometry) const
Tests for if geometry is disjoint of another (uses GEOS)
virtual bool dropZValue()=0
Drops any z-dimensions which exist in the geometry.
static QgsGeometry fromPointXY(const QgsPointXY &point)
Creates a new geometry from a QgsPointXY object.
void validateGeometry(QVector< QgsGeometry::Error > &errors, ValidationMethod method=ValidatorQgisInternal, QgsGeometry::ValidityFlags flags=nullptr) const
Validates geometry and produces a list of geometry errors.
static QgsGeometry::OperationResult addRing(QgsAbstractGeometry *geometry, std::unique_ptr< QgsCurve > ring)
Add an interior ring to a geometry.
QgsGeometry extrude(double x, double y) const
Will extrude a line or (segmentized) curve by a given offset and return a polygon representation of i...
std::unique_ptr< QgsAbstractGeometry > geometry
Definition: qgsgeometry.cpp: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:209
static std::unique_ptr< QgsMultiPolygon > fromMultiPolygonXY(const QgsMultiPolygonXY &multipoly)
Construct geometry from a multipolygon.
std::unique_ptr< QgsLineString > smoothCurve(const QgsLineString &line, const unsigned int iterations, const double offset, double squareDistThreshold, double maxAngleRads, bool isRing)
QDataStream & operator>>(QDataStream &in, QgsGeometry &geometry)
Reads a geometry from stream in into geometry. QGIS version compatibility is not guaranteed.
int avoidIntersections(const QList< QgsVectorLayer *> &avoidIntersectionsLayers, const QHash< QgsVectorLayer *, QSet< QgsFeatureId > > &ignoreFeatures=(QHash< QgsVectorLayer *, QSet< QgsFeatureId > >()))
Modifies geometry to avoid intersections with the layers specified in project properties.
double x
Definition: qgspoint.h:41
QgsGeometry difference(const QgsGeometry &geometry) const
Returns a geometry representing the points making up this geometry that do not make up other...