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