QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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, double defaultZ, double defaultM ) 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( defaultZ );
1541  }
1542  if ( ! newGeom.constGet()->isMeasure() && QgsWkbTypes::hasM( type ) )
1543  {
1544  newGeom.get()->addMValue( defaultM );
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  const QgsAbstractGeometry *geom = d->geometry->simplifiedTypeRef();
2576  return 0.0;
2577 
2578  // always operate on segmentized geometries
2579  QgsGeometry segmentized = *this;
2580  if ( QgsWkbTypes::isCurvedType( geom->wkbType() ) )
2581  {
2582  segmentized = QgsGeometry( static_cast< const QgsCurve * >( geom )->segmentize() );
2583  }
2584 
2585  QgsVertexId previous;
2586  QgsVertexId next;
2587  if ( !QgsGeometryUtils::verticesAtDistance( *segmentized.constGet(), distance, previous, next ) )
2588  return 0.0;
2589 
2590  if ( previous == next )
2591  {
2592  // distance coincided exactly with a vertex
2593  QgsVertexId v2 = previous;
2594  QgsVertexId v1;
2595  QgsVertexId v3;
2596  segmentized.constGet()->adjacentVertices( v2, v1, v3 );
2597  if ( v1.isValid() && v3.isValid() )
2598  {
2599  QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
2600  QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
2601  QgsPoint p3 = segmentized.constGet()->vertexAt( v3 );
2602  double angle1 = QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2603  double angle2 = QgsGeometryUtils::lineAngle( p2.x(), p2.y(), p3.x(), p3.y() );
2604  return QgsGeometryUtils::averageAngle( angle1, angle2 );
2605  }
2606  else if ( v3.isValid() )
2607  {
2608  QgsPoint p1 = segmentized.constGet()->vertexAt( v2 );
2609  QgsPoint p2 = segmentized.constGet()->vertexAt( v3 );
2610  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2611  }
2612  else
2613  {
2614  QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
2615  QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
2616  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2617  }
2618  }
2619  else
2620  {
2621  QgsPoint p1 = segmentized.constGet()->vertexAt( previous );
2622  QgsPoint p2 = segmentized.constGet()->vertexAt( next );
2623  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2624  }
2625 }
2626 
2628 {
2629  if ( !d->geometry || geometry.isNull() )
2630  {
2631  return QgsGeometry();
2632  }
2633 
2634  QgsGeos geos( d->geometry.get() );
2635 
2636  mLastError.clear();
2637  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.intersection( geometry.d->geometry.get(), &mLastError ) );
2638 
2639  if ( !resultGeom )
2640  {
2641  QgsGeometry geom;
2642  geom.mLastError = mLastError;
2643  return geom;
2644  }
2645 
2646  return QgsGeometry( std::move( resultGeom ) );
2647 }
2648 
2650 {
2651  if ( !d->geometry || geometry.isNull() )
2652  {
2653  return QgsGeometry();
2654  }
2655 
2656  QgsGeos geos( d->geometry.get() );
2657  mLastError.clear();
2658  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.combine( geometry.d->geometry.get(), &mLastError ) );
2659  if ( !resultGeom )
2660  {
2661  QgsGeometry geom;
2662  geom.mLastError = mLastError;
2663  return geom;
2664  }
2665  return QgsGeometry( std::move( resultGeom ) );
2666 }
2667 
2669 {
2670  if ( !d->geometry )
2671  {
2672  return QgsGeometry();
2673  }
2674 
2675  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::LineString )
2676  {
2677  // special case - a single linestring was passed
2678  return QgsGeometry( *this );
2679  }
2680 
2681  QgsGeos geos( d->geometry.get() );
2682  mLastError.clear();
2683  QgsGeometry result = geos.mergeLines( &mLastError );
2684  result.mLastError = mLastError;
2685  return result;
2686 }
2687 
2689 {
2690  if ( !d->geometry || geometry.isNull() )
2691  {
2692  return QgsGeometry();
2693  }
2694 
2695  QgsGeos geos( d->geometry.get() );
2696 
2697  mLastError.clear();
2698  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.difference( geometry.d->geometry.get(), &mLastError ) );
2699  if ( !resultGeom )
2700  {
2701  QgsGeometry geom;
2702  geom.mLastError = mLastError;
2703  return geom;
2704  }
2705  return QgsGeometry( std::move( resultGeom ) );
2706 }
2707 
2709 {
2710  if ( !d->geometry || geometry.isNull() )
2711  {
2712  return QgsGeometry();
2713  }
2714 
2715  QgsGeos geos( d->geometry.get() );
2716 
2717  mLastError.clear();
2718  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.symDifference( geometry.d->geometry.get(), &mLastError ) );
2719  if ( !resultGeom )
2720  {
2721  QgsGeometry geom;
2722  geom.mLastError = mLastError;
2723  return geom;
2724  }
2725  return QgsGeometry( std::move( resultGeom ) );
2726 }
2727 
2728 QgsGeometry QgsGeometry::extrude( double x, double y )
2729 {
2730  QgsInternalGeometryEngine engine( *this );
2731 
2732  return engine.extrude( x, y );
2733 }
2734 
2736 
2737 QVector<QgsPointXY> QgsGeometry::randomPointsInPolygon( int count, const std::function< bool( const QgsPointXY & ) > &acceptPoint, unsigned long seed, QgsFeedback *feedback, int maxTriesPerPoint ) const
2738 {
2740  return QVector< QgsPointXY >();
2741 
2742  return QgsInternalGeometryEngine::randomPointsInPolygon( *this, count, acceptPoint, seed, feedback, maxTriesPerPoint );
2743 }
2744 
2745 QVector<QgsPointXY> QgsGeometry::randomPointsInPolygon( int count, unsigned long seed, QgsFeedback *feedback ) const
2746 {
2748  return QVector< QgsPointXY >();
2749 
2750  return QgsInternalGeometryEngine::randomPointsInPolygon( *this, count, []( const QgsPointXY & ) { return true; }, seed, feedback, 0 );
2751 }
2753 
2754 int QgsGeometry::wkbSize( QgsAbstractGeometry::WkbFlags flags ) const
2755 {
2756  return d->geometry ? d->geometry->wkbSize( flags ) : 0;
2757 }
2758 
2759 QByteArray QgsGeometry::asWkb( QgsAbstractGeometry::WkbFlags flags ) const
2760 {
2761  return d->geometry ? d->geometry->asWkb( flags ) : QByteArray();
2762 }
2763 
2764 QVector<QgsGeometry> QgsGeometry::asGeometryCollection() const
2765 {
2766  QVector<QgsGeometry> geometryList;
2767  if ( !d->geometry )
2768  {
2769  return geometryList;
2770  }
2771 
2772  QgsGeometryCollection *gc = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
2773  if ( gc )
2774  {
2775  int numGeom = gc->numGeometries();
2776  geometryList.reserve( numGeom );
2777  for ( int i = 0; i < numGeom; ++i )
2778  {
2779  geometryList.append( QgsGeometry( gc->geometryN( i )->clone() ) );
2780  }
2781  }
2782  else //a singlepart geometry
2783  {
2784  geometryList.append( *this );
2785  }
2786 
2787  return geometryList;
2788 }
2789 
2790 QPointF QgsGeometry::asQPointF() const
2791 {
2792  QgsPointXY point = asPoint();
2793  return point.toQPointF();
2794 }
2795 
2796 QPolygonF QgsGeometry::asQPolygonF() const
2797 {
2798  const QgsAbstractGeometry *part = constGet();
2799 
2800  // if a geometry collection, get first part only
2801  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection *>( part ) )
2802  {
2803  if ( collection->numGeometries() > 0 )
2804  part = collection->geometryN( 0 );
2805  else
2806  return QPolygonF();
2807  }
2808 
2809  if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( part ) )
2810  return curve->asQPolygonF();
2811  else if ( const QgsCurvePolygon *polygon = qgsgeometry_cast< const QgsCurvePolygon * >( part ) )
2812  return polygon->exteriorRing() ? polygon->exteriorRing()->asQPolygonF() : QPolygonF();
2813  return QPolygonF();
2814 }
2815 
2816 bool QgsGeometry::deleteRing( int ringNum, int partNum )
2817 {
2818  if ( !d->geometry )
2819  {
2820  return false;
2821  }
2822 
2823  detach();
2824  bool ok = QgsGeometryEditUtils::deleteRing( d->geometry.get(), ringNum, partNum );
2825  return ok;
2826 }
2827 
2828 bool QgsGeometry::deletePart( int partNum )
2829 {
2830  if ( !d->geometry )
2831  {
2832  return false;
2833  }
2834 
2835  if ( !isMultipart() && partNum < 1 )
2836  {
2837  set( nullptr );
2838  return true;
2839  }
2840 
2841  detach();
2842  bool ok = QgsGeometryEditUtils::deletePart( d->geometry.get(), partNum );
2843  return ok;
2844 }
2845 
2846 int QgsGeometry::avoidIntersections( const QList<QgsVectorLayer *> &avoidIntersectionsLayers, const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures )
2847 {
2848  if ( !d->geometry )
2849  {
2850  return 1;
2851  }
2852 
2853  QgsWkbTypes::Type geomTypeBeforeModification = wkbType();
2854 
2855  bool haveInvalidGeometry = false;
2856  std::unique_ptr< QgsAbstractGeometry > diffGeom = QgsGeometryEditUtils::avoidIntersections( *( d->geometry ), avoidIntersectionsLayers, haveInvalidGeometry, ignoreFeatures );
2857  if ( diffGeom )
2858  {
2859  reset( std::move( diffGeom ) );
2860  }
2861 
2862  if ( geomTypeBeforeModification != wkbType() )
2863  return 2;
2864  if ( haveInvalidGeometry )
2865  return 4;
2866 
2867  return 0;
2868 }
2869 
2870 
2872 {
2873  if ( !d->geometry )
2874  return QgsGeometry();
2875 
2876  mLastError.clear();
2877 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=8 )
2878  QgsGeos geos( d->geometry.get() );
2879  std::unique_ptr< QgsAbstractGeometry > g( geos.makeValid( &mLastError ) );
2880 #else
2881  std::unique_ptr< QgsAbstractGeometry > g( _qgis_lwgeom_make_valid( d->geometry.get(), mLastError ) );
2882 #endif
2883 
2884  QgsGeometry result = QgsGeometry( std::move( g ) );
2885  result.mLastError = mLastError;
2886  return result;
2887 }
2888 
2890 {
2891  return forcePolygonClockwise();
2892 }
2893 
2895 {
2896  if ( !d->geometry )
2897  return QgsGeometry();
2898 
2899  if ( isMultipart() )
2900  {
2901  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( d->geometry.get() );
2902  std::unique_ptr< QgsGeometryCollection > newCollection( collection->createEmptyWithSameType() );
2903  newCollection->reserve( collection->numGeometries() );
2904  for ( int i = 0; i < collection->numGeometries(); ++i )
2905  {
2906  const QgsAbstractGeometry *g = collection->geometryN( i );
2907  if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( g ) )
2908  {
2909  std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2910  corrected->forceClockwise();
2911  newCollection->addGeometry( corrected.release() );
2912  }
2913  else
2914  {
2915  newCollection->addGeometry( g->clone() );
2916  }
2917  }
2918  return QgsGeometry( std::move( newCollection ) );
2919  }
2920  else
2921  {
2922  if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( d->geometry.get() ) )
2923  {
2924  std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2925  corrected->forceClockwise();
2926  return QgsGeometry( std::move( corrected ) );
2927  }
2928  else
2929  {
2930  // not a curve polygon, so return unchanged
2931  return *this;
2932  }
2933  }
2934 }
2935 
2937 {
2938  if ( !d->geometry )
2939  return QgsGeometry();
2940 
2941  if ( isMultipart() )
2942  {
2943  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( d->geometry.get() );
2944  std::unique_ptr< QgsGeometryCollection > newCollection( collection->createEmptyWithSameType() );
2945  newCollection->reserve( collection->numGeometries() );
2946  for ( int i = 0; i < collection->numGeometries(); ++i )
2947  {
2948  const QgsAbstractGeometry *g = collection->geometryN( i );
2949  if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( g ) )
2950  {
2951  std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2952  corrected->forceCounterClockwise();
2953  newCollection->addGeometry( corrected.release() );
2954  }
2955  else
2956  {
2957  newCollection->addGeometry( g->clone() );
2958  }
2959  }
2960  return QgsGeometry( std::move( newCollection ) );
2961  }
2962  else
2963  {
2964  if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( d->geometry.get() ) )
2965  {
2966  std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2967  corrected->forceCounterClockwise();
2968  return QgsGeometry( std::move( corrected ) );
2969  }
2970  else
2971  {
2972  // not a curve polygon, so return unchanged
2973  return *this;
2974  }
2975  }
2976 }
2977 
2978 
2979 void QgsGeometry::validateGeometry( QVector<QgsGeometry::Error> &errors, const Qgis::GeometryValidationEngine method, const Qgis::GeometryValidityFlags flags ) const
2980 {
2981  errors.clear();
2982  if ( !d->geometry )
2983  return;
2984 
2985  // avoid expensive calcs for trivial point geometries
2987  {
2988  return;
2989  }
2990 
2991  switch ( method )
2992  {
2993  case Qgis::GeometryValidationEngine::QgisInternal:
2994  QgsGeometryValidator::validateGeometry( *this, errors, method );
2995  return;
2996 
2997  case Qgis::GeometryValidationEngine::Geos:
2998  {
2999  QgsGeos geos( d->geometry.get() );
3000  QString error;
3001  QgsGeometry errorLoc;
3002  if ( !geos.isValid( &error, flags & Qgis::GeometryValidityFlag::AllowSelfTouchingHoles, &errorLoc ) )
3003  {
3004  if ( errorLoc.isNull() )
3005  {
3006  errors.append( QgsGeometry::Error( error ) );
3007  }
3008  else
3009  {
3010  const QgsPointXY point = errorLoc.asPoint();
3011  errors.append( QgsGeometry::Error( error, point ) );
3012  }
3013  return;
3014  }
3015  }
3016  }
3017 }
3018 
3020 {
3021  if ( !d->geometry )
3022  {
3023  return;
3024  }
3025 
3026  detach();
3027  d->geometry->normalize();
3028 }
3029 
3030 bool QgsGeometry::isGeosValid( Qgis::GeometryValidityFlags flags ) const
3031 {
3032  if ( !d->geometry )
3033  {
3034  return false;
3035  }
3036 
3037  return d->geometry->isValid( mLastError, flags );
3038 }
3039 
3041 {
3042  if ( !d->geometry )
3043  return false;
3044 
3045  QgsGeos geos( d->geometry.get() );
3046  mLastError.clear();
3047  return geos.isSimple( &mLastError );
3048 }
3049 
3050 bool QgsGeometry::isAxisParallelRectangle( double maximumDeviation, bool simpleRectanglesOnly ) const
3051 {
3052  if ( !d->geometry )
3053  return false;
3054 
3055  QgsInternalGeometryEngine engine( *this );
3056  return engine.isAxisParallelRectangle( maximumDeviation, simpleRectanglesOnly );
3057 }
3058 
3060 {
3061  if ( !d->geometry || !g.d->geometry )
3062  {
3063  return false;
3064  }
3065 
3066  // fast check - are they shared copies of the same underlying geometry?
3067  if ( d == g.d )
3068  return true;
3069 
3070  // fast check - distinct geometry types?
3071  if ( type() != g.type() )
3072  return false;
3073 
3074  // avoid calling geos for trivial point case
3075  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::Point
3076  && QgsWkbTypes::flatType( g.d->geometry->wkbType() ) == QgsWkbTypes::Point )
3077  {
3078  return equals( g );
3079  }
3080 
3081  // another nice fast check upfront -- if the bounding boxes aren't equal, the geometries themselves can't be equal!
3082  if ( d->geometry->boundingBox() != g.d->geometry->boundingBox() )
3083  return false;
3084 
3085  QgsGeos geos( d->geometry.get() );
3086  mLastError.clear();
3087  return geos.isEqual( g.d->geometry.get(), &mLastError );
3088 }
3089 
3090 QgsGeometry QgsGeometry::unaryUnion( const QVector<QgsGeometry> &geometries )
3091 {
3092  QgsGeos geos( nullptr );
3093 
3094  QString error;
3095  std::unique_ptr< QgsAbstractGeometry > geom( geos.combine( geometries, &error ) );
3096  QgsGeometry result( std::move( geom ) );
3097  result.mLastError = error;
3098  return result;
3099 }
3100 
3101 QgsGeometry QgsGeometry::polygonize( const QVector<QgsGeometry> &geometryList )
3102 {
3103  QVector<const QgsAbstractGeometry *> geomV2List;
3104  for ( const QgsGeometry &g : geometryList )
3105  {
3106  if ( !( g.isNull() ) )
3107  {
3108  geomV2List.append( g.constGet() );
3109  }
3110  }
3111 
3112  QString error;
3113  QgsGeometry result = QgsGeos::polygonize( geomV2List, &error );
3114  result.mLastError = error;
3115  return result;
3116 }
3117 
3119 {
3121  {
3122  return;
3123  }
3124 
3125  std::unique_ptr< QgsAbstractGeometry > straightGeom( d->geometry->segmentize( tolerance, toleranceType ) );
3126  reset( std::move( straightGeom ) );
3127 }
3128 
3130 {
3131  if ( !d->geometry )
3132  {
3133  return false;
3134  }
3135 
3136  return d->geometry->hasCurvedSegments();
3137 }
3138 
3140 {
3141  if ( !d->geometry )
3142  {
3144  }
3145 
3146  detach();
3147  d->geometry->transform( ct, direction, transformZ );
3149 }
3150 
3151 Qgis::GeometryOperationResult QgsGeometry::transform( const QTransform &ct, double zTranslate, double zScale, double mTranslate, double mScale )
3152 {
3153  if ( !d->geometry )
3154  {
3156  }
3157 
3158  detach();
3159  d->geometry->transform( ct, zTranslate, zScale, mTranslate, mScale );
3161 }
3162 
3164 {
3165  if ( d->geometry )
3166  {
3167  detach();
3168  d->geometry->transform( mtp.transform() );
3169  }
3170 }
3171 
3173 {
3174  if ( !d->geometry || rectangle.isNull() || rectangle.isEmpty() )
3175  {
3176  return QgsGeometry();
3177  }
3178 
3179  QgsGeos geos( d->geometry.get() );
3180  mLastError.clear();
3181  std::unique_ptr< QgsAbstractGeometry > resultGeom = geos.clip( rectangle, &mLastError );
3182  if ( !resultGeom )
3183  {
3184  QgsGeometry result;
3185  result.mLastError = mLastError;
3186  return result;
3187  }
3188  return QgsGeometry( std::move( resultGeom ) );
3189 }
3190 
3191 void QgsGeometry::draw( QPainter &p ) const
3192 {
3193  if ( d->geometry )
3194  {
3195  d->geometry->draw( p );
3196  }
3197 }
3198 
3199 static bool vertexIndexInfo( const QgsAbstractGeometry *g, int vertexIndex, int &partIndex, int &ringIndex, int &vertex )
3200 {
3201  if ( vertexIndex < 0 )
3202  return false; // clearly something wrong
3203 
3204  if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
3205  {
3206  partIndex = 0;
3207  for ( int i = 0; i < geomCollection->numGeometries(); ++i )
3208  {
3209  const QgsAbstractGeometry *part = geomCollection->geometryN( i );
3210 
3211  // count total number of vertices in the part
3212  int numPoints = 0;
3213  for ( int k = 0; k < part->ringCount(); ++k )
3214  numPoints += part->vertexCount( 0, k );
3215 
3216  if ( vertexIndex < numPoints )
3217  {
3218  int nothing;
3219  return vertexIndexInfo( part, vertexIndex, nothing, ringIndex, vertex ); // set ring_index + index
3220  }
3221  vertexIndex -= numPoints;
3222  partIndex++;
3223  }
3224  }
3225  else if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
3226  {
3227  const QgsCurve *ring = curvePolygon->exteriorRing();
3228  if ( vertexIndex < ring->numPoints() )
3229  {
3230  partIndex = 0;
3231  ringIndex = 0;
3232  vertex = vertexIndex;
3233  return true;
3234  }
3235  vertexIndex -= ring->numPoints();
3236  ringIndex = 1;
3237  for ( int i = 0; i < curvePolygon->numInteriorRings(); ++i )
3238  {
3239  const QgsCurve *ring = curvePolygon->interiorRing( i );
3240  if ( vertexIndex < ring->numPoints() )
3241  {
3242  partIndex = 0;
3243  vertex = vertexIndex;
3244  return true;
3245  }
3246  vertexIndex -= ring->numPoints();
3247  ringIndex += 1;
3248  }
3249  }
3250  else if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
3251  {
3252  if ( vertexIndex < curve->numPoints() )
3253  {
3254  partIndex = 0;
3255  ringIndex = 0;
3256  vertex = vertexIndex;
3257  return true;
3258  }
3259  }
3260  else if ( qgsgeometry_cast<const QgsPoint *>( g ) )
3261  {
3262  if ( vertexIndex == 0 )
3263  {
3264  partIndex = 0;
3265  ringIndex = 0;
3266  vertex = 0;
3267  return true;
3268  }
3269  }
3270 
3271  return false;
3272 }
3273 
3275 {
3276  if ( !d->geometry )
3277  {
3278  return false;
3279  }
3280 
3281  id.type = Qgis::VertexType::Segment;
3282 
3283  bool res = vertexIndexInfo( d->geometry.get(), nr, id.part, id.ring, id.vertex );
3284  if ( !res )
3285  return false;
3286 
3287  // now let's find out if it is a straight or circular segment
3288  const QgsAbstractGeometry *g = d->geometry.get();
3289  if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
3290  {
3291  g = geomCollection->geometryN( id.part );
3292  }
3293 
3294  if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
3295  {
3296  g = id.ring == 0 ? curvePolygon->exteriorRing() : curvePolygon->interiorRing( id.ring - 1 );
3297  }
3298 
3299  if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
3300  {
3301  QgsPoint p;
3302  res = curve->pointAt( id.vertex, p, id.type );
3303  if ( !res )
3304  return false;
3305  }
3306 
3307  return true;
3308 }
3309 
3311 {
3312  if ( !d->geometry )
3313  {
3314  return -1;
3315  }
3316  return d->geometry->vertexNumberFromVertexId( id );
3317 }
3318 
3319 QString QgsGeometry::lastError() const
3320 {
3321  return mLastError;
3322 }
3323 
3324 void QgsGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
3325 {
3326  if ( !d->geometry )
3327  return;
3328 
3329  detach();
3330 
3331  d->geometry->filterVertices( filter );
3332 }
3333 
3334 void QgsGeometry::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
3335 {
3336  if ( !d->geometry )
3337  return;
3338 
3339  detach();
3340 
3341  d->geometry->transformVertices( transform );
3342 }
3343 
3344 void QgsGeometry::convertPointList( const QVector<QgsPointXY> &input, QgsPointSequence &output )
3345 {
3346  output.clear();
3347  for ( const QgsPointXY &p : input )
3348  {
3349  output.append( QgsPoint( p ) );
3350  }
3351 }
3352 
3353 void QgsGeometry::convertPointList( const QgsPointSequence &input, QVector<QgsPointXY> &output )
3354 {
3355  output.clear();
3356  for ( const QgsPoint &p : input )
3357  {
3358  output.append( QgsPointXY( p.x(), p.y() ) );
3359  }
3360 }
3361 
3362 void QgsGeometry::convertPolygon( const QgsPolygon &input, QgsPolygonXY &output )
3363 {
3364  output.clear();
3365 
3366  auto convertRing = []( const QgsCurve * ring ) -> QgsPolylineXY
3367  {
3368  QgsPolylineXY res;
3369  bool doSegmentation = ( QgsWkbTypes::flatType( ring->wkbType() ) == QgsWkbTypes::CompoundCurve
3371  std::unique_ptr< QgsLineString > segmentizedLine;
3372  const QgsLineString *line = nullptr;
3373  if ( doSegmentation )
3374  {
3375  segmentizedLine.reset( ring->curveToLine() );
3376  line = segmentizedLine.get();
3377  }
3378  else
3379  {
3380  line = qgsgeometry_cast<const QgsLineString *>( ring );
3381  if ( !line )
3382  {
3383  return res;
3384  }
3385  }
3386 
3387  int nVertices = line->numPoints();
3388  res.resize( nVertices );
3389  QgsPointXY *data = res.data();
3390  const double *xData = line->xData();
3391  const double *yData = line->yData();
3392  for ( int i = 0; i < nVertices; ++i )
3393  {
3394  data->setX( *xData++ );
3395  data->setY( *yData++ );
3396  data++;
3397  }
3398  return res;
3399  };
3400 
3401  if ( const QgsCurve *exterior = input.exteriorRing() )
3402  {
3403  output.push_back( convertRing( exterior ) );
3404  }
3405 
3406  const int interiorRingCount = input.numInteriorRings();
3407  output.reserve( output.size() + interiorRingCount );
3408  for ( int n = 0; n < interiorRingCount; ++n )
3409  {
3410  output.push_back( convertRing( input.interiorRing( n ) ) );
3411  }
3412 }
3413 
3415 {
3416  return QgsGeometry( std::make_unique< QgsPoint >( point.x(), point.y() ) );
3417 }
3418 
3419 QgsGeometry QgsGeometry::fromQPolygonF( const QPolygonF &polygon )
3420 {
3421  std::unique_ptr < QgsLineString > ring( QgsLineString::fromQPolygonF( polygon ) );
3422 
3423  if ( polygon.isClosed() )
3424  {
3425  std::unique_ptr< QgsPolygon > poly = std::make_unique< QgsPolygon >();
3426  poly->setExteriorRing( ring.release() );
3427  return QgsGeometry( std::move( poly ) );
3428  }
3429  else
3430  {
3431  return QgsGeometry( std::move( ring ) );
3432  }
3433 }
3434 
3436 {
3438  QgsPolygonXY result;
3439  result << createPolylineFromQPolygonF( polygon );
3440  return result;
3442 }
3443 
3445 {
3446  QgsPolylineXY result;
3447  result.reserve( polygon.count() );
3448  for ( const QPointF &p : polygon )
3449  {
3450  result.append( QgsPointXY( p ) );
3451  }
3452  return result;
3453 }
3454 
3455 bool QgsGeometry::compare( const QgsPolylineXY &p1, const QgsPolylineXY &p2, double epsilon )
3456 {
3457  if ( p1.count() != p2.count() )
3458  return false;
3459 
3460  for ( int i = 0; i < p1.count(); ++i )
3461  {
3462  if ( !p1.at( i ).compare( p2.at( i ), epsilon ) )
3463  return false;
3464  }
3465  return true;
3466 }
3467 
3468 bool QgsGeometry::compare( const QgsPolygonXY &p1, const QgsPolygonXY &p2, double epsilon )
3469 {
3470  if ( p1.count() != p2.count() )
3471  return false;
3472 
3473  for ( int i = 0; i < p1.count(); ++i )
3474  {
3475  if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
3476  return false;
3477  }
3478  return true;
3479 }
3480 
3481 
3482 bool QgsGeometry::compare( const QgsMultiPolygonXY &p1, const QgsMultiPolygonXY &p2, double epsilon )
3483 {
3484  if ( p1.count() != p2.count() )
3485  return false;
3486 
3487  for ( int i = 0; i < p1.count(); ++i )
3488  {
3489  if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
3490  return false;
3491  }
3492  return true;
3493 }
3494 
3495 QgsGeometry QgsGeometry::smooth( const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3496 {
3497  if ( !d->geometry || d->geometry->isEmpty() )
3498  return QgsGeometry();
3499 
3500  QgsGeometry geom = *this;
3502  geom = QgsGeometry( d->geometry->segmentize() );
3503 
3504  switch ( QgsWkbTypes::flatType( geom.wkbType() ) )
3505  {
3506  case QgsWkbTypes::Point:
3508  //can't smooth a point based geometry
3509  return geom;
3510 
3512  {
3513  const QgsLineString *lineString = qgsgeometry_cast< const QgsLineString * >( geom.constGet() );
3514  return QgsGeometry( smoothLine( *lineString, iterations, offset, minimumDistance, maxAngle ) );
3515  }
3516 
3518  {
3519  const QgsMultiLineString *multiLine = qgsgeometry_cast< const QgsMultiLineString * >( geom.constGet() );
3520 
3521  std::unique_ptr< QgsMultiLineString > resultMultiline = std::make_unique< QgsMultiLineString> ();
3522  resultMultiline->reserve( multiLine->numGeometries() );
3523  for ( int i = 0; i < multiLine->numGeometries(); ++i )
3524  {
3525  resultMultiline->addGeometry( smoothLine( *( multiLine->lineStringN( i ) ), iterations, offset, minimumDistance, maxAngle ).release() );
3526  }
3527  return QgsGeometry( std::move( resultMultiline ) );
3528  }
3529 
3530  case QgsWkbTypes::Polygon:
3531  {
3532  const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon * >( geom.constGet() );
3533  return QgsGeometry( smoothPolygon( *poly, iterations, offset, minimumDistance, maxAngle ) );
3534  }
3535 
3537  {
3538  const QgsMultiPolygon *multiPoly = qgsgeometry_cast< const QgsMultiPolygon * >( geom.constGet() );
3539 
3540  std::unique_ptr< QgsMultiPolygon > resultMultiPoly = std::make_unique< QgsMultiPolygon >();
3541  resultMultiPoly->reserve( multiPoly->numGeometries() );
3542  for ( int i = 0; i < multiPoly->numGeometries(); ++i )
3543  {
3544  resultMultiPoly->addGeometry( smoothPolygon( *( multiPoly->polygonN( i ) ), iterations, offset, minimumDistance, maxAngle ).release() );
3545  }
3546  return QgsGeometry( std::move( resultMultiPoly ) );
3547  }
3548 
3549  case QgsWkbTypes::Unknown:
3550  default:
3551  return QgsGeometry( *this );
3552  }
3553 }
3554 
3555 std::unique_ptr< QgsLineString > smoothCurve( const QgsLineString &line, const unsigned int iterations,
3556  const double offset, double squareDistThreshold, double maxAngleRads,
3557  bool isRing )
3558 {
3559  std::unique_ptr< QgsLineString > result = std::make_unique< QgsLineString >( line );
3560  QgsPointSequence outputLine;
3561  for ( unsigned int iteration = 0; iteration < iterations; ++iteration )
3562  {
3563  outputLine.resize( 0 );
3564  outputLine.reserve( 2 * ( result->numPoints() - 1 ) );
3565  bool skipFirst = false;
3566  bool skipLast = false;
3567  if ( isRing )
3568  {
3569  QgsPoint p1 = result->pointN( result->numPoints() - 2 );
3570  QgsPoint p2 = result->pointN( 0 );
3571  QgsPoint p3 = result->pointN( 1 );
3572  double angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3573  p3.x(), p3.y() );
3574  angle = std::fabs( M_PI - angle );
3575  skipFirst = angle > maxAngleRads;
3576  }
3577  for ( int i = 0; i < result->numPoints() - 1; i++ )
3578  {
3579  QgsPoint p1 = result->pointN( i );
3580  QgsPoint p2 = result->pointN( i + 1 );
3581 
3582  double angle = M_PI;
3583  if ( i == 0 && isRing )
3584  {
3585  QgsPoint p3 = result->pointN( result->numPoints() - 2 );
3586  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3587  p3.x(), p3.y() );
3588  }
3589  else if ( i < result->numPoints() - 2 )
3590  {
3591  QgsPoint p3 = result->pointN( i + 2 );
3592  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3593  p3.x(), p3.y() );
3594  }
3595  else if ( i == result->numPoints() - 2 && isRing )
3596  {
3597  QgsPoint p3 = result->pointN( 1 );
3598  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3599  p3.x(), p3.y() );
3600  }
3601 
3602  skipLast = angle < M_PI - maxAngleRads || angle > M_PI + maxAngleRads;
3603 
3604  // don't apply distance threshold to first or last segment
3605  if ( i == 0 || i >= result->numPoints() - 2
3606  || QgsGeometryUtils::sqrDistance2D( p1, p2 ) > squareDistThreshold )
3607  {
3608  if ( !isRing )
3609  {
3610  if ( !skipFirst )
3611  outputLine << ( i == 0 ? result->pointN( i ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset ) );
3612  if ( !skipLast )
3613  outputLine << ( i == result->numPoints() - 2 ? result->pointN( i + 1 ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset ) );
3614  else
3615  outputLine << p2;
3616  }
3617  else
3618  {
3619  // ring
3620  if ( !skipFirst )
3621  outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset );
3622  else if ( i == 0 )
3623  outputLine << p1;
3624  if ( !skipLast )
3625  outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset );
3626  else
3627  outputLine << p2;
3628  }
3629  }
3630  skipFirst = skipLast;
3631  }
3632 
3633  if ( isRing && outputLine.at( 0 ) != outputLine.at( outputLine.count() - 1 ) )
3634  outputLine << outputLine.at( 0 );
3635 
3636  result->setPoints( outputLine );
3637  }
3638  return result;
3639 }
3640 
3641 std::unique_ptr<QgsLineString> QgsGeometry::smoothLine( const QgsLineString &line, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3642 {
3643  double maxAngleRads = maxAngle * M_PI / 180.0;
3644  double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
3645  return smoothCurve( line, iterations, offset, squareDistThreshold, maxAngleRads, false );
3646 }
3647 
3648 std::unique_ptr<QgsPolygon> QgsGeometry::smoothPolygon( const QgsPolygon &polygon, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3649 {
3650  double maxAngleRads = maxAngle * M_PI / 180.0;
3651  double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
3652  std::unique_ptr< QgsPolygon > resultPoly = std::make_unique< QgsPolygon >();
3653 
3654  resultPoly->setExteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.exteriorRing() ) ), iterations, offset,
3655  squareDistThreshold, maxAngleRads, true ).release() );
3656 
3657  for ( int i = 0; i < polygon.numInteriorRings(); ++i )
3658  {
3659  resultPoly->addInteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.interiorRing( i ) ) ), iterations, offset,
3660  squareDistThreshold, maxAngleRads, true ).release() );
3661  }
3662  return resultPoly;
3663 }
3664 
3665 QgsGeometry QgsGeometry::convertToPoint( bool destMultipart ) const
3666 {
3667  switch ( type() )
3668  {
3670  {
3671  bool srcIsMultipart = isMultipart();
3672 
3673  if ( ( destMultipart && srcIsMultipart ) ||
3674  ( !destMultipart && !srcIsMultipart ) )
3675  {
3676  // return a copy of the same geom
3677  return QgsGeometry( *this );
3678  }
3679  if ( destMultipart )
3680  {
3681  // layer is multipart => make a multipoint with a single point
3682  return fromMultiPointXY( QgsMultiPointXY() << asPoint() );
3683  }
3684  else
3685  {
3686  // destination is singlepart => make a single part if possible
3687  QgsMultiPointXY multiPoint = asMultiPoint();
3688  if ( multiPoint.count() == 1 )
3689  {
3690  return fromPointXY( multiPoint[0] );
3691  }
3692  }
3693  return QgsGeometry();
3694  }
3695 
3697  {
3698  // only possible if destination is multipart
3699  if ( !destMultipart )
3700  return QgsGeometry();
3701 
3702  // input geometry is multipart
3703  if ( isMultipart() )
3704  {
3705  const QgsMultiPolylineXY multiLine = asMultiPolyline();
3706  QgsMultiPointXY multiPoint;
3707  for ( const QgsPolylineXY &l : multiLine )
3708  for ( const QgsPointXY &p : l )
3709  multiPoint << p;
3710  return fromMultiPointXY( multiPoint );
3711  }
3712  // input geometry is not multipart: copy directly the line into a multipoint
3713  else
3714  {
3715  QgsPolylineXY line = asPolyline();
3716  if ( !line.isEmpty() )
3717  return fromMultiPointXY( line );
3718  }
3719  return QgsGeometry();
3720  }
3721 
3723  {
3724  // can only transform if destination is multipoint
3725  if ( !destMultipart )
3726  return QgsGeometry();
3727 
3728  // input geometry is multipart: make a multipoint from multipolygon
3729  if ( isMultipart() )
3730  {
3731  const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3732  QgsMultiPointXY multiPoint;
3733  for ( const QgsPolygonXY &poly : multiPolygon )
3734  for ( const QgsPolylineXY &line : poly )
3735  for ( const QgsPointXY &pt : line )
3736  multiPoint << pt;
3737  return fromMultiPointXY( multiPoint );
3738  }
3739  // input geometry is not multipart: make a multipoint from polygon
3740  else
3741  {
3742  const QgsPolygonXY polygon = asPolygon();
3743  QgsMultiPointXY multiPoint;
3744  for ( const QgsPolylineXY &line : polygon )
3745  for ( const QgsPointXY &pt : line )
3746  multiPoint << pt;
3747  return fromMultiPointXY( multiPoint );
3748  }
3749  }
3750 
3751  default:
3752  return QgsGeometry();
3753  }
3754 }
3755 
3756 QgsGeometry QgsGeometry::convertToLine( bool destMultipart ) const
3757 {
3758  switch ( type() )
3759  {
3761  {
3762  if ( !isMultipart() )
3763  return QgsGeometry();
3764 
3765  QgsMultiPointXY multiPoint = asMultiPoint();
3766  if ( multiPoint.count() < 2 )
3767  return QgsGeometry();
3768 
3769  if ( destMultipart )
3770  return fromMultiPolylineXY( QgsMultiPolylineXY() << multiPoint );
3771  else
3772  return fromPolylineXY( multiPoint );
3773  }
3774 
3776  {
3777  bool srcIsMultipart = isMultipart();
3778 
3779  if ( ( destMultipart && srcIsMultipart ) ||
3780  ( !destMultipart && ! srcIsMultipart ) )
3781  {
3782  // return a copy of the same geom
3783  return QgsGeometry( *this );
3784  }
3785  if ( destMultipart )
3786  {
3787  // destination is multipart => makes a multipoint with a single line
3788  QgsPolylineXY line = asPolyline();
3789  if ( !line.isEmpty() )
3790  return fromMultiPolylineXY( QgsMultiPolylineXY() << line );
3791  }
3792  else
3793  {
3794  // destination is singlepart => make a single part if possible
3795  QgsMultiPolylineXY multiLine = asMultiPolyline();
3796  if ( multiLine.count() == 1 )
3797  return fromPolylineXY( multiLine[0] );
3798  }
3799  return QgsGeometry();
3800  }
3801 
3803  {
3804  // input geometry is multipolygon
3805  if ( isMultipart() )
3806  {
3807  const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3808  QgsMultiPolylineXY multiLine;
3809  for ( const QgsPolygonXY &poly : multiPolygon )
3810  for ( const QgsPolylineXY &line : poly )
3811  multiLine << line;
3812 
3813  if ( destMultipart )
3814  {
3815  // destination is multipart
3816  return fromMultiPolylineXY( multiLine );
3817  }
3818  else if ( multiLine.count() == 1 )
3819  {
3820  // destination is singlepart => make a single part if possible
3821  return fromPolylineXY( multiLine[0] );
3822  }
3823  }
3824  // input geometry is single polygon
3825  else
3826  {
3827  QgsPolygonXY polygon = asPolygon();
3828  // if polygon has rings
3829  if ( polygon.count() > 1 )
3830  {
3831  // cannot fit a polygon with rings in a single line layer
3832  // TODO: would it be better to remove rings?
3833  if ( destMultipart )
3834  {
3835  const QgsPolygonXY polygon = asPolygon();
3836  QgsMultiPolylineXY multiLine;
3837  multiLine.reserve( polygon.count() );
3838  for ( const QgsPolylineXY &line : polygon )
3839  multiLine << line;
3840  return fromMultiPolylineXY( multiLine );
3841  }
3842  }
3843  // no rings
3844  else if ( polygon.count() == 1 )
3845  {
3846  if ( destMultipart )
3847  {
3848  return fromMultiPolylineXY( polygon );
3849  }
3850  else
3851  {
3852  return fromPolylineXY( polygon[0] );
3853  }
3854  }
3855  }
3856  return QgsGeometry();
3857  }
3858 
3859  default:
3860  return QgsGeometry();
3861  }
3862 }
3863 
3864 QgsGeometry QgsGeometry::convertToPolygon( bool destMultipart ) const
3865 {
3866  switch ( type() )
3867  {
3869  {
3870  if ( !isMultipart() )
3871  return QgsGeometry();
3872 
3873  QgsMultiPointXY multiPoint = asMultiPoint();
3874  if ( multiPoint.count() < 3 )
3875  return QgsGeometry();
3876 
3877  if ( multiPoint.last() != multiPoint.first() )
3878  multiPoint << multiPoint.first();
3879 
3880  QgsPolygonXY polygon = QgsPolygonXY() << multiPoint;
3881  if ( destMultipart )
3882  return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3883  else
3884  return fromPolygonXY( polygon );
3885  }
3886 
3888  {
3889  // input geometry is multiline
3890  if ( isMultipart() )
3891  {
3892  QgsMultiPolylineXY multiLine = asMultiPolyline();
3893  QgsMultiPolygonXY multiPolygon;
3894  for ( QgsMultiPolylineXY::iterator multiLineIt = multiLine.begin(); multiLineIt != multiLine.end(); ++multiLineIt )
3895  {
3896  // do not create polygon for a 1 segment line
3897  if ( ( *multiLineIt ).count() < 3 )
3898  return QgsGeometry();
3899  if ( ( *multiLineIt ).count() == 3 && ( *multiLineIt ).first() == ( *multiLineIt ).last() )
3900  return QgsGeometry();
3901 
3902  // add closing node
3903  if ( ( *multiLineIt ).first() != ( *multiLineIt ).last() )
3904  *multiLineIt << ( *multiLineIt ).first();
3905  multiPolygon << ( QgsPolygonXY() << *multiLineIt );
3906  }
3907  // check that polygons were inserted
3908  if ( !multiPolygon.isEmpty() )
3909  {
3910  if ( destMultipart )
3911  {
3912  return fromMultiPolygonXY( multiPolygon );
3913  }
3914  else if ( multiPolygon.count() == 1 )
3915  {
3916  // destination is singlepart => make a single part if possible
3917  return fromPolygonXY( multiPolygon[0] );
3918  }
3919  }
3920  }
3921  // input geometry is single line
3922  else
3923  {
3924  QgsPolylineXY line = asPolyline();
3925 
3926  // do not create polygon for a 1 segment line
3927  if ( line.count() < 3 )
3928  return QgsGeometry();
3929  if ( line.count() == 3 && line.first() == line.last() )
3930  return QgsGeometry();
3931 
3932  // add closing node
3933  if ( line.first() != line.last() )
3934  line << line.first();
3935 
3936  // destination is multipart
3937  if ( destMultipart )
3938  {
3939  return fromMultiPolygonXY( QgsMultiPolygonXY() << ( QgsPolygonXY() << line ) );
3940  }
3941  else
3942  {
3943  return fromPolygonXY( QgsPolygonXY() << line );
3944  }
3945  }
3946  return QgsGeometry();
3947  }
3948 
3950  {
3951  bool srcIsMultipart = isMultipart();
3952 
3953  if ( ( destMultipart && srcIsMultipart ) ||
3954  ( !destMultipart && ! srcIsMultipart ) )
3955  {
3956  // return a copy of the same geom
3957  return QgsGeometry( *this );
3958  }
3959  if ( destMultipart )
3960  {
3961  // destination is multipart => makes a multipoint with a single polygon
3962  QgsPolygonXY polygon = asPolygon();
3963  if ( !polygon.isEmpty() )
3964  return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3965  }
3966  else
3967  {
3968  QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3969  if ( multiPolygon.count() == 1 )
3970  {
3971  // destination is singlepart => make a single part if possible
3972  return fromPolygonXY( multiPolygon[0] );
3973  }
3974  }
3975  return QgsGeometry();
3976  }
3977 
3978  default:
3979  return QgsGeometry();
3980  }
3981 }
3982 
3984 {
3985  return new QgsGeos( geometry );
3986 }
3987 
3988 QDataStream &operator<<( QDataStream &out, const QgsGeometry &geometry )
3989 {
3990  out << geometry.asWkb();
3991  return out;
3992 }
3993 
3994 QDataStream &operator>>( QDataStream &in, QgsGeometry &geometry )
3995 {
3996  QByteArray byteArray;
3997  in >> byteArray;
3998  if ( byteArray.isEmpty() )
3999  {
4000  geometry.set( nullptr );
4001  return in;
4002  }
4003 
4004  geometry.fromWkb( byteArray );
4005  return in;
4006 }
4007 
4008 
4010 {
4011  return mMessage;
4012 }
4013 
4015 {
4016  return mLocation;
4017 }
4018 
4020 {
4021  return mHasLocation;
4022 }
BufferSide
Side of line to buffer.
Definition: qgis.h:733
DashPatternSizeAdjustment
Dash pattern size adjustment options.
Definition: qgis.h:1218
AngularDirection
Angular directions.
Definition: qgis.h:1279
GeometryOperationResult
Success or failure of a geometry operation.
Definition: qgis.h:681
@ 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:721
JoinStyle
Join styles for buffers.
Definition: qgis.h:758
EndCapStyle
End cap styles for buffers.
Definition: qgis.h:745
DashPatternLineEndingRule
Dash pattern line ending rules.
Definition: qgis.h:1203
TransformDirection
Indicates the direction (forward or inverse) of a transform.
Definition: qgis.h:930
The part_iterator class provides STL-style iterator for const references to geometry parts.
The part_iterator class provides STL-style iterator for geometry parts.
The vertex_iterator class provides STL-style iterator for vertices.
Abstract base class for all geometries.
virtual int ringCount(int part=0) const =0
Returns the number of rings of which this geometry is built.
virtual bool addZValue(double zValue=0)=0
Adds a z-dimension to the geometry, initialized to a preset value.
virtual QgsAbstractGeometry * boundary() const =0
Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the...
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
virtual bool dropMValue()=0
Drops any measure values which exist in the geometry.
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
virtual int vertexCount(int part=0, int ring=0) const =0
Returns the number of vertices of which this geometry is built.
virtual QgsRectangle boundingBox() const =0
Returns the minimal bounding box for the geometry.
virtual QgsPoint vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
virtual void adjacentVertices(QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex) const =0
Returns the vertices adjacent to a specified vertex within a geometry.
virtual bool addMValue(double mValue=0)=0
Adds a measure to the geometry, initialized to a preset value.
virtual double length() const
Returns the planar, 2-dimensional length of the geometry.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
virtual bool dropZValue()=0
Drops any z-dimensions which exist in the geometry.
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
Circle geometry type.
Definition: qgscircle.h:44
double radius() const SIP_HOLDGIL
Returns the radius of the circle.
Definition: qgscircle.h:311
static QgsCircle from2Points(const QgsPoint &pt1, const QgsPoint &pt2) SIP_HOLDGIL
Constructs a circle by 2 points on the circle.
Definition: qgscircle.cpp:38
bool contains(const QgsPoint &point, double epsilon=1E-8) const
Returns true if the circle contains the point.
Definition: qgscircle.cpp:453
static QgsCircle minimalCircleFrom3Points(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double epsilon=1E-8) SIP_HOLDGIL
Constructs the smallest circle from 3 points.
Definition: qgscircle.cpp:326
QgsCircularString * toCircularString(bool oriented=false) const
Returns a circular string from the circle.
Definition: qgscircle.cpp:430
Circular string geometry type.
static QgsCircularString fromTwoPointsAndCenter(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &center, bool useShortestArc=true)
Creates a circular string with a single arc representing the curve from p1 to p2 with the specified c...
Compound curve geometry type.
bool toggleCircularAtVertex(QgsVertexId position)
Converts the vertex at the given position from/to circular.
A const WKB pointer.
Definition: qgswkbptr.h:138
Class for doing transforms between two map coordinate systems.
Curve polygon geometry type.
virtual QgsPolygon * toPolygon(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a new polygon geometry corresponding to a segmentized approximation of the curve.
virtual void setExteriorRing(QgsCurve *ring)
Sets the exterior ring of the polygon.
virtual void addInteriorRing(QgsCurve *ring)
Adds an interior ring to the geometry (takes ownership)
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
int numInteriorRings() const SIP_HOLDGIL
Returns the number of interior rings contained with the curve polygon.
bool removeInteriorRing(int ringIndex)
Removes an interior ring from the polygon.
Abstract base class for curved geometry type.
Definition: qgscurve.h:36
virtual int numPoints() const =0
Returns the number of points in the curve.
QgsCurve * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
Definition: qgscurve.cpp:175
virtual QgsPoint * interpolatePoint(double distance) const =0
Returns an interpolated point on the curve at the specified distance.
virtual QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const =0
Returns a new line string geometry corresponding to a segmentized approximation of the curve.
QgsCurve * clone() const override=0
Clones the geometry by performing a deep copy.
QgsPoint center() const SIP_HOLDGIL
Returns the center point.
Definition: qgsellipse.h:121
virtual QgsPolygon * toPolygon(unsigned int segments=36) const
Returns a segmented polygon.
Definition: qgsellipse.cpp:224
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:45
Geometry collection.
virtual bool insertGeometry(QgsAbstractGeometry *g, int index)
Inserts a geometry before a specified index and takes ownership.
int numGeometries() const SIP_HOLDGIL
Returns the number of geometries within the collection.
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
virtual bool removeGeometry(int nr)
Removes a geometry from the collection.
QgsGeometryCollection * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
virtual bool addGeometry(QgsAbstractGeometry *g)
Adds a geometry and takes ownership. Returns true in case of success.
int partCount() const override
Returns count of parts contained in the geometry.
Java-style iterator for const traversal of parts of a geometry.
static Qgis::GeometryOperationResult addRing(QgsAbstractGeometry *geometry, std::unique_ptr< QgsCurve > ring)
Add an interior ring to a geometry.
static std::unique_ptr< QgsAbstractGeometry > avoidIntersections(const QgsAbstractGeometry &geom, const QList< QgsVectorLayer * > &avoidIntersectionsLayers, bool &haveInvalidGeometry, const QHash< QgsVectorLayer *, QSet< QgsFeatureId > > &ignoreFeatures=(QHash< QgsVectorLayer *, QSet< QgsFeatureId > >()))
Alters a geometry so that it avoids intersections with features from all open vector layers.
static bool deletePart(QgsAbstractGeometry *geom, int partNum)
Deletes a part from a geometry.
static bool deleteRing(QgsAbstractGeometry *geom, int ringNum, int partNum=0)
Deletes a ring from a geometry.
static Qgis::GeometryOperationResult addPart(QgsAbstractGeometry *geometry, std::unique_ptr< QgsAbstractGeometry > part)
Add a part to multi type geometry.
A geometry engine is a low-level representation of a QgsAbstractGeometry object, optimised for use wi...
EngineOperationResult
Success or failure of a geometry operation.
@ NothingHappened
Nothing happened, without any error.
@ InvalidBaseGeometry
The geometry on which the operation occurs is not valid.
@ InvalidInput
The input is not valid.
@ NodedGeometryError
Error occurred while creating a noded geometry.
@ EngineError
Error occurred in the geometry engine.
@ SplitCannotSplitPoint
Points cannot be split.
@ Success
Operation succeeded.
@ MethodNotImplemented
Method not implemented in geometry engine.
static std::unique_ptr< QgsMultiPolygon > fromMultiPolygonXY(const QgsMultiPolygonXY &multipoly)
Construct geometry from a multipolygon.
static std::unique_ptr< QgsAbstractGeometry > geomFromWkb(QgsConstWkbPtr &wkb)
Construct geometry from a WKB string.
static std::unique_ptr< QgsAbstractGeometry > fromPolylineXY(const QgsPolylineXY &polyline)
Construct geometry from a polyline.
static std::unique_ptr< QgsMultiPoint > fromMultiPointXY(const QgsMultiPointXY &multipoint)
Construct geometry from a multipoint.
static std::unique_ptr< QgsAbstractGeometry > geomFromWkt(const QString &text)
Construct geometry from a WKT string.
static std::unique_ptr< QgsAbstractGeometry > geomFromWkbType(QgsWkbTypes::Type t)
Returns empty geometry from wkb type.
static std::unique_ptr< QgsMultiLineString > fromMultiPolylineXY(const QgsMultiPolylineXY &multiline)
Construct geometry from a multipolyline.
static std::unique_ptr< QgsGeometryCollection > createCollectionOfType(QgsWkbTypes::Type type)
Returns a new geometry collection matching a specified WKB type.
static std::unique_ptr< QgsAbstractGeometry > fromPointXY(const QgsPointXY &point)
Construct geometry from a point.
static std::unique_ptr< QgsPolygon > fromPolygonXY(const QgsPolygonXY &polygon)
Construct geometry from a polygon.
Java-style iterator for traversal of parts of a geometry.
static double sqrDistance2D(const QgsPoint &pt1, const QgsPoint &pt2) SIP_HOLDGIL
Returns the squared 2D distance between two points.
static bool verticesAtDistance(const QgsAbstractGeometry &geometry, double distance, QgsVertexId &previousVertex, QgsVertexId &nextVertex)
Retrieves the vertices which are before and after the interpolated point at a specified distance alon...
static double distanceToVertex(const QgsAbstractGeometry &geom, QgsVertexId id)
Returns the distance along a geometry from its first vertex to the specified vertex.
static double averageAngle(double x1, double y1, double x2, double y2, double x3, double y3) SIP_HOLDGIL
Calculates the average angle (in radians) between the two linear segments from (x1,...
static double lineAngle(double x1, double y1, double x2, double y2) SIP_HOLDGIL
Calculates the direction of line joining two points in radians, clockwise from the north direction.
static double angleBetweenThreePoints(double x1, double y1, double x2, double y2, double x3, double y3) SIP_HOLDGIL
Calculates the angle between the lines AB and BC, where AB and BC described by points a,...
static QgsPoint closestVertex(const QgsAbstractGeometry &geom, const QgsPoint &pt, QgsVertexId &id)
Returns the closest vertex to a geometry for a specified point.
static QgsPointXY interpolatePointOnLine(double x1, double y1, double x2, double y2, double fraction) SIP_HOLDGIL
Interpolates the position of a point a fraction of the way along the line from (x1,...
static void validateGeometry(const QgsGeometry &geometry, QVector< QgsGeometry::Error > &errors, Qgis::GeometryValidationEngine method=Qgis::GeometryValidationEngine::QgisInternal)
Validate geometry and produce a list of geometry errors.
A geometry error.
Definition: qgsgeometry.h:2405
bool hasWhere() const
true if the location available from
QgsPointXY where() const
The coordinates at which the error is located and should be visualized.
QString what() const
A human readable error message containing details about the error.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:125
QgsGeometry() SIP_HOLDGIL
Constructor.
Definition: qgsgeometry.cpp:66
bool deleteRing(int ringNum, int partNum=0)
Deletes a ring in polygon or multipolygon.
QVector< QgsPointXY > randomPointsInPolygon(int count, const std::function< bool(const QgsPointXY &) > &acceptPoint, unsigned long seed=0, QgsFeedback *feedback=nullptr, int maxTriesPerPoint=0) const
Returns a list of count random points generated inside a (multi)polygon geometry (if acceptPoint is s...
double hausdorffDistanceDensify(const QgsGeometry &geom, double densifyFraction) const
Returns the Hausdorff distance between this geometry and geom.
QgsGeometry densifyByCount(int extraNodesPerSegment) const
Returns a copy of the geometry which has been densified by adding the specified number of extra nodes...
QgsGeometry clipped(const QgsRectangle &rectangle)
Clips the geometry using the specified rectangle.
double lineLocatePoint(const QgsGeometry &point) const
Returns a distance representing the location along this linestring of the closest point on this lines...
int makeDifferenceInPlace(const QgsGeometry &other)
Changes this geometry such that it does not intersect the other geometry.
QVector< QgsGeometry > coerceToType(QgsWkbTypes::Type type, double defaultZ=0, double defaultM=0) const
Attempts to coerce this geometry into the specified destination type.
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
void adjacentVertices(int atVertex, int &beforeVertex, int &afterVertex) const
Returns the indexes of the vertices before and after the given vertex index.
QgsMultiPolygonXY asMultiPolygon() const
Returns the contents of the geometry as a multi-polygon.
bool deleteVertex(int atVertex)
Deletes the vertex at the given position number and item (first number is index 0)
double length() const
Returns the planar, 2-dimensional length of geometry.
QgsGeometry offsetCurve(double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit) const
Returns an offset line at a given distance and side from an input line.
static bool compare(const QgsPolylineXY &p1, const QgsPolylineXY &p2, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compares two polylines for equality within a specified tolerance.
QgsVertexIterator vertices() const
Returns a read-only, Java-style iterator for traversal of vertices of all the geometry,...
QgsGeometry densifyByDistance(double distance) const
Densifies the geometry by adding regularly placed extra nodes inside each segment so that the maximum...
QgsGeometry poleOfInaccessibility(double precision, double *distanceToBoundary=nullptr) const
Calculates the approximate pole of inaccessibility for a surface, which is the most distant internal ...
QgsGeometry largestEmptyCircle(double tolerance, const QgsGeometry &boundary=QgsGeometry()) const SIP_THROW(QgsNotSupportedException)
Constructs the Largest Empty Circle for a set of obstacle geometries, up to a specified tolerance.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
QgsAbstractGeometry::const_part_iterator const_parts_begin() const
Returns STL-style const iterator pointing to the first part of the geometry.
QgsGeometry difference(const QgsGeometry &geometry) const
Returns a geometry representing the points making up this geometry that do not make up other.
QgsGeometry squareWaves(double wavelength, double amplitude, bool strictWavelength=false) const
Constructs square waves along the boundary of the geometry, with the specified wavelength and amplitu...
static QgsGeometry polygonize(const QVector< QgsGeometry > &geometries)
Creates a GeometryCollection geometry containing possible polygons formed from the constituent linewo...
QgsGeometry triangularWaves(double wavelength, double amplitude, bool strictWavelength=false) const
Constructs triangular waves along the boundary of the geometry, with the specified wavelength and amp...
bool boundingBoxIntersects(const QgsRectangle &rectangle) const
Returns true if the bounding box of this geometry intersects with a rectangle.
bool vertexIdFromVertexNr(int number, QgsVertexId &id) const
Calculates the vertex ID from a vertex number.
QgsGeometry pointOnSurface() const
Returns a point guaranteed to lie on the surface of a geometry.
bool touches(const QgsGeometry &geometry) const
Returns true if the geometry touches another geometry.
static QgsGeometry fromQPointF(QPointF point) SIP_HOLDGIL
Construct geometry from a QPointF.
void transformVertices(const std::function< QgsPoint(const QgsPoint &) > &transform)
Transforms the vertices from the geometry in place, applying the transform function to every vertex.
QgsGeometry applyDashPattern(const QVector< double > &pattern, Qgis::DashPatternLineEndingRule startRule=Qgis::DashPatternLineEndingRule::NoRule, Qgis::DashPatternLineEndingRule endRule=Qgis::DashPatternLineEndingRule::NoRule, Qgis::DashPatternSizeAdjustment adjustment=Qgis::DashPatternSizeAdjustment::ScaleBothDashAndGap, double patternOffset=0) const
Applies a dash pattern to a geometry, returning a MultiLineString geometry which is the input geometr...
QgsGeometry roundWaves(double wavelength, double amplitude, bool strictWavelength=false) const
Constructs rounded (sine-like) waves along the boundary of the geometry, with the specified wavelengt...
QgsGeometry nearestPoint(const QgsGeometry &other) const
Returns the nearest (closest) point on this geometry to another geometry.
QgsGeometry makeDifference(const QgsGeometry &other) const
Returns the geometry formed by modifying this geometry such that it does not intersect the other geom...
static QgsGeometry collectGeometry(const QVector< QgsGeometry > &geometries)
Creates a new multipart geometry from a list of QgsGeometry objects.
static QgsGeometry fromMultiPolylineXY(const QgsMultiPolylineXY &multiline)
Creates a new geometry from a QgsMultiPolylineXY object.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
bool isAxisParallelRectangle(double maximumDeviation, bool simpleRectanglesOnly=false) const
Returns true if the geometry is a polygon that is almost an axis-parallel rectangle.
static QgsGeometry fromQPolygonF(const QPolygonF &polygon)
Construct geometry from a QPolygonF.
static QgsGeometry unaryUnion(const QVector< QgsGeometry > &geometries)
Compute the unary union on a list of geometries.
QgsGeometry variableWidthBufferByM(int segments) const
Calculates a variable width buffer for a (multi)linestring geometry, where the width at each node is ...
static QgsGeometry fromPolylineXY(const QgsPolylineXY &polyline)
Creates a new LineString geometry from a list of QgsPointXY points.
QgsMultiPointXY asMultiPoint() const
Returns the contents of the geometry as a multi-point.
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
QgsPointXY closestVertex(const QgsPointXY &point, int &closestVertexIndex, int &previousVertexIndex, int &nextVertexIndex, double &sqrDist) const
Returns the vertex closest to the given point, the corresponding vertex index, squared distance snap ...
Qgis::GeometryOperationResult addPart(const QVector< QgsPointXY > &points, QgsWkbTypes::GeometryType geomType=QgsWkbTypes::UnknownGeometry)
Adds a new part to a the geometry.
void normalize()
Reorganizes the geometry into a normalized form (or "canonical" form).
int wkbSize(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const
Returns the length of the QByteArray returned by asWkb()
QgsGeometry minimumWidth() const SIP_THROW(QgsNotSupportedException)
Returns a linestring geometry which represents the minimum diameter of the geometry.
QgsPolygonXY asPolygon() const
Returns the contents of the geometry as a polygon.
bool disjoint(const QgsGeometry &geometry) const
Returns true if the geometry is disjoint of another geometry.
QgsGeometry combine(const QgsGeometry &geometry) const
Returns a geometry representing all the points in this geometry and other (a union geometry operation...
QVector< QgsGeometry > asGeometryCollection() const
Returns contents of the geometry as a list of geometries.
QgsGeometry roundWavesRandomized(double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed=0) const
Constructs randomized rounded (sine-like) waves along the boundary of the geometry,...
double distance(const QgsGeometry &geom) const
Returns the minimum distance between this geometry and another geometry.
QgsGeometry interpolate(double distance) const
Returns an interpolated point on the geometry at the specified distance.
QgsGeometry extrude(double x, double y)
Returns an extruded version of this geometry.
static Q_DECL_DEPRECATED QgsPolylineXY createPolylineFromQPolygonF(const QPolygonF &polygon)
Creates a QgsPolylineXY from a QPolygonF.
Q_GADGET bool isNull
Definition: qgsgeometry.h:127
void mapToPixel(const QgsMapToPixel &mtp)
Transforms the geometry from map units to pixels in place.
static QgsGeometry fromMultiPointXY(const QgsMultiPointXY &multipoint)
Creates a new geometry from a QgsMultiPointXY object.
QgsGeometry singleSidedBuffer(double distance, int segments, Qgis::BufferSide side, Qgis::JoinStyle joinStyle=Qgis::JoinStyle::Round, double miterLimit=2.0) const
Returns a single sided buffer for a (multi)line geometry.
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
double minimumClearance() const SIP_THROW(QgsNotSupportedException)
Computes the minimum clearance of a geometry.
double sqrDistToVertexAt(QgsPointXY &point SIP_IN, int atVertex) const
Returns the squared Cartesian distance between the given point to the given vertex index (vertex at t...
bool isMultipart() const SIP_HOLDGIL
Returns true if WKB of the geometry is of WKBMulti* type.
QgsGeometry intersection(const QgsGeometry &geometry) const
Returns a geometry representing the points shared by this geometry and other.
bool contains(const QgsPointXY *p) const
Returns true if the geometry contains the point p.
QgsGeometry convertToType(QgsWkbTypes::GeometryType destType, bool destMultipart=false) const
Try to convert the geometry to the requested type.
QgsPolylineXY asPolyline() const
Returns the contents of the geometry as a polyline.
QgsAbstractGeometry::part_iterator parts_begin()
Returns STL-style iterator pointing to the first part of the geometry.
QgsGeometry forceRHR() const
Forces geometries to respect the Right-Hand-Rule, in which the area that is bounded by a polygon is t...
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
QgsGeometry snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0) const
Returns a new geometry with all points or vertices snapped to the closest point of the grid.
QgsGeometry minimumClearanceLine() const SIP_THROW(QgsNotSupportedException)
Returns a LineString whose endpoints define the minimum clearance of a geometry.
virtual json asJsonObject(int precision=17) const
Exports the geometry to a json object.
void filterVertices(const std::function< bool(const QgsPoint &) > &filter)
Filters the vertices from the geometry in place, removing any which do not return true for the filter...
bool equals(const QgsGeometry &geometry) const
Test if this geometry is exactly equal to another geometry.
bool isGeosValid(Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const
Checks validity of the geometry using GEOS.
bool insertVertex(double x, double y, int beforeVertex)
Insert a new vertex before the given vertex index, ring and item (first number is index 0) If the req...
static Q_DECL_DEPRECATED QgsPolygonXY createPolygonFromQPolygonF(const QPolygonF &polygon)
Creates a QgsPolygonXYfrom a QPolygonF.
bool convertToSingleType()
Converts multi type geometry into single type geometry e.g.
Qgis::GeometryOperationResult addRing(const QVector< QgsPointXY > &ring)
Adds a new ring to this geometry.
QPointF asQPointF() const SIP_HOLDGIL
Returns contents of the geometry as a QPointF if wkbType is WKBPoint, otherwise returns a null QPoint...
static QgsGeometry fromPointXY(const QgsPointXY &point) SIP_HOLDGIL
Creates a new geometry from a QgsPointXY object.
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:128
bool requiresConversionToStraightSegments() const
Returns true if the geometry is a curved geometry type which requires conversion to display as straig...
bool isSimple() const
Determines whether the geometry is simple (according to OGC definition), i.e.
static QgsGeometry fromPolyline(const QgsPolyline &polyline)
Creates a new LineString geometry from a list of QgsPoint points.
void validateGeometry(QVector< QgsGeometry::Error > &errors, Qgis::GeometryValidationEngine method=Qgis::GeometryValidationEngine::QgisInternal, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const
Validates geometry and produces a list of geometry errors.
QgsMultiPolylineXY asMultiPolyline() const
Returns the contents of the geometry as a multi-linestring.
QgsGeometry taperedBuffer(double startWidth, double endWidth, int segments) const
Calculates a variable width buffer ("tapered buffer") for a (multi)curve geometry.
bool within(const QgsGeometry &geometry) const
Returns true if the geometry is completely within another geometry.
double frechetDistanceDensify(const QgsGeometry &geom, double densifyFraction) const SIP_THROW(QgsNotSupportedException)
Returns the Fréchet distance between this geometry and geom, restricted to discrete points for both g...
void convertToStraightSegment(double tolerance=M_PI/180., QgsAbstractGeometry::SegmentationToleranceType toleranceType=QgsAbstractGeometry::MaximumAngle)
Converts the geometry to straight line segments, if it is a curved geometry type.
double area() const
Returns the planar, 2-dimensional area of the geometry.
QgsGeometry centroid() const
Returns the center of mass of a geometry.
bool crosses(const QgsGeometry &geometry) const
Returns true if the geometry crosses another geometry.
QgsGeometry & operator=(QgsGeometry const &rhs)
Creates a deep copy of the object.
Definition: qgsgeometry.cpp:98
QgsGeometry orthogonalize(double tolerance=1.0E-8, int maxIterations=1000, double angleThreshold=15.0) const
Attempts to orthogonalize a line or polygon geometry by shifting vertices to make the geometries angl...
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine representing the specified geometry.
QgsGeometry makeValid() const
Attempts to make an invalid geometry valid without losing vertices.
double hausdorffDistance(const QgsGeometry &geom) const
Returns the Hausdorff distance between this geometry and geom.
QString lastError() const SIP_HOLDGIL
Returns an error string referring to the last error encountered either when this geometry was created...
QgsGeometryPartIterator parts()
Returns Java-style iterator for traversal of parts of the geometry.
QPolygonF asQPolygonF() const SIP_HOLDGIL
Returns contents of the geometry as a QPolygonF.
QgsGeometry convertToCurves(double distanceTolerance=1e-8, double angleTolerance=1e-8) const
Attempts to convert a non-curved geometry into a curved geometry type (e.g.
QgsGeometry voronoiDiagram(const QgsGeometry &extent=QgsGeometry(), double tolerance=0.0, bool edgesOnly=false) const
Creates a Voronoi diagram for the nodes contained within the geometry.
void set(QgsAbstractGeometry *geometry)
Sets the underlying geometry store.
QgsGeometry convexHull() const
Returns the smallest convex polygon that contains all the points in the geometry.
QgsGeometry sharedPaths(const QgsGeometry &other) const
Find paths shared between the two given lineal geometries (this and other).
virtual ~QgsGeometry()
Definition: qgsgeometry.cpp:71
static QgsGeometry fromPolygonXY(const QgsPolygonXY &polygon)
Creates a new geometry from a QgsPolygonXY.
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer's length.
QgsGeometry minimalEnclosingCircle(QgsPointXY &center, double &radius, unsigned int segments=36) const
Returns the minimal enclosing circle for the geometry.
QgsGeometry mergeLines() const
Merges any connected lines in a LineString/MultiLineString geometry and converts them to single line ...
static QgsGeometry fromMultiPolygonXY(const QgsMultiPolygonXY &multipoly)
Creates a new geometry from a QgsMultiPolygonXY.
QgsGeometry buffer(double distance, int segments) const
Returns a buffer region around this geometry having the given width and with a specified number of se...
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
QgsGeometry symDifference(const QgsGeometry &geometry) const
Returns a geometry representing the points making up this geometry that do not make up other.
QgsGeometry node() const
Returns a (Multi)LineString representing the fully noded version of a collection of linestrings.
double distanceToVertex(int vertex) const
Returns the distance along this geometry from its first vertex to the specified vertex.
int vertexNrFromVertexId(QgsVertexId id) const
Returns the vertex number corresponding to a vertex id.
QgsAbstractGeometry::const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry.
bool removeDuplicateNodes(double epsilon=4 *std::numeric_limits< double >::epsilon(), bool useZValues=false)
Removes duplicate nodes from the geometry, wherever removing the nodes does not result in a degenerat...
QgsAbstractGeometry::part_iterator parts_end()
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry.
QgsAbstractGeometry::vertex_iterator vertices_begin() const
Returns STL-style iterator pointing to the first vertex of the geometry.
QgsGeometry forcePolygonClockwise() const
Forces geometries to respect the exterior ring is clockwise, interior rings are counter-clockwise con...
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
QString asJson(int precision=17) const
Exports the geometry to a GeoJSON string.
static QgsGeometry createWedgeBuffer(const QgsPoint &center, double azimuth, double angularWidth, double outerRadius, double innerRadius=0)
Creates a wedge shaped buffer from a center point.
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const
Export the geometry to WKB.
QgsGeometry extendLine(double startDistance, double endDistance) const
Extends a (multi)line geometry by extrapolating out the start or end of the line by a specified dista...
static void convertPointList(const QVector< QgsPointXY > &input, QgsPointSequence &output)
Upgrades a point list from QgsPointXY to QgsPoint.
QgsGeometry orientedMinimumBoundingBox() const
Returns the oriented minimum bounding box for the geometry, which is the smallest (by area) rotated r...
QgsGeometry triangularWavesRandomized(double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed=0) const
Constructs randomized triangular waves along the boundary of the geometry, with the specified wavelen...
QgsGeometry squareWavesRandomized(double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed=0) const
Constructs randomized square waves along the boundary of the geometry, with the specified wavelength ...
QgsGeometryConstPartIterator constParts() const
Returns Java-style iterator for traversal of parts of the geometry.
QgsGeometry simplify(double tolerance) const
Returns a simplified version of this geometry using a specified tolerance value.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Qgis::GeometryOperationResult rotate(double rotation, const QgsPointXY &center)
Rotate this geometry around the Z axis.
Qgis::GeometryOperationResult translate(double dx, double dy, double dz=0.0, double dm=0.0)
Translates this geometry by dx, dy, dz and dm.
double interpolateAngle(double distance) const
Returns the angle parallel to the linestring or polygon boundary at the specified distance along the ...
double angleAtVertex(int vertex) const
Returns the bisector angle for this geometry at the specified vertex.
Qgis::GeometryOperationResult reshapeGeometry(const QgsLineString &reshapeLineString)
Replaces a part of this geometry with another line.
double closestVertexWithContext(const QgsPointXY &point, int &atVertex) const
Searches for the closest vertex in this geometry to the given point.
QgsGeometry delaunayTriangulation(double tolerance=0.0, bool edgesOnly=false) const
Returns the Delaunay triangulation for the vertices of the geometry.
void draw(QPainter &p) const
Draws the geometry onto a QPainter.
bool convertGeometryCollectionToSubclass(QgsWkbTypes::GeometryType geomType)
Converts geometry collection to a the desired geometry type subclass (multi-point,...
double frechetDistance(const QgsGeometry &geom) const SIP_THROW(QgsNotSupportedException)
Returns the Fréchet distance between this geometry and geom, restricted to discrete points for both g...
QgsGeometry smooth(unsigned int iterations=1, double offset=0.25, double minimumDistance=-1.0, double maxAngle=180.0) const
Smooths a geometry by rounding off corners using the Chaikin algorithm.
QgsGeometry forcePolygonCounterClockwise() const
Forces geometries to respect the exterior ring is counter-clockwise, interior rings are clockwise con...
QString asWkt(int precision=17) const
Exports the geometry to WKT.
Q_DECL_DEPRECATED Qgis::GeometryOperationResult splitGeometry(const QVector< QgsPointXY > &splitLine, QVector< QgsGeometry > &newGeometries, bool topological, QVector< QgsPointXY > &topologyTestPoints, bool splitFeature=true)
Splits this geometry according to a given line.
bool toggleCircularAtVertex(int atVertex)
Converts the vertex at the given position from/to circular.
bool moveVertex(double x, double y, int atVertex)
Moves the vertex at the given position number and item (first number is index 0) to the given coordin...
bool isGeosEqual(const QgsGeometry &) const
Compares the geometry with another geometry using GEOS.
double closestSegmentWithContext(const QgsPointXY &point, QgsPointXY &minDistPoint, int &nextVertexIndex, int *leftOrRightOfSegment=nullptr, double epsilon=DEFAULT_SEGMENT_EPSILON) const
Searches for the closest segment of geometry to the given point.
QgsGeometry subdivide(int maxNodes=256) const
Subdivides the geometry.
bool intersects(const QgsRectangle &rectangle) const
Returns true if this geometry exactly intersects with a rectangle.
QgsAbstractGeometry::vertex_iterator vertices_end() const
Returns STL-style iterator pointing to the imaginary vertex after the last vertex of the geometry.
bool deletePart(int partNum)
Deletes part identified by the part number.
QgsGeometry removeInteriorRings(double minimumAllowedArea=-1) const
Removes the interior rings from a (multi)polygon geometry.
bool overlaps(const QgsGeometry &geometry) const
Returns true if the geometry overlaps another geometry.
int avoidIntersections(const QList< QgsVectorLayer * > &avoidIntersectionsLayers, const QHash< QgsVectorLayer *, QSet< QgsFeatureId > > &ignoreFeatures=(QHash< QgsVectorLayer *, QSet< QgsFeatureId > >()))
Modifies geometry to avoid intersections with the layers specified in project properties.
QgsGeometry shortestLine(const QgsGeometry &other) const
Returns the shortest line joining this geometry to another geometry.
Does vector analysis using the geos library and handles import, export, exception handling*.
Definition: qgsgeos.h:104
double hausdorffDistanceDensify(const QgsAbstractGeometry *geom, double densifyFraction, QString *errorMsg=nullptr) const
Returns the Hausdorff distance between this geometry and geom.
Definition: qgsgeos.cpp: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:2065
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2064
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:1578
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