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