QGIS API Documentation  3.1.0-Master (f35745f)
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  for ( const QgsGeometry &part : parts )
1662  {
1663  QgsGeometry result = part.offsetCurve( distance, segments, joinStyle, miterLimit );
1664  if ( result )
1665  results << result;
1666  }
1667  if ( results.isEmpty() )
1668  return QgsGeometry();
1669 
1670  QgsGeometry first = results.takeAt( 0 );
1671  for ( const QgsGeometry &result : qgis::as_const( results ) )
1672  {
1673  first.addPart( result );
1674  }
1675  return first;
1676  }
1677  else
1678  {
1679  QgsGeos geos( d->geometry.get() );
1680  mLastError.clear();
1681  QgsAbstractGeometry *offsetGeom = geos.offsetCurve( distance, segments, joinStyle, miterLimit, &mLastError );
1682  if ( !offsetGeom )
1683  {
1684  QgsGeometry result;
1685  result.mLastError = mLastError;
1686  return result;
1687  }
1688  return QgsGeometry( offsetGeom );
1689  }
1690 }
1691 
1692 QgsGeometry QgsGeometry::singleSidedBuffer( double distance, int segments, BufferSide side, JoinStyle joinStyle, double miterLimit ) const
1693 {
1694  if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
1695  {
1696  return QgsGeometry();
1697  }
1698 
1699  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
1700  {
1701  const QVector<QgsGeometry> parts = asGeometryCollection();
1702  QVector<QgsGeometry> results;
1703  for ( const QgsGeometry &part : parts )
1704  {
1705  QgsGeometry result = part.singleSidedBuffer( distance, segments, side, joinStyle, miterLimit );
1706  if ( result )
1707  results << result;
1708  }
1709  if ( results.isEmpty() )
1710  return QgsGeometry();
1711 
1712  QgsGeometry first = results.takeAt( 0 );
1713  for ( const QgsGeometry &result : qgis::as_const( results ) )
1714  {
1715  first.addPart( result );
1716  }
1717  return first;
1718  }
1719  else
1720  {
1721  QgsGeos geos( d->geometry.get() );
1722  mLastError.clear();
1723  std::unique_ptr< QgsAbstractGeometry > bufferGeom = geos.singleSidedBuffer( distance, segments, side,
1724  joinStyle, miterLimit, &mLastError );
1725  if ( !bufferGeom )
1726  {
1727  QgsGeometry result;
1728  result.mLastError = mLastError;
1729  return result;
1730  }
1731  return QgsGeometry( std::move( bufferGeom ) );
1732  }
1733 }
1734 
1735 QgsGeometry QgsGeometry::extendLine( double startDistance, double endDistance ) const
1736 {
1737  if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
1738  {
1739  return QgsGeometry();
1740  }
1741 
1742  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
1743  {
1744  const QVector<QgsGeometry> parts = asGeometryCollection();
1745  QVector<QgsGeometry> results;
1746  for ( const QgsGeometry &part : parts )
1747  {
1748  QgsGeometry result = part.extendLine( startDistance, endDistance );
1749  if ( result )
1750  results << result;
1751  }
1752  if ( results.isEmpty() )
1753  return QgsGeometry();
1754 
1755  QgsGeometry first = results.takeAt( 0 );
1756  for ( const QgsGeometry &result : qgis::as_const( results ) )
1757  {
1758  first.addPart( result );
1759  }
1760  return first;
1761  }
1762  else
1763  {
1764  QgsLineString *line = qgsgeometry_cast< QgsLineString * >( d->geometry.get() );
1765  if ( !line )
1766  return QgsGeometry();
1767 
1768  std::unique_ptr< QgsLineString > newLine( line->clone() );
1769  newLine->extend( startDistance, endDistance );
1770  return QgsGeometry( std::move( newLine ) );
1771  }
1772 }
1773 
1774 QgsGeometry QgsGeometry::simplify( double tolerance ) const
1775 {
1776  if ( !d->geometry )
1777  {
1778  return QgsGeometry();
1779  }
1780 
1781  QgsGeos geos( d->geometry.get() );
1782  mLastError.clear();
1783  std::unique_ptr< QgsAbstractGeometry > simplifiedGeom( geos.simplify( tolerance, &mLastError ) );
1784  if ( !simplifiedGeom )
1785  {
1786  QgsGeometry result;
1787  result.mLastError = mLastError;
1788  return result;
1789  }
1790  return QgsGeometry( std::move( simplifiedGeom ) );
1791 }
1792 
1793 QgsGeometry QgsGeometry::densifyByCount( int extraNodesPerSegment ) const
1794 {
1795  QgsInternalGeometryEngine engine( *this );
1796 
1797  return engine.densifyByCount( extraNodesPerSegment );
1798 }
1799 
1801 {
1802  QgsInternalGeometryEngine engine( *this );
1803 
1804  return engine.densifyByDistance( distance );
1805 }
1806 
1808 {
1809  if ( !d->geometry )
1810  {
1811  return QgsGeometry();
1812  }
1813 
1814  QgsGeos geos( d->geometry.get() );
1815 
1816  mLastError.clear();
1817  QgsGeometry result( geos.centroid( &mLastError ) );
1818  result.mLastError = mLastError;
1819  return result;
1820 }
1821 
1823 {
1824  if ( !d->geometry )
1825  {
1826  return QgsGeometry();
1827  }
1828 
1829  QgsGeos geos( d->geometry.get() );
1830 
1831  mLastError.clear();
1832  QgsGeometry result( geos.pointOnSurface( &mLastError ) );
1833  result.mLastError = mLastError;
1834  return result;
1835 }
1836 
1837 QgsGeometry QgsGeometry::poleOfInaccessibility( double precision, double *distanceToBoundary ) const
1838 {
1839  QgsInternalGeometryEngine engine( *this );
1840 
1841  return engine.poleOfInaccessibility( precision, distanceToBoundary );
1842 }
1843 
1845 {
1846  if ( !d->geometry )
1847  {
1848  return QgsGeometry();
1849  }
1850  QgsGeos geos( d->geometry.get() );
1851  mLastError.clear();
1852  std::unique_ptr< QgsAbstractGeometry > cHull( geos.convexHull( &mLastError ) );
1853  if ( !cHull )
1854  {
1855  QgsGeometry geom;
1856  geom.mLastError = mLastError;
1857  return geom;
1858  }
1859  return QgsGeometry( std::move( cHull ) );
1860 }
1861 
1862 QgsGeometry QgsGeometry::voronoiDiagram( const QgsGeometry &extent, double tolerance, bool edgesOnly ) const
1863 {
1864  if ( !d->geometry )
1865  {
1866  return QgsGeometry();
1867  }
1868 
1869  QgsGeos geos( d->geometry.get() );
1870  mLastError.clear();
1871  QgsGeometry result = geos.voronoiDiagram( extent.constGet(), tolerance, edgesOnly, &mLastError );
1872  result.mLastError = mLastError;
1873  return result;
1874 }
1875 
1876 QgsGeometry QgsGeometry::delaunayTriangulation( double tolerance, bool edgesOnly ) const
1877 {
1878  if ( !d->geometry )
1879  {
1880  return QgsGeometry();
1881  }
1882 
1883  QgsGeos geos( d->geometry.get() );
1884  mLastError.clear();
1885  QgsGeometry result = geos.delaunayTriangulation( tolerance, edgesOnly );
1886  result.mLastError = mLastError;
1887  return result;
1888 }
1889 
1891 {
1892  if ( !d->geometry )
1893  {
1894  return QgsGeometry();
1895  }
1896 
1897  const QgsAbstractGeometry *geom = d->geometry.get();
1898  std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
1899  if ( QgsWkbTypes::isCurvedType( d->geometry->wkbType() ) )
1900  {
1901  segmentizedCopy.reset( d->geometry->segmentize() );
1902  geom = segmentizedCopy.get();
1903  }
1904 
1905  QgsGeos geos( geom );
1906  mLastError.clear();
1907  std::unique_ptr< QgsAbstractGeometry > result( geos.subdivide( maxNodes, &mLastError ) );
1908  if ( !result )
1909  {
1910  QgsGeometry geom;
1911  geom.mLastError = mLastError;
1912  return geom;
1913  }
1914  return QgsGeometry( std::move( result ) );
1915 }
1916 
1918 {
1919  if ( !d->geometry )
1920  {
1921  return QgsGeometry();
1922  }
1923 
1924  QgsGeometry line = *this;
1926  line = QgsGeometry( d->geometry->boundary() );
1927 
1928  QgsGeos geos( line.constGet() );
1929  mLastError.clear();
1930  std::unique_ptr< QgsAbstractGeometry > result( geos.interpolate( distance, &mLastError ) );
1931  if ( !result )
1932  {
1933  QgsGeometry geom;
1934  geom.mLastError = mLastError;
1935  return geom;
1936  }
1937  return QgsGeometry( std::move( result ) );
1938 }
1939 
1940 double QgsGeometry::lineLocatePoint( const QgsGeometry &point ) const
1941 {
1942  if ( type() != QgsWkbTypes::LineGeometry )
1943  return -1;
1944 
1945  if ( QgsWkbTypes::flatType( point.wkbType() ) != QgsWkbTypes::Point )
1946  return -1;
1947 
1948  QgsGeometry segmentized = *this;
1950  {
1951  segmentized = QgsGeometry( static_cast< QgsCurve * >( d->geometry.get() )->segmentize() );
1952  }
1953 
1954  QgsGeos geos( d->geometry.get() );
1955  mLastError.clear();
1956  return geos.lineLocatePoint( *( static_cast< QgsPoint * >( point.d->geometry.get() ) ), &mLastError );
1957 }
1958 
1960 {
1961  if ( !d->geometry )
1962  return 0.0;
1963 
1964  // always operate on segmentized geometries
1965  QgsGeometry segmentized = *this;
1967  {
1968  segmentized = QgsGeometry( static_cast< QgsCurve * >( d->geometry.get() )->segmentize() );
1969  }
1970 
1971  QgsVertexId previous;
1972  QgsVertexId next;
1973  if ( !QgsGeometryUtils::verticesAtDistance( *segmentized.constGet(), distance, previous, next ) )
1974  return 0.0;
1975 
1976  if ( previous == next )
1977  {
1978  // distance coincided exactly with a vertex
1979  QgsVertexId v2 = previous;
1980  QgsVertexId v1;
1981  QgsVertexId v3;
1982  segmentized.constGet()->adjacentVertices( v2, v1, v3 );
1983  if ( v1.isValid() && v3.isValid() )
1984  {
1985  QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
1986  QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
1987  QgsPoint p3 = segmentized.constGet()->vertexAt( v3 );
1988  double angle1 = QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
1989  double angle2 = QgsGeometryUtils::lineAngle( p2.x(), p2.y(), p3.x(), p3.y() );
1990  return QgsGeometryUtils::averageAngle( angle1, angle2 );
1991  }
1992  else if ( v3.isValid() )
1993  {
1994  QgsPoint p1 = segmentized.constGet()->vertexAt( v2 );
1995  QgsPoint p2 = segmentized.constGet()->vertexAt( v3 );
1996  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
1997  }
1998  else
1999  {
2000  QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
2001  QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
2002  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2003  }
2004  }
2005  else
2006  {
2007  QgsPoint p1 = segmentized.constGet()->vertexAt( previous );
2008  QgsPoint p2 = segmentized.constGet()->vertexAt( next );
2009  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2010  }
2011 }
2012 
2014 {
2015  if ( !d->geometry || geometry.isNull() )
2016  {
2017  return QgsGeometry();
2018  }
2019 
2020  QgsGeos geos( d->geometry.get() );
2021 
2022  mLastError.clear();
2023  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.intersection( geometry.d->geometry.get(), &mLastError ) );
2024 
2025  if ( !resultGeom )
2026  {
2027  QgsGeometry geom;
2028  geom.mLastError = mLastError;
2029  return geom;
2030  }
2031 
2032  return QgsGeometry( std::move( resultGeom ) );
2033 }
2034 
2036 {
2037  if ( !d->geometry || geometry.isNull() )
2038  {
2039  return QgsGeometry();
2040  }
2041 
2042  QgsGeos geos( d->geometry.get() );
2043  mLastError.clear();
2044  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.combine( geometry.d->geometry.get(), &mLastError ) );
2045  if ( !resultGeom )
2046  {
2047  QgsGeometry geom;
2048  geom.mLastError = mLastError;
2049  return geom;
2050  }
2051  return QgsGeometry( std::move( resultGeom ) );
2052 }
2053 
2055 {
2056  if ( !d->geometry )
2057  {
2058  return QgsGeometry();
2059  }
2060 
2061  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::LineString )
2062  {
2063  // special case - a single linestring was passed
2064  return QgsGeometry( *this );
2065  }
2066 
2067  QgsGeos geos( d->geometry.get() );
2068  mLastError.clear();
2069  QgsGeometry result = geos.mergeLines( &mLastError );
2070  result.mLastError = mLastError;
2071  return result;
2072 }
2073 
2075 {
2076  if ( !d->geometry || geometry.isNull() )
2077  {
2078  return QgsGeometry();
2079  }
2080 
2081  QgsGeos geos( d->geometry.get() );
2082 
2083  mLastError.clear();
2084  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.difference( geometry.d->geometry.get(), &mLastError ) );
2085  if ( !resultGeom )
2086  {
2087  QgsGeometry geom;
2088  geom.mLastError = mLastError;
2089  return geom;
2090  }
2091  return QgsGeometry( std::move( resultGeom ) );
2092 }
2093 
2095 {
2096  if ( !d->geometry || geometry.isNull() )
2097  {
2098  return QgsGeometry();
2099  }
2100 
2101  QgsGeos geos( d->geometry.get() );
2102 
2103  mLastError.clear();
2104  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.symDifference( geometry.d->geometry.get(), &mLastError ) );
2105  if ( !resultGeom )
2106  {
2107  QgsGeometry geom;
2108  geom.mLastError = mLastError;
2109  return geom;
2110  }
2111  return QgsGeometry( std::move( resultGeom ) );
2112 }
2113 
2114 QgsGeometry QgsGeometry::extrude( double x, double y )
2115 {
2116  QgsInternalGeometryEngine engine( *this );
2117 
2118  return engine.extrude( x, y );
2119 }
2120 
2121 QByteArray QgsGeometry::asWkb() const
2122 {
2123  return d->geometry ? d->geometry->asWkb() : QByteArray();
2124 }
2125 
2126 QVector<QgsGeometry> QgsGeometry::asGeometryCollection() const
2127 {
2128  QVector<QgsGeometry> geometryList;
2129  if ( !d->geometry )
2130  {
2131  return geometryList;
2132  }
2133 
2135  if ( gc )
2136  {
2137  int numGeom = gc->numGeometries();
2138  geometryList.reserve( numGeom );
2139  for ( int i = 0; i < numGeom; ++i )
2140  {
2141  geometryList.append( QgsGeometry( gc->geometryN( i )->clone() ) );
2142  }
2143  }
2144  else //a singlepart geometry
2145  {
2146  geometryList.append( QgsGeometry( d->geometry->clone() ) );
2147  }
2148 
2149  return geometryList;
2150 }
2151 
2152 QPointF QgsGeometry::asQPointF() const
2153 {
2154  QgsPointXY point = asPoint();
2155  return point.toQPointF();
2156 }
2157 
2158 QPolygonF QgsGeometry::asQPolygonF() const
2159 {
2160  QPolygonF result;
2161  QgsPolylineXY polyline;
2163  if ( type == QgsWkbTypes::LineString || type == QgsWkbTypes::LineString25D )
2164  {
2165  polyline = asPolyline();
2166  }
2167  else if ( type == QgsWkbTypes::Polygon || type == QgsWkbTypes::Polygon25D )
2168  {
2169  QgsPolygonXY polygon = asPolygon();
2170  if ( polygon.empty() )
2171  return result;
2172  polyline = polygon.at( 0 );
2173  }
2174  else
2175  {
2176  return result;
2177  }
2178 
2179  for ( const QgsPointXY &p : qgis::as_const( polyline ) )
2180  {
2181  result << p.toQPointF();
2182  }
2183  return result;
2184 }
2185 
2186 bool QgsGeometry::deleteRing( int ringNum, int partNum )
2187 {
2188  if ( !d->geometry )
2189  {
2190  return false;
2191  }
2192 
2193  detach();
2194  bool ok = QgsGeometryEditUtils::deleteRing( d->geometry.get(), ringNum, partNum );
2195  return ok;
2196 }
2197 
2198 bool QgsGeometry::deletePart( int partNum )
2199 {
2200  if ( !d->geometry )
2201  {
2202  return false;
2203  }
2204 
2205  if ( !isMultipart() && partNum < 1 )
2206  {
2207  set( nullptr );
2208  return true;
2209  }
2210 
2211  detach();
2212  bool ok = QgsGeometryEditUtils::deletePart( d->geometry.get(), partNum );
2213  return ok;
2214 }
2215 
2216 int QgsGeometry::avoidIntersections( const QList<QgsVectorLayer *> &avoidIntersectionsLayers, const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures )
2217 {
2218  if ( !d->geometry )
2219  {
2220  return 1;
2221  }
2222 
2223  std::unique_ptr< QgsAbstractGeometry > diffGeom = QgsGeometryEditUtils::avoidIntersections( *( d->geometry ), avoidIntersectionsLayers, ignoreFeatures );
2224  if ( diffGeom )
2225  {
2226  reset( std::move( diffGeom ) );
2227  }
2228  return 0;
2229 }
2230 
2231 
2233 {
2234  if ( !d->geometry )
2235  return QgsGeometry();
2236 
2237  mLastError.clear();
2238  std::unique_ptr< QgsAbstractGeometry > g( _qgis_lwgeom_make_valid( d->geometry.get(), mLastError ) );
2239 
2240  QgsGeometry result = QgsGeometry( std::move( g ) );
2241  result.mLastError = mLastError;
2242  return result;
2243 }
2244 
2245 
2246 void QgsGeometry::validateGeometry( QVector<QgsGeometry::Error> &errors, ValidationMethod method ) const
2247 {
2248  QgsGeometryValidator::validateGeometry( *this, errors, method );
2249 }
2250 
2252 {
2253  if ( !d->geometry )
2254  {
2255  return false;
2256  }
2257 
2258  QgsGeos geos( d->geometry.get() );
2259  mLastError.clear();
2260  return geos.isValid( &mLastError );
2261 }
2262 
2264 {
2265  if ( !d->geometry )
2266  return false;
2267 
2268  QgsGeos geos( d->geometry.get() );
2269  mLastError.clear();
2270  return geos.isSimple( &mLastError );
2271 }
2272 
2274 {
2275  if ( !d->geometry || !g.d->geometry )
2276  {
2277  return false;
2278  }
2279 
2280  QgsGeos geos( d->geometry.get() );
2281  mLastError.clear();
2282  return geos.isEqual( g.d->geometry.get(), &mLastError );
2283 }
2284 
2285 QgsGeometry QgsGeometry::unaryUnion( const QVector<QgsGeometry> &geometries )
2286 {
2287  QgsGeos geos( nullptr );
2288 
2289  QString error;
2290  std::unique_ptr< QgsAbstractGeometry > geom( geos.combine( geometries, &error ) );
2291  QgsGeometry result( std::move( geom ) );
2292  result.mLastError = error;
2293  return result;
2294 }
2295 
2296 QgsGeometry QgsGeometry::polygonize( const QVector<QgsGeometry> &geometryList )
2297 {
2298  QgsGeos geos( nullptr );
2299 
2300  QVector<const QgsAbstractGeometry *> geomV2List;
2301  for ( const QgsGeometry &g : geometryList )
2302  {
2303  if ( !( g.isNull() ) )
2304  {
2305  geomV2List.append( g.constGet() );
2306  }
2307  }
2308 
2309  QString error;
2310  QgsGeometry result = geos.polygonize( geomV2List, &error );
2311  result.mLastError = error;
2312  return result;
2313 }
2314 
2316 {
2318  {
2319  return;
2320  }
2321 
2322  std::unique_ptr< QgsAbstractGeometry > straightGeom( d->geometry->segmentize() );
2323  reset( std::move( straightGeom ) );
2324 }
2325 
2327 {
2328  if ( !d->geometry )
2329  {
2330  return false;
2331  }
2332 
2333  return d->geometry->hasCurvedSegments();
2334 }
2335 
2337 {
2338  if ( !d->geometry )
2339  {
2341  }
2342 
2343  detach();
2344  d->geometry->transform( ct );
2345  return QgsGeometry::Success;
2346 }
2347 
2348 QgsGeometry::OperationResult QgsGeometry::transform( const QTransform &ct, double zTranslate, double zScale, double mTranslate, double mScale )
2349 {
2350  if ( !d->geometry )
2351  {
2353  }
2354 
2355  detach();
2356  d->geometry->transform( ct, zTranslate, zScale, mTranslate, mScale );
2357  return QgsGeometry::Success;
2358 }
2359 
2361 {
2362  if ( d->geometry )
2363  {
2364  detach();
2365  d->geometry->transform( mtp.transform() );
2366  }
2367 }
2368 
2370 {
2371  if ( !d->geometry || rectangle.isNull() || rectangle.isEmpty() )
2372  {
2373  return QgsGeometry();
2374  }
2375 
2376  QgsGeos geos( d->geometry.get() );
2377  mLastError.clear();
2378  std::unique_ptr< QgsAbstractGeometry > resultGeom = geos.clip( rectangle, &mLastError );
2379  if ( !resultGeom )
2380  {
2381  QgsGeometry result;
2382  result.mLastError = mLastError;
2383  return result;
2384  }
2385  return QgsGeometry( std::move( resultGeom ) );
2386 }
2387 
2388 void QgsGeometry::draw( QPainter &p ) const
2389 {
2390  if ( d->geometry )
2391  {
2392  d->geometry->draw( p );
2393  }
2394 }
2395 
2396 static bool vertexIndexInfo( const QgsAbstractGeometry *g, int vertexIndex, int &partIndex, int &ringIndex, int &vertex )
2397 {
2398  if ( vertexIndex < 0 )
2399  return false; // clearly something wrong
2400 
2401  if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
2402  {
2403  partIndex = 0;
2404  int offset = 0;
2405  for ( int i = 0; i < geomCollection->numGeometries(); ++i )
2406  {
2407  const QgsAbstractGeometry *part = geomCollection->geometryN( i );
2408 
2409  // count total number of vertices in the part
2410  int numPoints = 0;
2411  for ( int k = 0; k < part->ringCount(); ++k )
2412  numPoints += part->vertexCount( 0, k );
2413 
2414  if ( vertexIndex < numPoints )
2415  {
2416  int nothing;
2417  return vertexIndexInfo( part, vertexIndex, nothing, ringIndex, vertex ); // set ring_index + index
2418  }
2419  vertexIndex -= numPoints;
2420  offset += numPoints;
2421  partIndex++;
2422  }
2423  }
2424  else if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
2425  {
2426  const QgsCurve *ring = curvePolygon->exteriorRing();
2427  if ( vertexIndex < ring->numPoints() )
2428  {
2429  partIndex = 0;
2430  ringIndex = 0;
2431  vertex = vertexIndex;
2432  return true;
2433  }
2434  vertexIndex -= ring->numPoints();
2435  ringIndex = 1;
2436  for ( int i = 0; i < curvePolygon->numInteriorRings(); ++i )
2437  {
2438  const QgsCurve *ring = curvePolygon->interiorRing( i );
2439  if ( vertexIndex < ring->numPoints() )
2440  {
2441  partIndex = 0;
2442  vertex = vertexIndex;
2443  return true;
2444  }
2445  vertexIndex -= ring->numPoints();
2446  ringIndex += 1;
2447  }
2448  }
2449  else if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
2450  {
2451  if ( vertexIndex < curve->numPoints() )
2452  {
2453  partIndex = 0;
2454  ringIndex = 0;
2455  vertex = vertexIndex;
2456  return true;
2457  }
2458  }
2459  else if ( qgsgeometry_cast<const QgsPoint *>( g ) )
2460  {
2461  if ( vertexIndex == 0 )
2462  {
2463  partIndex = 0;
2464  ringIndex = 0;
2465  vertex = 0;
2466  return true;
2467  }
2468  }
2469 
2470  return false;
2471 }
2472 
2474 {
2475  if ( !d->geometry )
2476  {
2477  return false;
2478  }
2479 
2480  id.type = QgsVertexId::SegmentVertex;
2481 
2482  bool res = vertexIndexInfo( d->geometry.get(), nr, id.part, id.ring, id.vertex );
2483  if ( !res )
2484  return false;
2485 
2486  // now let's find out if it is a straight or circular segment
2487  const QgsAbstractGeometry *g = d->geometry.get();
2488  if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
2489  {
2490  g = geomCollection->geometryN( id.part );
2491  }
2492 
2493  if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
2494  {
2495  g = id.ring == 0 ? curvePolygon->exteriorRing() : curvePolygon->interiorRing( id.ring - 1 );
2496  }
2497 
2498  if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
2499  {
2500  QgsPoint p;
2501  res = curve->pointAt( id.vertex, p, id.type );
2502  if ( !res )
2503  return false;
2504  }
2505 
2506  return true;
2507 }
2508 
2510 {
2511  if ( !d->geometry )
2512  {
2513  return -1;
2514  }
2515  return d->geometry->vertexNumberFromVertexId( id );
2516 }
2517 
2518 QString QgsGeometry::lastError() const
2519 {
2520  return mLastError;
2521 }
2522 
2523 void QgsGeometry::convertPointList( const QVector<QgsPointXY> &input, QgsPointSequence &output )
2524 {
2525  output.clear();
2526  for ( const QgsPointXY &p : input )
2527  {
2528  output.append( QgsPoint( p ) );
2529  }
2530 }
2531 
2532 void QgsGeometry::convertPointList( const QgsPointSequence &input, QVector<QgsPointXY> &output )
2533 {
2534  output.clear();
2535  for ( const QgsPoint &p : input )
2536  {
2537  output.append( QgsPointXY( p.x(), p.y() ) );
2538  }
2539 }
2540 
2541 QgsGeometry::operator bool() const
2542 {
2543  return d->geometry.get();
2544 }
2545 
2546 void QgsGeometry::convertToPolyline( const QgsPointSequence &input, QgsPolylineXY &output )
2547 {
2548  output.clear();
2549  output.resize( input.size() );
2550 
2551  for ( int i = 0; i < input.size(); ++i )
2552  {
2553  const QgsPoint &pt = input.at( i );
2554  output[i].setX( pt.x() );
2555  output[i].setY( pt.y() );
2556  }
2557 }
2558 
2559 void QgsGeometry::convertPolygon( const QgsPolygon &input, QgsPolygonXY &output )
2560 {
2561  output.clear();
2562  QgsCoordinateSequence coords = input.coordinateSequence();
2563  if ( coords.empty() )
2564  {
2565  return;
2566  }
2567  const QgsRingSequence &rings = coords[0];
2568  output.resize( rings.size() );
2569  for ( int i = 0; i < rings.size(); ++i )
2570  {
2571  convertToPolyline( rings[i], output[i] );
2572  }
2573 }
2574 
2575 GEOSContextHandle_t QgsGeometry::getGEOSHandler()
2576 {
2577  return QgsGeos::getGEOSHandler();
2578 }
2579 
2581 {
2582  return QgsGeometry( qgis::make_unique< QgsPoint >( point.x(), point.y() ) );
2583 }
2584 
2585 QgsGeometry QgsGeometry::fromQPolygonF( const QPolygonF &polygon )
2586 {
2587  if ( polygon.isClosed() )
2588  {
2590  }
2591  else
2592  {
2594  }
2595 }
2596 
2598 {
2599  QgsPolygonXY result;
2600  result << createPolylineFromQPolygonF( polygon );
2601  return result;
2602 }
2603 
2605 {
2606  QgsPolylineXY result;
2607  for ( const QPointF &p : polygon )
2608  {
2609  result.append( QgsPointXY( p ) );
2610  }
2611  return result;
2612 }
2613 
2614 bool QgsGeometry::compare( const QgsPolylineXY &p1, const QgsPolylineXY &p2, double epsilon )
2615 {
2616  if ( p1.count() != p2.count() )
2617  return false;
2618 
2619  for ( int i = 0; i < p1.count(); ++i )
2620  {
2621  if ( !p1.at( i ).compare( p2.at( i ), epsilon ) )
2622  return false;
2623  }
2624  return true;
2625 }
2626 
2627 bool QgsGeometry::compare( const QgsPolygonXY &p1, const QgsPolygonXY &p2, double epsilon )
2628 {
2629  if ( p1.count() != p2.count() )
2630  return false;
2631 
2632  for ( int i = 0; i < p1.count(); ++i )
2633  {
2634  if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
2635  return false;
2636  }
2637  return true;
2638 }
2639 
2640 
2641 bool QgsGeometry::compare( const QgsMultiPolygonXY &p1, const QgsMultiPolygonXY &p2, double epsilon )
2642 {
2643  if ( p1.count() != p2.count() )
2644  return false;
2645 
2646  for ( int i = 0; i < p1.count(); ++i )
2647  {
2648  if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
2649  return false;
2650  }
2651  return true;
2652 }
2653 
2654 QgsGeometry QgsGeometry::smooth( const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
2655 {
2656  if ( !d->geometry || d->geometry->isEmpty() )
2657  return QgsGeometry();
2658 
2659  QgsGeometry geom = *this;
2661  geom = QgsGeometry( d->geometry->segmentize() );
2662 
2663  switch ( QgsWkbTypes::flatType( geom.wkbType() ) )
2664  {
2665  case QgsWkbTypes::Point:
2667  //can't smooth a point based geometry
2668  return geom;
2669 
2671  {
2672  QgsLineString *lineString = static_cast< QgsLineString * >( d->geometry.get() );
2673  return QgsGeometry( smoothLine( *lineString, iterations, offset, minimumDistance, maxAngle ) );
2674  }
2675 
2677  {
2678  QgsMultiLineString *multiLine = static_cast< QgsMultiLineString * >( d->geometry.get() );
2679 
2680  std::unique_ptr< QgsMultiLineString > resultMultiline = qgis::make_unique< QgsMultiLineString> ();
2681  for ( int i = 0; i < multiLine->numGeometries(); ++i )
2682  {
2683  resultMultiline->addGeometry( smoothLine( *( static_cast< QgsLineString * >( multiLine->geometryN( i ) ) ), iterations, offset, minimumDistance, maxAngle ).release() );
2684  }
2685  return QgsGeometry( std::move( resultMultiline ) );
2686  }
2687 
2688  case QgsWkbTypes::Polygon:
2689  {
2690  QgsPolygon *poly = static_cast< QgsPolygon * >( d->geometry.get() );
2691  return QgsGeometry( smoothPolygon( *poly, iterations, offset, minimumDistance, maxAngle ) );
2692  }
2693 
2695  {
2696  QgsMultiPolygon *multiPoly = static_cast< QgsMultiPolygon * >( d->geometry.get() );
2697 
2698  std::unique_ptr< QgsMultiPolygon > resultMultiPoly = qgis::make_unique< QgsMultiPolygon >();
2699  for ( int i = 0; i < multiPoly->numGeometries(); ++i )
2700  {
2701  resultMultiPoly->addGeometry( smoothPolygon( *( static_cast< QgsPolygon * >( multiPoly->geometryN( i ) ) ), iterations, offset, minimumDistance, maxAngle ).release() );
2702  }
2703  return QgsGeometry( std::move( resultMultiPoly ) );
2704  }
2705 
2706  case QgsWkbTypes::Unknown:
2707  default:
2708  return QgsGeometry( *this );
2709  }
2710 }
2711 
2712 inline QgsPoint interpolatePointOnLine( const QgsPoint &p1, const QgsPoint &p2, const double offset )
2713 {
2714  double deltaX = p2.x() - p1.x();
2715  double deltaY = p2.y() - p1.y();
2716  return QgsPoint( p1.x() + deltaX * offset, p1.y() + deltaY * offset );
2717 }
2718 
2719 std::unique_ptr< QgsLineString > smoothCurve( const QgsLineString &line, const unsigned int iterations,
2720  const double offset, double squareDistThreshold, double maxAngleRads,
2721  bool isRing )
2722 {
2723  std::unique_ptr< QgsLineString > result = qgis::make_unique< QgsLineString >( line );
2724  for ( unsigned int iteration = 0; iteration < iterations; ++iteration )
2725  {
2726  QgsPointSequence outputLine;
2727  outputLine.reserve( 2 * ( result->numPoints() - 1 ) );
2728  bool skipFirst = false;
2729  bool skipLast = false;
2730  if ( isRing )
2731  {
2732  QgsPoint p1 = result->pointN( result->numPoints() - 2 );
2733  QgsPoint p2 = result->pointN( 0 );
2734  QgsPoint p3 = result->pointN( 1 );
2735  double angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
2736  p3.x(), p3.y() );
2737  angle = std::fabs( M_PI - angle );
2738  skipFirst = angle > maxAngleRads;
2739  }
2740  for ( int i = 0; i < result->numPoints() - 1; i++ )
2741  {
2742  QgsPoint p1 = result->pointN( i );
2743  QgsPoint p2 = result->pointN( i + 1 );
2744 
2745  double angle = M_PI;
2746  if ( i == 0 && isRing )
2747  {
2748  QgsPoint p3 = result->pointN( result->numPoints() - 2 );
2749  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
2750  p3.x(), p3.y() );
2751  }
2752  else if ( i < result->numPoints() - 2 )
2753  {
2754  QgsPoint p3 = result->pointN( i + 2 );
2755  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
2756  p3.x(), p3.y() );
2757  }
2758  else if ( i == result->numPoints() - 2 && isRing )
2759  {
2760  QgsPoint p3 = result->pointN( 1 );
2761  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
2762  p3.x(), p3.y() );
2763  }
2764 
2765  skipLast = angle < M_PI - maxAngleRads || angle > M_PI + maxAngleRads;
2766 
2767  // don't apply distance threshold to first or last segment
2768  if ( i == 0 || i >= result->numPoints() - 2
2769  || QgsGeometryUtils::sqrDistance2D( p1, p2 ) > squareDistThreshold )
2770  {
2771  if ( !isRing )
2772  {
2773  if ( !skipFirst )
2774  outputLine << ( i == 0 ? result->pointN( i ) : interpolatePointOnLine( p1, p2, offset ) );
2775  if ( !skipLast )
2776  outputLine << ( i == result->numPoints() - 2 ? result->pointN( i + 1 ) : interpolatePointOnLine( p1, p2, 1.0 - offset ) );
2777  else
2778  outputLine << p2;
2779  }
2780  else
2781  {
2782  // ring
2783  if ( !skipFirst )
2784  outputLine << interpolatePointOnLine( p1, p2, offset );
2785  else if ( i == 0 )
2786  outputLine << p1;
2787  if ( !skipLast )
2788  outputLine << interpolatePointOnLine( p1, p2, 1.0 - offset );
2789  else
2790  outputLine << p2;
2791  }
2792  }
2793  skipFirst = skipLast;
2794  }
2795 
2796  if ( isRing && outputLine.at( 0 ) != outputLine.at( outputLine.count() - 1 ) )
2797  outputLine << outputLine.at( 0 );
2798 
2799  result->setPoints( outputLine );
2800  }
2801  return result;
2802 }
2803 
2804 std::unique_ptr<QgsLineString> QgsGeometry::smoothLine( const QgsLineString &line, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
2805 {
2806  double maxAngleRads = maxAngle * M_PI / 180.0;
2807  double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
2808  return smoothCurve( line, iterations, offset, squareDistThreshold, maxAngleRads, false );
2809 }
2810 
2811 std::unique_ptr<QgsPolygon> QgsGeometry::smoothPolygon( const QgsPolygon &polygon, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
2812 {
2813  double maxAngleRads = maxAngle * M_PI / 180.0;
2814  double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
2815  std::unique_ptr< QgsPolygon > resultPoly = qgis::make_unique< QgsPolygon >();
2816 
2817  resultPoly->setExteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.exteriorRing() ) ), iterations, offset,
2818  squareDistThreshold, maxAngleRads, true ).release() );
2819 
2820  for ( int i = 0; i < polygon.numInteriorRings(); ++i )
2821  {
2822  resultPoly->addInteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.interiorRing( i ) ) ), iterations, offset,
2823  squareDistThreshold, maxAngleRads, true ).release() );
2824  }
2825  return resultPoly;
2826 }
2827 
2828 QgsGeometry QgsGeometry::convertToPoint( bool destMultipart ) const
2829 {
2830  switch ( type() )
2831  {
2833  {
2834  bool srcIsMultipart = isMultipart();
2835 
2836  if ( ( destMultipart && srcIsMultipart ) ||
2837  ( !destMultipart && !srcIsMultipart ) )
2838  {
2839  // return a copy of the same geom
2840  return QgsGeometry( *this );
2841  }
2842  if ( destMultipart )
2843  {
2844  // layer is multipart => make a multipoint with a single point
2845  return fromMultiPointXY( QgsMultiPointXY() << asPoint() );
2846  }
2847  else
2848  {
2849  // destination is singlepart => make a single part if possible
2850  QgsMultiPointXY multiPoint = asMultiPoint();
2851  if ( multiPoint.count() == 1 )
2852  {
2853  return fromPointXY( multiPoint[0] );
2854  }
2855  }
2856  return QgsGeometry();
2857  }
2858 
2860  {
2861  // only possible if destination is multipart
2862  if ( !destMultipart )
2863  return QgsGeometry();
2864 
2865  // input geometry is multipart
2866  if ( isMultipart() )
2867  {
2868  const QgsMultiPolylineXY multiLine = asMultiPolyline();
2869  QgsMultiPointXY multiPoint;
2870  for ( const QgsPolylineXY &l : multiLine )
2871  for ( const QgsPointXY &p : l )
2872  multiPoint << p;
2873  return fromMultiPointXY( multiPoint );
2874  }
2875  // input geometry is not multipart: copy directly the line into a multipoint
2876  else
2877  {
2878  QgsPolylineXY line = asPolyline();
2879  if ( !line.isEmpty() )
2880  return fromMultiPointXY( line );
2881  }
2882  return QgsGeometry();
2883  }
2884 
2886  {
2887  // can only transform if destination is multipoint
2888  if ( !destMultipart )
2889  return QgsGeometry();
2890 
2891  // input geometry is multipart: make a multipoint from multipolygon
2892  if ( isMultipart() )
2893  {
2894  const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
2895  QgsMultiPointXY multiPoint;
2896  for ( const QgsPolygonXY &poly : multiPolygon )
2897  for ( const QgsPolylineXY &line : poly )
2898  for ( const QgsPointXY &pt : line )
2899  multiPoint << pt;
2900  return fromMultiPointXY( multiPoint );
2901  }
2902  // input geometry is not multipart: make a multipoint from polygon
2903  else
2904  {
2905  const QgsPolygonXY polygon = asPolygon();
2906  QgsMultiPointXY multiPoint;
2907  for ( const QgsPolylineXY &line : polygon )
2908  for ( const QgsPointXY &pt : line )
2909  multiPoint << pt;
2910  return fromMultiPointXY( multiPoint );
2911  }
2912  }
2913 
2914  default:
2915  return QgsGeometry();
2916  }
2917 }
2918 
2919 QgsGeometry QgsGeometry::convertToLine( bool destMultipart ) const
2920 {
2921  switch ( type() )
2922  {
2924  {
2925  if ( !isMultipart() )
2926  return QgsGeometry();
2927 
2928  QgsMultiPointXY multiPoint = asMultiPoint();
2929  if ( multiPoint.count() < 2 )
2930  return QgsGeometry();
2931 
2932  if ( destMultipart )
2933  return fromMultiPolylineXY( QgsMultiPolylineXY() << multiPoint );
2934  else
2935  return fromPolylineXY( multiPoint );
2936  }
2937 
2939  {
2940  bool srcIsMultipart = isMultipart();
2941 
2942  if ( ( destMultipart && srcIsMultipart ) ||
2943  ( !destMultipart && ! srcIsMultipart ) )
2944  {
2945  // return a copy of the same geom
2946  return QgsGeometry( *this );
2947  }
2948  if ( destMultipart )
2949  {
2950  // destination is multipart => makes a multipoint with a single line
2951  QgsPolylineXY line = asPolyline();
2952  if ( !line.isEmpty() )
2953  return fromMultiPolylineXY( QgsMultiPolylineXY() << line );
2954  }
2955  else
2956  {
2957  // destination is singlepart => make a single part if possible
2958  QgsMultiPolylineXY multiLine = asMultiPolyline();
2959  if ( multiLine.count() == 1 )
2960  return fromPolylineXY( multiLine[0] );
2961  }
2962  return QgsGeometry();
2963  }
2964 
2966  {
2967  // input geometry is multipolygon
2968  if ( isMultipart() )
2969  {
2970  const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
2971  QgsMultiPolylineXY multiLine;
2972  for ( const QgsPolygonXY &poly : multiPolygon )
2973  for ( const QgsPolylineXY &line : poly )
2974  multiLine << line;
2975 
2976  if ( destMultipart )
2977  {
2978  // destination is multipart
2979  return fromMultiPolylineXY( multiLine );
2980  }
2981  else if ( multiLine.count() == 1 )
2982  {
2983  // destination is singlepart => make a single part if possible
2984  return fromPolylineXY( multiLine[0] );
2985  }
2986  }
2987  // input geometry is single polygon
2988  else
2989  {
2990  QgsPolygonXY polygon = asPolygon();
2991  // if polygon has rings
2992  if ( polygon.count() > 1 )
2993  {
2994  // cannot fit a polygon with rings in a single line layer
2995  // TODO: would it be better to remove rings?
2996  if ( destMultipart )
2997  {
2998  const QgsPolygonXY polygon = asPolygon();
2999  QgsMultiPolylineXY multiLine;
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.
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:893
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:2704
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
int numPoints() const override
Returns the number of points in the curve.
QgsPointXY closestVertex(const QgsPointXY &point, int &atVertex, int &beforeVertex, int &afterVertex, double &sqrDist) const
Returns the vertex closest to the given point, the corresponding vertex index, squared distance snap ...
QgsGeometry poleOfInaccessibility(double precision, double *distanceToBoundary=nullptr) const
Calculates the approximate pole of inaccessibility for a surface, which is the most distant internal ...
static std::unique_ptr< QgsMultiPoint > fromMultiPointXY(const QgsMultiPointXY &multipoint)
Construct geometry from a multipoint.
bool deletePart(int partNum)
Deletes part identified by the part number.
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:1024
bool convertToSingleType()
Converts multi type geometry into single type geometry e.g.
bool equals(const QgsGeometry &geometry) const
Test if this geometry is exactly equal to another geometry.
Utility class for identifying a unique vertex within a geometry.
bool isEmpty() const
Returns true if the rectangle is empty.
Geometry collection.
QgsPolygonXY asPolygon() const
Returns contents of the geometry as a polygon if wkbType is WKBPolygon, otherwise an empty list...
QgsPoint interpolatePointOnLine(const QgsPoint &p1, const QgsPoint &p2, const double offset)
static QgsGeometry fromQPointF(QPointF point)
Construct geometry from a QPointF.
virtual QgsPolygon * toPolygon(unsigned int segments=36) const
Returns a segmented polygon.
Definition: qgsellipse.cpp: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:1237
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:2144
QgsGeometry densifyByDistance(double distance) const
Densifies the geometry by adding regularly placed extra nodes inside each segment so that the maximum...
Method not implemented in geometry engine.
virtual double area() const
Returns the area of the geometry.
virtual int ringCount(int part=0) const =0
Returns the number of rings of which this geometry is built.
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
virtual QgsPolygon * toPolygon(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a new polygon geometry corresponding to a segmentized approximation of the curve...
QgsGeometry pointOnSurface() const
Returns a point guaranteed to lie on the surface of a geometry.
bool touches(const QgsGeometry &geometry) const
Test for if geometry touch another (uses GEOS)
Abstract base class for all geometries.
QgsCoordinateSequence coordinateSequence() const override
Retrieves the sequence of geometries, rings and nodes.
The vertex_iterator class provides STL-style iterator for vertices.
void convertToStraightSegment()
Converts the geometry to straight line segments, if it is a curved geometry type. ...
const QgsCurve * exteriorRing() const
Does vector analysis using the geos library and handles import, export, exception handling*...
Definition: qgsgeos.h:98
static std::unique_ptr< QgsMultiLineString > fromMultiPolylineXY(const QgsMultiPolylineXY &multiline)
Construct geometry from a multipolyline.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
QgsGeometry densifyByDistance(double distance) const
Densifies the geometry by adding regularly placed extra nodes inside each segment so that the maximum...
QgsWkbTypes::GeometryType type() const
Returns type of the geometry as a QgsWkbTypes::GeometryType.
double length() const
Returns the length of geometry using GEOS.
This class offers geometry processing methods.
void setX(double x)
Sets the x value of the point.
Definition: qgspointxy.h:104
QByteArray asWkb() const
Export the geometry to WKB.
Error occurred while creating a noded geometry.
double x
Definition: qgspointxy.h:47
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
QgsGeometry extrude(double x, double y)
Returns an extruded version of this geometry.
Error occurred in the geometry engine.
void draw(QPainter &p) const
Draws the geometry onto a QPainter.
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
int numGeometries() const
Returns the number of geometries within the collection.
Contains geos related utilities and functions.
Definition: qgsgeos.h:36
void setX(double x)
Sets the point&#39;s x-coordinate.
Definition: qgspoint.h:192
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h: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:885
QVector< QgsPoint > QgsPointSequence
static void convertPointList(const QVector< QgsPointXY > &input, QgsPointSequence &output)
Upgrades a point list from QgsPointXY to QgsPoint.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:137
static QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
static QgsGeometry::OperationResult addPart(QgsAbstractGeometry *geometry, std::unique_ptr< QgsAbstractGeometry > part)
Add a part to multi type geometry.
virtual void adjacentVertices(QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex) const =0
Returns the vertices adjacent to a specified vertex within a geometry.
int partCount() const override
Returns count of parts contained in the geometry.
QVector< QgsPointSequence > QgsRingSequence
QString lastError() const
Returns an error string referring to the last error encountered either when this geometry was created...
QgsGeometry simplify(double tolerance) const
Returns a simplified version of this geometry using a specified tolerance value.
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
Definition: qgsgeometry.h:49
static double sqrDistance2D(const QgsPoint &pt1, const QgsPoint &pt2)
Returns the squared 2D distance between two points.
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
static std::unique_ptr< QgsAbstractGeometry > geomFromWkt(const QString &text)
Construct geometry from a WKT string.
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
double hausdorffDistance(const QgsGeometry &geom) const
Returns the Hausdorff distance between this geometry and geom.
OperationResult transform(const QgsCoordinateTransform &ct)
Transforms this geometry as described by CoordinateTransform ct.
QgsPointXY asPoint() const
Returns contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [0...
The base geometry on which the operation is done is invalid or empty.
Definition: qgsgeometry.h: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:1383
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:902
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...