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