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