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