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