QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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  pt2 = pt1;
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  QgsGeometry g = fromRect( r );
1137  return intersects( g );
1138 }
1139 
1140 bool QgsGeometry::intersects( const QgsGeometry &geometry ) const
1141 {
1142  if ( !d->geometry || geometry.isNull() )
1143  {
1144  return false;
1145  }
1146 
1147  QgsGeos geos( d->geometry.get() );
1148  mLastError.clear();
1149  return geos.intersects( geometry.d->geometry.get(), &mLastError );
1150 }
1151 
1152 bool QgsGeometry::boundingBoxIntersects( const QgsRectangle &rectangle ) const
1153 {
1154  if ( !d->geometry )
1155  {
1156  return false;
1157  }
1158 
1159  return d->geometry->boundingBox().intersects( rectangle );
1160 }
1161 
1163 {
1164  if ( !d->geometry || geometry.isNull() )
1165  {
1166  return false;
1167  }
1168 
1169  return d->geometry->boundingBox().intersects( geometry.constGet()->boundingBox() );
1170 }
1171 
1172 bool QgsGeometry::contains( const QgsPointXY *p ) const
1173 {
1174  if ( !d->geometry || !p )
1175  {
1176  return false;
1177  }
1178 
1179  QgsPoint pt( p->x(), p->y() );
1180  QgsGeos geos( d->geometry.get() );
1181  mLastError.clear();
1182  return geos.contains( &pt, &mLastError );
1183 }
1184 
1185 bool QgsGeometry::contains( const QgsGeometry &geometry ) const
1186 {
1187  if ( !d->geometry || geometry.isNull() )
1188  {
1189  return false;
1190  }
1191 
1192  QgsGeos geos( d->geometry.get() );
1193  mLastError.clear();
1194  return geos.contains( geometry.d->geometry.get(), &mLastError );
1195 }
1196 
1197 bool QgsGeometry::disjoint( const QgsGeometry &geometry ) const
1198 {
1199  if ( !d->geometry || geometry.isNull() )
1200  {
1201  return false;
1202  }
1203 
1204  QgsGeos geos( d->geometry.get() );
1205  mLastError.clear();
1206  return geos.disjoint( geometry.d->geometry.get(), &mLastError );
1207 }
1208 
1209 bool QgsGeometry::equals( const QgsGeometry &geometry ) const
1210 {
1211  if ( !d->geometry || geometry.isNull() )
1212  {
1213  return false;
1214  }
1215 
1216  // fast check - are they shared copies of the same underlying geometry?
1217  if ( d == geometry.d )
1218  return true;
1219 
1220  // slower check - actually test the geometries
1221  return *d->geometry == *geometry.d->geometry;
1222 }
1223 
1224 bool QgsGeometry::touches( const QgsGeometry &geometry ) const
1225 {
1226  if ( !d->geometry || geometry.isNull() )
1227  {
1228  return false;
1229  }
1230 
1231  QgsGeos geos( d->geometry.get() );
1232  mLastError.clear();
1233  return geos.touches( geometry.d->geometry.get(), &mLastError );
1234 }
1235 
1236 bool QgsGeometry::overlaps( const QgsGeometry &geometry ) const
1237 {
1238  if ( !d->geometry || geometry.isNull() )
1239  {
1240  return false;
1241  }
1242 
1243  QgsGeos geos( d->geometry.get() );
1244  mLastError.clear();
1245  return geos.overlaps( geometry.d->geometry.get(), &mLastError );
1246 }
1247 
1248 bool QgsGeometry::within( const QgsGeometry &geometry ) const
1249 {
1250  if ( !d->geometry || geometry.isNull() )
1251  {
1252  return false;
1253  }
1254 
1255  QgsGeos geos( d->geometry.get() );
1256  mLastError.clear();
1257  return geos.within( geometry.d->geometry.get(), &mLastError );
1258 }
1259 
1260 bool QgsGeometry::crosses( const QgsGeometry &geometry ) const
1261 {
1262  if ( !d->geometry || geometry.isNull() )
1263  {
1264  return false;
1265  }
1266 
1267  QgsGeos geos( d->geometry.get() );
1268  mLastError.clear();
1269  return geos.crosses( geometry.d->geometry.get(), &mLastError );
1270 }
1271 
1272 QString QgsGeometry::asWkt( int precision ) const
1273 {
1274  if ( !d->geometry )
1275  {
1276  return QString();
1277  }
1278  return d->geometry->asWkt( precision );
1279 }
1280 
1281 QString QgsGeometry::asJson( int precision ) const
1282 {
1283  return QString::fromStdString( asJsonObject( precision ).dump() );
1284 }
1285 
1287 {
1288  if ( !d->geometry )
1289  {
1290  return nullptr;
1291  }
1292  return d->geometry->asJsonObject( precision );
1293 
1294 }
1295 
1297 {
1298  switch ( destType )
1299  {
1301  return convertToPoint( destMultipart );
1302 
1304  return convertToLine( destMultipart );
1305 
1307  return convertToPolygon( destMultipart );
1308 
1309  default:
1310  return QgsGeometry();
1311  }
1312 }
1313 
1315 {
1316  if ( !d->geometry )
1317  {
1318  return false;
1319  }
1320 
1321  if ( isMultipart() ) //already multitype, no need to convert
1322  {
1323  return true;
1324  }
1325 
1326  std::unique_ptr< QgsAbstractGeometry >geom = QgsGeometryFactory::geomFromWkbType( QgsWkbTypes::multiType( d->geometry->wkbType() ) );
1327  QgsGeometryCollection *multiGeom = qgsgeometry_cast<QgsGeometryCollection *>( geom.get() );
1328  if ( !multiGeom )
1329  {
1330  return false;
1331  }
1332 
1333  //try to avoid cloning existing geometry whenever we can
1334 
1335  //want to see a magic trick?... gather round kiddies...
1336  detach(); // maybe a clone, hopefully not if we're the only ref to the private data
1337  // now we cheat a bit and steal the private geometry and add it direct to the multigeom
1338  // we can do this because we're the only ref to this geometry, guaranteed by the detach call above
1339  multiGeom->addGeometry( d->geometry.release() );
1340  // and replace it with the multi geometry.
1341  // TADA! a clone free conversion in some cases
1342  d->geometry = std::move( geom );
1343  return true;
1344 }
1345 
1347 {
1348  if ( !d->geometry )
1349  {
1350  return false;
1351  }
1352 
1353  if ( !isMultipart() ) //already single part, no need to convert
1354  {
1355  return true;
1356  }
1357 
1359  if ( !multiGeom || multiGeom->partCount() < 1 )
1360  return false;
1361 
1362  std::unique_ptr< QgsAbstractGeometry > firstPart( multiGeom->geometryN( 0 )->clone() );
1363  reset( std::move( firstPart ) );
1364  return true;
1365 }
1366 
1367 
1369 {
1370  const QgsGeometryCollection *origGeom = qgsgeometry_cast<const QgsGeometryCollection *>( constGet() );
1371  if ( !origGeom )
1372  return false;
1373 
1374  std::unique_ptr<QgsGeometryCollection> resGeom;
1375  switch ( geomType )
1376  {
1378  resGeom = qgis::make_unique<QgsMultiPoint>();
1379  break;
1381  resGeom = qgis::make_unique<QgsMultiLineString>();
1382  break;
1384  resGeom = qgis::make_unique<QgsMultiPolygon>();
1385  break;
1386  default:
1387  break;
1388  }
1389  if ( !resGeom )
1390  return false;
1391 
1392  resGeom->reserve( origGeom->numGeometries() );
1393  for ( int i = 0; i < origGeom->numGeometries(); ++i )
1394  {
1395  const QgsAbstractGeometry *g = origGeom->geometryN( i );
1396  if ( QgsWkbTypes::geometryType( g->wkbType() ) == geomType )
1397  resGeom->addGeometry( g->clone() );
1398  }
1399 
1400  set( resGeom.release() );
1401  return true;
1402 }
1403 
1404 
1406 {
1407  if ( !d->geometry || QgsWkbTypes::flatType( d->geometry->wkbType() ) != QgsWkbTypes::Point )
1408  {
1409  return QgsPointXY();
1410  }
1411  QgsPoint *pt = qgsgeometry_cast<QgsPoint *>( d->geometry.get() );
1412  if ( !pt )
1413  {
1414  return QgsPointXY();
1415  }
1416 
1417  return QgsPointXY( pt->x(), pt->y() );
1418 }
1419 
1421 {
1422  QgsPolylineXY polyLine;
1423  if ( !d->geometry )
1424  {
1425  return polyLine;
1426  }
1427 
1428  bool doSegmentation = ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::CompoundCurve
1430  std::unique_ptr< QgsLineString > segmentizedLine;
1431  QgsLineString *line = nullptr;
1432  if ( doSegmentation )
1433  {
1434  QgsCurve *curve = qgsgeometry_cast<QgsCurve *>( d->geometry.get() );
1435  if ( !curve )
1436  {
1437  return polyLine;
1438  }
1439  segmentizedLine.reset( curve->curveToLine() );
1440  line = segmentizedLine.get();
1441  }
1442  else
1443  {
1444  line = qgsgeometry_cast<QgsLineString *>( d->geometry.get() );
1445  if ( !line )
1446  {
1447  return polyLine;
1448  }
1449  }
1450 
1451  int nVertices = line->numPoints();
1452  polyLine.resize( nVertices );
1453  QgsPointXY *data = polyLine.data();
1454  const double *xData = line->xData();
1455  const double *yData = line->yData();
1456  for ( int i = 0; i < nVertices; ++i )
1457  {
1458  data->setX( *xData++ );
1459  data->setY( *yData++ );
1460  data++;
1461  }
1462 
1463  return polyLine;
1464 }
1465 
1467 {
1468  if ( !d->geometry )
1469  return QgsPolygonXY();
1470 
1471  bool doSegmentation = ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::CurvePolygon );
1472 
1473  QgsPolygon *p = nullptr;
1474  std::unique_ptr< QgsPolygon > segmentized;
1475  if ( doSegmentation )
1476  {
1477  QgsCurvePolygon *curvePoly = qgsgeometry_cast<QgsCurvePolygon *>( d->geometry.get() );
1478  if ( !curvePoly )
1479  {
1480  return QgsPolygonXY();
1481  }
1482  segmentized.reset( curvePoly->toPolygon() );
1483  p = segmentized.get();
1484  }
1485  else
1486  {
1487  p = qgsgeometry_cast<QgsPolygon *>( d->geometry.get() );
1488  }
1489 
1490  if ( !p )
1491  {
1492  return QgsPolygonXY();
1493  }
1494 
1495  QgsPolygonXY polygon;
1496  convertPolygon( *p, polygon );
1497 
1498  return polygon;
1499 }
1500 
1502 {
1503  if ( !d->geometry || QgsWkbTypes::flatType( d->geometry->wkbType() ) != QgsWkbTypes::MultiPoint )
1504  {
1505  return QgsMultiPointXY();
1506  }
1507 
1508  const QgsMultiPoint *mp = qgsgeometry_cast<QgsMultiPoint *>( d->geometry.get() );
1509  if ( !mp )
1510  {
1511  return QgsMultiPointXY();
1512  }
1513 
1514  int nPoints = mp->numGeometries();
1515  QgsMultiPointXY multiPoint( nPoints );
1516  for ( int i = 0; i < nPoints; ++i )
1517  {
1518  const QgsPoint *pt = static_cast<const QgsPoint *>( mp->geometryN( i ) );
1519  multiPoint[i].setX( pt->x() );
1520  multiPoint[i].setY( pt->y() );
1521  }
1522  return multiPoint;
1523 }
1524 
1526 {
1527  if ( !d->geometry )
1528  {
1529  return QgsMultiPolylineXY();
1530  }
1531 
1532  QgsGeometryCollection *geomCollection = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
1533  if ( !geomCollection )
1534  {
1535  return QgsMultiPolylineXY();
1536  }
1537 
1538  int nLines = geomCollection->numGeometries();
1539  if ( nLines < 1 )
1540  {
1541  return QgsMultiPolylineXY();
1542  }
1543 
1544  QgsMultiPolylineXY mpl;
1545  mpl.reserve( nLines );
1546  for ( int i = 0; i < nLines; ++i )
1547  {
1548  const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( geomCollection->geometryN( i ) );
1549  std::unique_ptr< QgsLineString > segmentized;
1550  if ( !line )
1551  {
1552  const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( geomCollection->geometryN( i ) );
1553  if ( !curve )
1554  {
1555  continue;
1556  }
1557  segmentized.reset( curve->curveToLine() );
1558  line = segmentized.get();
1559  }
1560 
1561  QgsPolylineXY polyLine;
1562  int nVertices = line->numPoints();
1563  polyLine.resize( nVertices );
1564  QgsPointXY *data = polyLine.data();
1565  const double *xData = line->xData();
1566  const double *yData = line->yData();
1567  for ( int i = 0; i < nVertices; ++i )
1568  {
1569  data->setX( *xData++ );
1570  data->setY( *yData++ );
1571  data++;
1572  }
1573  mpl.append( polyLine );
1574  }
1575  return mpl;
1576 }
1577 
1579 {
1580  if ( !d->geometry )
1581  {
1582  return QgsMultiPolygonXY();
1583  }
1584 
1585  QgsGeometryCollection *geomCollection = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
1586  if ( !geomCollection )
1587  {
1588  return QgsMultiPolygonXY();
1589  }
1590 
1591  int nPolygons = geomCollection->numGeometries();
1592  if ( nPolygons < 1 )
1593  {
1594  return QgsMultiPolygonXY();
1595  }
1596 
1597  QgsMultiPolygonXY mp;
1598  for ( int i = 0; i < nPolygons; ++i )
1599  {
1600  const QgsPolygon *polygon = qgsgeometry_cast<const QgsPolygon *>( geomCollection->geometryN( i ) );
1601  if ( !polygon )
1602  {
1603  const QgsCurvePolygon *cPolygon = qgsgeometry_cast<const QgsCurvePolygon *>( geomCollection->geometryN( i ) );
1604  if ( cPolygon )
1605  {
1606  polygon = cPolygon->toPolygon();
1607  }
1608  else
1609  {
1610  continue;
1611  }
1612  }
1613 
1614  QgsPolygonXY poly;
1615  convertPolygon( *polygon, poly );
1616  mp.append( poly );
1617  }
1618  return mp;
1619 }
1620 
1621 double QgsGeometry::area() const
1622 {
1623  if ( !d->geometry )
1624  {
1625  return -1.0;
1626  }
1627  QgsGeos g( d->geometry.get() );
1628 
1629 #if 0
1630  //debug: compare geos area with calculation in QGIS
1631  double geosArea = g.area();
1632  double qgisArea = 0;
1633  QgsSurface *surface = qgsgeometry_cast<QgsSurface *>( d->geometry );
1634  if ( surface )
1635  {
1636  qgisArea = surface->area();
1637  }
1638 #endif
1639 
1640  mLastError.clear();
1641  return g.area( &mLastError );
1642 }
1643 
1644 double QgsGeometry::length() const
1645 {
1646  if ( !d->geometry )
1647  {
1648  return -1.0;
1649  }
1650  QgsGeos g( d->geometry.get() );
1651  mLastError.clear();
1652  return g.length( &mLastError );
1653 }
1654 
1655 double QgsGeometry::distance( const QgsGeometry &geom ) const
1656 {
1657  if ( !d->geometry || !geom.d->geometry )
1658  {
1659  return -1.0;
1660  }
1661 
1662  // avoid calling geos for trivial point-to-point distance calculations
1664  {
1665  return qgsgeometry_cast< const QgsPoint * >( d->geometry.get() )->distance( *qgsgeometry_cast< const QgsPoint * >( geom.constGet() ) );
1666  }
1667 
1668  QgsGeos g( d->geometry.get() );
1669  mLastError.clear();
1670  return g.distance( geom.d->geometry.get(), &mLastError );
1671 }
1672 
1673 double QgsGeometry::hausdorffDistance( const QgsGeometry &geom ) const
1674 {
1675  if ( !d->geometry || !geom.d->geometry )
1676  {
1677  return -1.0;
1678  }
1679 
1680  QgsGeos g( d->geometry.get() );
1681  mLastError.clear();
1682  return g.hausdorffDistance( geom.d->geometry.get(), &mLastError );
1683 }
1684 
1685 double QgsGeometry::hausdorffDistanceDensify( const QgsGeometry &geom, double densifyFraction ) const
1686 {
1687  if ( !d->geometry || !geom.d->geometry )
1688  {
1689  return -1.0;
1690  }
1691 
1692  QgsGeos g( d->geometry.get() );
1693  mLastError.clear();
1694  return g.hausdorffDistanceDensify( geom.d->geometry.get(), densifyFraction, &mLastError );
1695 }
1696 
1698 {
1699  if ( !d->geometry || d->geometry.get()->isEmpty() )
1701  return d->geometry->vertices_begin();
1702 }
1703 
1705 {
1706  if ( !d->geometry || d->geometry.get()->isEmpty() )
1708  return d->geometry->vertices_end();
1709 }
1710 
1712 {
1713  if ( !d->geometry || d->geometry.get()->isEmpty() )
1714  return QgsVertexIterator();
1715  return QgsVertexIterator( d->geometry.get() );
1716 }
1717 
1719 {
1720  if ( !d->geometry )
1722 
1723  detach();
1724  return d->geometry->parts_begin();
1725 }
1726 
1728 {
1729  if ( !d->geometry )
1731  return d->geometry->parts_end();
1732 }
1733 
1735 {
1736  if ( !d->geometry )
1738  return d->geometry->const_parts_begin();
1739 }
1740 
1742 {
1743  if ( !d->geometry )
1745  return d->geometry->const_parts_end();
1746 }
1747 
1749 {
1750  if ( !d->geometry )
1751  return QgsGeometryPartIterator();
1752 
1753  detach();
1754  return QgsGeometryPartIterator( d->geometry.get() );
1755 }
1756 
1758 {
1759  if ( !d->geometry )
1761 
1762  return QgsGeometryConstPartIterator( d->geometry.get() );
1763 }
1764 
1765 QgsGeometry QgsGeometry::buffer( double distance, int segments ) const
1766 {
1767  if ( !d->geometry )
1768  {
1769  return QgsGeometry();
1770  }
1771 
1772  QgsGeos g( d->geometry.get() );
1773  mLastError.clear();
1774  std::unique_ptr<QgsAbstractGeometry> geom( g.buffer( distance, segments, &mLastError ) );
1775  if ( !geom )
1776  {
1777  QgsGeometry result;
1778  result.mLastError = mLastError;
1779  return result;
1780  }
1781  return QgsGeometry( std::move( geom ) );
1782 }
1783 
1784 QgsGeometry QgsGeometry::buffer( double distance, int segments, EndCapStyle endCapStyle, JoinStyle joinStyle, double miterLimit ) const
1785 {
1786  if ( !d->geometry )
1787  {
1788  return QgsGeometry();
1789  }
1790 
1791  QgsGeos g( d->geometry.get() );
1792  mLastError.clear();
1793  QgsAbstractGeometry *geom = g.buffer( distance, segments, endCapStyle, joinStyle, miterLimit, &mLastError );
1794  if ( !geom )
1795  {
1796  QgsGeometry result;
1797  result.mLastError = mLastError;
1798  return result;
1799  }
1800  return QgsGeometry( geom );
1801 }
1802 
1803 QgsGeometry QgsGeometry::offsetCurve( double distance, int segments, JoinStyle joinStyle, double miterLimit ) const
1804 {
1805  if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
1806  {
1807  return QgsGeometry();
1808  }
1809 
1810  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
1811  {
1812  const QVector<QgsGeometry> parts = asGeometryCollection();
1813  QVector<QgsGeometry> results;
1814  results.reserve( parts.count() );
1815  for ( const QgsGeometry &part : parts )
1816  {
1817  QgsGeometry result = part.offsetCurve( distance, segments, joinStyle, miterLimit );
1818  if ( !result.isNull() )
1819  results << result;
1820  }
1821  if ( results.isEmpty() )
1822  return QgsGeometry();
1823 
1824  QgsGeometry first = results.takeAt( 0 );
1825  for ( const QgsGeometry &result : qgis::as_const( results ) )
1826  {
1827  first.addPart( result );
1828  }
1829  return first;
1830  }
1831  else
1832  {
1833  QgsGeos geos( d->geometry.get() );
1834  mLastError.clear();
1835 
1836  // GEOS can flip the curve orientation in some circumstances. So record previous orientation and correct if required
1837  const QgsCurve::Orientation prevOrientation = qgsgeometry_cast< const QgsCurve * >( d->geometry.get() )->orientation();
1838 
1839  std::unique_ptr< QgsAbstractGeometry > offsetGeom( geos.offsetCurve( distance, segments, joinStyle, miterLimit, &mLastError ) );
1840  if ( !offsetGeom )
1841  {
1842  QgsGeometry result;
1843  result.mLastError = mLastError;
1844  return result;
1845  }
1846 
1847  if ( const QgsCurve *offsetCurve = qgsgeometry_cast< const QgsCurve * >( offsetGeom.get() ) )
1848  {
1849  const QgsCurve::Orientation newOrientation = offsetCurve->orientation();
1850  if ( newOrientation != prevOrientation )
1851  {
1852  // GEOS has flipped line orientation, flip it back
1853  std::unique_ptr< QgsAbstractGeometry > flipped( offsetCurve->reversed() );
1854  offsetGeom = std::move( flipped );
1855  }
1856  }
1857  return QgsGeometry( std::move( offsetGeom ) );
1858  }
1859 }
1860 
1861 QgsGeometry QgsGeometry::singleSidedBuffer( double distance, int segments, BufferSide side, JoinStyle joinStyle, double miterLimit ) const
1862 {
1863  if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
1864  {
1865  return QgsGeometry();
1866  }
1867 
1868  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
1869  {
1870  const QVector<QgsGeometry> parts = asGeometryCollection();
1871  QVector<QgsGeometry> results;
1872  results.reserve( parts.count() );
1873  for ( const QgsGeometry &part : parts )
1874  {
1875  QgsGeometry result = part.singleSidedBuffer( distance, segments, side, joinStyle, miterLimit );
1876  if ( !result.isNull() )
1877  results << result;
1878  }
1879  if ( results.isEmpty() )
1880  return QgsGeometry();
1881 
1882  QgsGeometry first = results.takeAt( 0 );
1883  for ( const QgsGeometry &result : qgis::as_const( results ) )
1884  {
1885  first.addPart( result );
1886  }
1887  return first;
1888  }
1889  else
1890  {
1891  QgsGeos geos( d->geometry.get() );
1892  mLastError.clear();
1893  std::unique_ptr< QgsAbstractGeometry > bufferGeom = geos.singleSidedBuffer( distance, segments, side,
1894  joinStyle, miterLimit, &mLastError );
1895  if ( !bufferGeom )
1896  {
1897  QgsGeometry result;
1898  result.mLastError = mLastError;
1899  return result;
1900  }
1901  return QgsGeometry( std::move( bufferGeom ) );
1902  }
1903 }
1904 
1905 QgsGeometry QgsGeometry::taperedBuffer( double startWidth, double endWidth, int segments ) const
1906 {
1907  QgsInternalGeometryEngine engine( *this );
1908 
1909  return engine.taperedBuffer( startWidth, endWidth, segments );
1910 }
1911 
1913 {
1914  QgsInternalGeometryEngine engine( *this );
1915 
1916  return engine.variableWidthBufferByM( segments );
1917 }
1918 
1919 QgsGeometry QgsGeometry::extendLine( double startDistance, double endDistance ) const
1920 {
1921  if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
1922  {
1923  return QgsGeometry();
1924  }
1925 
1926  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
1927  {
1928  const QVector<QgsGeometry> parts = asGeometryCollection();
1929  QVector<QgsGeometry> results;
1930  results.reserve( parts.count() );
1931  for ( const QgsGeometry &part : parts )
1932  {
1933  QgsGeometry result = part.extendLine( startDistance, endDistance );
1934  if ( !result.isNull() )
1935  results << result;
1936  }
1937  if ( results.isEmpty() )
1938  return QgsGeometry();
1939 
1940  QgsGeometry first = results.takeAt( 0 );
1941  for ( const QgsGeometry &result : qgis::as_const( results ) )
1942  {
1943  first.addPart( result );
1944  }
1945  return first;
1946  }
1947  else
1948  {
1949  QgsLineString *line = qgsgeometry_cast< QgsLineString * >( d->geometry.get() );
1950  if ( !line )
1951  return QgsGeometry();
1952 
1953  std::unique_ptr< QgsLineString > newLine( line->clone() );
1954  newLine->extend( startDistance, endDistance );
1955  return QgsGeometry( std::move( newLine ) );
1956  }
1957 }
1958 
1959 QgsGeometry QgsGeometry::simplify( double tolerance ) const
1960 {
1961  if ( !d->geometry )
1962  {
1963  return QgsGeometry();
1964  }
1965 
1966  QgsGeos geos( d->geometry.get() );
1967  mLastError.clear();
1968  std::unique_ptr< QgsAbstractGeometry > simplifiedGeom( geos.simplify( tolerance, &mLastError ) );
1969  if ( !simplifiedGeom )
1970  {
1971  QgsGeometry result;
1972  result.mLastError = mLastError;
1973  return result;
1974  }
1975  return QgsGeometry( std::move( simplifiedGeom ) );
1976 }
1977 
1978 QgsGeometry QgsGeometry::densifyByCount( int extraNodesPerSegment ) const
1979 {
1980  QgsInternalGeometryEngine engine( *this );
1981 
1982  return engine.densifyByCount( extraNodesPerSegment );
1983 }
1984 
1986 {
1987  QgsInternalGeometryEngine engine( *this );
1988 
1989  return engine.densifyByDistance( distance );
1990 }
1991 
1993 {
1994  if ( !d->geometry )
1995  {
1996  return QgsGeometry();
1997  }
1998 
1999  // avoid calling geos for trivial point centroids
2000  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::Point )
2001  {
2002  QgsGeometry c = *this;
2003  c.get()->dropZValue();
2004  c.get()->dropMValue();
2005  return c;
2006  }
2007 
2008  QgsGeos geos( d->geometry.get() );
2009 
2010  mLastError.clear();
2011  QgsGeometry result( geos.centroid( &mLastError ) );
2012  result.mLastError = mLastError;
2013  return result;
2014 }
2015 
2017 {
2018  if ( !d->geometry )
2019  {
2020  return QgsGeometry();
2021  }
2022 
2023  QgsGeos geos( d->geometry.get() );
2024 
2025  mLastError.clear();
2026  QgsGeometry result( geos.pointOnSurface( &mLastError ) );
2027  result.mLastError = mLastError;
2028  return result;
2029 }
2030 
2031 QgsGeometry QgsGeometry::poleOfInaccessibility( double precision, double *distanceToBoundary ) const
2032 {
2033  QgsInternalGeometryEngine engine( *this );
2034 
2035  return engine.poleOfInaccessibility( precision, distanceToBoundary );
2036 }
2037 
2039 {
2040  if ( !d->geometry )
2041  {
2042  return QgsGeometry();
2043  }
2044  QgsGeos geos( d->geometry.get() );
2045  mLastError.clear();
2046  std::unique_ptr< QgsAbstractGeometry > cHull( geos.convexHull( &mLastError ) );
2047  if ( !cHull )
2048  {
2049  QgsGeometry geom;
2050  geom.mLastError = mLastError;
2051  return geom;
2052  }
2053  return QgsGeometry( std::move( cHull ) );
2054 }
2055 
2056 QgsGeometry QgsGeometry::voronoiDiagram( const QgsGeometry &extent, double tolerance, bool edgesOnly ) const
2057 {
2058  if ( !d->geometry )
2059  {
2060  return QgsGeometry();
2061  }
2062 
2063  QgsGeos geos( d->geometry.get() );
2064  mLastError.clear();
2065  QgsGeometry result = geos.voronoiDiagram( extent.constGet(), tolerance, edgesOnly, &mLastError );
2066  result.mLastError = mLastError;
2067  return result;
2068 }
2069 
2070 QgsGeometry QgsGeometry::delaunayTriangulation( double tolerance, bool edgesOnly ) const
2071 {
2072  if ( !d->geometry )
2073  {
2074  return QgsGeometry();
2075  }
2076 
2077  QgsGeos geos( d->geometry.get() );
2078  mLastError.clear();
2079  QgsGeometry result = geos.delaunayTriangulation( tolerance, edgesOnly );
2080  result.mLastError = mLastError;
2081  return result;
2082 }
2083 
2085 {
2086  if ( !d->geometry )
2087  {
2088  return QgsGeometry();
2089  }
2090 
2091  const QgsAbstractGeometry *geom = d->geometry.get();
2092  std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
2093  if ( QgsWkbTypes::isCurvedType( d->geometry->wkbType() ) )
2094  {
2095  segmentizedCopy.reset( d->geometry->segmentize() );
2096  geom = segmentizedCopy.get();
2097  }
2098 
2099  QgsGeos geos( geom );
2100  mLastError.clear();
2101  std::unique_ptr< QgsAbstractGeometry > result( geos.subdivide( maxNodes, &mLastError ) );
2102  if ( !result )
2103  {
2104  QgsGeometry geom;
2105  geom.mLastError = mLastError;
2106  return geom;
2107  }
2108  return QgsGeometry( std::move( result ) );
2109 }
2110 
2112 {
2113  if ( !d->geometry )
2114  {
2115  return QgsGeometry();
2116  }
2117 
2118  QgsGeometry line = *this;
2119  if ( type() == QgsWkbTypes::PointGeometry )
2120  return QgsGeometry();
2121  else if ( type() == QgsWkbTypes::PolygonGeometry )
2122  {
2123  line = QgsGeometry( d->geometry->boundary() );
2124  }
2125 
2126  const QgsCurve *curve = nullptr;
2127  if ( line.isMultipart() )
2128  {
2129  // if multi part, just use first part
2130  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( line.constGet() );
2131  if ( collection && collection->numGeometries() > 0 )
2132  {
2133  curve = qgsgeometry_cast< const QgsCurve * >( collection->geometryN( 0 ) );
2134  }
2135  }
2136  else
2137  {
2138  curve = qgsgeometry_cast< const QgsCurve * >( line.constGet() );
2139  }
2140  if ( !curve )
2141  return QgsGeometry();
2142 
2143  std::unique_ptr< QgsPoint > result( curve->interpolatePoint( distance ) );
2144  if ( !result )
2145  {
2146  return QgsGeometry();
2147  }
2148  return QgsGeometry( std::move( result ) );
2149 }
2150 
2151 double QgsGeometry::lineLocatePoint( const QgsGeometry &point ) const
2152 {
2153  if ( type() != QgsWkbTypes::LineGeometry )
2154  return -1;
2155 
2156  if ( QgsWkbTypes::flatType( point.wkbType() ) != QgsWkbTypes::Point )
2157  return -1;
2158 
2159  QgsGeometry segmentized = *this;
2161  {
2162  segmentized = QgsGeometry( static_cast< QgsCurve * >( d->geometry.get() )->segmentize() );
2163  }
2164 
2165  QgsGeos geos( d->geometry.get() );
2166  mLastError.clear();
2167  return geos.lineLocatePoint( *( static_cast< QgsPoint * >( point.d->geometry.get() ) ), &mLastError );
2168 }
2169 
2171 {
2172  if ( !d->geometry )
2173  return 0.0;
2174 
2175  // always operate on segmentized geometries
2176  QgsGeometry segmentized = *this;
2178  {
2179  segmentized = QgsGeometry( static_cast< QgsCurve * >( d->geometry.get() )->segmentize() );
2180  }
2181 
2182  QgsVertexId previous;
2183  QgsVertexId next;
2184  if ( !QgsGeometryUtils::verticesAtDistance( *segmentized.constGet(), distance, previous, next ) )
2185  return 0.0;
2186 
2187  if ( previous == next )
2188  {
2189  // distance coincided exactly with a vertex
2190  QgsVertexId v2 = previous;
2191  QgsVertexId v1;
2192  QgsVertexId v3;
2193  segmentized.constGet()->adjacentVertices( v2, v1, v3 );
2194  if ( v1.isValid() && v3.isValid() )
2195  {
2196  QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
2197  QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
2198  QgsPoint p3 = segmentized.constGet()->vertexAt( v3 );
2199  double angle1 = QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2200  double angle2 = QgsGeometryUtils::lineAngle( p2.x(), p2.y(), p3.x(), p3.y() );
2201  return QgsGeometryUtils::averageAngle( angle1, angle2 );
2202  }
2203  else if ( v3.isValid() )
2204  {
2205  QgsPoint p1 = segmentized.constGet()->vertexAt( v2 );
2206  QgsPoint p2 = segmentized.constGet()->vertexAt( v3 );
2207  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2208  }
2209  else
2210  {
2211  QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
2212  QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
2213  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2214  }
2215  }
2216  else
2217  {
2218  QgsPoint p1 = segmentized.constGet()->vertexAt( previous );
2219  QgsPoint p2 = segmentized.constGet()->vertexAt( next );
2220  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2221  }
2222 }
2223 
2225 {
2226  if ( !d->geometry || geometry.isNull() )
2227  {
2228  return QgsGeometry();
2229  }
2230 
2231  QgsGeos geos( d->geometry.get() );
2232 
2233  mLastError.clear();
2234  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.intersection( geometry.d->geometry.get(), &mLastError ) );
2235 
2236  if ( !resultGeom )
2237  {
2238  QgsGeometry geom;
2239  geom.mLastError = mLastError;
2240  return geom;
2241  }
2242 
2243  return QgsGeometry( std::move( resultGeom ) );
2244 }
2245 
2247 {
2248  if ( !d->geometry || geometry.isNull() )
2249  {
2250  return QgsGeometry();
2251  }
2252 
2253  QgsGeos geos( d->geometry.get() );
2254  mLastError.clear();
2255  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.combine( geometry.d->geometry.get(), &mLastError ) );
2256  if ( !resultGeom )
2257  {
2258  QgsGeometry geom;
2259  geom.mLastError = mLastError;
2260  return geom;
2261  }
2262  return QgsGeometry( std::move( resultGeom ) );
2263 }
2264 
2266 {
2267  if ( !d->geometry )
2268  {
2269  return QgsGeometry();
2270  }
2271 
2272  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::LineString )
2273  {
2274  // special case - a single linestring was passed
2275  return QgsGeometry( *this );
2276  }
2277 
2278  QgsGeos geos( d->geometry.get() );
2279  mLastError.clear();
2280  QgsGeometry result = geos.mergeLines( &mLastError );
2281  result.mLastError = mLastError;
2282  return result;
2283 }
2284 
2286 {
2287  if ( !d->geometry || geometry.isNull() )
2288  {
2289  return QgsGeometry();
2290  }
2291 
2292  QgsGeos geos( d->geometry.get() );
2293 
2294  mLastError.clear();
2295  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.difference( geometry.d->geometry.get(), &mLastError ) );
2296  if ( !resultGeom )
2297  {
2298  QgsGeometry geom;
2299  geom.mLastError = mLastError;
2300  return geom;
2301  }
2302  return QgsGeometry( std::move( resultGeom ) );
2303 }
2304 
2306 {
2307  if ( !d->geometry || geometry.isNull() )
2308  {
2309  return QgsGeometry();
2310  }
2311 
2312  QgsGeos geos( d->geometry.get() );
2313 
2314  mLastError.clear();
2315  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.symDifference( geometry.d->geometry.get(), &mLastError ) );
2316  if ( !resultGeom )
2317  {
2318  QgsGeometry geom;
2319  geom.mLastError = mLastError;
2320  return geom;
2321  }
2322  return QgsGeometry( std::move( resultGeom ) );
2323 }
2324 
2325 QgsGeometry QgsGeometry::extrude( double x, double y )
2326 {
2327  QgsInternalGeometryEngine engine( *this );
2328 
2329  return engine.extrude( x, y );
2330 }
2331 
2333 QVector<QgsPointXY> QgsGeometry::randomPointsInPolygon( int count, const std::function< bool( const QgsPointXY & ) > &acceptPoint, unsigned long seed, QgsFeedback *feedback )
2334 {
2336  return QVector< QgsPointXY >();
2337 
2338  return QgsInternalGeometryEngine::randomPointsInPolygon( *this, count, acceptPoint, seed, feedback );
2339 }
2340 
2341 QVector<QgsPointXY> QgsGeometry::randomPointsInPolygon( int count, unsigned long seed, QgsFeedback *feedback )
2342 {
2344  return QVector< QgsPointXY >();
2345 
2346  return QgsInternalGeometryEngine::randomPointsInPolygon( *this, count, []( const QgsPointXY & ) { return true; }, seed, feedback );
2347 }
2349 
2350 QByteArray QgsGeometry::asWkb() const
2351 {
2352  return d->geometry ? d->geometry->asWkb() : QByteArray();
2353 }
2354 
2355 QVector<QgsGeometry> QgsGeometry::asGeometryCollection() const
2356 {
2357  QVector<QgsGeometry> geometryList;
2358  if ( !d->geometry )
2359  {
2360  return geometryList;
2361  }
2362 
2364  if ( gc )
2365  {
2366  int numGeom = gc->numGeometries();
2367  geometryList.reserve( numGeom );
2368  for ( int i = 0; i < numGeom; ++i )
2369  {
2370  geometryList.append( QgsGeometry( gc->geometryN( i )->clone() ) );
2371  }
2372  }
2373  else //a singlepart geometry
2374  {
2375  geometryList.append( *this );
2376  }
2377 
2378  return geometryList;
2379 }
2380 
2381 QPointF QgsGeometry::asQPointF() const
2382 {
2383  QgsPointXY point = asPoint();
2384  return point.toQPointF();
2385 }
2386 
2387 QPolygonF QgsGeometry::asQPolygonF() const
2388 {
2389  const QgsWkbTypes::Type type = wkbType();
2390  const QgsLineString *line = nullptr;
2392  {
2393  line = qgsgeometry_cast< const QgsLineString * >( constGet() );
2394  }
2395  else if ( QgsWkbTypes::flatType( type ) == QgsWkbTypes::Polygon )
2396  {
2397  const QgsPolygon *polygon = qgsgeometry_cast< const QgsPolygon * >( constGet() );
2398  if ( polygon )
2399  line = qgsgeometry_cast< const QgsLineString * >( polygon->exteriorRing() );
2400  }
2401 
2402  if ( line )
2403  {
2404  const double *srcX = line->xData();
2405  const double *srcY = line->yData();
2406  const int count = line->numPoints();
2407  QPolygonF res( count );
2408  QPointF *dest = res.data();
2409  for ( int i = 0; i < count; ++i )
2410  {
2411  *dest++ = QPointF( *srcX++, *srcY++ );
2412  }
2413  return res;
2414  }
2415  else
2416  {
2417  return QPolygonF();
2418  }
2419 }
2420 
2421 bool QgsGeometry::deleteRing( int ringNum, int partNum )
2422 {
2423  if ( !d->geometry )
2424  {
2425  return false;
2426  }
2427 
2428  detach();
2429  bool ok = QgsGeometryEditUtils::deleteRing( d->geometry.get(), ringNum, partNum );
2430  return ok;
2431 }
2432 
2433 bool QgsGeometry::deletePart( int partNum )
2434 {
2435  if ( !d->geometry )
2436  {
2437  return false;
2438  }
2439 
2440  if ( !isMultipart() && partNum < 1 )
2441  {
2442  set( nullptr );
2443  return true;
2444  }
2445 
2446  detach();
2447  bool ok = QgsGeometryEditUtils::deletePart( d->geometry.get(), partNum );
2448  return ok;
2449 }
2450 
2451 int QgsGeometry::avoidIntersections( const QList<QgsVectorLayer *> &avoidIntersectionsLayers, const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures )
2452 {
2453  if ( !d->geometry )
2454  {
2455  return 1;
2456  }
2457 
2458  std::unique_ptr< QgsAbstractGeometry > diffGeom = QgsGeometryEditUtils::avoidIntersections( *( d->geometry ), avoidIntersectionsLayers, ignoreFeatures );
2459  if ( diffGeom )
2460  {
2461  reset( std::move( diffGeom ) );
2462  }
2463  return 0;
2464 }
2465 
2466 
2468 {
2469  if ( !d->geometry )
2470  return QgsGeometry();
2471 
2472  mLastError.clear();
2473  std::unique_ptr< QgsAbstractGeometry > g( _qgis_lwgeom_make_valid( d->geometry.get(), mLastError ) );
2474 
2475  QgsGeometry result = QgsGeometry( std::move( g ) );
2476  result.mLastError = mLastError;
2477  return result;
2478 }
2479 
2481 {
2482  if ( !d->geometry )
2483  return QgsGeometry();
2484 
2485  if ( isMultipart() )
2486  {
2487  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( d->geometry.get() );
2488  std::unique_ptr< QgsGeometryCollection > newCollection( collection->createEmptyWithSameType() );
2489  newCollection->reserve( collection->numGeometries() );
2490  for ( int i = 0; i < collection->numGeometries(); ++i )
2491  {
2492  const QgsAbstractGeometry *g = collection->geometryN( i );
2493  if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( g ) )
2494  {
2495  std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2496  corrected->forceRHR();
2497  newCollection->addGeometry( corrected.release() );
2498  }
2499  else
2500  {
2501  newCollection->addGeometry( g->clone() );
2502  }
2503  }
2504  return QgsGeometry( std::move( newCollection ) );
2505  }
2506  else
2507  {
2508  if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( d->geometry.get() ) )
2509  {
2510  std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2511  corrected->forceRHR();
2512  return QgsGeometry( std::move( corrected ) );
2513  }
2514  else
2515  {
2516  // not a curve polygon, so return unchanged
2517  return *this;
2518  }
2519  }
2520 }
2521 
2522 
2523 void QgsGeometry::validateGeometry( QVector<QgsGeometry::Error> &errors, const ValidationMethod method, const QgsGeometry::ValidityFlags flags ) const
2524 {
2525  errors.clear();
2526  if ( !d->geometry )
2527  return;
2528 
2529  // avoid expensive calcs for trivial point geometries
2531  {
2532  return;
2533  }
2534 
2535  switch ( method )
2536  {
2537  case ValidatorQgisInternal:
2538  QgsGeometryValidator::validateGeometry( *this, errors, method );
2539  return;
2540 
2541  case ValidatorGeos:
2542  {
2543  QgsGeos geos( d->geometry.get() );
2544  QString error;
2545  QgsGeometry errorLoc;
2546  if ( !geos.isValid( &error, flags & FlagAllowSelfTouchingHoles, &errorLoc ) )
2547  {
2548  if ( errorLoc.isNull() )
2549  {
2550  errors.append( QgsGeometry::Error( error ) );
2551  }
2552  else
2553  {
2554  const QgsPointXY point = errorLoc.asPoint();
2555  errors.append( QgsGeometry::Error( error, point ) );
2556  }
2557  return;
2558  }
2559  }
2560  }
2561 }
2562 
2563 bool QgsGeometry::isGeosValid( const QgsGeometry::ValidityFlags flags ) const
2564 {
2565  if ( !d->geometry )
2566  {
2567  return false;
2568  }
2569 
2570  return d->geometry->isValid( mLastError, static_cast< int >( flags ) );
2571 }
2572 
2574 {
2575  if ( !d->geometry )
2576  return false;
2577 
2578  QgsGeos geos( d->geometry.get() );
2579  mLastError.clear();
2580  return geos.isSimple( &mLastError );
2581 }
2582 
2584 {
2585  if ( !d->geometry || !g.d->geometry )
2586  {
2587  return false;
2588  }
2589 
2590  // fast check - are they shared copies of the same underlying geometry?
2591  if ( d == g.d )
2592  return true;
2593 
2594  // avoid calling geos for trivial point case
2595  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::Point
2596  && QgsWkbTypes::flatType( g.d->geometry->wkbType() ) == QgsWkbTypes::Point )
2597  {
2598  return equals( g );
2599  }
2600 
2601  // another nice fast check upfront -- if the bounding boxes aren't equal, the geometries themselves can't be equal!
2602  if ( d->geometry->boundingBox() != g.d->geometry->boundingBox() )
2603  return false;
2604 
2605  QgsGeos geos( d->geometry.get() );
2606  mLastError.clear();
2607  return geos.isEqual( g.d->geometry.get(), &mLastError );
2608 }
2609 
2610 QgsGeometry QgsGeometry::unaryUnion( const QVector<QgsGeometry> &geometries )
2611 {
2612  QgsGeos geos( nullptr );
2613 
2614  QString error;
2615  std::unique_ptr< QgsAbstractGeometry > geom( geos.combine( geometries, &error ) );
2616  QgsGeometry result( std::move( geom ) );
2617  result.mLastError = error;
2618  return result;
2619 }
2620 
2621 QgsGeometry QgsGeometry::polygonize( const QVector<QgsGeometry> &geometryList )
2622 {
2623  QgsGeos geos( nullptr );
2624 
2625  QVector<const QgsAbstractGeometry *> geomV2List;
2626  for ( const QgsGeometry &g : geometryList )
2627  {
2628  if ( !( g.isNull() ) )
2629  {
2630  geomV2List.append( g.constGet() );
2631  }
2632  }
2633 
2634  QString error;
2635  QgsGeometry result = geos.polygonize( geomV2List, &error );
2636  result.mLastError = error;
2637  return result;
2638 }
2639 
2641 {
2643  {
2644  return;
2645  }
2646 
2647  std::unique_ptr< QgsAbstractGeometry > straightGeom( d->geometry->segmentize( tolerance, toleranceType ) );
2648  reset( std::move( straightGeom ) );
2649 }
2650 
2652 {
2653  if ( !d->geometry )
2654  {
2655  return false;
2656  }
2657 
2658  return d->geometry->hasCurvedSegments();
2659 }
2660 
2662 {
2663  if ( !d->geometry )
2664  {
2666  }
2667 
2668  detach();
2669  d->geometry->transform( ct, direction, transformZ );
2670  return QgsGeometry::Success;
2671 }
2672 
2673 QgsGeometry::OperationResult QgsGeometry::transform( const QTransform &ct, double zTranslate, double zScale, double mTranslate, double mScale )
2674 {
2675  if ( !d->geometry )
2676  {
2678  }
2679 
2680  detach();
2681  d->geometry->transform( ct, zTranslate, zScale, mTranslate, mScale );
2682  return QgsGeometry::Success;
2683 }
2684 
2686 {
2687  if ( d->geometry )
2688  {
2689  detach();
2690  d->geometry->transform( mtp.transform() );
2691  }
2692 }
2693 
2695 {
2696  if ( !d->geometry || rectangle.isNull() || rectangle.isEmpty() )
2697  {
2698  return QgsGeometry();
2699  }
2700 
2701  QgsGeos geos( d->geometry.get() );
2702  mLastError.clear();
2703  std::unique_ptr< QgsAbstractGeometry > resultGeom = geos.clip( rectangle, &mLastError );
2704  if ( !resultGeom )
2705  {
2706  QgsGeometry result;
2707  result.mLastError = mLastError;
2708  return result;
2709  }
2710  return QgsGeometry( std::move( resultGeom ) );
2711 }
2712 
2713 void QgsGeometry::draw( QPainter &p ) const
2714 {
2715  if ( d->geometry )
2716  {
2717  d->geometry->draw( p );
2718  }
2719 }
2720 
2721 static bool vertexIndexInfo( const QgsAbstractGeometry *g, int vertexIndex, int &partIndex, int &ringIndex, int &vertex )
2722 {
2723  if ( vertexIndex < 0 )
2724  return false; // clearly something wrong
2725 
2726  if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
2727  {
2728  partIndex = 0;
2729  int offset = 0;
2730  for ( int i = 0; i < geomCollection->numGeometries(); ++i )
2731  {
2732  const QgsAbstractGeometry *part = geomCollection->geometryN( i );
2733 
2734  // count total number of vertices in the part
2735  int numPoints = 0;
2736  for ( int k = 0; k < part->ringCount(); ++k )
2737  numPoints += part->vertexCount( 0, k );
2738 
2739  if ( vertexIndex < numPoints )
2740  {
2741  int nothing;
2742  return vertexIndexInfo( part, vertexIndex, nothing, ringIndex, vertex ); // set ring_index + index
2743  }
2744  vertexIndex -= numPoints;
2745  offset += numPoints;
2746  partIndex++;
2747  }
2748  }
2749  else if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
2750  {
2751  const QgsCurve *ring = curvePolygon->exteriorRing();
2752  if ( vertexIndex < ring->numPoints() )
2753  {
2754  partIndex = 0;
2755  ringIndex = 0;
2756  vertex = vertexIndex;
2757  return true;
2758  }
2759  vertexIndex -= ring->numPoints();
2760  ringIndex = 1;
2761  for ( int i = 0; i < curvePolygon->numInteriorRings(); ++i )
2762  {
2763  const QgsCurve *ring = curvePolygon->interiorRing( i );
2764  if ( vertexIndex < ring->numPoints() )
2765  {
2766  partIndex = 0;
2767  vertex = vertexIndex;
2768  return true;
2769  }
2770  vertexIndex -= ring->numPoints();
2771  ringIndex += 1;
2772  }
2773  }
2774  else if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
2775  {
2776  if ( vertexIndex < curve->numPoints() )
2777  {
2778  partIndex = 0;
2779  ringIndex = 0;
2780  vertex = vertexIndex;
2781  return true;
2782  }
2783  }
2784  else if ( qgsgeometry_cast<const QgsPoint *>( g ) )
2785  {
2786  if ( vertexIndex == 0 )
2787  {
2788  partIndex = 0;
2789  ringIndex = 0;
2790  vertex = 0;
2791  return true;
2792  }
2793  }
2794 
2795  return false;
2796 }
2797 
2799 {
2800  if ( !d->geometry )
2801  {
2802  return false;
2803  }
2804 
2805  id.type = QgsVertexId::SegmentVertex;
2806 
2807  bool res = vertexIndexInfo( d->geometry.get(), nr, id.part, id.ring, id.vertex );
2808  if ( !res )
2809  return false;
2810 
2811  // now let's find out if it is a straight or circular segment
2812  const QgsAbstractGeometry *g = d->geometry.get();
2813  if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
2814  {
2815  g = geomCollection->geometryN( id.part );
2816  }
2817 
2818  if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
2819  {
2820  g = id.ring == 0 ? curvePolygon->exteriorRing() : curvePolygon->interiorRing( id.ring - 1 );
2821  }
2822 
2823  if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
2824  {
2825  QgsPoint p;
2826  res = curve->pointAt( id.vertex, p, id.type );
2827  if ( !res )
2828  return false;
2829  }
2830 
2831  return true;
2832 }
2833 
2835 {
2836  if ( !d->geometry )
2837  {
2838  return -1;
2839  }
2840  return d->geometry->vertexNumberFromVertexId( id );
2841 }
2842 
2843 QString QgsGeometry::lastError() const
2844 {
2845  return mLastError;
2846 }
2847 
2848 void QgsGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
2849 {
2850  if ( !d->geometry )
2851  return;
2852 
2853  detach();
2854 
2855  d->geometry->filterVertices( filter );
2856 }
2857 
2858 void QgsGeometry::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
2859 {
2860  if ( !d->geometry )
2861  return;
2862 
2863  detach();
2864 
2865  d->geometry->transformVertices( transform );
2866 }
2867 
2868 void QgsGeometry::convertPointList( const QVector<QgsPointXY> &input, QgsPointSequence &output )
2869 {
2870  output.clear();
2871  for ( const QgsPointXY &p : input )
2872  {
2873  output.append( QgsPoint( p ) );
2874  }
2875 }
2876 
2877 void QgsGeometry::convertPointList( const QgsPointSequence &input, QVector<QgsPointXY> &output )
2878 {
2879  output.clear();
2880  for ( const QgsPoint &p : input )
2881  {
2882  output.append( QgsPointXY( p.x(), p.y() ) );
2883  }
2884 }
2885 
2886 void QgsGeometry::convertToPolyline( const QgsPointSequence &input, QgsPolylineXY &output )
2887 {
2888  output.clear();
2889  output.resize( input.size() );
2890 
2891  for ( int i = 0; i < input.size(); ++i )
2892  {
2893  const QgsPoint &pt = input.at( i );
2894  output[i].setX( pt.x() );
2895  output[i].setY( pt.y() );
2896  }
2897 }
2898 
2899 void QgsGeometry::convertPolygon( const QgsPolygon &input, QgsPolygonXY &output )
2900 {
2901  output.clear();
2902  QgsCoordinateSequence coords = input.coordinateSequence();
2903  if ( coords.empty() )
2904  {
2905  return;
2906  }
2907  const QgsRingSequence &rings = coords[0];
2908  output.resize( rings.size() );
2909  for ( int i = 0; i < rings.size(); ++i )
2910  {
2911  convertToPolyline( rings[i], output[i] );
2912  }
2913 }
2914 
2916 {
2917  return QgsGeometry( qgis::make_unique< QgsPoint >( point.x(), point.y() ) );
2918 }
2919 
2920 QgsGeometry QgsGeometry::fromQPolygonF( const QPolygonF &polygon )
2921 {
2922  std::unique_ptr < QgsLineString > ring( QgsLineString::fromQPolygonF( polygon ) );
2923 
2924  if ( polygon.isClosed() )
2925  {
2926  std::unique_ptr< QgsPolygon > poly = qgis::make_unique< QgsPolygon >();
2927  poly->setExteriorRing( ring.release() );
2928  return QgsGeometry( std::move( poly ) );
2929  }
2930  else
2931  {
2932  return QgsGeometry( std::move( ring ) );
2933  }
2934 }
2935 
2937 {
2939  QgsPolygonXY result;
2940  result << createPolylineFromQPolygonF( polygon );
2941  return result;
2943 }
2944 
2946 {
2947  QgsPolylineXY result;
2948  result.reserve( polygon.count() );
2949  for ( const QPointF &p : polygon )
2950  {
2951  result.append( QgsPointXY( p ) );
2952  }
2953  return result;
2954 }
2955 
2956 bool QgsGeometry::compare( const QgsPolylineXY &p1, const QgsPolylineXY &p2, double epsilon )
2957 {
2958  if ( p1.count() != p2.count() )
2959  return false;
2960 
2961  for ( int i = 0; i < p1.count(); ++i )
2962  {
2963  if ( !p1.at( i ).compare( p2.at( i ), epsilon ) )
2964  return false;
2965  }
2966  return true;
2967 }
2968 
2969 bool QgsGeometry::compare( const QgsPolygonXY &p1, const QgsPolygonXY &p2, double epsilon )
2970 {
2971  if ( p1.count() != p2.count() )
2972  return false;
2973 
2974  for ( int i = 0; i < p1.count(); ++i )
2975  {
2976  if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
2977  return false;
2978  }
2979  return true;
2980 }
2981 
2982 
2983 bool QgsGeometry::compare( const QgsMultiPolygonXY &p1, const QgsMultiPolygonXY &p2, double epsilon )
2984 {
2985  if ( p1.count() != p2.count() )
2986  return false;
2987 
2988  for ( int i = 0; i < p1.count(); ++i )
2989  {
2990  if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
2991  return false;
2992  }
2993  return true;
2994 }
2995 
2996 QgsGeometry QgsGeometry::smooth( const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
2997 {
2998  if ( !d->geometry || d->geometry->isEmpty() )
2999  return QgsGeometry();
3000 
3001  QgsGeometry geom = *this;
3003  geom = QgsGeometry( d->geometry->segmentize() );
3004 
3005  switch ( QgsWkbTypes::flatType( geom.wkbType() ) )
3006  {
3007  case QgsWkbTypes::Point:
3009  //can't smooth a point based geometry
3010  return geom;
3011 
3013  {
3014  QgsLineString *lineString = static_cast< QgsLineString * >( d->geometry.get() );
3015  return QgsGeometry( smoothLine( *lineString, iterations, offset, minimumDistance, maxAngle ) );
3016  }
3017 
3019  {
3020  QgsMultiLineString *multiLine = static_cast< QgsMultiLineString * >( d->geometry.get() );
3021 
3022  std::unique_ptr< QgsMultiLineString > resultMultiline = qgis::make_unique< QgsMultiLineString> ();
3023  resultMultiline->reserve( multiLine->numGeometries() );
3024  for ( int i = 0; i < multiLine->numGeometries(); ++i )
3025  {
3026  resultMultiline->addGeometry( smoothLine( *( static_cast< QgsLineString * >( multiLine->geometryN( i ) ) ), iterations, offset, minimumDistance, maxAngle ).release() );
3027  }
3028  return QgsGeometry( std::move( resultMultiline ) );
3029  }
3030 
3031  case QgsWkbTypes::Polygon:
3032  {
3033  QgsPolygon *poly = static_cast< QgsPolygon * >( d->geometry.get() );
3034  return QgsGeometry( smoothPolygon( *poly, iterations, offset, minimumDistance, maxAngle ) );
3035  }
3036 
3038  {
3039  QgsMultiPolygon *multiPoly = static_cast< QgsMultiPolygon * >( d->geometry.get() );
3040 
3041  std::unique_ptr< QgsMultiPolygon > resultMultiPoly = qgis::make_unique< QgsMultiPolygon >();
3042  resultMultiPoly->reserve( multiPoly->numGeometries() );
3043  for ( int i = 0; i < multiPoly->numGeometries(); ++i )
3044  {
3045  resultMultiPoly->addGeometry( smoothPolygon( *( static_cast< QgsPolygon * >( multiPoly->geometryN( i ) ) ), iterations, offset, minimumDistance, maxAngle ).release() );
3046  }
3047  return QgsGeometry( std::move( resultMultiPoly ) );
3048  }
3049 
3050  case QgsWkbTypes::Unknown:
3051  default:
3052  return QgsGeometry( *this );
3053  }
3054 }
3055 
3056 std::unique_ptr< QgsLineString > smoothCurve( const QgsLineString &line, const unsigned int iterations,
3057  const double offset, double squareDistThreshold, double maxAngleRads,
3058  bool isRing )
3059 {
3060  std::unique_ptr< QgsLineString > result = qgis::make_unique< QgsLineString >( line );
3061  QgsPointSequence outputLine;
3062  for ( unsigned int iteration = 0; iteration < iterations; ++iteration )
3063  {
3064  outputLine.resize( 0 );
3065  outputLine.reserve( 2 * ( result->numPoints() - 1 ) );
3066  bool skipFirst = false;
3067  bool skipLast = false;
3068  if ( isRing )
3069  {
3070  QgsPoint p1 = result->pointN( result->numPoints() - 2 );
3071  QgsPoint p2 = result->pointN( 0 );
3072  QgsPoint p3 = result->pointN( 1 );
3073  double angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3074  p3.x(), p3.y() );
3075  angle = std::fabs( M_PI - angle );
3076  skipFirst = angle > maxAngleRads;
3077  }
3078  for ( int i = 0; i < result->numPoints() - 1; i++ )
3079  {
3080  QgsPoint p1 = result->pointN( i );
3081  QgsPoint p2 = result->pointN( i + 1 );
3082 
3083  double angle = M_PI;
3084  if ( i == 0 && isRing )
3085  {
3086  QgsPoint p3 = result->pointN( result->numPoints() - 2 );
3087  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3088  p3.x(), p3.y() );
3089  }
3090  else if ( i < result->numPoints() - 2 )
3091  {
3092  QgsPoint p3 = result->pointN( i + 2 );
3093  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3094  p3.x(), p3.y() );
3095  }
3096  else if ( i == result->numPoints() - 2 && isRing )
3097  {
3098  QgsPoint p3 = result->pointN( 1 );
3099  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3100  p3.x(), p3.y() );
3101  }
3102 
3103  skipLast = angle < M_PI - maxAngleRads || angle > M_PI + maxAngleRads;
3104 
3105  // don't apply distance threshold to first or last segment
3106  if ( i == 0 || i >= result->numPoints() - 2
3107  || QgsGeometryUtils::sqrDistance2D( p1, p2 ) > squareDistThreshold )
3108  {
3109  if ( !isRing )
3110  {
3111  if ( !skipFirst )
3112  outputLine << ( i == 0 ? result->pointN( i ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset ) );
3113  if ( !skipLast )
3114  outputLine << ( i == result->numPoints() - 2 ? result->pointN( i + 1 ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset ) );
3115  else
3116  outputLine << p2;
3117  }
3118  else
3119  {
3120  // ring
3121  if ( !skipFirst )
3122  outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset );
3123  else if ( i == 0 )
3124  outputLine << p1;
3125  if ( !skipLast )
3126  outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset );
3127  else
3128  outputLine << p2;
3129  }
3130  }
3131  skipFirst = skipLast;
3132  }
3133 
3134  if ( isRing && outputLine.at( 0 ) != outputLine.at( outputLine.count() - 1 ) )
3135  outputLine << outputLine.at( 0 );
3136 
3137  result->setPoints( outputLine );
3138  }
3139  return result;
3140 }
3141 
3142 std::unique_ptr<QgsLineString> QgsGeometry::smoothLine( const QgsLineString &line, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3143 {
3144  double maxAngleRads = maxAngle * M_PI / 180.0;
3145  double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
3146  return smoothCurve( line, iterations, offset, squareDistThreshold, maxAngleRads, false );
3147 }
3148 
3149 std::unique_ptr<QgsPolygon> QgsGeometry::smoothPolygon( const QgsPolygon &polygon, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3150 {
3151  double maxAngleRads = maxAngle * M_PI / 180.0;
3152  double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
3153  std::unique_ptr< QgsPolygon > resultPoly = qgis::make_unique< QgsPolygon >();
3154 
3155  resultPoly->setExteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.exteriorRing() ) ), iterations, offset,
3156  squareDistThreshold, maxAngleRads, true ).release() );
3157 
3158  for ( int i = 0; i < polygon.numInteriorRings(); ++i )
3159  {
3160  resultPoly->addInteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.interiorRing( i ) ) ), iterations, offset,
3161  squareDistThreshold, maxAngleRads, true ).release() );
3162  }
3163  return resultPoly;
3164 }
3165 
3166 QgsGeometry QgsGeometry::convertToPoint( bool destMultipart ) const
3167 {
3168  switch ( type() )
3169  {
3171  {
3172  bool srcIsMultipart = isMultipart();
3173 
3174  if ( ( destMultipart && srcIsMultipart ) ||
3175  ( !destMultipart && !srcIsMultipart ) )
3176  {
3177  // return a copy of the same geom
3178  return QgsGeometry( *this );
3179  }
3180  if ( destMultipart )
3181  {
3182  // layer is multipart => make a multipoint with a single point
3183  return fromMultiPointXY( QgsMultiPointXY() << asPoint() );
3184  }
3185  else
3186  {
3187  // destination is singlepart => make a single part if possible
3188  QgsMultiPointXY multiPoint = asMultiPoint();
3189  if ( multiPoint.count() == 1 )
3190  {
3191  return fromPointXY( multiPoint[0] );
3192  }
3193  }
3194  return QgsGeometry();
3195  }
3196 
3198  {
3199  // only possible if destination is multipart
3200  if ( !destMultipart )
3201  return QgsGeometry();
3202 
3203  // input geometry is multipart
3204  if ( isMultipart() )
3205  {
3206  const QgsMultiPolylineXY multiLine = asMultiPolyline();
3207  QgsMultiPointXY multiPoint;
3208  for ( const QgsPolylineXY &l : multiLine )
3209  for ( const QgsPointXY &p : l )
3210  multiPoint << p;
3211  return fromMultiPointXY( multiPoint );
3212  }
3213  // input geometry is not multipart: copy directly the line into a multipoint
3214  else
3215  {
3216  QgsPolylineXY line = asPolyline();
3217  if ( !line.isEmpty() )
3218  return fromMultiPointXY( line );
3219  }
3220  return QgsGeometry();
3221  }
3222 
3224  {
3225  // can only transform if destination is multipoint
3226  if ( !destMultipart )
3227  return QgsGeometry();
3228 
3229  // input geometry is multipart: make a multipoint from multipolygon
3230  if ( isMultipart() )
3231  {
3232  const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3233  QgsMultiPointXY multiPoint;
3234  for ( const QgsPolygonXY &poly : multiPolygon )
3235  for ( const QgsPolylineXY &line : poly )
3236  for ( const QgsPointXY &pt : line )
3237  multiPoint << pt;
3238  return fromMultiPointXY( multiPoint );
3239  }
3240  // input geometry is not multipart: make a multipoint from polygon
3241  else
3242  {
3243  const QgsPolygonXY polygon = asPolygon();
3244  QgsMultiPointXY multiPoint;
3245  for ( const QgsPolylineXY &line : polygon )
3246  for ( const QgsPointXY &pt : line )
3247  multiPoint << pt;
3248  return fromMultiPointXY( multiPoint );
3249  }
3250  }
3251 
3252  default:
3253  return QgsGeometry();
3254  }
3255 }
3256 
3257 QgsGeometry QgsGeometry::convertToLine( bool destMultipart ) const
3258 {
3259  switch ( type() )
3260  {
3262  {
3263  if ( !isMultipart() )
3264  return QgsGeometry();
3265 
3266  QgsMultiPointXY multiPoint = asMultiPoint();
3267  if ( multiPoint.count() < 2 )
3268  return QgsGeometry();
3269 
3270  if ( destMultipart )
3271  return fromMultiPolylineXY( QgsMultiPolylineXY() << multiPoint );
3272  else
3273  return fromPolylineXY( multiPoint );
3274  }
3275 
3277  {
3278  bool srcIsMultipart = isMultipart();
3279 
3280  if ( ( destMultipart && srcIsMultipart ) ||
3281  ( !destMultipart && ! srcIsMultipart ) )
3282  {
3283  // return a copy of the same geom
3284  return QgsGeometry( *this );
3285  }
3286  if ( destMultipart )
3287  {
3288  // destination is multipart => makes a multipoint with a single line
3289  QgsPolylineXY line = asPolyline();
3290  if ( !line.isEmpty() )
3291  return fromMultiPolylineXY( QgsMultiPolylineXY() << line );
3292  }
3293  else
3294  {
3295  // destination is singlepart => make a single part if possible
3296  QgsMultiPolylineXY multiLine = asMultiPolyline();
3297  if ( multiLine.count() == 1 )
3298  return fromPolylineXY( multiLine[0] );
3299  }
3300  return QgsGeometry();
3301  }
3302 
3304  {
3305  // input geometry is multipolygon
3306  if ( isMultipart() )
3307  {
3308  const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3309  QgsMultiPolylineXY multiLine;
3310  for ( const QgsPolygonXY &poly : multiPolygon )
3311  for ( const QgsPolylineXY &line : poly )
3312  multiLine << line;
3313 
3314  if ( destMultipart )
3315  {
3316  // destination is multipart
3317  return fromMultiPolylineXY( multiLine );
3318  }
3319  else if ( multiLine.count() == 1 )
3320  {
3321  // destination is singlepart => make a single part if possible
3322  return fromPolylineXY( multiLine[0] );
3323  }
3324  }
3325  // input geometry is single polygon
3326  else
3327  {
3328  QgsPolygonXY polygon = asPolygon();
3329  // if polygon has rings
3330  if ( polygon.count() > 1 )
3331  {
3332  // cannot fit a polygon with rings in a single line layer
3333  // TODO: would it be better to remove rings?
3334  if ( destMultipart )
3335  {
3336  const QgsPolygonXY polygon = asPolygon();
3337  QgsMultiPolylineXY multiLine;
3338  multiLine.reserve( polygon.count() );
3339  for ( const QgsPolylineXY &line : polygon )
3340  multiLine << line;
3341  return fromMultiPolylineXY( multiLine );
3342  }
3343  }
3344  // no rings
3345  else if ( polygon.count() == 1 )
3346  {
3347  if ( destMultipart )
3348  {
3349  return fromMultiPolylineXY( polygon );
3350  }
3351  else
3352  {
3353  return fromPolylineXY( polygon[0] );
3354  }
3355  }
3356  }
3357  return QgsGeometry();
3358  }
3359 
3360  default:
3361  return QgsGeometry();
3362  }
3363 }
3364 
3365 QgsGeometry QgsGeometry::convertToPolygon( bool destMultipart ) const
3366 {
3367  switch ( type() )
3368  {
3370  {
3371  if ( !isMultipart() )
3372  return QgsGeometry();
3373 
3374  QgsMultiPointXY multiPoint = asMultiPoint();
3375  if ( multiPoint.count() < 3 )
3376  return QgsGeometry();
3377 
3378  if ( multiPoint.last() != multiPoint.first() )
3379  multiPoint << multiPoint.first();
3380 
3381  QgsPolygonXY polygon = QgsPolygonXY() << multiPoint;
3382  if ( destMultipart )
3383  return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3384  else
3385  return fromPolygonXY( polygon );
3386  }
3387 
3389  {
3390  // input geometry is multiline
3391  if ( isMultipart() )
3392  {
3393  QgsMultiPolylineXY multiLine = asMultiPolyline();
3394  QgsMultiPolygonXY multiPolygon;
3395  for ( QgsMultiPolylineXY::iterator multiLineIt = multiLine.begin(); multiLineIt != multiLine.end(); ++multiLineIt )
3396  {
3397  // do not create polygon for a 1 segment line
3398  if ( ( *multiLineIt ).count() < 3 )
3399  return QgsGeometry();
3400  if ( ( *multiLineIt ).count() == 3 && ( *multiLineIt ).first() == ( *multiLineIt ).last() )
3401  return QgsGeometry();
3402 
3403  // add closing node
3404  if ( ( *multiLineIt ).first() != ( *multiLineIt ).last() )
3405  *multiLineIt << ( *multiLineIt ).first();
3406  multiPolygon << ( QgsPolygonXY() << *multiLineIt );
3407  }
3408  // check that polygons were inserted
3409  if ( !multiPolygon.isEmpty() )
3410  {
3411  if ( destMultipart )
3412  {
3413  return fromMultiPolygonXY( multiPolygon );
3414  }
3415  else if ( multiPolygon.count() == 1 )
3416  {
3417  // destination is singlepart => make a single part if possible
3418  return fromPolygonXY( multiPolygon[0] );
3419  }
3420  }
3421  }
3422  // input geometry is single line
3423  else
3424  {
3425  QgsPolylineXY line = asPolyline();
3426 
3427  // do not create polygon for a 1 segment line
3428  if ( line.count() < 3 )
3429  return QgsGeometry();
3430  if ( line.count() == 3 && line.first() == line.last() )
3431  return QgsGeometry();
3432 
3433  // add closing node
3434  if ( line.first() != line.last() )
3435  line << line.first();
3436 
3437  // destination is multipart
3438  if ( destMultipart )
3439  {
3440  return fromMultiPolygonXY( QgsMultiPolygonXY() << ( QgsPolygonXY() << line ) );
3441  }
3442  else
3443  {
3444  return fromPolygonXY( QgsPolygonXY() << line );
3445  }
3446  }
3447  return QgsGeometry();
3448  }
3449 
3451  {
3452  bool srcIsMultipart = isMultipart();
3453 
3454  if ( ( destMultipart && srcIsMultipart ) ||
3455  ( !destMultipart && ! srcIsMultipart ) )
3456  {
3457  // return a copy of the same geom
3458  return QgsGeometry( *this );
3459  }
3460  if ( destMultipart )
3461  {
3462  // destination is multipart => makes a multipoint with a single polygon
3463  QgsPolygonXY polygon = asPolygon();
3464  if ( !polygon.isEmpty() )
3465  return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3466  }
3467  else
3468  {
3469  QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3470  if ( multiPolygon.count() == 1 )
3471  {
3472  // destination is singlepart => make a single part if possible
3473  return fromPolygonXY( multiPolygon[0] );
3474  }
3475  }
3476  return QgsGeometry();
3477  }
3478 
3479  default:
3480  return QgsGeometry();
3481  }
3482 }
3483 
3485 {
3486  return new QgsGeos( geometry );
3487 }
3488 
3489 QDataStream &operator<<( QDataStream &out, const QgsGeometry &geometry )
3490 {
3491  out << geometry.asWkb();
3492  return out;
3493 }
3494 
3495 QDataStream &operator>>( QDataStream &in, QgsGeometry &geometry )
3496 {
3497  QByteArray byteArray;
3498  in >> byteArray;
3499  if ( byteArray.isEmpty() )
3500  {
3501  geometry.set( nullptr );
3502  return in;
3503  }
3504 
3505  geometry.fromWkb( byteArray );
3506  return in;
3507 }
3508 
3509 
3511 {
3512  return mMessage;
3513 }
3514 
3516 {
3517  return mLocation;
3518 }
3519 
3521 {
3522  return mHasLocation;
3523 }
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...
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:2006
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.
QVector< QgsPointXY > randomPointsInPolygon(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 (multi)polygon geometry. ...
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:280
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:649
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:1100
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:44
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:367
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.
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:2005
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:2267
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:234
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
virtual QgsPolygon * toPolygon(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a new polygon geometry corresponding to a segmentized approximation of the curve...
static QgsPointXY interpolatePointOnLine(double x1, double y1, double x2, double y2, double fraction)
Interpolates the position of a point a fraction of the way along the line from (x1, y1) to (x2, y2).
QgsGeometry pointOnSurface() const
Returns a point guaranteed to lie on the surface of a geometry.
bool touches(const QgsGeometry &geometry) const
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:675
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:262
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:1092
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:650
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:2003
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.
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:1109
const QgsCurve * exteriorRing() const
Returns the curve polygon&#39;s exterior ring.
void set(QgsAbstractGeometry *geometry)
Sets the underlying geometry store.
QgsGeometry densifyByCount(int extraNodesPerSegment) const
Densifies the geometry by adding the specified number of extra nodes within each segment of the geome...
bool contains(const QgsPointXY *p) const
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;. Negativ values mean left a...
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...