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