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