QGIS API Documentation  3.23.0-Master (b5237dafc3)
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 
953  splitLineString.dropZValue();
954  splitLineString.dropMValue();
955 
956  QgsGeos geos( d->geometry.get() );
957  mLastError.clear();
958  QgsGeometryEngine::EngineOperationResult result = geos.splitGeometry( splitLineString, newGeoms, topological, topologyTestPoints, &mLastError, skipIntersectionTest );
959 
960  if ( result == QgsGeometryEngine::Success )
961  {
962  if ( splitFeature )
963  *this = newGeoms.takeAt( 0 );
964  newGeometries = newGeoms;
965  }
966 
967  switch ( result )
968  {
983  //default: do not implement default to handle properly all cases
984  }
985 
986  // this should never be reached
987  Q_ASSERT( false );
989 }
990 
991 Qgis::GeometryOperationResult QgsGeometry::splitGeometry( const QgsCurve *curve, QVector<QgsGeometry> &newGeometries, bool preserveCircular, bool topological, QgsPointSequence &topologyTestPoints, bool splitFeature )
992 {
993  std::unique_ptr<QgsLineString> segmentizedLine( curve->curveToLine() );
994  QgsPointSequence points;
995  segmentizedLine->points( points );
996  Qgis::GeometryOperationResult result = splitGeometry( points, newGeometries, topological, topologyTestPoints, splitFeature );
997 
999  {
1000  if ( preserveCircular )
1001  {
1002  for ( int i = 0; i < newGeometries.count(); ++i )
1003  newGeometries[i] = newGeometries[i].convertToCurves();
1004  *this = convertToCurves();
1005  }
1006  }
1007 
1008  return result;
1009 }
1010 
1012 {
1013  if ( !d->geometry )
1014  {
1016  }
1017 
1018  QgsGeos geos( d->geometry.get() );
1020  mLastError.clear();
1021  std::unique_ptr< QgsAbstractGeometry > geom( geos.reshapeGeometry( reshapeLineString, &errorCode, &mLastError ) );
1022  if ( errorCode == QgsGeometryEngine::Success && geom )
1023  {
1024  reset( std::move( geom ) );
1026  }
1027 
1028  switch ( errorCode )
1029  {
1040  case QgsGeometryEngine::SplitCannotSplitPoint: // should not happen
1044  }
1045 
1046  // should not be reached
1048 }
1049 
1051 {
1052  if ( !d->geometry || !other.d->geometry )
1053  {
1054  return 0;
1055  }
1056 
1057  QgsGeos geos( d->geometry.get() );
1058 
1059  mLastError.clear();
1060  std::unique_ptr< QgsAbstractGeometry > diffGeom( geos.intersection( other.constGet(), &mLastError ) );
1061  if ( !diffGeom )
1062  {
1063  return 1;
1064  }
1065 
1066  reset( std::move( diffGeom ) );
1067  return 0;
1068 }
1069 
1071 {
1072  if ( !d->geometry || other.isNull() )
1073  {
1074  return QgsGeometry();
1075  }
1076 
1077  QgsGeos geos( d->geometry.get() );
1078 
1079  mLastError.clear();
1080  std::unique_ptr< QgsAbstractGeometry > diffGeom( geos.intersection( other.constGet(), &mLastError ) );
1081  if ( !diffGeom )
1082  {
1083  QgsGeometry result;
1084  result.mLastError = mLastError;
1085  return result;
1086  }
1087 
1088  return QgsGeometry( diffGeom.release() );
1089 }
1090 
1092 {
1093  if ( d->geometry )
1094  {
1095  return d->geometry->boundingBox();
1096  }
1097  return QgsRectangle();
1098 }
1099 
1100 QgsGeometry QgsGeometry::orientedMinimumBoundingBox( double &area, double &angle, double &width, double &height ) const
1101 {
1102  mLastError.clear();
1103  QgsInternalGeometryEngine engine( *this );
1104  const QgsGeometry res = engine.orientedMinimumBoundingBox( area, angle, width, height );
1105  if ( res.isNull() )
1106  mLastError = engine.lastError();
1107  return res;
1108 }
1109 
1111 {
1112  double area, angle, width, height;
1113  return orientedMinimumBoundingBox( area, angle, width, height );
1114 }
1115 
1116 static QgsCircle __recMinimalEnclosingCircle( QgsMultiPointXY points, QgsMultiPointXY boundary )
1117 {
1118  auto l_boundary = boundary.length();
1119  QgsCircle circ_mec;
1120  if ( ( points.length() == 0 ) || ( l_boundary == 3 ) )
1121  {
1122  switch ( l_boundary )
1123  {
1124  case 0:
1125  circ_mec = QgsCircle();
1126  break;
1127  case 1:
1128  circ_mec = QgsCircle( QgsPoint( boundary.last() ), 0 );
1129  boundary.pop_back();
1130  break;
1131  case 2:
1132  {
1133  QgsPointXY p1 = boundary.last();
1134  boundary.pop_back();
1135  QgsPointXY p2 = boundary.last();
1136  boundary.pop_back();
1137  circ_mec = QgsCircle::from2Points( QgsPoint( p1 ), QgsPoint( p2 ) );
1138  }
1139  break;
1140  default:
1141  QgsPoint p1( boundary.at( 0 ) );
1142  QgsPoint p2( boundary.at( 1 ) );
1143  QgsPoint p3( boundary.at( 2 ) );
1144  circ_mec = QgsCircle::minimalCircleFrom3Points( p1, p2, p3 );
1145  break;
1146  }
1147  return circ_mec;
1148  }
1149  else
1150  {
1151  QgsPointXY pxy = points.last();
1152  points.pop_back();
1153  circ_mec = __recMinimalEnclosingCircle( points, boundary );
1154  QgsPoint p( pxy );
1155  if ( !circ_mec.contains( p ) )
1156  {
1157  boundary.append( pxy );
1158  circ_mec = __recMinimalEnclosingCircle( points, boundary );
1159  }
1160  }
1161  return circ_mec;
1162 }
1163 
1164 QgsGeometry QgsGeometry::minimalEnclosingCircle( QgsPointXY &center, double &radius, unsigned int segments ) const
1165 {
1166  center = QgsPointXY();
1167  radius = 0;
1168 
1169  if ( isEmpty() )
1170  {
1171  return QgsGeometry();
1172  }
1173 
1174  /* optimization */
1175  QgsGeometry hull = convexHull();
1176  if ( hull.isNull() )
1177  return QgsGeometry();
1178 
1179  QgsMultiPointXY P = hull.convertToPoint( true ).asMultiPoint();
1180  QgsMultiPointXY R;
1181 
1182  QgsCircle circ = __recMinimalEnclosingCircle( P, R );
1183  center = QgsPointXY( circ.center() );
1184  radius = circ.radius();
1185  QgsGeometry geom;
1186  geom.set( circ.toPolygon( segments ) );
1187  return geom;
1188 
1189 }
1190 
1191 QgsGeometry QgsGeometry::minimalEnclosingCircle( unsigned int segments ) const
1192 {
1193  QgsPointXY center;
1194  double radius;
1195  return minimalEnclosingCircle( center, radius, segments );
1196 
1197 }
1198 
1199 QgsGeometry QgsGeometry::orthogonalize( double tolerance, int maxIterations, double angleThreshold ) const
1200 {
1201  QgsInternalGeometryEngine engine( *this );
1202 
1203  return engine.orthogonalize( tolerance, maxIterations, angleThreshold );
1204 }
1205 
1206 QgsGeometry QgsGeometry::triangularWaves( double wavelength, double amplitude, bool strictWavelength ) const
1207 {
1208  QgsInternalGeometryEngine engine( *this );
1209  return engine.triangularWaves( wavelength, amplitude, strictWavelength );
1210 }
1211 
1212 QgsGeometry QgsGeometry::triangularWavesRandomized( double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed ) const
1213 {
1214  QgsInternalGeometryEngine engine( *this );
1215  return engine.triangularWavesRandomized( minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, seed );
1216 }
1217 
1218 QgsGeometry QgsGeometry::squareWaves( double wavelength, double amplitude, bool strictWavelength ) const
1219 {
1220  QgsInternalGeometryEngine engine( *this );
1221  return engine.squareWaves( wavelength, amplitude, strictWavelength );
1222 }
1223 
1224 QgsGeometry QgsGeometry::squareWavesRandomized( double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed ) const
1225 {
1226  QgsInternalGeometryEngine engine( *this );
1227  return engine.squareWavesRandomized( minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, seed );
1228 }
1229 
1230 QgsGeometry QgsGeometry::roundWaves( double wavelength, double amplitude, bool strictWavelength ) const
1231 {
1232  QgsInternalGeometryEngine engine( *this );
1233  return engine.roundWaves( wavelength, amplitude, strictWavelength );
1234 }
1235 
1236 QgsGeometry QgsGeometry::roundWavesRandomized( double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed ) const
1237 {
1238  QgsInternalGeometryEngine engine( *this );
1239  return engine.roundWavesRandomized( minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, seed );
1240 }
1241 
1242 QgsGeometry QgsGeometry::applyDashPattern( const QVector<double> &pattern, Qgis::DashPatternLineEndingRule startRule, Qgis::DashPatternLineEndingRule endRule, Qgis::DashPatternSizeAdjustment adjustment, double patternOffset ) const
1243 {
1244  QgsInternalGeometryEngine engine( *this );
1245  return engine.applyDashPattern( pattern, startRule, endRule, adjustment, patternOffset );
1246 }
1247 
1248 QgsGeometry QgsGeometry::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing ) const
1249 {
1250  if ( !d->geometry )
1251  {
1252  return QgsGeometry();
1253  }
1254  return QgsGeometry( d->geometry->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing ) );
1255 }
1256 
1257 bool QgsGeometry::removeDuplicateNodes( double epsilon, bool useZValues )
1258 {
1259  if ( !d->geometry )
1260  return false;
1261 
1262  detach();
1263  return d->geometry->removeDuplicateNodes( epsilon, useZValues );
1264 }
1265 
1267 {
1268  // fast case, check bounding boxes
1269  if ( !boundingBoxIntersects( r ) )
1270  return false;
1271 
1272  // optimise trivial case for point intersections -- the bounding box test has already given us the answer
1273  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::Point )
1274  {
1275  return true;
1276  }
1277 
1278  QgsGeometry g = fromRect( r );
1279  return intersects( g );
1280 }
1281 
1282 bool QgsGeometry::intersects( const QgsGeometry &geometry ) const
1283 {
1284  if ( !d->geometry || geometry.isNull() )
1285  {
1286  return false;
1287  }
1288 
1289  QgsGeos geos( d->geometry.get() );
1290  mLastError.clear();
1291  return geos.intersects( geometry.d->geometry.get(), &mLastError );
1292 }
1293 
1294 bool QgsGeometry::boundingBoxIntersects( const QgsRectangle &rectangle ) const
1295 {
1296  if ( !d->geometry )
1297  {
1298  return false;
1299  }
1300 
1301  return d->geometry->boundingBoxIntersects( rectangle );
1302 }
1303 
1305 {
1306  if ( !d->geometry || geometry.isNull() )
1307  {
1308  return false;
1309  }
1310 
1311  return d->geometry->boundingBoxIntersects( geometry.constGet()->boundingBox() );
1312 }
1313 
1314 bool QgsGeometry::contains( const QgsPointXY *p ) const
1315 {
1316  if ( !d->geometry || !p )
1317  {
1318  return false;
1319  }
1320 
1321  QgsPoint pt( p->x(), p->y() );
1322  QgsGeos geos( d->geometry.get() );
1323  mLastError.clear();
1324  return geos.contains( &pt, &mLastError );
1325 }
1326 
1327 bool QgsGeometry::contains( const QgsGeometry &geometry ) const
1328 {
1329  if ( !d->geometry || geometry.isNull() )
1330  {
1331  return false;
1332  }
1333 
1334  QgsGeos geos( d->geometry.get() );
1335  mLastError.clear();
1336  return geos.contains( geometry.d->geometry.get(), &mLastError );
1337 }
1338 
1339 bool QgsGeometry::disjoint( const QgsGeometry &geometry ) const
1340 {
1341  if ( !d->geometry || geometry.isNull() )
1342  {
1343  return false;
1344  }
1345 
1346  QgsGeos geos( d->geometry.get() );
1347  mLastError.clear();
1348  return geos.disjoint( geometry.d->geometry.get(), &mLastError );
1349 }
1350 
1351 bool QgsGeometry::equals( const QgsGeometry &geometry ) const
1352 {
1353  if ( !d->geometry || geometry.isNull() )
1354  {
1355  return false;
1356  }
1357 
1358  // fast check - are they shared copies of the same underlying geometry?
1359  if ( d == geometry.d )
1360  return true;
1361 
1362  // fast check - distinct geometry types?
1363  if ( type() != geometry.type() )
1364  return false;
1365 
1366  // slower check - actually test the geometries
1367  return *d->geometry == *geometry.d->geometry;
1368 }
1369 
1370 bool QgsGeometry::touches( const QgsGeometry &geometry ) const
1371 {
1372  if ( !d->geometry || geometry.isNull() )
1373  {
1374  return false;
1375  }
1376 
1377  QgsGeos geos( d->geometry.get() );
1378  mLastError.clear();
1379  return geos.touches( geometry.d->geometry.get(), &mLastError );
1380 }
1381 
1382 bool QgsGeometry::overlaps( const QgsGeometry &geometry ) const
1383 {
1384  if ( !d->geometry || geometry.isNull() )
1385  {
1386  return false;
1387  }
1388 
1389  QgsGeos geos( d->geometry.get() );
1390  mLastError.clear();
1391  return geos.overlaps( geometry.d->geometry.get(), &mLastError );
1392 }
1393 
1394 bool QgsGeometry::within( const QgsGeometry &geometry ) const
1395 {
1396  if ( !d->geometry || geometry.isNull() )
1397  {
1398  return false;
1399  }
1400 
1401  QgsGeos geos( d->geometry.get() );
1402  mLastError.clear();
1403  return geos.within( geometry.d->geometry.get(), &mLastError );
1404 }
1405 
1406 bool QgsGeometry::crosses( const QgsGeometry &geometry ) const
1407 {
1408  if ( !d->geometry || geometry.isNull() )
1409  {
1410  return false;
1411  }
1412 
1413  QgsGeos geos( d->geometry.get() );
1414  mLastError.clear();
1415  return geos.crosses( geometry.d->geometry.get(), &mLastError );
1416 }
1417 
1418 QString QgsGeometry::asWkt( int precision ) const
1419 {
1420  if ( !d->geometry )
1421  {
1422  return QString();
1423  }
1424  return d->geometry->asWkt( precision );
1425 }
1426 
1427 QString QgsGeometry::asJson( int precision ) const
1428 {
1429  return QString::fromStdString( asJsonObject( precision ).dump() );
1430 }
1431 
1433 {
1434  if ( !d->geometry )
1435  {
1436  return nullptr;
1437  }
1438  return d->geometry->asJsonObject( precision );
1439 
1440 }
1441 
1442 QVector<QgsGeometry> QgsGeometry::coerceToType( const QgsWkbTypes::Type type ) const
1443 {
1444  QVector< QgsGeometry > res;
1445  if ( isNull() )
1446  return res;
1447 
1448  if ( wkbType() == type || type == QgsWkbTypes::Unknown )
1449  {
1450  res << *this;
1451  return res;
1452  }
1453 
1454  if ( type == QgsWkbTypes::NoGeometry )
1455  {
1456  return res;
1457  }
1458 
1459  QgsGeometry newGeom = *this;
1460 
1461  // Curved -> straight
1463  {
1464  newGeom = QgsGeometry( d->geometry.get()->segmentize() );
1465  }
1466 
1467  // polygon -> line
1469  newGeom.type() == QgsWkbTypes::PolygonGeometry )
1470  {
1471  // boundary gives us a (multi)line string of exterior + interior rings
1472  newGeom = QgsGeometry( newGeom.constGet()->boundary() );
1473  }
1474  // line -> polygon
1476  newGeom.type() == QgsWkbTypes::LineGeometry )
1477  {
1478  std::unique_ptr< QgsGeometryCollection > gc( QgsGeometryFactory::createCollectionOfType( type ) );
1479  const QgsGeometry source = newGeom;
1480  for ( auto part = source.const_parts_begin(); part != source.const_parts_end(); ++part )
1481  {
1482  std::unique_ptr< QgsAbstractGeometry > exterior( ( *part )->clone() );
1483  if ( QgsCurve *curve = qgsgeometry_cast< QgsCurve * >( exterior.get() ) )
1484  {
1486  {
1487  std::unique_ptr< QgsCurvePolygon > cp = std::make_unique< QgsCurvePolygon >();
1488  cp->setExteriorRing( curve );
1489  exterior.release();
1490  gc->addGeometry( cp.release() );
1491  }
1492  else
1493  {
1494  std::unique_ptr< QgsPolygon > p = std::make_unique< QgsPolygon >();
1495  p->setExteriorRing( qgsgeometry_cast< QgsLineString * >( curve ) );
1496  exterior.release();
1497  gc->addGeometry( p.release() );
1498  }
1499  }
1500  }
1501  newGeom = QgsGeometry( std::move( gc ) );
1502  }
1503 
1504  // line/polygon -> points
1506  ( newGeom.type() == QgsWkbTypes::LineGeometry ||
1507  newGeom.type() == QgsWkbTypes::PolygonGeometry ) )
1508  {
1509  // lines/polygons to a point layer, extract all vertices
1510  std::unique_ptr< QgsMultiPoint > mp = std::make_unique< QgsMultiPoint >();
1511  const QgsGeometry source = newGeom;
1512  QSet< QgsPoint > added;
1513  for ( auto vertex = source.vertices_begin(); vertex != source.vertices_end(); ++vertex )
1514  {
1515  if ( added.contains( *vertex ) )
1516  continue; // avoid duplicate points, e.g. start/end of rings
1517  mp->addGeometry( ( *vertex ).clone() );
1518  added.insert( *vertex );
1519  }
1520  newGeom = QgsGeometry( std::move( mp ) );
1521  }
1522 
1523  // Single -> multi
1524  if ( QgsWkbTypes::isMultiType( type ) && ! newGeom.isMultipart( ) )
1525  {
1526  newGeom.convertToMultiType();
1527  }
1528  // Drop Z/M
1529  if ( newGeom.constGet()->is3D() && ! QgsWkbTypes::hasZ( type ) )
1530  {
1531  newGeom.get()->dropZValue();
1532  }
1533  if ( newGeom.constGet()->isMeasure() && ! QgsWkbTypes::hasM( type ) )
1534  {
1535  newGeom.get()->dropMValue();
1536  }
1537  // Add Z/M back, set to 0
1538  if ( ! newGeom.constGet()->is3D() && QgsWkbTypes::hasZ( type ) )
1539  {
1540  newGeom.get()->addZValue( 0.0 );
1541  }
1542  if ( ! newGeom.constGet()->isMeasure() && QgsWkbTypes::hasM( type ) )
1543  {
1544  newGeom.get()->addMValue( 0.0 );
1545  }
1546 
1547  // Multi -> single
1548  if ( ! QgsWkbTypes::isMultiType( type ) && newGeom.isMultipart( ) )
1549  {
1550  const QgsGeometryCollection *parts( static_cast< const QgsGeometryCollection * >( newGeom.constGet() ) );
1551  res.reserve( parts->partCount() );
1552  for ( int i = 0; i < parts->partCount( ); i++ )
1553  {
1554  res << QgsGeometry( parts->geometryN( i )->clone() );
1555  }
1556  }
1557  else
1558  {
1559  res << newGeom;
1560  }
1561  return res;
1562 }
1563 
1565 {
1566  switch ( destType )
1567  {
1569  return convertToPoint( destMultipart );
1570 
1572  return convertToLine( destMultipart );
1573 
1575  return convertToPolygon( destMultipart );
1576 
1577  default:
1578  return QgsGeometry();
1579  }
1580 }
1581 
1583 {
1584  if ( !d->geometry )
1585  {
1586  return false;
1587  }
1588 
1589  if ( isMultipart() ) //already multitype, no need to convert
1590  {
1591  return true;
1592  }
1593 
1594  std::unique_ptr< QgsAbstractGeometry >geom = QgsGeometryFactory::geomFromWkbType( QgsWkbTypes::multiType( d->geometry->wkbType() ) );
1595  QgsGeometryCollection *multiGeom = qgsgeometry_cast<QgsGeometryCollection *>( geom.get() );
1596  if ( !multiGeom )
1597  {
1598  return false;
1599  }
1600 
1601  //try to avoid cloning existing geometry whenever we can
1602 
1603  //want to see a magic trick?... gather round kiddies...
1604  detach(); // maybe a clone, hopefully not if we're the only ref to the private data
1605  // now we cheat a bit and steal the private geometry and add it direct to the multigeom
1606  // we can do this because we're the only ref to this geometry, guaranteed by the detach call above
1607  multiGeom->addGeometry( d->geometry.release() );
1608  // and replace it with the multi geometry.
1609  // TADA! a clone free conversion in some cases
1610  d->geometry = std::move( geom );
1611  return true;
1612 }
1613 
1615 {
1616  if ( !d->geometry )
1617  {
1618  return false;
1619  }
1620 
1621  if ( !isMultipart() ) //already single part, no need to convert
1622  {
1623  return true;
1624  }
1625 
1626  QgsGeometryCollection *multiGeom = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
1627  if ( !multiGeom || multiGeom->partCount() < 1 )
1628  return false;
1629 
1630  std::unique_ptr< QgsAbstractGeometry > firstPart( multiGeom->geometryN( 0 )->clone() );
1631  reset( std::move( firstPart ) );
1632  return true;
1633 }
1634 
1635 
1637 {
1638  const QgsGeometryCollection *origGeom = qgsgeometry_cast<const QgsGeometryCollection *>( constGet() );
1639  if ( !origGeom )
1640  return false;
1641 
1642  std::unique_ptr<QgsGeometryCollection> resGeom;
1643  switch ( geomType )
1644  {
1646  resGeom = std::make_unique<QgsMultiPoint>();
1647  break;
1649  resGeom = std::make_unique<QgsMultiLineString>();
1650  break;
1652  resGeom = std::make_unique<QgsMultiPolygon>();
1653  break;
1654  default:
1655  break;
1656  }
1657  if ( !resGeom )
1658  return false;
1659 
1660  resGeom->reserve( origGeom->numGeometries() );
1661  for ( int i = 0; i < origGeom->numGeometries(); ++i )
1662  {
1663  const QgsAbstractGeometry *g = origGeom->geometryN( i );
1664  if ( QgsWkbTypes::geometryType( g->wkbType() ) == geomType )
1665  resGeom->addGeometry( g->clone() );
1666  }
1667 
1668  set( resGeom.release() );
1669  return true;
1670 }
1671 
1672 
1674 {
1675  if ( !d->geometry )
1676  {
1677  return QgsPointXY();
1678  }
1679  if ( QgsPoint *pt = qgsgeometry_cast<QgsPoint *>( d->geometry->simplifiedTypeRef() ) )
1680  {
1681  return QgsPointXY( pt->x(), pt->y() );
1682  }
1683  else
1684  {
1685  return QgsPointXY();
1686  }
1687 }
1688 
1690 {
1691  QgsPolylineXY polyLine;
1692  if ( !d->geometry )
1693  {
1694  return polyLine;
1695  }
1696 
1697  bool doSegmentation = ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::CompoundCurve
1699  std::unique_ptr< QgsLineString > segmentizedLine;
1700  QgsLineString *line = nullptr;
1701  if ( doSegmentation )
1702  {
1703  QgsCurve *curve = qgsgeometry_cast<QgsCurve *>( d->geometry.get() );
1704  if ( !curve )
1705  {
1706  return polyLine;
1707  }
1708  segmentizedLine.reset( curve->curveToLine() );
1709  line = segmentizedLine.get();
1710  }
1711  else
1712  {
1713  line = qgsgeometry_cast<QgsLineString *>( d->geometry.get() );
1714  if ( !line )
1715  {
1716  return polyLine;
1717  }
1718  }
1719 
1720  int nVertices = line->numPoints();
1721  polyLine.resize( nVertices );
1722  QgsPointXY *data = polyLine.data();
1723  const double *xData = line->xData();
1724  const double *yData = line->yData();
1725  for ( int i = 0; i < nVertices; ++i )
1726  {
1727  data->setX( *xData++ );
1728  data->setY( *yData++ );
1729  data++;
1730  }
1731 
1732  return polyLine;
1733 }
1734 
1736 {
1737  if ( !d->geometry )
1738  return QgsPolygonXY();
1739 
1740  bool doSegmentation = ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::CurvePolygon );
1741 
1742  QgsPolygon *p = nullptr;
1743  std::unique_ptr< QgsPolygon > segmentized;
1744  if ( doSegmentation )
1745  {
1746  QgsCurvePolygon *curvePoly = qgsgeometry_cast<QgsCurvePolygon *>( d->geometry.get() );
1747  if ( !curvePoly )
1748  {
1749  return QgsPolygonXY();
1750  }
1751  segmentized.reset( curvePoly->toPolygon() );
1752  p = segmentized.get();
1753  }
1754  else
1755  {
1756  p = qgsgeometry_cast<QgsPolygon *>( d->geometry.get() );
1757  }
1758 
1759  if ( !p )
1760  {
1761  return QgsPolygonXY();
1762  }
1763 
1764  QgsPolygonXY polygon;
1765  convertPolygon( *p, polygon );
1766 
1767  return polygon;
1768 }
1769 
1771 {
1772  if ( !d->geometry || QgsWkbTypes::flatType( d->geometry->wkbType() ) != QgsWkbTypes::MultiPoint )
1773  {
1774  return QgsMultiPointXY();
1775  }
1776 
1777  const QgsMultiPoint *mp = qgsgeometry_cast<QgsMultiPoint *>( d->geometry.get() );
1778  if ( !mp )
1779  {
1780  return QgsMultiPointXY();
1781  }
1782 
1783  int nPoints = mp->numGeometries();
1784  QgsMultiPointXY multiPoint( nPoints );
1785  for ( int i = 0; i < nPoints; ++i )
1786  {
1787  const QgsPoint *pt = mp->pointN( i );
1788  multiPoint[i].setX( pt->x() );
1789  multiPoint[i].setY( pt->y() );
1790  }
1791  return multiPoint;
1792 }
1793 
1795 {
1796  if ( !d->geometry )
1797  {
1798  return QgsMultiPolylineXY();
1799  }
1800 
1801  QgsGeometryCollection *geomCollection = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
1802  if ( !geomCollection )
1803  {
1804  return QgsMultiPolylineXY();
1805  }
1806 
1807  int nLines = geomCollection->numGeometries();
1808  if ( nLines < 1 )
1809  {
1810  return QgsMultiPolylineXY();
1811  }
1812 
1813  QgsMultiPolylineXY mpl;
1814  mpl.reserve( nLines );
1815  for ( int i = 0; i < nLines; ++i )
1816  {
1817  const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( geomCollection->geometryN( i ) );
1818  std::unique_ptr< QgsLineString > segmentized;
1819  if ( !line )
1820  {
1821  const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( geomCollection->geometryN( i ) );
1822  if ( !curve )
1823  {
1824  continue;
1825  }
1826  segmentized.reset( curve->curveToLine() );
1827  line = segmentized.get();
1828  }
1829 
1830  QgsPolylineXY polyLine;
1831  int nVertices = line->numPoints();
1832  polyLine.resize( nVertices );
1833  QgsPointXY *data = polyLine.data();
1834  const double *xData = line->xData();
1835  const double *yData = line->yData();
1836  for ( int i = 0; i < nVertices; ++i )
1837  {
1838  data->setX( *xData++ );
1839  data->setY( *yData++ );
1840  data++;
1841  }
1842  mpl.append( polyLine );
1843  }
1844  return mpl;
1845 }
1846 
1848 {
1849  if ( !d->geometry )
1850  {
1851  return QgsMultiPolygonXY();
1852  }
1853 
1854  const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( d->geometry.get() );
1855  if ( !geomCollection )
1856  {
1857  return QgsMultiPolygonXY();
1858  }
1859 
1860  const int nPolygons = geomCollection->numGeometries();
1861  if ( nPolygons < 1 )
1862  {
1863  return QgsMultiPolygonXY();
1864  }
1865 
1866  QgsMultiPolygonXY mp;
1867  mp.reserve( nPolygons );
1868  for ( int i = 0; i < nPolygons; ++i )
1869  {
1870  const QgsPolygon *polygon = qgsgeometry_cast<const QgsPolygon *>( geomCollection->geometryN( i ) );
1871  if ( !polygon )
1872  {
1873  const QgsCurvePolygon *cPolygon = qgsgeometry_cast<const QgsCurvePolygon *>( geomCollection->geometryN( i ) );
1874  if ( cPolygon )
1875  {
1876  polygon = cPolygon->toPolygon();
1877  }
1878  else
1879  {
1880  continue;
1881  }
1882  }
1883 
1884  QgsPolygonXY poly;
1885  convertPolygon( *polygon, poly );
1886  mp.push_back( poly );
1887  }
1888  return mp;
1889 }
1890 
1891 double QgsGeometry::area() const
1892 {
1893  if ( !d->geometry )
1894  {
1895  return -1.0;
1896  }
1897 
1898  return d->geometry->area();
1899 }
1900 
1901 double QgsGeometry::length() const
1902 {
1903  if ( !d->geometry )
1904  {
1905  return -1.0;
1906  }
1907 
1908  switch ( QgsWkbTypes::geometryType( d->geometry->wkbType() ) )
1909  {
1911  return 0.0;
1912 
1914  return d->geometry->length();
1915 
1917  return d->geometry->perimeter();
1918 
1921  return d->geometry->length();
1922  }
1923  return -1;
1924 }
1925 
1926 double QgsGeometry::distance( const QgsGeometry &geom ) const
1927 {
1928  if ( !d->geometry || !geom.d->geometry )
1929  {
1930  return -1.0;
1931  }
1932 
1933  // avoid calling geos for trivial point-to-point distance calculations
1935  {
1936  return qgsgeometry_cast< const QgsPoint * >( d->geometry.get() )->distance( *qgsgeometry_cast< const QgsPoint * >( geom.constGet() ) );
1937  }
1938 
1939  QgsGeos g( d->geometry.get() );
1940  mLastError.clear();
1941  return g.distance( geom.d->geometry.get(), &mLastError );
1942 }
1943 
1944 double QgsGeometry::hausdorffDistance( const QgsGeometry &geom ) const
1945 {
1946  if ( !d->geometry || !geom.d->geometry )
1947  {
1948  return -1.0;
1949  }
1950 
1951  QgsGeos g( d->geometry.get() );
1952  mLastError.clear();
1953  return g.hausdorffDistance( geom.d->geometry.get(), &mLastError );
1954 }
1955 
1956 double QgsGeometry::hausdorffDistanceDensify( const QgsGeometry &geom, double densifyFraction ) const
1957 {
1958  if ( !d->geometry || !geom.d->geometry )
1959  {
1960  return -1.0;
1961  }
1962 
1963  QgsGeos g( d->geometry.get() );
1964  mLastError.clear();
1965  return g.hausdorffDistanceDensify( geom.d->geometry.get(), densifyFraction, &mLastError );
1966 }
1967 
1968 
1969 double QgsGeometry::frechetDistance( const QgsGeometry &geom ) const
1970 {
1971  if ( !d->geometry || !geom.d->geometry )
1972  {
1973  return -1.0;
1974  }
1975 
1976  QgsGeos g( d->geometry.get() );
1977  mLastError.clear();
1978  return g.frechetDistance( geom.d->geometry.get(), &mLastError );
1979 }
1980 
1981 double QgsGeometry::frechetDistanceDensify( const QgsGeometry &geom, double densifyFraction ) const
1982 {
1983  if ( !d->geometry || !geom.d->geometry )
1984  {
1985  return -1.0;
1986  }
1987 
1988  QgsGeos g( d->geometry.get() );
1989  mLastError.clear();
1990  return g.frechetDistanceDensify( geom.d->geometry.get(), densifyFraction, &mLastError );
1991 }
1992 
1994 {
1995  if ( !d->geometry || d->geometry.get()->isEmpty() )
1997  return d->geometry->vertices_begin();
1998 }
1999 
2001 {
2002  if ( !d->geometry || d->geometry.get()->isEmpty() )
2004  return d->geometry->vertices_end();
2005 }
2006 
2008 {
2009  if ( !d->geometry || d->geometry.get()->isEmpty() )
2010  return QgsVertexIterator();
2011  return QgsVertexIterator( d->geometry.get() );
2012 }
2013 
2015 {
2016  if ( !d->geometry )
2018 
2019  detach();
2020  return d->geometry->parts_begin();
2021 }
2022 
2024 {
2025  if ( !d->geometry )
2027  return d->geometry->parts_end();
2028 }
2029 
2031 {
2032  if ( !d->geometry )
2034  return d->geometry->const_parts_begin();
2035 }
2036 
2038 {
2039  if ( !d->geometry )
2041  return d->geometry->const_parts_end();
2042 }
2043 
2045 {
2046  if ( !d->geometry )
2047  return QgsGeometryPartIterator();
2048 
2049  detach();
2050  return QgsGeometryPartIterator( d->geometry.get() );
2051 }
2052 
2054 {
2055  if ( !d->geometry )
2057 
2058  return QgsGeometryConstPartIterator( d->geometry.get() );
2059 }
2060 
2061 QgsGeometry QgsGeometry::buffer( double distance, int segments ) const
2062 {
2063  if ( !d->geometry )
2064  {
2065  return QgsGeometry();
2066  }
2067 
2068  QgsGeos g( d->geometry.get() );
2069  mLastError.clear();
2070  std::unique_ptr<QgsAbstractGeometry> geom( g.buffer( distance, segments, &mLastError ) );
2071  if ( !geom )
2072  {
2073  QgsGeometry result;
2074  result.mLastError = mLastError;
2075  return result;
2076  }
2077  return QgsGeometry( std::move( geom ) );
2078 }
2079 
2080 QgsGeometry QgsGeometry::buffer( double distance, int segments, Qgis::EndCapStyle endCapStyle, Qgis::JoinStyle joinStyle, double miterLimit ) const
2081 {
2082  if ( !d->geometry )
2083  {
2084  return QgsGeometry();
2085  }
2086 
2087  QgsGeos g( d->geometry.get() );
2088  mLastError.clear();
2089  QgsAbstractGeometry *geom = g.buffer( distance, segments, endCapStyle, joinStyle, miterLimit, &mLastError );
2090  if ( !geom )
2091  {
2092  QgsGeometry result;
2093  result.mLastError = mLastError;
2094  return result;
2095  }
2096  return QgsGeometry( geom );
2097 }
2098 
2099 QgsGeometry QgsGeometry::offsetCurve( double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit ) const
2100 {
2101  if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
2102  {
2103  return QgsGeometry();
2104  }
2105 
2106  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
2107  {
2108  const QVector<QgsGeometry> parts = asGeometryCollection();
2109  QVector<QgsGeometry> results;
2110  results.reserve( parts.count() );
2111  for ( const QgsGeometry &part : parts )
2112  {
2113  QgsGeometry result = part.offsetCurve( distance, segments, joinStyle, miterLimit );
2114  if ( !result.isNull() )
2115  results << result;
2116  }
2117  if ( results.isEmpty() )
2118  return QgsGeometry();
2119 
2120  QgsGeometry first = results.takeAt( 0 );
2121  for ( const QgsGeometry &result : std::as_const( results ) )
2122  {
2123  first.addPart( result );
2124  }
2125  return first;
2126  }
2127  else
2128  {
2129  QgsGeos geos( d->geometry.get() );
2130  mLastError.clear();
2131 
2132  // GEOS can flip the curve orientation in some circumstances. So record previous orientation and correct if required
2133  const Qgis::AngularDirection prevOrientation = qgsgeometry_cast< const QgsCurve * >( d->geometry.get() )->orientation();
2134 
2135  std::unique_ptr< QgsAbstractGeometry > offsetGeom( geos.offsetCurve( distance, segments, joinStyle, miterLimit, &mLastError ) );
2136  if ( !offsetGeom )
2137  {
2138  QgsGeometry result;
2139  result.mLastError = mLastError;
2140  return result;
2141  }
2142 
2143  if ( const QgsCurve *offsetCurve = qgsgeometry_cast< const QgsCurve * >( offsetGeom.get() ) )
2144  {
2145  const Qgis::AngularDirection newOrientation = offsetCurve->orientation();
2146  if ( newOrientation != prevOrientation )
2147  {
2148  // GEOS has flipped line orientation, flip it back
2149  std::unique_ptr< QgsAbstractGeometry > flipped( offsetCurve->reversed() );
2150  offsetGeom = std::move( flipped );
2151  }
2152  }
2153  return QgsGeometry( std::move( offsetGeom ) );
2154  }
2155 }
2156 
2157 QgsGeometry QgsGeometry::singleSidedBuffer( double distance, int segments, Qgis::BufferSide side, Qgis::JoinStyle joinStyle, double miterLimit ) const
2158 {
2159  if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
2160  {
2161  return QgsGeometry();
2162  }
2163 
2164  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
2165  {
2166  const QVector<QgsGeometry> parts = asGeometryCollection();
2167  QVector<QgsGeometry> results;
2168  results.reserve( parts.count() );
2169  for ( const QgsGeometry &part : parts )
2170  {
2171  QgsGeometry result = part.singleSidedBuffer( distance, segments, side, joinStyle, miterLimit );
2172  if ( !result.isNull() )
2173  results << result;
2174  }
2175  if ( results.isEmpty() )
2176  return QgsGeometry();
2177 
2178  QgsGeometry first = results.takeAt( 0 );
2179  for ( const QgsGeometry &result : std::as_const( results ) )
2180  {
2181  first.addPart( result );
2182  }
2183  return first;
2184  }
2185  else
2186  {
2187  QgsGeos geos( d->geometry.get() );
2188  mLastError.clear();
2189  std::unique_ptr< QgsAbstractGeometry > bufferGeom = geos.singleSidedBuffer( distance, segments, side,
2190  joinStyle, miterLimit, &mLastError );
2191  if ( !bufferGeom )
2192  {
2193  QgsGeometry result;
2194  result.mLastError = mLastError;
2195  return result;
2196  }
2197  return QgsGeometry( std::move( bufferGeom ) );
2198  }
2199 }
2200 
2201 QgsGeometry QgsGeometry::taperedBuffer( double startWidth, double endWidth, int segments ) const
2202 {
2203  QgsInternalGeometryEngine engine( *this );
2204 
2205  return engine.taperedBuffer( startWidth, endWidth, segments );
2206 }
2207 
2209 {
2210  QgsInternalGeometryEngine engine( *this );
2211 
2212  return engine.variableWidthBufferByM( segments );
2213 }
2214 
2215 QgsGeometry QgsGeometry::extendLine( double startDistance, double endDistance ) const
2216 {
2217  if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
2218  {
2219  return QgsGeometry();
2220  }
2221 
2222  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
2223  {
2224  const QVector<QgsGeometry> parts = asGeometryCollection();
2225  QVector<QgsGeometry> results;
2226  results.reserve( parts.count() );
2227  for ( const QgsGeometry &part : parts )
2228  {
2229  QgsGeometry result = part.extendLine( startDistance, endDistance );
2230  if ( !result.isNull() )
2231  results << result;
2232  }
2233  if ( results.isEmpty() )
2234  return QgsGeometry();
2235 
2236  QgsGeometry first = results.takeAt( 0 );
2237  for ( const QgsGeometry &result : std::as_const( results ) )
2238  {
2239  first.addPart( result );
2240  }
2241  return first;
2242  }
2243  else
2244  {
2245  QgsLineString *line = qgsgeometry_cast< QgsLineString * >( d->geometry.get() );
2246  if ( !line )
2247  return QgsGeometry();
2248 
2249  std::unique_ptr< QgsLineString > newLine( line->clone() );
2250  newLine->extend( startDistance, endDistance );
2251  return QgsGeometry( std::move( newLine ) );
2252  }
2253 }
2254 
2255 QgsGeometry QgsGeometry::simplify( double tolerance ) const
2256 {
2257  if ( !d->geometry )
2258  {
2259  return QgsGeometry();
2260  }
2261 
2262  QgsGeos geos( d->geometry.get() );
2263  mLastError.clear();
2264  std::unique_ptr< QgsAbstractGeometry > simplifiedGeom( geos.simplify( tolerance, &mLastError ) );
2265  if ( !simplifiedGeom )
2266  {
2267  QgsGeometry result;
2268  result.mLastError = mLastError;
2269  return result;
2270  }
2271  return QgsGeometry( std::move( simplifiedGeom ) );
2272 }
2273 
2274 QgsGeometry QgsGeometry::densifyByCount( int extraNodesPerSegment ) const
2275 {
2276  QgsInternalGeometryEngine engine( *this );
2277 
2278  return engine.densifyByCount( extraNodesPerSegment );
2279 }
2280 
2282 {
2283  QgsInternalGeometryEngine engine( *this );
2284 
2285  return engine.densifyByDistance( distance );
2286 }
2287 
2288 QgsGeometry QgsGeometry::convertToCurves( double distanceTolerance, double angleTolerance ) const
2289 {
2290  QgsInternalGeometryEngine engine( *this );
2291 
2292  return engine.convertToCurves( distanceTolerance, angleTolerance );
2293 }
2294 
2296 {
2297  if ( !d->geometry )
2298  {
2299  return QgsGeometry();
2300  }
2301 
2302  // avoid calling geos for trivial point centroids
2303  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::Point )
2304  {
2305  QgsGeometry c = *this;
2306  c.get()->dropZValue();
2307  c.get()->dropMValue();
2308  return c;
2309  }
2310 
2311  QgsGeos geos( d->geometry.get() );
2312 
2313  mLastError.clear();
2314  QgsGeometry result( geos.centroid( &mLastError ) );
2315  result.mLastError = mLastError;
2316  return result;
2317 }
2318 
2320 {
2321  if ( !d->geometry )
2322  {
2323  return QgsGeometry();
2324  }
2325 
2326  QgsGeos geos( d->geometry.get() );
2327 
2328  mLastError.clear();
2329  QgsGeometry result( geos.pointOnSurface( &mLastError ) );
2330  result.mLastError = mLastError;
2331  return result;
2332 }
2333 
2334 QgsGeometry QgsGeometry::poleOfInaccessibility( double precision, double *distanceToBoundary ) const
2335 {
2336  QgsInternalGeometryEngine engine( *this );
2337 
2338  return engine.poleOfInaccessibility( precision, distanceToBoundary );
2339 }
2340 
2341 QgsGeometry QgsGeometry::largestEmptyCircle( double tolerance, const QgsGeometry &boundary ) const
2342 {
2343  if ( !d->geometry )
2344  {
2345  return QgsGeometry();
2346  }
2347 
2348  QgsGeos geos( d->geometry.get() );
2349 
2350  mLastError.clear();
2351  QgsGeometry result( geos.largestEmptyCircle( tolerance, boundary.constGet(), &mLastError ) );
2352  result.mLastError = mLastError;
2353  return result;
2354 }
2355 
2357 {
2358  if ( !d->geometry )
2359  {
2360  return QgsGeometry();
2361  }
2362 
2363  QgsGeos geos( d->geometry.get() );
2364 
2365  mLastError.clear();
2366  QgsGeometry result( geos.minimumWidth( &mLastError ) );
2367  result.mLastError = mLastError;
2368  return result;
2369 }
2370 
2372 {
2373  if ( !d->geometry )
2374  {
2375  return std::numeric_limits< double >::quiet_NaN();
2376  }
2377 
2378  QgsGeos geos( d->geometry.get() );
2379 
2380  mLastError.clear();
2381  return geos.minimumClearance( &mLastError );
2382 }
2383 
2385 {
2386  if ( !d->geometry )
2387  {
2388  return QgsGeometry();
2389  }
2390 
2391  QgsGeos geos( d->geometry.get() );
2392 
2393  mLastError.clear();
2394  QgsGeometry result( geos.minimumClearanceLine( &mLastError ) );
2395  result.mLastError = mLastError;
2396  return result;
2397 }
2398 
2400 {
2401  if ( !d->geometry )
2402  {
2403  return QgsGeometry();
2404  }
2405  QgsGeos geos( d->geometry.get() );
2406  mLastError.clear();
2407  std::unique_ptr< QgsAbstractGeometry > cHull( geos.convexHull( &mLastError ) );
2408  if ( !cHull )
2409  {
2410  QgsGeometry geom;
2411  geom.mLastError = mLastError;
2412  return geom;
2413  }
2414  return QgsGeometry( std::move( cHull ) );
2415 }
2416 
2417 QgsGeometry QgsGeometry::voronoiDiagram( const QgsGeometry &extent, double tolerance, bool edgesOnly ) const
2418 {
2419  if ( !d->geometry )
2420  {
2421  return QgsGeometry();
2422  }
2423 
2424  QgsGeos geos( d->geometry.get() );
2425  mLastError.clear();
2426  QgsGeometry result = geos.voronoiDiagram( extent.constGet(), tolerance, edgesOnly, &mLastError );
2427  result.mLastError = mLastError;
2428  return result;
2429 }
2430 
2431 QgsGeometry QgsGeometry::delaunayTriangulation( double tolerance, bool edgesOnly ) const
2432 {
2433  if ( !d->geometry )
2434  {
2435  return QgsGeometry();
2436  }
2437 
2438  QgsGeos geos( d->geometry.get() );
2439  mLastError.clear();
2440  QgsGeometry result = geos.delaunayTriangulation( tolerance, edgesOnly );
2441  result.mLastError = mLastError;
2442  return result;
2443 }
2444 
2446 {
2447  if ( !d->geometry )
2448  {
2449  return QgsGeometry();
2450  }
2451 
2452  QgsGeos geos( d->geometry.get() );
2453  mLastError.clear();
2454  QgsGeometry result( geos.node( &mLastError ) );
2455  result.mLastError = mLastError;
2456  return result;
2457 }
2458 
2460 {
2461  if ( !d->geometry )
2462  {
2463  return QgsGeometry();
2464  }
2465 
2466  QgsGeos geos( d->geometry.get() );
2467  mLastError.clear();
2468  QgsGeometry result( geos.sharedPaths( other.constGet(), &mLastError ) );
2469  result.mLastError = mLastError;
2470  return result;
2471 }
2472 
2474 {
2475  if ( !d->geometry )
2476  {
2477  return QgsGeometry();
2478  }
2479 
2480  const QgsAbstractGeometry *geom = d->geometry.get();
2481  std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
2482  if ( QgsWkbTypes::isCurvedType( d->geometry->wkbType() ) )
2483  {
2484  segmentizedCopy.reset( d->geometry->segmentize() );
2485  geom = segmentizedCopy.get();
2486  }
2487 
2488  QgsGeos geos( geom );
2489  mLastError.clear();
2490  std::unique_ptr< QgsAbstractGeometry > result( geos.subdivide( maxNodes, &mLastError ) );
2491  if ( !result )
2492  {
2493  QgsGeometry geom;
2494  geom.mLastError = mLastError;
2495  return geom;
2496  }
2497  return QgsGeometry( std::move( result ) );
2498 }
2499 
2500 QgsGeometry QgsGeometry::interpolate( double distance ) const
2501 {
2502  if ( !d->geometry )
2503  {
2504  return QgsGeometry();
2505  }
2506 
2507  QgsGeometry line = *this;
2508  if ( type() == QgsWkbTypes::PointGeometry )
2509  return QgsGeometry();
2510  else if ( type() == QgsWkbTypes::PolygonGeometry )
2511  {
2512  line = QgsGeometry( d->geometry->boundary() );
2513  }
2514 
2515  const QgsCurve *curve = nullptr;
2516  if ( line.isMultipart() )
2517  {
2518  // if multi part, iterate through parts to find target part
2519  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( line.constGet() );
2520  for ( int part = 0; part < collection->numGeometries(); ++part )
2521  {
2522  const QgsCurve *candidate = qgsgeometry_cast< const QgsCurve * >( collection->geometryN( part ) );
2523  if ( !candidate )
2524  continue;
2525  const double candidateLength = candidate->length();
2526  if ( candidateLength >= distance )
2527  {
2528  curve = candidate;
2529  break;
2530  }
2531 
2532  distance -= candidateLength;
2533  }
2534  }
2535  else
2536  {
2537  curve = qgsgeometry_cast< const QgsCurve * >( line.constGet() );
2538  }
2539  if ( !curve )
2540  return QgsGeometry();
2541 
2542  std::unique_ptr< QgsPoint > result( curve->interpolatePoint( distance ) );
2543  if ( !result )
2544  {
2545  return QgsGeometry();
2546  }
2547  return QgsGeometry( std::move( result ) );
2548 }
2549 
2550 double QgsGeometry::lineLocatePoint( const QgsGeometry &point ) const
2551 {
2552  if ( type() != QgsWkbTypes::LineGeometry )
2553  return -1;
2554 
2555  if ( QgsWkbTypes::flatType( point.wkbType() ) != QgsWkbTypes::Point )
2556  return -1;
2557 
2558  QgsGeometry segmentized = *this;
2560  {
2561  segmentized = QgsGeometry( static_cast< QgsCurve * >( d->geometry.get() )->segmentize() );
2562  }
2563 
2564  QgsGeos geos( d->geometry.get() );
2565  mLastError.clear();
2566  return geos.lineLocatePoint( *( static_cast< QgsPoint * >( point.d->geometry.get() ) ), &mLastError );
2567 }
2568 
2569 double QgsGeometry::interpolateAngle( double distance ) const
2570 {
2571  if ( !d->geometry )
2572  return 0.0;
2573 
2574  // always operate on segmentized geometries
2575  QgsGeometry segmentized = *this;
2577  {
2578  segmentized = QgsGeometry( static_cast< QgsCurve * >( d->geometry.get() )->segmentize() );
2579  }
2580 
2581  QgsVertexId previous;
2582  QgsVertexId next;
2583  if ( !QgsGeometryUtils::verticesAtDistance( *segmentized.constGet(), distance, previous, next ) )
2584  return 0.0;
2585 
2586  if ( previous == next )
2587  {
2588  // distance coincided exactly with a vertex
2589  QgsVertexId v2 = previous;
2590  QgsVertexId v1;
2591  QgsVertexId v3;
2592  segmentized.constGet()->adjacentVertices( v2, v1, v3 );
2593  if ( v1.isValid() && v3.isValid() )
2594  {
2595  QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
2596  QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
2597  QgsPoint p3 = segmentized.constGet()->vertexAt( v3 );
2598  double angle1 = QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2599  double angle2 = QgsGeometryUtils::lineAngle( p2.x(), p2.y(), p3.x(), p3.y() );
2600  return QgsGeometryUtils::averageAngle( angle1, angle2 );
2601  }
2602  else if ( v3.isValid() )
2603  {
2604  QgsPoint p1 = segmentized.constGet()->vertexAt( v2 );
2605  QgsPoint p2 = segmentized.constGet()->vertexAt( v3 );
2606  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2607  }
2608  else
2609  {
2610  QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
2611  QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
2612  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2613  }
2614  }
2615  else
2616  {
2617  QgsPoint p1 = segmentized.constGet()->vertexAt( previous );
2618  QgsPoint p2 = segmentized.constGet()->vertexAt( next );
2619  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2620  }
2621 }
2622 
2624 {
2625  if ( !d->geometry || geometry.isNull() )
2626  {
2627  return QgsGeometry();
2628  }
2629 
2630  QgsGeos geos( d->geometry.get() );
2631 
2632  mLastError.clear();
2633  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.intersection( geometry.d->geometry.get(), &mLastError ) );
2634 
2635  if ( !resultGeom )
2636  {
2637  QgsGeometry geom;
2638  geom.mLastError = mLastError;
2639  return geom;
2640  }
2641 
2642  return QgsGeometry( std::move( resultGeom ) );
2643 }
2644 
2646 {
2647  if ( !d->geometry || geometry.isNull() )
2648  {
2649  return QgsGeometry();
2650  }
2651 
2652  QgsGeos geos( d->geometry.get() );
2653  mLastError.clear();
2654  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.combine( geometry.d->geometry.get(), &mLastError ) );
2655  if ( !resultGeom )
2656  {
2657  QgsGeometry geom;
2658  geom.mLastError = mLastError;
2659  return geom;
2660  }
2661  return QgsGeometry( std::move( resultGeom ) );
2662 }
2663 
2665 {
2666  if ( !d->geometry )
2667  {
2668  return QgsGeometry();
2669  }
2670 
2671  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::LineString )
2672  {
2673  // special case - a single linestring was passed
2674  return QgsGeometry( *this );
2675  }
2676 
2677  QgsGeos geos( d->geometry.get() );
2678  mLastError.clear();
2679  QgsGeometry result = geos.mergeLines( &mLastError );
2680  result.mLastError = mLastError;
2681  return result;
2682 }
2683 
2685 {
2686  if ( !d->geometry || geometry.isNull() )
2687  {
2688  return QgsGeometry();
2689  }
2690 
2691  QgsGeos geos( d->geometry.get() );
2692 
2693  mLastError.clear();
2694  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.difference( geometry.d->geometry.get(), &mLastError ) );
2695  if ( !resultGeom )
2696  {
2697  QgsGeometry geom;
2698  geom.mLastError = mLastError;
2699  return geom;
2700  }
2701  return QgsGeometry( std::move( resultGeom ) );
2702 }
2703 
2705 {
2706  if ( !d->geometry || geometry.isNull() )
2707  {
2708  return QgsGeometry();
2709  }
2710 
2711  QgsGeos geos( d->geometry.get() );
2712 
2713  mLastError.clear();
2714  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.symDifference( geometry.d->geometry.get(), &mLastError ) );
2715  if ( !resultGeom )
2716  {
2717  QgsGeometry geom;
2718  geom.mLastError = mLastError;
2719  return geom;
2720  }
2721  return QgsGeometry( std::move( resultGeom ) );
2722 }
2723 
2724 QgsGeometry QgsGeometry::extrude( double x, double y )
2725 {
2726  QgsInternalGeometryEngine engine( *this );
2727 
2728  return engine.extrude( x, y );
2729 }
2730 
2732 
2733 QVector<QgsPointXY> QgsGeometry::randomPointsInPolygon( int count, const std::function< bool( const QgsPointXY & ) > &acceptPoint, unsigned long seed, QgsFeedback *feedback, int maxTriesPerPoint ) const
2734 {
2736  return QVector< QgsPointXY >();
2737 
2738  return QgsInternalGeometryEngine::randomPointsInPolygon( *this, count, acceptPoint, seed, feedback, maxTriesPerPoint );
2739 }
2740 
2741 QVector<QgsPointXY> QgsGeometry::randomPointsInPolygon( int count, unsigned long seed, QgsFeedback *feedback ) const
2742 {
2744  return QVector< QgsPointXY >();
2745 
2746  return QgsInternalGeometryEngine::randomPointsInPolygon( *this, count, []( const QgsPointXY & ) { return true; }, seed, feedback, 0 );
2747 }
2749 
2750 int QgsGeometry::wkbSize( QgsAbstractGeometry::WkbFlags flags ) const
2751 {
2752  return d->geometry ? d->geometry->wkbSize( flags ) : 0;
2753 }
2754 
2755 QByteArray QgsGeometry::asWkb( QgsAbstractGeometry::WkbFlags flags ) const
2756 {
2757  return d->geometry ? d->geometry->asWkb( flags ) : QByteArray();
2758 }
2759 
2760 QVector<QgsGeometry> QgsGeometry::asGeometryCollection() const
2761 {
2762  QVector<QgsGeometry> geometryList;
2763  if ( !d->geometry )
2764  {
2765  return geometryList;
2766  }
2767 
2768  QgsGeometryCollection *gc = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
2769  if ( gc )
2770  {
2771  int numGeom = gc->numGeometries();
2772  geometryList.reserve( numGeom );
2773  for ( int i = 0; i < numGeom; ++i )
2774  {
2775  geometryList.append( QgsGeometry( gc->geometryN( i )->clone() ) );
2776  }
2777  }
2778  else //a singlepart geometry
2779  {
2780  geometryList.append( *this );
2781  }
2782 
2783  return geometryList;
2784 }
2785 
2786 QPointF QgsGeometry::asQPointF() const
2787 {
2788  QgsPointXY point = asPoint();
2789  return point.toQPointF();
2790 }
2791 
2792 QPolygonF QgsGeometry::asQPolygonF() const
2793 {
2794  const QgsAbstractGeometry *part = constGet();
2795 
2796  // if a geometry collection, get first part only
2797  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection *>( part ) )
2798  {
2799  if ( collection->numGeometries() > 0 )
2800  part = collection->geometryN( 0 );
2801  else
2802  return QPolygonF();
2803  }
2804 
2805  if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( part ) )
2806  return curve->asQPolygonF();
2807  else if ( const QgsCurvePolygon *polygon = qgsgeometry_cast< const QgsCurvePolygon * >( part ) )
2808  return polygon->exteriorRing() ? polygon->exteriorRing()->asQPolygonF() : QPolygonF();
2809  return QPolygonF();
2810 }
2811 
2812 bool QgsGeometry::deleteRing( int ringNum, int partNum )
2813 {
2814  if ( !d->geometry )
2815  {
2816  return false;
2817  }
2818 
2819  detach();
2820  bool ok = QgsGeometryEditUtils::deleteRing( d->geometry.get(), ringNum, partNum );
2821  return ok;
2822 }
2823 
2824 bool QgsGeometry::deletePart( int partNum )
2825 {
2826  if ( !d->geometry )
2827  {
2828  return false;
2829  }
2830 
2831  if ( !isMultipart() && partNum < 1 )
2832  {
2833  set( nullptr );
2834  return true;
2835  }
2836 
2837  detach();
2838  bool ok = QgsGeometryEditUtils::deletePart( d->geometry.get(), partNum );
2839  return ok;
2840 }
2841 
2842 int QgsGeometry::avoidIntersections( const QList<QgsVectorLayer *> &avoidIntersectionsLayers, const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures )
2843 {
2844  if ( !d->geometry )
2845  {
2846  return 1;
2847  }
2848 
2849  QgsWkbTypes::Type geomTypeBeforeModification = wkbType();
2850 
2851  bool haveInvalidGeometry = false;
2852  std::unique_ptr< QgsAbstractGeometry > diffGeom = QgsGeometryEditUtils::avoidIntersections( *( d->geometry ), avoidIntersectionsLayers, haveInvalidGeometry, ignoreFeatures );
2853  if ( diffGeom )
2854  {
2855  reset( std::move( diffGeom ) );
2856  }
2857 
2858  if ( geomTypeBeforeModification != wkbType() )
2859  return 2;
2860  if ( haveInvalidGeometry )
2861  return 4;
2862 
2863  return 0;
2864 }
2865 
2866 
2868 {
2869  if ( !d->geometry )
2870  return QgsGeometry();
2871 
2872  mLastError.clear();
2873 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=8 )
2874  QgsGeos geos( d->geometry.get() );
2875  std::unique_ptr< QgsAbstractGeometry > g( geos.makeValid( &mLastError ) );
2876 #else
2877  std::unique_ptr< QgsAbstractGeometry > g( _qgis_lwgeom_make_valid( d->geometry.get(), mLastError ) );
2878 #endif
2879 
2880  QgsGeometry result = QgsGeometry( std::move( g ) );
2881  result.mLastError = mLastError;
2882  return result;
2883 }
2884 
2886 {
2887  return forcePolygonClockwise();
2888 }
2889 
2891 {
2892  if ( !d->geometry )
2893  return QgsGeometry();
2894 
2895  if ( isMultipart() )
2896  {
2897  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( d->geometry.get() );
2898  std::unique_ptr< QgsGeometryCollection > newCollection( collection->createEmptyWithSameType() );
2899  newCollection->reserve( collection->numGeometries() );
2900  for ( int i = 0; i < collection->numGeometries(); ++i )
2901  {
2902  const QgsAbstractGeometry *g = collection->geometryN( i );
2903  if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( g ) )
2904  {
2905  std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2906  corrected->forceClockwise();
2907  newCollection->addGeometry( corrected.release() );
2908  }
2909  else
2910  {
2911  newCollection->addGeometry( g->clone() );
2912  }
2913  }
2914  return QgsGeometry( std::move( newCollection ) );
2915  }
2916  else
2917  {
2918  if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( d->geometry.get() ) )
2919  {
2920  std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2921  corrected->forceClockwise();
2922  return QgsGeometry( std::move( corrected ) );
2923  }
2924  else
2925  {
2926  // not a curve polygon, so return unchanged
2927  return *this;
2928  }
2929  }
2930 }
2931 
2933 {
2934  if ( !d->geometry )
2935  return QgsGeometry();
2936 
2937  if ( isMultipart() )
2938  {
2939  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( d->geometry.get() );
2940  std::unique_ptr< QgsGeometryCollection > newCollection( collection->createEmptyWithSameType() );
2941  newCollection->reserve( collection->numGeometries() );
2942  for ( int i = 0; i < collection->numGeometries(); ++i )
2943  {
2944  const QgsAbstractGeometry *g = collection->geometryN( i );
2945  if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( g ) )
2946  {
2947  std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2948  corrected->forceCounterClockwise();
2949  newCollection->addGeometry( corrected.release() );
2950  }
2951  else
2952  {
2953  newCollection->addGeometry( g->clone() );
2954  }
2955  }
2956  return QgsGeometry( std::move( newCollection ) );
2957  }
2958  else
2959  {
2960  if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( d->geometry.get() ) )
2961  {
2962  std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2963  corrected->forceCounterClockwise();
2964  return QgsGeometry( std::move( corrected ) );
2965  }
2966  else
2967  {
2968  // not a curve polygon, so return unchanged
2969  return *this;
2970  }
2971  }
2972 }
2973 
2974 
2975 void QgsGeometry::validateGeometry( QVector<QgsGeometry::Error> &errors, const Qgis::GeometryValidationEngine method, const Qgis::GeometryValidityFlags flags ) const
2976 {
2977  errors.clear();
2978  if ( !d->geometry )
2979  return;
2980 
2981  // avoid expensive calcs for trivial point geometries
2983  {
2984  return;
2985  }
2986 
2987  switch ( method )
2988  {
2989  case Qgis::GeometryValidationEngine::QgisInternal:
2990  QgsGeometryValidator::validateGeometry( *this, errors, method );
2991  return;
2992 
2993  case Qgis::GeometryValidationEngine::Geos:
2994  {
2995  QgsGeos geos( d->geometry.get() );
2996  QString error;
2997  QgsGeometry errorLoc;
2998  if ( !geos.isValid( &error, flags & Qgis::GeometryValidityFlag::AllowSelfTouchingHoles, &errorLoc ) )
2999  {
3000  if ( errorLoc.isNull() )
3001  {
3002  errors.append( QgsGeometry::Error( error ) );
3003  }
3004  else
3005  {
3006  const QgsPointXY point = errorLoc.asPoint();
3007  errors.append( QgsGeometry::Error( error, point ) );
3008  }
3009  return;
3010  }
3011  }
3012  }
3013 }
3014 
3016 {
3017  if ( !d->geometry )
3018  {
3019  return;
3020  }
3021 
3022  detach();
3023  d->geometry->normalize();
3024 }
3025 
3026 bool QgsGeometry::isGeosValid( Qgis::GeometryValidityFlags flags ) const
3027 {
3028  if ( !d->geometry )
3029  {
3030  return false;
3031  }
3032 
3033  return d->geometry->isValid( mLastError, flags );
3034 }
3035 
3037 {
3038  if ( !d->geometry )
3039  return false;
3040 
3041  QgsGeos geos( d->geometry.get() );
3042  mLastError.clear();
3043  return geos.isSimple( &mLastError );
3044 }
3045 
3046 bool QgsGeometry::isAxisParallelRectangle( double maximumDeviation, bool simpleRectanglesOnly ) const
3047 {
3048  if ( !d->geometry )
3049  return false;
3050 
3051  QgsInternalGeometryEngine engine( *this );
3052  return engine.isAxisParallelRectangle( maximumDeviation, simpleRectanglesOnly );
3053 }
3054 
3056 {
3057  if ( !d->geometry || !g.d->geometry )
3058  {
3059  return false;
3060  }
3061 
3062  // fast check - are they shared copies of the same underlying geometry?
3063  if ( d == g.d )
3064  return true;
3065 
3066  // fast check - distinct geometry types?
3067  if ( type() != g.type() )
3068  return false;
3069 
3070  // avoid calling geos for trivial point case
3071  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::Point
3072  && QgsWkbTypes::flatType( g.d->geometry->wkbType() ) == QgsWkbTypes::Point )
3073  {
3074  return equals( g );
3075  }
3076 
3077  // another nice fast check upfront -- if the bounding boxes aren't equal, the geometries themselves can't be equal!
3078  if ( d->geometry->boundingBox() != g.d->geometry->boundingBox() )
3079  return false;
3080 
3081  QgsGeos geos( d->geometry.get() );
3082  mLastError.clear();
3083  return geos.isEqual( g.d->geometry.get(), &mLastError );
3084 }
3085 
3086 QgsGeometry QgsGeometry::unaryUnion( const QVector<QgsGeometry> &geometries )
3087 {
3088  QgsGeos geos( nullptr );
3089 
3090  QString error;
3091  std::unique_ptr< QgsAbstractGeometry > geom( geos.combine( geometries, &error ) );
3092  QgsGeometry result( std::move( geom ) );
3093  result.mLastError = error;
3094  return result;
3095 }
3096 
3097 QgsGeometry QgsGeometry::polygonize( const QVector<QgsGeometry> &geometryList )
3098 {
3099  QVector<const QgsAbstractGeometry *> geomV2List;
3100  for ( const QgsGeometry &g : geometryList )
3101  {
3102  if ( !( g.isNull() ) )
3103  {
3104  geomV2List.append( g.constGet() );
3105  }
3106  }
3107 
3108  QString error;
3109  QgsGeometry result = QgsGeos::polygonize( geomV2List, &error );
3110  result.mLastError = error;
3111  return result;
3112 }
3113 
3115 {
3117  {
3118  return;
3119  }
3120 
3121  std::unique_ptr< QgsAbstractGeometry > straightGeom( d->geometry->segmentize( tolerance, toleranceType ) );
3122  reset( std::move( straightGeom ) );
3123 }
3124 
3126 {
3127  if ( !d->geometry )
3128  {
3129  return false;
3130  }
3131 
3132  return d->geometry->hasCurvedSegments();
3133 }
3134 
3136 {
3137  if ( !d->geometry )
3138  {
3140  }
3141 
3142  detach();
3143  d->geometry->transform( ct, direction, transformZ );
3145 }
3146 
3147 Qgis::GeometryOperationResult QgsGeometry::transform( const QTransform &ct, double zTranslate, double zScale, double mTranslate, double mScale )
3148 {
3149  if ( !d->geometry )
3150  {
3152  }
3153 
3154  detach();
3155  d->geometry->transform( ct, zTranslate, zScale, mTranslate, mScale );
3157 }
3158 
3160 {
3161  if ( d->geometry )
3162  {
3163  detach();
3164  d->geometry->transform( mtp.transform() );
3165  }
3166 }
3167 
3169 {
3170  if ( !d->geometry || rectangle.isNull() || rectangle.isEmpty() )
3171  {
3172  return QgsGeometry();
3173  }
3174 
3175  QgsGeos geos( d->geometry.get() );
3176  mLastError.clear();
3177  std::unique_ptr< QgsAbstractGeometry > resultGeom = geos.clip( rectangle, &mLastError );
3178  if ( !resultGeom )
3179  {
3180  QgsGeometry result;
3181  result.mLastError = mLastError;
3182  return result;
3183  }
3184  return QgsGeometry( std::move( resultGeom ) );
3185 }
3186 
3187 void QgsGeometry::draw( QPainter &p ) const
3188 {
3189  if ( d->geometry )
3190  {
3191  d->geometry->draw( p );
3192  }
3193 }
3194 
3195 static bool vertexIndexInfo( const QgsAbstractGeometry *g, int vertexIndex, int &partIndex, int &ringIndex, int &vertex )
3196 {
3197  if ( vertexIndex < 0 )
3198  return false; // clearly something wrong
3199 
3200  if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
3201  {
3202  partIndex = 0;
3203  int offset = 0;
3204  for ( int i = 0; i < geomCollection->numGeometries(); ++i )
3205  {
3206  const QgsAbstractGeometry *part = geomCollection->geometryN( i );
3207 
3208  // count total number of vertices in the part
3209  int numPoints = 0;
3210  for ( int k = 0; k < part->ringCount(); ++k )
3211  numPoints += part->vertexCount( 0, k );
3212 
3213  if ( vertexIndex < numPoints )
3214  {
3215  int nothing;
3216  return vertexIndexInfo( part, vertexIndex, nothing, ringIndex, vertex ); // set ring_index + index
3217  }
3218  vertexIndex -= numPoints;
3219  offset += numPoints;
3220  partIndex++;
3221  }
3222  }
3223  else if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
3224  {
3225  const QgsCurve *ring = curvePolygon->exteriorRing();
3226  if ( vertexIndex < ring->numPoints() )
3227  {
3228  partIndex = 0;
3229  ringIndex = 0;
3230  vertex = vertexIndex;
3231  return true;
3232  }
3233  vertexIndex -= ring->numPoints();
3234  ringIndex = 1;
3235  for ( int i = 0; i < curvePolygon->numInteriorRings(); ++i )
3236  {
3237  const QgsCurve *ring = curvePolygon->interiorRing( i );
3238  if ( vertexIndex < ring->numPoints() )
3239  {
3240  partIndex = 0;
3241  vertex = vertexIndex;
3242  return true;
3243  }
3244  vertexIndex -= ring->numPoints();
3245  ringIndex += 1;
3246  }
3247  }
3248  else if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
3249  {
3250  if ( vertexIndex < curve->numPoints() )
3251  {
3252  partIndex = 0;
3253  ringIndex = 0;
3254  vertex = vertexIndex;
3255  return true;
3256  }
3257  }
3258  else if ( qgsgeometry_cast<const QgsPoint *>( g ) )
3259  {
3260  if ( vertexIndex == 0 )
3261  {
3262  partIndex = 0;
3263  ringIndex = 0;
3264  vertex = 0;
3265  return true;
3266  }
3267  }
3268 
3269  return false;
3270 }
3271 
3273 {
3274  if ( !d->geometry )
3275  {
3276  return false;
3277  }
3278 
3279  id.type = Qgis::VertexType::Segment;
3280 
3281  bool res = vertexIndexInfo( d->geometry.get(), nr, id.part, id.ring, id.vertex );
3282  if ( !res )
3283  return false;
3284 
3285  // now let's find out if it is a straight or circular segment
3286  const QgsAbstractGeometry *g = d->geometry.get();
3287  if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
3288  {
3289  g = geomCollection->geometryN( id.part );
3290  }
3291 
3292  if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
3293  {
3294  g = id.ring == 0 ? curvePolygon->exteriorRing() : curvePolygon->interiorRing( id.ring - 1 );
3295  }
3296 
3297  if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
3298  {
3299  QgsPoint p;
3300  res = curve->pointAt( id.vertex, p, id.type );
3301  if ( !res )
3302  return false;
3303  }
3304 
3305  return true;
3306 }
3307 
3309 {
3310  if ( !d->geometry )
3311  {
3312  return -1;
3313  }
3314  return d->geometry->vertexNumberFromVertexId( id );
3315 }
3316 
3317 QString QgsGeometry::lastError() const
3318 {
3319  return mLastError;
3320 }
3321 
3322 void QgsGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
3323 {
3324  if ( !d->geometry )
3325  return;
3326 
3327  detach();
3328 
3329  d->geometry->filterVertices( filter );
3330 }
3331 
3332 void QgsGeometry::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
3333 {
3334  if ( !d->geometry )
3335  return;
3336 
3337  detach();
3338 
3339  d->geometry->transformVertices( transform );
3340 }
3341 
3342 void QgsGeometry::convertPointList( const QVector<QgsPointXY> &input, QgsPointSequence &output )
3343 {
3344  output.clear();
3345  for ( const QgsPointXY &p : input )
3346  {
3347  output.append( QgsPoint( p ) );
3348  }
3349 }
3350 
3351 void QgsGeometry::convertPointList( const QgsPointSequence &input, QVector<QgsPointXY> &output )
3352 {
3353  output.clear();
3354  for ( const QgsPoint &p : input )
3355  {
3356  output.append( QgsPointXY( p.x(), p.y() ) );
3357  }
3358 }
3359 
3360 void QgsGeometry::convertPolygon( const QgsPolygon &input, QgsPolygonXY &output )
3361 {
3362  output.clear();
3363 
3364  auto convertRing = []( const QgsCurve * ring ) -> QgsPolylineXY
3365  {
3366  QgsPolylineXY res;
3367  bool doSegmentation = ( QgsWkbTypes::flatType( ring->wkbType() ) == QgsWkbTypes::CompoundCurve
3369  std::unique_ptr< QgsLineString > segmentizedLine;
3370  const QgsLineString *line = nullptr;
3371  if ( doSegmentation )
3372  {
3373  segmentizedLine.reset( ring->curveToLine() );
3374  line = segmentizedLine.get();
3375  }
3376  else
3377  {
3378  line = qgsgeometry_cast<const QgsLineString *>( ring );
3379  if ( !line )
3380  {
3381  return res;
3382  }
3383  }
3384 
3385  int nVertices = line->numPoints();
3386  res.resize( nVertices );
3387  QgsPointXY *data = res.data();
3388  const double *xData = line->xData();
3389  const double *yData = line->yData();
3390  for ( int i = 0; i < nVertices; ++i )
3391  {
3392  data->setX( *xData++ );
3393  data->setY( *yData++ );
3394  data++;
3395  }
3396  return res;
3397  };
3398 
3399  if ( const QgsCurve *exterior = input.exteriorRing() )
3400  {
3401  output.push_back( convertRing( exterior ) );
3402  }
3403 
3404  const int interiorRingCount = input.numInteriorRings();
3405  output.reserve( output.size() + interiorRingCount );
3406  for ( int n = 0; n < interiorRingCount; ++n )
3407  {
3408  output.push_back( convertRing( input.interiorRing( n ) ) );
3409  }
3410 }
3411 
3413 {
3414  return QgsGeometry( std::make_unique< QgsPoint >( point.x(), point.y() ) );
3415 }
3416 
3417 QgsGeometry QgsGeometry::fromQPolygonF( const QPolygonF &polygon )
3418 {
3419  std::unique_ptr < QgsLineString > ring( QgsLineString::fromQPolygonF( polygon ) );
3420 
3421  if ( polygon.isClosed() )
3422  {
3423  std::unique_ptr< QgsPolygon > poly = std::make_unique< QgsPolygon >();
3424  poly->setExteriorRing( ring.release() );
3425  return QgsGeometry( std::move( poly ) );
3426  }
3427  else
3428  {
3429  return QgsGeometry( std::move( ring ) );
3430  }
3431 }
3432 
3434 {
3436  QgsPolygonXY result;
3437  result << createPolylineFromQPolygonF( polygon );
3438  return result;
3440 }
3441 
3443 {
3444  QgsPolylineXY result;
3445  result.reserve( polygon.count() );
3446  for ( const QPointF &p : polygon )
3447  {
3448  result.append( QgsPointXY( p ) );
3449  }
3450  return result;
3451 }
3452 
3453 bool QgsGeometry::compare( const QgsPolylineXY &p1, const QgsPolylineXY &p2, double epsilon )
3454 {
3455  if ( p1.count() != p2.count() )
3456  return false;
3457 
3458  for ( int i = 0; i < p1.count(); ++i )
3459  {
3460  if ( !p1.at( i ).compare( p2.at( i ), epsilon ) )
3461  return false;
3462  }
3463  return true;
3464 }
3465 
3466 bool QgsGeometry::compare( const QgsPolygonXY &p1, const QgsPolygonXY &p2, double epsilon )
3467 {
3468  if ( p1.count() != p2.count() )
3469  return false;
3470 
3471  for ( int i = 0; i < p1.count(); ++i )
3472  {
3473  if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
3474  return false;
3475  }
3476  return true;
3477 }
3478 
3479 
3480 bool QgsGeometry::compare( const QgsMultiPolygonXY &p1, const QgsMultiPolygonXY &p2, double epsilon )
3481 {
3482  if ( p1.count() != p2.count() )
3483  return false;
3484 
3485  for ( int i = 0; i < p1.count(); ++i )
3486  {
3487  if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
3488  return false;
3489  }
3490  return true;
3491 }
3492 
3493 QgsGeometry QgsGeometry::smooth( const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3494 {
3495  if ( !d->geometry || d->geometry->isEmpty() )
3496  return QgsGeometry();
3497 
3498  QgsGeometry geom = *this;
3500  geom = QgsGeometry( d->geometry->segmentize() );
3501 
3502  switch ( QgsWkbTypes::flatType( geom.wkbType() ) )
3503  {
3504  case QgsWkbTypes::Point:
3506  //can't smooth a point based geometry
3507  return geom;
3508 
3510  {
3511  const QgsLineString *lineString = qgsgeometry_cast< const QgsLineString * >( geom.constGet() );
3512  return QgsGeometry( smoothLine( *lineString, iterations, offset, minimumDistance, maxAngle ) );
3513  }
3514 
3516  {
3517  const QgsMultiLineString *multiLine = qgsgeometry_cast< const QgsMultiLineString * >( geom.constGet() );
3518 
3519  std::unique_ptr< QgsMultiLineString > resultMultiline = std::make_unique< QgsMultiLineString> ();
3520  resultMultiline->reserve( multiLine->numGeometries() );
3521  for ( int i = 0; i < multiLine->numGeometries(); ++i )
3522  {
3523  resultMultiline->addGeometry( smoothLine( *( multiLine->lineStringN( i ) ), iterations, offset, minimumDistance, maxAngle ).release() );
3524  }
3525  return QgsGeometry( std::move( resultMultiline ) );
3526  }
3527 
3528  case QgsWkbTypes::Polygon:
3529  {
3530  const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon * >( geom.constGet() );
3531  return QgsGeometry( smoothPolygon( *poly, iterations, offset, minimumDistance, maxAngle ) );
3532  }
3533 
3535  {
3536  const QgsMultiPolygon *multiPoly = qgsgeometry_cast< const QgsMultiPolygon * >( geom.constGet() );
3537 
3538  std::unique_ptr< QgsMultiPolygon > resultMultiPoly = std::make_unique< QgsMultiPolygon >();
3539  resultMultiPoly->reserve( multiPoly->numGeometries() );
3540  for ( int i = 0; i < multiPoly->numGeometries(); ++i )
3541  {
3542  resultMultiPoly->addGeometry( smoothPolygon( *( multiPoly->polygonN( i ) ), iterations, offset, minimumDistance, maxAngle ).release() );
3543  }
3544  return QgsGeometry( std::move( resultMultiPoly ) );
3545  }
3546 
3547  case QgsWkbTypes::Unknown:
3548  default:
3549  return QgsGeometry( *this );
3550  }
3551 }
3552 
3553 std::unique_ptr< QgsLineString > smoothCurve( const QgsLineString &line, const unsigned int iterations,
3554  const double offset, double squareDistThreshold, double maxAngleRads,
3555  bool isRing )
3556 {
3557  std::unique_ptr< QgsLineString > result = std::make_unique< QgsLineString >( line );
3558  QgsPointSequence outputLine;
3559  for ( unsigned int iteration = 0; iteration < iterations; ++iteration )
3560  {
3561  outputLine.resize( 0 );
3562  outputLine.reserve( 2 * ( result->numPoints() - 1 ) );
3563  bool skipFirst = false;
3564  bool skipLast = false;
3565  if ( isRing )
3566  {
3567  QgsPoint p1 = result->pointN( result->numPoints() - 2 );
3568  QgsPoint p2 = result->pointN( 0 );
3569  QgsPoint p3 = result->pointN( 1 );
3570  double angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3571  p3.x(), p3.y() );
3572  angle = std::fabs( M_PI - angle );
3573  skipFirst = angle > maxAngleRads;
3574  }
3575  for ( int i = 0; i < result->numPoints() - 1; i++ )
3576  {
3577  QgsPoint p1 = result->pointN( i );
3578  QgsPoint p2 = result->pointN( i + 1 );
3579 
3580  double angle = M_PI;
3581  if ( i == 0 && isRing )
3582  {
3583  QgsPoint p3 = result->pointN( result->numPoints() - 2 );
3584  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3585  p3.x(), p3.y() );
3586  }
3587  else if ( i < result->numPoints() - 2 )
3588  {
3589  QgsPoint p3 = result->pointN( i + 2 );
3590  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3591  p3.x(), p3.y() );
3592  }
3593  else if ( i == result->numPoints() - 2 && isRing )
3594  {
3595  QgsPoint p3 = result->pointN( 1 );
3596  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3597  p3.x(), p3.y() );
3598  }
3599 
3600  skipLast = angle < M_PI - maxAngleRads || angle > M_PI + maxAngleRads;
3601 
3602  // don't apply distance threshold to first or last segment
3603  if ( i == 0 || i >= result->numPoints() - 2
3604  || QgsGeometryUtils::sqrDistance2D( p1, p2 ) > squareDistThreshold )
3605  {
3606  if ( !isRing )
3607  {
3608  if ( !skipFirst )
3609  outputLine << ( i == 0 ? result->pointN( i ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset ) );
3610  if ( !skipLast )
3611  outputLine << ( i == result->numPoints() - 2 ? result->pointN( i + 1 ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset ) );
3612  else
3613  outputLine << p2;
3614  }
3615  else
3616  {
3617  // ring
3618  if ( !skipFirst )
3619  outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset );
3620  else if ( i == 0 )
3621  outputLine << p1;
3622  if ( !skipLast )
3623  outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset );
3624  else
3625  outputLine << p2;
3626  }
3627  }
3628  skipFirst = skipLast;
3629  }
3630 
3631  if ( isRing && outputLine.at( 0 ) != outputLine.at( outputLine.count() - 1 ) )
3632  outputLine << outputLine.at( 0 );
3633 
3634  result->setPoints( outputLine );
3635  }
3636  return result;
3637 }
3638 
3639 std::unique_ptr<QgsLineString> QgsGeometry::smoothLine( const QgsLineString &line, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3640 {
3641  double maxAngleRads = maxAngle * M_PI / 180.0;
3642  double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
3643  return smoothCurve( line, iterations, offset, squareDistThreshold, maxAngleRads, false );
3644 }
3645 
3646 std::unique_ptr<QgsPolygon> QgsGeometry::smoothPolygon( const QgsPolygon &polygon, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3647 {
3648  double maxAngleRads = maxAngle * M_PI / 180.0;
3649  double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
3650  std::unique_ptr< QgsPolygon > resultPoly = std::make_unique< QgsPolygon >();
3651 
3652  resultPoly->setExteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.exteriorRing() ) ), iterations, offset,
3653  squareDistThreshold, maxAngleRads, true ).release() );
3654 
3655  for ( int i = 0; i < polygon.numInteriorRings(); ++i )
3656  {
3657  resultPoly->addInteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.interiorRing( i ) ) ), iterations, offset,
3658  squareDistThreshold, maxAngleRads, true ).release() );
3659  }
3660  return resultPoly;
3661 }
3662 
3663 QgsGeometry QgsGeometry::convertToPoint( bool destMultipart ) const
3664 {
3665  switch ( type() )
3666  {
3668  {
3669  bool srcIsMultipart = isMultipart();
3670 
3671  if ( ( destMultipart && srcIsMultipart ) ||
3672  ( !destMultipart && !srcIsMultipart ) )
3673  {
3674  // return a copy of the same geom
3675  return QgsGeometry( *this );
3676  }
3677  if ( destMultipart )
3678  {
3679  // layer is multipart => make a multipoint with a single point
3680  return fromMultiPointXY( QgsMultiPointXY() << asPoint() );
3681  }
3682  else
3683  {
3684  // destination is singlepart => make a single part if possible
3685  QgsMultiPointXY multiPoint = asMultiPoint();
3686  if ( multiPoint.count() == 1 )
3687  {
3688  return fromPointXY( multiPoint[0] );
3689  }
3690  }
3691  return QgsGeometry();
3692  }
3693 
3695  {
3696  // only possible if destination is multipart
3697  if ( !destMultipart )
3698  return QgsGeometry();
3699 
3700  // input geometry is multipart
3701  if ( isMultipart() )
3702  {
3703  const QgsMultiPolylineXY multiLine = asMultiPolyline();
3704  QgsMultiPointXY multiPoint;
3705  for ( const QgsPolylineXY &l : multiLine )
3706  for ( const QgsPointXY &p : l )
3707  multiPoint << p;
3708  return fromMultiPointXY( multiPoint );
3709  }
3710  // input geometry is not multipart: copy directly the line into a multipoint
3711  else
3712  {
3713  QgsPolylineXY line = asPolyline();
3714  if ( !line.isEmpty() )
3715  return fromMultiPointXY( line );
3716  }
3717  return QgsGeometry();
3718  }
3719 
3721  {
3722  // can only transform if destination is multipoint
3723  if ( !destMultipart )
3724  return QgsGeometry();
3725 
3726  // input geometry is multipart: make a multipoint from multipolygon
3727  if ( isMultipart() )
3728  {
3729  const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3730  QgsMultiPointXY multiPoint;
3731  for ( const QgsPolygonXY &poly : multiPolygon )
3732  for ( const QgsPolylineXY &line : poly )
3733  for ( const QgsPointXY &pt : line )
3734  multiPoint << pt;
3735  return fromMultiPointXY( multiPoint );
3736  }
3737  // input geometry is not multipart: make a multipoint from polygon
3738  else
3739  {
3740  const QgsPolygonXY polygon = asPolygon();
3741  QgsMultiPointXY multiPoint;
3742  for ( const QgsPolylineXY &line : polygon )
3743  for ( const QgsPointXY &pt : line )
3744  multiPoint << pt;
3745  return fromMultiPointXY( multiPoint );
3746  }
3747  }
3748 
3749  default:
3750  return QgsGeometry();
3751  }
3752 }
3753 
3754 QgsGeometry QgsGeometry::convertToLine( bool destMultipart ) const
3755 {
3756  switch ( type() )
3757  {
3759  {
3760  if ( !isMultipart() )
3761  return QgsGeometry();
3762 
3763  QgsMultiPointXY multiPoint = asMultiPoint();
3764  if ( multiPoint.count() < 2 )
3765  return QgsGeometry();
3766 
3767  if ( destMultipart )
3768  return fromMultiPolylineXY( QgsMultiPolylineXY() << multiPoint );
3769  else
3770  return fromPolylineXY( multiPoint );
3771  }
3772 
3774  {
3775  bool srcIsMultipart = isMultipart();
3776 
3777  if ( ( destMultipart && srcIsMultipart ) ||
3778  ( !destMultipart && ! srcIsMultipart ) )
3779  {
3780  // return a copy of the same geom
3781  return QgsGeometry( *this );
3782  }
3783  if ( destMultipart )
3784  {
3785  // destination is multipart => makes a multipoint with a single line
3786  QgsPolylineXY line = asPolyline();
3787  if ( !line.isEmpty() )
3788  return fromMultiPolylineXY( QgsMultiPolylineXY() << line );
3789  }
3790  else
3791  {
3792  // destination is singlepart => make a single part if possible
3793  QgsMultiPolylineXY multiLine = asMultiPolyline();
3794  if ( multiLine.count() == 1 )
3795  return fromPolylineXY( multiLine[0] );
3796  }
3797  return QgsGeometry();
3798  }
3799 
3801  {
3802  // input geometry is multipolygon
3803  if ( isMultipart() )
3804  {
3805  const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3806  QgsMultiPolylineXY multiLine;
3807  for ( const QgsPolygonXY &poly : multiPolygon )
3808  for ( const QgsPolylineXY &line : poly )
3809  multiLine << line;
3810 
3811  if ( destMultipart )
3812  {
3813  // destination is multipart
3814  return fromMultiPolylineXY( multiLine );
3815  }
3816  else if ( multiLine.count() == 1 )
3817  {
3818  // destination is singlepart => make a single part if possible
3819  return fromPolylineXY( multiLine[0] );
3820  }
3821  }
3822  // input geometry is single polygon
3823  else
3824  {
3825  QgsPolygonXY polygon = asPolygon();
3826  // if polygon has rings
3827  if ( polygon.count() > 1 )
3828  {
3829  // cannot fit a polygon with rings in a single line layer
3830  // TODO: would it be better to remove rings?
3831  if ( destMultipart )
3832  {
3833  const QgsPolygonXY polygon = asPolygon();
3834  QgsMultiPolylineXY multiLine;
3835  multiLine.reserve( polygon.count() );
3836  for ( const QgsPolylineXY &line : polygon )
3837  multiLine << line;
3838  return fromMultiPolylineXY( multiLine );
3839  }
3840  }
3841  // no rings
3842  else if ( polygon.count() == 1 )
3843  {
3844  if ( destMultipart )
3845  {
3846  return fromMultiPolylineXY( polygon );
3847  }
3848  else
3849  {
3850  return fromPolylineXY( polygon[0] );
3851  }
3852  }
3853  }
3854  return QgsGeometry();
3855  }
3856 
3857  default:
3858  return QgsGeometry();
3859  }
3860 }
3861 
3862 QgsGeometry QgsGeometry::convertToPolygon( bool destMultipart ) const
3863 {
3864  switch ( type() )
3865  {
3867  {
3868  if ( !isMultipart() )
3869  return QgsGeometry();
3870 
3871  QgsMultiPointXY multiPoint = asMultiPoint();
3872  if ( multiPoint.count() < 3 )
3873  return QgsGeometry();
3874 
3875  if ( multiPoint.last() != multiPoint.first() )
3876  multiPoint << multiPoint.first();
3877 
3878  QgsPolygonXY polygon = QgsPolygonXY() << multiPoint;
3879  if ( destMultipart )
3880  return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3881  else
3882  return fromPolygonXY( polygon );
3883  }
3884 
3886  {
3887  // input geometry is multiline
3888  if ( isMultipart() )
3889  {
3890  QgsMultiPolylineXY multiLine = asMultiPolyline();
3891  QgsMultiPolygonXY multiPolygon;
3892  for ( QgsMultiPolylineXY::iterator multiLineIt = multiLine.begin(); multiLineIt != multiLine.end(); ++multiLineIt )
3893  {
3894  // do not create polygon for a 1 segment line
3895  if ( ( *multiLineIt ).count() < 3 )
3896  return QgsGeometry();
3897  if ( ( *multiLineIt ).count() == 3 && ( *multiLineIt ).first() == ( *multiLineIt ).last() )
3898  return QgsGeometry();
3899 
3900  // add closing node
3901  if ( ( *multiLineIt ).first() != ( *multiLineIt ).last() )
3902  *multiLineIt << ( *multiLineIt ).first();
3903  multiPolygon << ( QgsPolygonXY() << *multiLineIt );
3904  }
3905  // check that polygons were inserted
3906  if ( !multiPolygon.isEmpty() )
3907  {
3908  if ( destMultipart )
3909  {
3910  return fromMultiPolygonXY( multiPolygon );
3911  }
3912  else if ( multiPolygon.count() == 1 )
3913  {
3914  // destination is singlepart => make a single part if possible
3915  return fromPolygonXY( multiPolygon[0] );
3916  }
3917  }
3918  }
3919  // input geometry is single line
3920  else
3921  {
3922  QgsPolylineXY line = asPolyline();
3923 
3924  // do not create polygon for a 1 segment line
3925  if ( line.count() < 3 )
3926  return QgsGeometry();
3927  if ( line.count() == 3 && line.first() == line.last() )
3928  return QgsGeometry();
3929 
3930  // add closing node
3931  if ( line.first() != line.last() )
3932  line << line.first();
3933 
3934  // destination is multipart
3935  if ( destMultipart )
3936  {
3937  return fromMultiPolygonXY( QgsMultiPolygonXY() << ( QgsPolygonXY() << line ) );
3938  }
3939  else
3940  {
3941  return fromPolygonXY( QgsPolygonXY() << line );
3942  }
3943  }
3944  return QgsGeometry();
3945  }
3946 
3948  {
3949  bool srcIsMultipart = isMultipart();
3950 
3951  if ( ( destMultipart && srcIsMultipart ) ||
3952  ( !destMultipart && ! srcIsMultipart ) )
3953  {
3954  // return a copy of the same geom
3955  return QgsGeometry( *this );
3956  }
3957  if ( destMultipart )
3958  {
3959  // destination is multipart => makes a multipoint with a single polygon
3960  QgsPolygonXY polygon = asPolygon();
3961  if ( !polygon.isEmpty() )
3962  return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3963  }
3964  else
3965  {
3966  QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3967  if ( multiPolygon.count() == 1 )
3968  {
3969  // destination is singlepart => make a single part if possible
3970  return fromPolygonXY( multiPolygon[0] );
3971  }
3972  }
3973  return QgsGeometry();
3974  }
3975 
3976  default:
3977  return QgsGeometry();
3978  }
3979 }
3980 
3982 {
3983  return new QgsGeos( geometry );
3984 }
3985 
3986 QDataStream &operator<<( QDataStream &out, const QgsGeometry &geometry )
3987 {
3988  out << geometry.asWkb();
3989  return out;
3990 }
3991 
3992 QDataStream &operator>>( QDataStream &in, QgsGeometry &geometry )
3993 {
3994  QByteArray byteArray;
3995  in >> byteArray;
3996  if ( byteArray.isEmpty() )
3997  {
3998  geometry.set( nullptr );
3999  return in;
4000  }
4001 
4002  geometry.fromWkb( byteArray );
4003  return in;
4004 }
4005 
4006 
4008 {
4009  return mMessage;
4010 }
4011 
4013 {
4014  return mLocation;
4015 }
4016 
4018 {
4019  return mHasLocation;
4020 }
BufferSide
Side of line to buffer.
Definition: qgis.h:713
DashPatternSizeAdjustment
Dash pattern size adjustment options.
Definition: qgis.h:1198
AngularDirection
Angular directions.
Definition: qgis.h:1247
GeometryOperationResult
Success or failure of a geometry operation.
Definition: qgis.h:661
@ 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:701
JoinStyle
Join styles for buffers.
Definition: qgis.h:738
EndCapStyle
End cap styles for buffers.
Definition: qgis.h:725
DashPatternLineEndingRule
Dash pattern line ending rules.
Definition: qgis.h:1183
TransformDirection
Indicates the direction (forward or inverse) of a transform.
Definition: qgis.h:910
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:2401
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.
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.
QVector< QgsGeometry > coerceToType(QgsWkbTypes::Type type) const
Attempts to coerce this geometry into the specified destination type.
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:548
double hausdorffDistance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const
Returns the Hausdorff distance between this geometry and geom.
Definition: qgsgeos.cpp:525
QgsAbstractGeometry * buffer(double distance, int segments, QString *errorMsg=nullptr) const override
Definition: qgsgeos.cpp:1684
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:2646
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:571
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:600
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:44
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.
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
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.
bool dropMValue() override
Drops any measure values which exist in the geometry.
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:2029
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2028
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:1533
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