QGIS API Documentation  3.2.0-Bonn (bc43194)
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 QgsGeometry QgsGeometry::createWedgeBuffer( const QgsPoint &center, const double azimuth, const double angularWidth, const double outerRadius, const double innerRadius )
262 {
263  std::unique_ptr< QgsCompoundCurve > wedge = qgis::make_unique< QgsCompoundCurve >();
264 
265  const double startAngle = azimuth - angularWidth * 0.5;
266  const double endAngle = azimuth + angularWidth * 0.5;
267 
268  const QgsPoint outerP1 = center.project( outerRadius, startAngle );
269  const QgsPoint outerP2 = center.project( outerRadius, endAngle );
270 
271  const bool useShortestArc = angularWidth <= 180.0;
272 
273  wedge->addCurve( new QgsCircularString( QgsCircularString::fromTwoPointsAndCenter( outerP1, outerP2, center, useShortestArc ) ) );
274 
275  if ( !qgsDoubleNear( innerRadius, 0.0 ) && innerRadius > 0 )
276  {
277  const QgsPoint innerP1 = center.project( innerRadius, startAngle );
278  const QgsPoint innerP2 = center.project( innerRadius, endAngle );
279  wedge->addCurve( new QgsLineString( outerP2, innerP2 ) );
280  wedge->addCurve( new QgsCircularString( QgsCircularString::fromTwoPointsAndCenter( innerP2, innerP1, center, useShortestArc ) ) );
281  wedge->addCurve( new QgsLineString( innerP1, outerP1 ) );
282  }
283  else
284  {
285  wedge->addCurve( new QgsLineString( outerP2, center ) );
286  wedge->addCurve( new QgsLineString( center, outerP1 ) );
287  }
288 
289  std::unique_ptr< QgsCurvePolygon > cp = qgis::make_unique< QgsCurvePolygon >();
290  cp->setExteriorRing( wedge.release() );
291  return QgsGeometry( std::move( cp ) );
292 }
293 
294 void QgsGeometry::fromWkb( unsigned char *wkb, int length )
295 {
296  QgsConstWkbPtr ptr( wkb, length );
297  reset( QgsGeometryFactory::geomFromWkb( ptr ) );
298  delete [] wkb;
299 }
300 
301 void QgsGeometry::fromWkb( const QByteArray &wkb )
302 {
303  QgsConstWkbPtr ptr( wkb );
304  reset( QgsGeometryFactory::geomFromWkb( ptr ) );
305 }
306 
308 {
309  if ( !d->geometry )
310  {
311  return QgsWkbTypes::Unknown;
312  }
313  else
314  {
315  return d->geometry->wkbType();
316  }
317 }
318 
319 
321 {
322  if ( !d->geometry )
323  {
325  }
326  return static_cast< QgsWkbTypes::GeometryType >( QgsWkbTypes::geometryType( d->geometry->wkbType() ) );
327 }
328 
330 {
331  if ( !d->geometry )
332  {
333  return true;
334  }
335 
336  return d->geometry->isEmpty();
337 }
338 
340 {
341  if ( !d->geometry )
342  {
343  return false;
344  }
345  return QgsWkbTypes::isMultiType( d->geometry->wkbType() );
346 }
347 
348 QgsPointXY QgsGeometry::closestVertex( const QgsPointXY &point, int &atVertex, int &beforeVertex, int &afterVertex, double &sqrDist ) const
349 {
350  if ( !d->geometry )
351  {
352  sqrDist = -1;
353  return QgsPointXY( 0, 0 );
354  }
355 
356  QgsPoint pt( point.x(), point.y() );
357  QgsVertexId id;
358 
359  QgsPoint vp = QgsGeometryUtils::closestVertex( *( d->geometry ), pt, id );
360  if ( !id.isValid() )
361  {
362  sqrDist = -1;
363  return QgsPointXY( 0, 0 );
364  }
365  sqrDist = QgsGeometryUtils::sqrDistance2D( pt, vp );
366 
367  QgsVertexId prevVertex;
368  QgsVertexId nextVertex;
369  d->geometry->adjacentVertices( id, prevVertex, nextVertex );
370  atVertex = vertexNrFromVertexId( id );
371  beforeVertex = vertexNrFromVertexId( prevVertex );
372  afterVertex = vertexNrFromVertexId( nextVertex );
373  return QgsPointXY( vp.x(), vp.y() );
374 }
375 
376 double QgsGeometry::distanceToVertex( int vertex ) const
377 {
378  if ( !d->geometry )
379  {
380  return -1;
381  }
382 
383  QgsVertexId id;
384  if ( !vertexIdFromVertexNr( vertex, id ) )
385  {
386  return -1;
387  }
388 
389  return QgsGeometryUtils::distanceToVertex( *( d->geometry ), id );
390 }
391 
392 double QgsGeometry::angleAtVertex( int vertex ) const
393 {
394  if ( !d->geometry )
395  {
396  return 0;
397  }
398 
399  QgsVertexId v2;
400  if ( !vertexIdFromVertexNr( vertex, v2 ) )
401  {
402  return 0;
403  }
404 
405  return d->geometry->vertexAngle( v2 );
406 }
407 
408 void QgsGeometry::adjacentVertices( int atVertex, int &beforeVertex, int &afterVertex ) const
409 {
410  if ( !d->geometry )
411  {
412  return;
413  }
414 
415  QgsVertexId id;
416  if ( !vertexIdFromVertexNr( atVertex, id ) )
417  {
418  beforeVertex = -1;
419  afterVertex = -1;
420  return;
421  }
422 
423  QgsVertexId beforeVertexId, afterVertexId;
424  d->geometry->adjacentVertices( id, beforeVertexId, afterVertexId );
425  beforeVertex = vertexNrFromVertexId( beforeVertexId );
426  afterVertex = vertexNrFromVertexId( afterVertexId );
427 }
428 
429 bool QgsGeometry::moveVertex( double x, double y, int atVertex )
430 {
431  if ( !d->geometry )
432  {
433  return false;
434  }
435 
436  QgsVertexId id;
437  if ( !vertexIdFromVertexNr( atVertex, id ) )
438  {
439  return false;
440  }
441 
442  detach();
443 
444  return d->geometry->moveVertex( id, QgsPoint( x, y ) );
445 }
446 
447 bool QgsGeometry::moveVertex( const QgsPoint &p, int atVertex )
448 {
449  if ( !d->geometry )
450  {
451  return false;
452  }
453 
454  QgsVertexId id;
455  if ( !vertexIdFromVertexNr( atVertex, id ) )
456  {
457  return false;
458  }
459 
460  detach();
461 
462  return d->geometry->moveVertex( id, p );
463 }
464 
465 bool QgsGeometry::deleteVertex( int atVertex )
466 {
467  if ( !d->geometry )
468  {
469  return false;
470  }
471 
472  //maintain compatibility with < 2.10 API
473  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::MultiPoint )
474  {
475  detach();
476  //delete geometry instead of point
477  return static_cast< QgsGeometryCollection * >( d->geometry.get() )->removeGeometry( atVertex );
478  }
479 
480  //if it is a point, set the geometry to nullptr
481  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::Point )
482  {
483  reset( nullptr );
484  return true;
485  }
486 
487  QgsVertexId id;
488  if ( !vertexIdFromVertexNr( atVertex, id ) )
489  {
490  return false;
491  }
492 
493  detach();
494 
495  return d->geometry->deleteVertex( id );
496 }
497 
498 bool QgsGeometry::insertVertex( double x, double y, int beforeVertex )
499 {
500  if ( !d->geometry )
501  {
502  return false;
503  }
504 
505  //maintain compatibility with < 2.10 API
506  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::MultiPoint )
507  {
508  detach();
509  //insert geometry instead of point
510  return static_cast< QgsGeometryCollection * >( d->geometry.get() )->insertGeometry( new QgsPoint( x, y ), beforeVertex );
511  }
512 
513  QgsVertexId id;
514  if ( !vertexIdFromVertexNr( beforeVertex, id ) )
515  {
516  return false;
517  }
518 
519  detach();
520 
521  return d->geometry->insertVertex( id, QgsPoint( x, y ) );
522 }
523 
524 bool QgsGeometry::insertVertex( const QgsPoint &point, int beforeVertex )
525 {
526  if ( !d->geometry )
527  {
528  return false;
529  }
530 
531  //maintain compatibility with < 2.10 API
532  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::MultiPoint )
533  {
534  detach();
535  //insert geometry instead of point
536  return static_cast< QgsGeometryCollection * >( d->geometry.get() )->insertGeometry( new QgsPoint( point ), beforeVertex );
537  }
538 
539  QgsVertexId id;
540  if ( !vertexIdFromVertexNr( beforeVertex, id ) )
541  {
542  return false;
543  }
544 
545  detach();
546 
547  return d->geometry->insertVertex( id, point );
548 }
549 
550 QgsPoint QgsGeometry::vertexAt( int atVertex ) const
551 {
552  if ( !d->geometry )
553  {
554  return QgsPoint();
555  }
556 
557  QgsVertexId vId;
558  ( void )vertexIdFromVertexNr( atVertex, vId );
559  if ( vId.vertex < 0 )
560  {
561  return QgsPoint();
562  }
563  return d->geometry->vertexAt( vId );
564 }
565 
566 double QgsGeometry::sqrDistToVertexAt( QgsPointXY &point, int atVertex ) const
567 {
568  QgsPointXY vertexPoint = vertexAt( atVertex );
569  return QgsGeometryUtils::sqrDistance2D( QgsPoint( vertexPoint.x(), vertexPoint.y() ), QgsPoint( point.x(), point.y() ) );
570 }
571 
573 {
574  QgsGeos geos( d->geometry.get() );
575  mLastError.clear();
576  QgsGeometry result = geos.closestPoint( other );
577  result.mLastError = mLastError;
578  return result;
579 }
580 
582 {
583  QgsGeos geos( d->geometry.get() );
584  mLastError.clear();
585  QgsGeometry result = geos.shortestLine( other, &mLastError );
586  result.mLastError = mLastError;
587  return result;
588 }
589 
590 double QgsGeometry::closestVertexWithContext( const QgsPointXY &point, int &atVertex ) const
591 {
592  if ( !d->geometry )
593  {
594  return -1;
595  }
596 
597  QgsVertexId vId;
598  QgsPoint pt( point.x(), point.y() );
599  QgsPoint closestPoint = QgsGeometryUtils::closestVertex( *( d->geometry ), pt, vId );
600  if ( !vId.isValid() )
601  return -1;
602  atVertex = vertexNrFromVertexId( vId );
603  return QgsGeometryUtils::sqrDistance2D( closestPoint, pt );
604 }
605 
607  QgsPointXY &minDistPoint,
608  int &afterVertex,
609  int *leftOf,
610  double epsilon ) const
611 {
612  if ( !d->geometry )
613  {
614  return -1;
615  }
616 
617  QgsPoint segmentPt;
618  QgsVertexId vertexAfter;
619 
620  double sqrDist = d->geometry->closestSegment( QgsPoint( point.x(), point.y() ), segmentPt, vertexAfter, leftOf, epsilon );
621  if ( sqrDist < 0 )
622  return -1;
623 
624  minDistPoint.setX( segmentPt.x() );
625  minDistPoint.setY( segmentPt.y() );
626  afterVertex = vertexNrFromVertexId( vertexAfter );
627  return sqrDist;
628 }
629 
630 QgsGeometry::OperationResult QgsGeometry::addRing( const QVector<QgsPointXY> &ring )
631 {
632  std::unique_ptr< QgsLineString > ringLine = qgis::make_unique< QgsLineString >( ring );
633  return addRing( ringLine.release() );
634 }
635 
637 {
638  std::unique_ptr< QgsCurve > r( ring );
639  if ( !d->geometry )
640  {
642  }
643 
644  detach();
645 
646  return QgsGeometryEditUtils::addRing( d->geometry.get(), std::move( r ) );
647 }
648 
650 {
652  convertPointList( points, l );
653  return addPart( l, geomType );
654 }
655 
657 {
658  std::unique_ptr< QgsAbstractGeometry > partGeom;
659  if ( points.size() == 1 )
660  {
661  partGeom = qgis::make_unique< QgsPoint >( points[0] );
662  }
663  else if ( points.size() > 1 )
664  {
665  std::unique_ptr< QgsLineString > ringLine = qgis::make_unique< QgsLineString >();
666  ringLine->setPoints( points );
667  partGeom = std::move( ringLine );
668  }
669  return addPart( partGeom.release(), geomType );
670 }
671 
673 {
674  std::unique_ptr< QgsAbstractGeometry > p( part );
675  if ( !d->geometry )
676  {
677  switch ( geomType )
678  {
680  reset( qgis::make_unique< QgsMultiPoint >() );
681  break;
683  reset( qgis::make_unique< QgsMultiLineString >() );
684  break;
686  reset( qgis::make_unique< QgsMultiPolygon >() );
687  break;
688  default:
689  reset( nullptr );
690  return QgsGeometry::OperationResult::AddPartNotMultiGeometry;
691  }
692  }
693  else
694  {
695  detach();
696  }
697 
699  return QgsGeometryEditUtils::addPart( d->geometry.get(), std::move( p ) );
700 }
701 
703 {
704  if ( !d->geometry )
705  {
707  }
708  if ( !newPart || !newPart.d->geometry )
709  {
711  }
712 
713  return addPart( newPart.d->geometry->clone() );
714 }
715 
716 QgsGeometry QgsGeometry::removeInteriorRings( double minimumRingArea ) const
717 {
718  if ( !d->geometry || type() != QgsWkbTypes::PolygonGeometry )
719  {
720  return QgsGeometry();
721  }
722 
723  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
724  {
725  const QVector<QgsGeometry> parts = asGeometryCollection();
726  QVector<QgsGeometry> results;
727  for ( const QgsGeometry &part : parts )
728  {
729  QgsGeometry result = part.removeInteriorRings( minimumRingArea );
730  if ( result )
731  results << result;
732  }
733  if ( results.isEmpty() )
734  return QgsGeometry();
735 
736  QgsGeometry first = results.takeAt( 0 );
737  for ( const QgsGeometry &result : qgis::as_const( results ) )
738  {
739  first.addPart( result );
740  }
741  return first;
742  }
743  else
744  {
745  std::unique_ptr< QgsCurvePolygon > newPoly( static_cast< QgsCurvePolygon * >( d->geometry->clone() ) );
746  newPoly->removeInteriorRings( minimumRingArea );
747  return QgsGeometry( std::move( newPoly ) );
748  }
749 }
750 
751 QgsGeometry::OperationResult QgsGeometry::translate( double dx, double dy, double dz, double dm )
752 {
753  if ( !d->geometry )
754  {
756  }
757 
758  detach();
759 
760  d->geometry->transform( QTransform::fromTranslate( dx, dy ), dz, 1.0, dm );
761  return QgsGeometry::Success;
762 }
763 
765 {
766  if ( !d->geometry )
767  {
769  }
770 
771  detach();
772 
773  QTransform t = QTransform::fromTranslate( center.x(), center.y() );
774  t.rotate( -rotation );
775  t.translate( -center.x(), -center.y() );
776  d->geometry->transform( t );
777  return QgsGeometry::Success;
778 }
779 
780 QgsGeometry::OperationResult QgsGeometry::splitGeometry( const QVector<QgsPointXY> &splitLine, QVector<QgsGeometry> &newGeometries, bool topological, QVector<QgsPointXY> &topologyTestPoints )
781 {
782  if ( !d->geometry )
783  {
784  return QgsGeometry::OperationResult::InvalidBaseGeometry;
785  }
786 
787  QVector<QgsGeometry > newGeoms;
788  QgsLineString splitLineString( splitLine );
789  QgsPointSequence tp;
790 
791  QgsGeos geos( d->geometry.get() );
792  mLastError.clear();
793  QgsGeometryEngine::EngineOperationResult result = geos.splitGeometry( splitLineString, newGeoms, topological, tp, &mLastError );
794 
795  if ( result == QgsGeometryEngine::Success )
796  {
797  *this = newGeoms.takeAt( 0 );
798 
799  newGeometries = newGeoms;
800  }
801 
802  convertPointList( tp, topologyTestPoints );
803 
804  switch ( result )
805  {
807  return QgsGeometry::OperationResult::Success;
811  return QgsGeometry::OperationResult::GeometryEngineError;
813  return QgsGeometry::OperationResult::InvalidBaseGeometry;
815  return QgsGeometry::OperationResult::InvalidInputGeometryType;
817  return QgsGeometry::OperationResult::SplitCannotSplitPoint;
819  return QgsGeometry::OperationResult::NothingHappened;
820  //default: do not implement default to handle properly all cases
821  }
822 
823  // this should never be reached
824  Q_ASSERT( false );
826 }
827 
829 {
830  if ( !d->geometry )
831  {
832  return InvalidBaseGeometry;
833  }
834 
835  QgsGeos geos( d->geometry.get() );
837  mLastError.clear();
838  std::unique_ptr< QgsAbstractGeometry > geom( geos.reshapeGeometry( reshapeLineString, &errorCode, &mLastError ) );
839  if ( errorCode == QgsGeometryEngine::Success && geom )
840  {
841  reset( std::move( geom ) );
842  return Success;
843  }
844 
845  switch ( errorCode )
846  {
848  return Success;
852  return GeometryEngineError;
854  return InvalidBaseGeometry;
857  case QgsGeometryEngine::SplitCannotSplitPoint: // should not happen
858  return GeometryEngineError;
860  return NothingHappened;
861  }
862 
863  // should not be reached
864  return GeometryEngineError;
865 }
866 
868 {
869  if ( !d->geometry || !other.d->geometry )
870  {
871  return 0;
872  }
873 
874  QgsGeos geos( d->geometry.get() );
875 
876  mLastError.clear();
877  std::unique_ptr< QgsAbstractGeometry > diffGeom( geos.intersection( other.constGet(), &mLastError ) );
878  if ( !diffGeom )
879  {
880  return 1;
881  }
882 
883  reset( std::move( diffGeom ) );
884  return 0;
885 }
886 
888 {
889  if ( !d->geometry || other.isNull() )
890  {
891  return QgsGeometry();
892  }
893 
894  QgsGeos geos( d->geometry.get() );
895 
896  mLastError.clear();
897  std::unique_ptr< QgsAbstractGeometry > diffGeom( geos.intersection( other.constGet(), &mLastError ) );
898  if ( !diffGeom )
899  {
900  QgsGeometry result;
901  result.mLastError = mLastError;
902  return result;
903  }
904 
905  return QgsGeometry( diffGeom.release() );
906 }
907 
909 {
910  if ( d->geometry )
911  {
912  return d->geometry->boundingBox();
913  }
914  return QgsRectangle();
915 }
916 
917 QgsGeometry QgsGeometry::orientedMinimumBoundingBox( double &area, double &angle, double &width, double &height ) const
918 {
919  QgsRectangle minRect;
920  area = std::numeric_limits<double>::max();
921  angle = 0;
922  width = std::numeric_limits<double>::max();
923  height = std::numeric_limits<double>::max();
924 
925  if ( !d->geometry || d->geometry->nCoordinates() < 2 )
926  return QgsGeometry();
927 
928  QgsGeometry hull = convexHull();
929  if ( hull.isNull() )
930  return QgsGeometry();
931 
932  QgsVertexId vertexId;
933  QgsPoint pt0;
934  QgsPoint pt1;
935  QgsPoint pt2;
936  // get first point
937  hull.constGet()->nextVertex( vertexId, pt0 );
938  pt1 = pt0;
939  double prevAngle = 0.0;
940  while ( hull.constGet()->nextVertex( vertexId, pt2 ) )
941  {
942  double currentAngle = QgsGeometryUtils::lineAngle( pt1.x(), pt1.y(), pt2.x(), pt2.y() );
943  double rotateAngle = 180.0 / M_PI * ( currentAngle - prevAngle );
944  prevAngle = currentAngle;
945 
946  QTransform t = QTransform::fromTranslate( pt0.x(), pt0.y() );
947  t.rotate( rotateAngle );
948  t.translate( -pt0.x(), -pt0.y() );
949 
950  hull.get()->transform( t );
951 
952  QgsRectangle bounds = hull.constGet()->boundingBox();
953  double currentArea = bounds.width() * bounds.height();
954  if ( currentArea < area )
955  {
956  minRect = bounds;
957  area = currentArea;
958  angle = 180.0 / M_PI * currentAngle;
959  width = bounds.width();
960  height = bounds.height();
961  }
962 
963  pt2 = pt1;
964  }
965 
966  QgsGeometry minBounds = QgsGeometry::fromRect( minRect );
967  minBounds.rotate( angle, QgsPointXY( pt0.x(), pt0.y() ) );
968 
969  // constrain angle to 0 - 180
970  if ( angle > 180.0 )
971  angle = std::fmod( angle, 180.0 );
972 
973  return minBounds;
974 }
975 
977 {
978  double area, angle, width, height;
979  return orientedMinimumBoundingBox( area, angle, width, height );
980 }
981 
982 static QgsCircle __recMinimalEnclosingCircle( QgsMultiPointXY points, QgsMultiPointXY boundary )
983 {
984  auto l_boundary = boundary.length();
985  QgsCircle circ_mec;
986  if ( ( points.length() == 0 ) || ( l_boundary == 3 ) )
987  {
988  switch ( l_boundary )
989  {
990  case 0:
991  circ_mec = QgsCircle();
992  break;
993  case 1:
994  circ_mec = QgsCircle( QgsPoint( boundary.last() ), 0 );
995  boundary.pop_back();
996  break;
997  case 2:
998  {
999  QgsPointXY p1 = boundary.last();
1000  boundary.pop_back();
1001  QgsPointXY p2 = boundary.last();
1002  boundary.pop_back();
1003  circ_mec = QgsCircle().from2Points( QgsPoint( p1 ), QgsPoint( p2 ) );
1004  }
1005  break;
1006  default:
1007  QgsPoint p1( boundary.at( 0 ) );
1008  QgsPoint p2( boundary.at( 1 ) );
1009  QgsPoint p3( boundary.at( 2 ) );
1010  circ_mec = QgsCircle().minimalCircleFrom3Points( p1, p2, p3 );
1011  break;
1012  }
1013  return circ_mec;
1014  }
1015  else
1016  {
1017  QgsPointXY pxy = points.last();
1018  points.pop_back();
1019  circ_mec = __recMinimalEnclosingCircle( points, boundary );
1020  QgsPoint p( pxy );
1021  if ( !circ_mec.contains( p ) )
1022  {
1023  boundary.append( pxy );
1024  circ_mec = __recMinimalEnclosingCircle( points, boundary );
1025  }
1026  }
1027  return circ_mec;
1028 }
1029 
1030 QgsGeometry QgsGeometry::minimalEnclosingCircle( QgsPointXY &center, double &radius, unsigned int segments ) const
1031 {
1032  center = QgsPointXY( );
1033  radius = 0;
1034 
1035  if ( !d->geometry )
1036  {
1037  return QgsGeometry();
1038  }
1039 
1040  /* optimization */
1041  QgsGeometry hull = convexHull();
1042  if ( hull.isNull() )
1043  return QgsGeometry();
1044 
1045  QgsMultiPointXY P = hull.convertToPoint( true ).asMultiPoint();
1046  QgsMultiPointXY R;
1047 
1048  QgsCircle circ = __recMinimalEnclosingCircle( P, R );
1049  center = QgsPointXY( circ.center() );
1050  radius = circ.radius();
1051  QgsGeometry geom;
1052  geom.set( circ.toPolygon( segments ) );
1053  return geom;
1054 
1055 }
1056 
1057 QgsGeometry QgsGeometry::minimalEnclosingCircle( unsigned int segments ) const
1058 {
1059  QgsPointXY center;
1060  double radius;
1061  return minimalEnclosingCircle( center, radius, segments );
1062 
1063 }
1064 
1065 QgsGeometry QgsGeometry::orthogonalize( double tolerance, int maxIterations, double angleThreshold ) const
1066 {
1067  QgsInternalGeometryEngine engine( *this );
1068 
1069  return engine.orthogonalize( tolerance, maxIterations, angleThreshold );
1070 }
1071 
1072 QgsGeometry QgsGeometry::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing ) const
1073 {
1074  if ( !d->geometry )
1075  {
1076  return QgsGeometry();
1077  }
1078  return QgsGeometry( d->geometry->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing ) );
1079 }
1080 
1081 bool QgsGeometry::removeDuplicateNodes( double epsilon, bool useZValues )
1082 {
1083  if ( !d->geometry )
1084  return false;
1085 
1086  detach();
1087  return d->geometry->removeDuplicateNodes( epsilon, useZValues );
1088 }
1089 
1091 {
1092  QgsGeometry g = fromRect( r );
1093  return intersects( g );
1094 }
1095 
1096 bool QgsGeometry::intersects( const QgsGeometry &geometry ) const
1097 {
1098  if ( !d->geometry || geometry.isNull() )
1099  {
1100  return false;
1101  }
1102 
1103  QgsGeos geos( d->geometry.get() );
1104  mLastError.clear();
1105  return geos.intersects( geometry.d->geometry.get(), &mLastError );
1106 }
1107 
1108 bool QgsGeometry::boundingBoxIntersects( const QgsRectangle &rectangle ) const
1109 {
1110  if ( !d->geometry )
1111  {
1112  return false;
1113  }
1114 
1115  return d->geometry->boundingBox().intersects( rectangle );
1116 }
1117 
1119 {
1120  if ( !d->geometry || geometry.isNull() )
1121  {
1122  return false;
1123  }
1124 
1125  return d->geometry->boundingBox().intersects( geometry.constGet()->boundingBox() );
1126 }
1127 
1128 bool QgsGeometry::contains( const QgsPointXY *p ) const
1129 {
1130  if ( !d->geometry || !p )
1131  {
1132  return false;
1133  }
1134 
1135  QgsPoint pt( p->x(), p->y() );
1136  QgsGeos geos( d->geometry.get() );
1137  mLastError.clear();
1138  return geos.contains( &pt, &mLastError );
1139 }
1140 
1141 bool QgsGeometry::contains( const QgsGeometry &geometry ) const
1142 {
1143  if ( !d->geometry || geometry.isNull() )
1144  {
1145  return false;
1146  }
1147 
1148  QgsGeos geos( d->geometry.get() );
1149  mLastError.clear();
1150  return geos.contains( geometry.d->geometry.get(), &mLastError );
1151 }
1152 
1153 bool QgsGeometry::disjoint( const QgsGeometry &geometry ) const
1154 {
1155  if ( !d->geometry || geometry.isNull() )
1156  {
1157  return false;
1158  }
1159 
1160  QgsGeos geos( d->geometry.get() );
1161  mLastError.clear();
1162  return geos.disjoint( geometry.d->geometry.get(), &mLastError );
1163 }
1164 
1165 bool QgsGeometry::equals( const QgsGeometry &geometry ) const
1166 {
1167  if ( !d->geometry || geometry.isNull() )
1168  {
1169  return false;
1170  }
1171 
1172  // fast check - are they shared copies of the same underlying geometry?
1173  if ( d == geometry.d )
1174  return true;
1175 
1176  // slower check - actually test the geometries
1177  return *d->geometry.get() == *geometry.d->geometry.get();
1178 }
1179 
1180 bool QgsGeometry::touches( const QgsGeometry &geometry ) const
1181 {
1182  if ( !d->geometry || geometry.isNull() )
1183  {
1184  return false;
1185  }
1186 
1187  QgsGeos geos( d->geometry.get() );
1188  mLastError.clear();
1189  return geos.touches( geometry.d->geometry.get(), &mLastError );
1190 }
1191 
1192 bool QgsGeometry::overlaps( const QgsGeometry &geometry ) const
1193 {
1194  if ( !d->geometry || geometry.isNull() )
1195  {
1196  return false;
1197  }
1198 
1199  QgsGeos geos( d->geometry.get() );
1200  mLastError.clear();
1201  return geos.overlaps( geometry.d->geometry.get(), &mLastError );
1202 }
1203 
1204 bool QgsGeometry::within( const QgsGeometry &geometry ) const
1205 {
1206  if ( !d->geometry || geometry.isNull() )
1207  {
1208  return false;
1209  }
1210 
1211  QgsGeos geos( d->geometry.get() );
1212  mLastError.clear();
1213  return geos.within( geometry.d->geometry.get(), &mLastError );
1214 }
1215 
1216 bool QgsGeometry::crosses( const QgsGeometry &geometry ) const
1217 {
1218  if ( !d->geometry || geometry.isNull() )
1219  {
1220  return false;
1221  }
1222 
1223  QgsGeos geos( d->geometry.get() );
1224  mLastError.clear();
1225  return geos.crosses( geometry.d->geometry.get(), &mLastError );
1226 }
1227 
1228 QString QgsGeometry::asWkt( int precision ) const
1229 {
1230  if ( !d->geometry )
1231  {
1232  return QString();
1233  }
1234  return d->geometry->asWkt( precision );
1235 }
1236 
1237 QString QgsGeometry::asJson( int precision ) const
1238 {
1239  if ( !d->geometry )
1240  {
1241  return QStringLiteral( "null" );
1242  }
1243  return d->geometry->asJson( precision );
1244 }
1245 
1247 {
1248  switch ( destType )
1249  {
1251  return convertToPoint( destMultipart );
1252 
1254  return convertToLine( destMultipart );
1255 
1257  return convertToPolygon( destMultipart );
1258 
1259  default:
1260  return QgsGeometry();
1261  }
1262 }
1263 
1265 {
1266  if ( !d->geometry )
1267  {
1268  return false;
1269  }
1270 
1271  if ( isMultipart() ) //already multitype, no need to convert
1272  {
1273  return true;
1274  }
1275 
1276  std::unique_ptr< QgsAbstractGeometry >geom = QgsGeometryFactory::geomFromWkbType( QgsWkbTypes::multiType( d->geometry->wkbType() ) );
1277  QgsGeometryCollection *multiGeom = qgsgeometry_cast<QgsGeometryCollection *>( geom.get() );
1278  if ( !multiGeom )
1279  {
1280  return false;
1281  }
1282 
1283  //try to avoid cloning existing geometry whenever we can
1284 
1285  //want to see a magic trick?... gather round kiddies...
1286  detach(); // maybe a clone, hopefully not if we're the only ref to the private data
1287  // now we cheat a bit and steal the private geometry and add it direct to the multigeom
1288  // we can do this because we're the only ref to this geometry, guaranteed by the detach call above
1289  multiGeom->addGeometry( d->geometry.release() );
1290  // and replace it with the multi geometry.
1291  // TADA! a clone free conversion in some cases
1292  d->geometry = std::move( geom );
1293  return true;
1294 }
1295 
1297 {
1298  if ( !d->geometry )
1299  {
1300  return false;
1301  }
1302 
1303  if ( !isMultipart() ) //already single part, no need to convert
1304  {
1305  return true;
1306  }
1307 
1309  if ( !multiGeom || multiGeom->partCount() < 1 )
1310  return false;
1311 
1312  std::unique_ptr< QgsAbstractGeometry > firstPart( multiGeom->geometryN( 0 )->clone() );
1313  reset( std::move( firstPart ) );
1314  return true;
1315 }
1316 
1317 
1319 {
1320  const QgsGeometryCollection *origGeom = qgsgeometry_cast<const QgsGeometryCollection *>( constGet() );
1321  if ( !origGeom )
1322  return false;
1323 
1324  std::unique_ptr<QgsGeometryCollection> resGeom;
1325  switch ( geomType )
1326  {
1328  resGeom = qgis::make_unique<QgsMultiPoint>();
1329  break;
1331  resGeom = qgis::make_unique<QgsMultiLineString>();
1332  break;
1334  resGeom = qgis::make_unique<QgsMultiPolygon>();
1335  break;
1336  default:
1337  break;
1338  }
1339  if ( !resGeom )
1340  return false;
1341 
1342  for ( int i = 0; i < origGeom->numGeometries(); ++i )
1343  {
1344  const QgsAbstractGeometry *g = origGeom->geometryN( i );
1345  if ( QgsWkbTypes::geometryType( g->wkbType() ) == geomType )
1346  resGeom->addGeometry( g->clone() );
1347  }
1348 
1349  set( resGeom.release() );
1350  return true;
1351 }
1352 
1353 
1355 {
1356  if ( !d->geometry || QgsWkbTypes::flatType( d->geometry->wkbType() ) != QgsWkbTypes::Point )
1357  {
1358  return QgsPointXY();
1359  }
1360  QgsPoint *pt = qgsgeometry_cast<QgsPoint *>( d->geometry.get() );
1361  if ( !pt )
1362  {
1363  return QgsPointXY();
1364  }
1365 
1366  return QgsPointXY( pt->x(), pt->y() );
1367 }
1368 
1370 {
1371  QgsPolylineXY polyLine;
1372  if ( !d->geometry )
1373  {
1374  return polyLine;
1375  }
1376 
1377  bool doSegmentation = ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::CompoundCurve
1379  std::unique_ptr< QgsLineString > segmentizedLine;
1380  QgsLineString *line = nullptr;
1381  if ( doSegmentation )
1382  {
1383  QgsCurve *curve = qgsgeometry_cast<QgsCurve *>( d->geometry.get() );
1384  if ( !curve )
1385  {
1386  return polyLine;
1387  }
1388  segmentizedLine.reset( curve->curveToLine() );
1389  line = segmentizedLine.get();
1390  }
1391  else
1392  {
1393  line = qgsgeometry_cast<QgsLineString *>( d->geometry.get() );
1394  if ( !line )
1395  {
1396  return polyLine;
1397  }
1398  }
1399 
1400  int nVertices = line->numPoints();
1401  polyLine.resize( nVertices );
1402  for ( int i = 0; i < nVertices; ++i )
1403  {
1404  polyLine[i].setX( line->xAt( i ) );
1405  polyLine[i].setY( line->yAt( i ) );
1406  }
1407 
1408  return polyLine;
1409 }
1410 
1412 {
1413  if ( !d->geometry )
1414  return QgsPolygonXY();
1415 
1416  bool doSegmentation = ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::CurvePolygon );
1417 
1418  QgsPolygon *p = nullptr;
1419  std::unique_ptr< QgsPolygon > segmentized;
1420  if ( doSegmentation )
1421  {
1422  QgsCurvePolygon *curvePoly = qgsgeometry_cast<QgsCurvePolygon *>( d->geometry.get() );
1423  if ( !curvePoly )
1424  {
1425  return QgsPolygonXY();
1426  }
1427  segmentized.reset( curvePoly->toPolygon() );
1428  p = segmentized.get();
1429  }
1430  else
1431  {
1432  p = qgsgeometry_cast<QgsPolygon *>( d->geometry.get() );
1433  }
1434 
1435  if ( !p )
1436  {
1437  return QgsPolygonXY();
1438  }
1439 
1440  QgsPolygonXY polygon;
1441  convertPolygon( *p, polygon );
1442 
1443  return polygon;
1444 }
1445 
1447 {
1448  if ( !d->geometry || QgsWkbTypes::flatType( d->geometry->wkbType() ) != QgsWkbTypes::MultiPoint )
1449  {
1450  return QgsMultiPointXY();
1451  }
1452 
1453  const QgsMultiPoint *mp = qgsgeometry_cast<QgsMultiPoint *>( d->geometry.get() );
1454  if ( !mp )
1455  {
1456  return QgsMultiPointXY();
1457  }
1458 
1459  int nPoints = mp->numGeometries();
1460  QgsMultiPointXY multiPoint( nPoints );
1461  for ( int i = 0; i < nPoints; ++i )
1462  {
1463  const QgsPoint *pt = static_cast<const QgsPoint *>( mp->geometryN( i ) );
1464  multiPoint[i].setX( pt->x() );
1465  multiPoint[i].setY( pt->y() );
1466  }
1467  return multiPoint;
1468 }
1469 
1471 {
1472  if ( !d->geometry )
1473  {
1474  return QgsMultiPolylineXY();
1475  }
1476 
1477  QgsGeometryCollection *geomCollection = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
1478  if ( !geomCollection )
1479  {
1480  return QgsMultiPolylineXY();
1481  }
1482 
1483  int nLines = geomCollection->numGeometries();
1484  if ( nLines < 1 )
1485  {
1486  return QgsMultiPolylineXY();
1487  }
1488 
1489  QgsMultiPolylineXY mpl;
1490  for ( int i = 0; i < nLines; ++i )
1491  {
1492  const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( geomCollection->geometryN( i ) );
1493  std::unique_ptr< QgsLineString > segmentized;
1494  if ( !line )
1495  {
1496  const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( geomCollection->geometryN( i ) );
1497  if ( !curve )
1498  {
1499  continue;
1500  }
1501  segmentized.reset( curve->curveToLine() );
1502  line = segmentized.get();
1503  }
1504 
1505  QgsPointSequence lineCoords;
1506  line->points( lineCoords );
1507  QgsPolylineXY polyLine;
1508  convertToPolyline( lineCoords, polyLine );
1509  mpl.append( polyLine );
1510  }
1511  return mpl;
1512 }
1513 
1515 {
1516  if ( !d->geometry )
1517  {
1518  return QgsMultiPolygonXY();
1519  }
1520 
1521  QgsGeometryCollection *geomCollection = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
1522  if ( !geomCollection )
1523  {
1524  return QgsMultiPolygonXY();
1525  }
1526 
1527  int nPolygons = geomCollection->numGeometries();
1528  if ( nPolygons < 1 )
1529  {
1530  return QgsMultiPolygonXY();
1531  }
1532 
1533  QgsMultiPolygonXY mp;
1534  for ( int i = 0; i < nPolygons; ++i )
1535  {
1536  const QgsPolygon *polygon = qgsgeometry_cast<const QgsPolygon *>( geomCollection->geometryN( i ) );
1537  if ( !polygon )
1538  {
1539  const QgsCurvePolygon *cPolygon = qgsgeometry_cast<const QgsCurvePolygon *>( geomCollection->geometryN( i ) );
1540  if ( cPolygon )
1541  {
1542  polygon = cPolygon->toPolygon();
1543  }
1544  else
1545  {
1546  continue;
1547  }
1548  }
1549 
1550  QgsPolygonXY poly;
1551  convertPolygon( *polygon, poly );
1552  mp.append( poly );
1553  }
1554  return mp;
1555 }
1556 
1557 double QgsGeometry::area() const
1558 {
1559  if ( !d->geometry )
1560  {
1561  return -1.0;
1562  }
1563  QgsGeos g( d->geometry.get() );
1564 
1565 #if 0
1566  //debug: compare geos area with calculation in QGIS
1567  double geosArea = g.area();
1568  double qgisArea = 0;
1569  QgsSurface *surface = qgsgeometry_cast<QgsSurface *>( d->geometry );
1570  if ( surface )
1571  {
1572  qgisArea = surface->area();
1573  }
1574 #endif
1575 
1576  mLastError.clear();
1577  return g.area( &mLastError );
1578 }
1579 
1580 double QgsGeometry::length() const
1581 {
1582  if ( !d->geometry )
1583  {
1584  return -1.0;
1585  }
1586  QgsGeos g( d->geometry.get() );
1587  mLastError.clear();
1588  return g.length( &mLastError );
1589 }
1590 
1591 double QgsGeometry::distance( const QgsGeometry &geom ) const
1592 {
1593  if ( !d->geometry || !geom.d->geometry )
1594  {
1595  return -1.0;
1596  }
1597 
1598  // avoid calling geos for trivial point-to-point distance calculations
1600  {
1601  return qgsgeometry_cast< const QgsPoint * >( d->geometry.get() )->distance( *qgsgeometry_cast< const QgsPoint * >( geom.constGet() ) );
1602  }
1603 
1604  QgsGeos g( d->geometry.get() );
1605  mLastError.clear();
1606  return g.distance( geom.d->geometry.get(), &mLastError );
1607 }
1608 
1609 double QgsGeometry::hausdorffDistance( const QgsGeometry &geom ) const
1610 {
1611  if ( !d->geometry || !geom.d->geometry )
1612  {
1613  return -1.0;
1614  }
1615 
1616  QgsGeos g( d->geometry.get() );
1617  mLastError.clear();
1618  return g.hausdorffDistance( geom.d->geometry.get(), &mLastError );
1619 }
1620 
1621 double QgsGeometry::hausdorffDistanceDensify( const QgsGeometry &geom, double densifyFraction ) const
1622 {
1623  if ( !d->geometry || !geom.d->geometry )
1624  {
1625  return -1.0;
1626  }
1627 
1628  QgsGeos g( d->geometry.get() );
1629  mLastError.clear();
1630  return g.hausdorffDistanceDensify( geom.d->geometry.get(), densifyFraction, &mLastError );
1631 }
1632 
1634 {
1635  if ( !d->geometry )
1637  return d->geometry->vertices_begin();
1638 }
1639 
1641 {
1642  if ( !d->geometry )
1644  return d->geometry->vertices_end();
1645 }
1646 
1648 {
1649  if ( !d->geometry )
1650  return QgsVertexIterator();
1651  return QgsVertexIterator( d->geometry.get() );
1652 }
1653 
1654 QgsGeometry QgsGeometry::buffer( double distance, int segments ) const
1655 {
1656  if ( !d->geometry )
1657  {
1658  return QgsGeometry();
1659  }
1660 
1661  QgsGeos g( d->geometry.get() );
1662  mLastError.clear();
1663  std::unique_ptr<QgsAbstractGeometry> geom( g.buffer( distance, segments, &mLastError ) );
1664  if ( !geom )
1665  {
1666  QgsGeometry result;
1667  result.mLastError = mLastError;
1668  return result;
1669  }
1670  return QgsGeometry( std::move( geom ) );
1671 }
1672 
1673 QgsGeometry QgsGeometry::buffer( double distance, int segments, EndCapStyle endCapStyle, JoinStyle joinStyle, double miterLimit ) const
1674 {
1675  if ( !d->geometry )
1676  {
1677  return QgsGeometry();
1678  }
1679 
1680  QgsGeos g( d->geometry.get() );
1681  mLastError.clear();
1682  QgsAbstractGeometry *geom = g.buffer( distance, segments, endCapStyle, joinStyle, miterLimit, &mLastError );
1683  if ( !geom )
1684  {
1685  QgsGeometry result;
1686  result.mLastError = mLastError;
1687  return result;
1688  }
1689  return QgsGeometry( geom );
1690 }
1691 
1692 QgsGeometry QgsGeometry::offsetCurve( double distance, int segments, 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  results.reserve( parts.count() );
1704  for ( const QgsGeometry &part : parts )
1705  {
1706  QgsGeometry result = part.offsetCurve( distance, segments, joinStyle, miterLimit );
1707  if ( result )
1708  results << result;
1709  }
1710  if ( results.isEmpty() )
1711  return QgsGeometry();
1712 
1713  QgsGeometry first = results.takeAt( 0 );
1714  for ( const QgsGeometry &result : qgis::as_const( results ) )
1715  {
1716  first.addPart( result );
1717  }
1718  return first;
1719  }
1720  else
1721  {
1722  QgsGeos geos( d->geometry.get() );
1723  mLastError.clear();
1724  QgsAbstractGeometry *offsetGeom = geos.offsetCurve( distance, segments, joinStyle, miterLimit, &mLastError );
1725  if ( !offsetGeom )
1726  {
1727  QgsGeometry result;
1728  result.mLastError = mLastError;
1729  return result;
1730  }
1731  return QgsGeometry( offsetGeom );
1732  }
1733 }
1734 
1735 QgsGeometry QgsGeometry::singleSidedBuffer( double distance, int segments, BufferSide side, JoinStyle joinStyle, double miterLimit ) 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  results.reserve( parts.count() );
1747  for ( const QgsGeometry &part : parts )
1748  {
1749  QgsGeometry result = part.singleSidedBuffer( distance, segments, side, joinStyle, miterLimit );
1750  if ( result )
1751  results << result;
1752  }
1753  if ( results.isEmpty() )
1754  return QgsGeometry();
1755 
1756  QgsGeometry first = results.takeAt( 0 );
1757  for ( const QgsGeometry &result : qgis::as_const( results ) )
1758  {
1759  first.addPart( result );
1760  }
1761  return first;
1762  }
1763  else
1764  {
1765  QgsGeos geos( d->geometry.get() );
1766  mLastError.clear();
1767  std::unique_ptr< QgsAbstractGeometry > bufferGeom = geos.singleSidedBuffer( distance, segments, side,
1768  joinStyle, miterLimit, &mLastError );
1769  if ( !bufferGeom )
1770  {
1771  QgsGeometry result;
1772  result.mLastError = mLastError;
1773  return result;
1774  }
1775  return QgsGeometry( std::move( bufferGeom ) );
1776  }
1777 }
1778 
1779 QgsGeometry QgsGeometry::taperedBuffer( double startWidth, double endWidth, int segments ) const
1780 {
1781  QgsInternalGeometryEngine engine( *this );
1782 
1783  return engine.taperedBuffer( startWidth, endWidth, segments );
1784 }
1785 
1787 {
1788  QgsInternalGeometryEngine engine( *this );
1789 
1790  return engine.variableWidthBufferByM( segments );
1791 }
1792 
1793 QgsGeometry QgsGeometry::extendLine( double startDistance, double endDistance ) const
1794 {
1795  if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
1796  {
1797  return QgsGeometry();
1798  }
1799 
1800  if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
1801  {
1802  const QVector<QgsGeometry> parts = asGeometryCollection();
1803  QVector<QgsGeometry> results;
1804  results.reserve( parts.count() );
1805  for ( const QgsGeometry &part : parts )
1806  {
1807  QgsGeometry result = part.extendLine( startDistance, endDistance );
1808  if ( result )
1809  results << result;
1810  }
1811  if ( results.isEmpty() )
1812  return QgsGeometry();
1813 
1814  QgsGeometry first = results.takeAt( 0 );
1815  for ( const QgsGeometry &result : qgis::as_const( results ) )
1816  {
1817  first.addPart( result );
1818  }
1819  return first;
1820  }
1821  else
1822  {
1823  QgsLineString *line = qgsgeometry_cast< QgsLineString * >( d->geometry.get() );
1824  if ( !line )
1825  return QgsGeometry();
1826 
1827  std::unique_ptr< QgsLineString > newLine( line->clone() );
1828  newLine->extend( startDistance, endDistance );
1829  return QgsGeometry( std::move( newLine ) );
1830  }
1831 }
1832 
1833 QgsGeometry QgsGeometry::simplify( double tolerance ) const
1834 {
1835  if ( !d->geometry )
1836  {
1837  return QgsGeometry();
1838  }
1839 
1840  QgsGeos geos( d->geometry.get() );
1841  mLastError.clear();
1842  std::unique_ptr< QgsAbstractGeometry > simplifiedGeom( geos.simplify( tolerance, &mLastError ) );
1843  if ( !simplifiedGeom )
1844  {
1845  QgsGeometry result;
1846  result.mLastError = mLastError;
1847  return result;
1848  }
1849  return QgsGeometry( std::move( simplifiedGeom ) );
1850 }
1851 
1852 QgsGeometry QgsGeometry::densifyByCount( int extraNodesPerSegment ) const
1853 {
1854  QgsInternalGeometryEngine engine( *this );
1855 
1856  return engine.densifyByCount( extraNodesPerSegment );
1857 }
1858 
1860 {
1861  QgsInternalGeometryEngine engine( *this );
1862 
1863  return engine.densifyByDistance( distance );
1864 }
1865 
1867 {
1868  if ( !d->geometry )
1869  {
1870  return QgsGeometry();
1871  }
1872 
1873  QgsGeos geos( d->geometry.get() );
1874 
1875  mLastError.clear();
1876  QgsGeometry result( geos.centroid( &mLastError ) );
1877  result.mLastError = mLastError;
1878  return result;
1879 }
1880 
1882 {
1883  if ( !d->geometry )
1884  {
1885  return QgsGeometry();
1886  }
1887 
1888  QgsGeos geos( d->geometry.get() );
1889 
1890  mLastError.clear();
1891  QgsGeometry result( geos.pointOnSurface( &mLastError ) );
1892  result.mLastError = mLastError;
1893  return result;
1894 }
1895 
1896 QgsGeometry QgsGeometry::poleOfInaccessibility( double precision, double *distanceToBoundary ) const
1897 {
1898  QgsInternalGeometryEngine engine( *this );
1899 
1900  return engine.poleOfInaccessibility( precision, distanceToBoundary );
1901 }
1902 
1904 {
1905  if ( !d->geometry )
1906  {
1907  return QgsGeometry();
1908  }
1909  QgsGeos geos( d->geometry.get() );
1910  mLastError.clear();
1911  std::unique_ptr< QgsAbstractGeometry > cHull( geos.convexHull( &mLastError ) );
1912  if ( !cHull )
1913  {
1914  QgsGeometry geom;
1915  geom.mLastError = mLastError;
1916  return geom;
1917  }
1918  return QgsGeometry( std::move( cHull ) );
1919 }
1920 
1921 QgsGeometry QgsGeometry::voronoiDiagram( const QgsGeometry &extent, double tolerance, bool edgesOnly ) const
1922 {
1923  if ( !d->geometry )
1924  {
1925  return QgsGeometry();
1926  }
1927 
1928  QgsGeos geos( d->geometry.get() );
1929  mLastError.clear();
1930  QgsGeometry result = geos.voronoiDiagram( extent.constGet(), tolerance, edgesOnly, &mLastError );
1931  result.mLastError = mLastError;
1932  return result;
1933 }
1934 
1935 QgsGeometry QgsGeometry::delaunayTriangulation( double tolerance, bool edgesOnly ) const
1936 {
1937  if ( !d->geometry )
1938  {
1939  return QgsGeometry();
1940  }
1941 
1942  QgsGeos geos( d->geometry.get() );
1943  mLastError.clear();
1944  QgsGeometry result = geos.delaunayTriangulation( tolerance, edgesOnly );
1945  result.mLastError = mLastError;
1946  return result;
1947 }
1948 
1950 {
1951  if ( !d->geometry )
1952  {
1953  return QgsGeometry();
1954  }
1955 
1956  const QgsAbstractGeometry *geom = d->geometry.get();
1957  std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
1958  if ( QgsWkbTypes::isCurvedType( d->geometry->wkbType() ) )
1959  {
1960  segmentizedCopy.reset( d->geometry->segmentize() );
1961  geom = segmentizedCopy.get();
1962  }
1963 
1964  QgsGeos geos( geom );
1965  mLastError.clear();
1966  std::unique_ptr< QgsAbstractGeometry > result( geos.subdivide( maxNodes, &mLastError ) );
1967  if ( !result )
1968  {
1969  QgsGeometry geom;
1970  geom.mLastError = mLastError;
1971  return geom;
1972  }
1973  return QgsGeometry( std::move( result ) );
1974 }
1975 
1977 {
1978  if ( !d->geometry )
1979  {
1980  return QgsGeometry();
1981  }
1982 
1983  QgsGeometry line = *this;
1985  line = QgsGeometry( d->geometry->boundary() );
1986 
1987  QgsGeos geos( line.constGet() );
1988  mLastError.clear();
1989  std::unique_ptr< QgsAbstractGeometry > result( geos.interpolate( distance, &mLastError ) );
1990  if ( !result )
1991  {
1992  QgsGeometry geom;
1993  geom.mLastError = mLastError;
1994  return geom;
1995  }
1996  return QgsGeometry( std::move( result ) );
1997 }
1998 
1999 double QgsGeometry::lineLocatePoint( const QgsGeometry &point ) const
2000 {
2001  if ( type() != QgsWkbTypes::LineGeometry )
2002  return -1;
2003 
2004  if ( QgsWkbTypes::flatType( point.wkbType() ) != QgsWkbTypes::Point )
2005  return -1;
2006 
2007  QgsGeometry segmentized = *this;
2009  {
2010  segmentized = QgsGeometry( static_cast< QgsCurve * >( d->geometry.get() )->segmentize() );
2011  }
2012 
2013  QgsGeos geos( d->geometry.get() );
2014  mLastError.clear();
2015  return geos.lineLocatePoint( *( static_cast< QgsPoint * >( point.d->geometry.get() ) ), &mLastError );
2016 }
2017 
2019 {
2020  if ( !d->geometry )
2021  return 0.0;
2022 
2023  // always operate on segmentized geometries
2024  QgsGeometry segmentized = *this;
2026  {
2027  segmentized = QgsGeometry( static_cast< QgsCurve * >( d->geometry.get() )->segmentize() );
2028  }
2029 
2030  QgsVertexId previous;
2031  QgsVertexId next;
2032  if ( !QgsGeometryUtils::verticesAtDistance( *segmentized.constGet(), distance, previous, next ) )
2033  return 0.0;
2034 
2035  if ( previous == next )
2036  {
2037  // distance coincided exactly with a vertex
2038  QgsVertexId v2 = previous;
2039  QgsVertexId v1;
2040  QgsVertexId v3;
2041  segmentized.constGet()->adjacentVertices( v2, v1, v3 );
2042  if ( v1.isValid() && v3.isValid() )
2043  {
2044  QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
2045  QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
2046  QgsPoint p3 = segmentized.constGet()->vertexAt( v3 );
2047  double angle1 = QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2048  double angle2 = QgsGeometryUtils::lineAngle( p2.x(), p2.y(), p3.x(), p3.y() );
2049  return QgsGeometryUtils::averageAngle( angle1, angle2 );
2050  }
2051  else if ( v3.isValid() )
2052  {
2053  QgsPoint p1 = segmentized.constGet()->vertexAt( v2 );
2054  QgsPoint p2 = segmentized.constGet()->vertexAt( v3 );
2055  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2056  }
2057  else
2058  {
2059  QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
2060  QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
2061  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2062  }
2063  }
2064  else
2065  {
2066  QgsPoint p1 = segmentized.constGet()->vertexAt( previous );
2067  QgsPoint p2 = segmentized.constGet()->vertexAt( next );
2068  return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2069  }
2070 }
2071 
2073 {
2074  if ( !d->geometry || geometry.isNull() )
2075  {
2076  return QgsGeometry();
2077  }
2078 
2079  QgsGeos geos( d->geometry.get() );
2080 
2081  mLastError.clear();
2082  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.intersection( geometry.d->geometry.get(), &mLastError ) );
2083 
2084  if ( !resultGeom )
2085  {
2086  QgsGeometry geom;
2087  geom.mLastError = mLastError;
2088  return geom;
2089  }
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  mLastError.clear();
2103  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.combine( geometry.d->geometry.get(), &mLastError ) );
2104  if ( !resultGeom )
2105  {
2106  QgsGeometry geom;
2107  geom.mLastError = mLastError;
2108  return geom;
2109  }
2110  return QgsGeometry( std::move( resultGeom ) );
2111 }
2112 
2114 {
2115  if ( !d->geometry )
2116  {
2117  return QgsGeometry();
2118  }
2119 
2120  if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::LineString )
2121  {
2122  // special case - a single linestring was passed
2123  return QgsGeometry( *this );
2124  }
2125 
2126  QgsGeos geos( d->geometry.get() );
2127  mLastError.clear();
2128  QgsGeometry result = geos.mergeLines( &mLastError );
2129  result.mLastError = mLastError;
2130  return result;
2131 }
2132 
2134 {
2135  if ( !d->geometry || geometry.isNull() )
2136  {
2137  return QgsGeometry();
2138  }
2139 
2140  QgsGeos geos( d->geometry.get() );
2141 
2142  mLastError.clear();
2143  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.difference( geometry.d->geometry.get(), &mLastError ) );
2144  if ( !resultGeom )
2145  {
2146  QgsGeometry geom;
2147  geom.mLastError = mLastError;
2148  return geom;
2149  }
2150  return QgsGeometry( std::move( resultGeom ) );
2151 }
2152 
2154 {
2155  if ( !d->geometry || geometry.isNull() )
2156  {
2157  return QgsGeometry();
2158  }
2159 
2160  QgsGeos geos( d->geometry.get() );
2161 
2162  mLastError.clear();
2163  std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.symDifference( geometry.d->geometry.get(), &mLastError ) );
2164  if ( !resultGeom )
2165  {
2166  QgsGeometry geom;
2167  geom.mLastError = mLastError;
2168  return geom;
2169  }
2170  return QgsGeometry( std::move( resultGeom ) );
2171 }
2172 
2173 QgsGeometry QgsGeometry::extrude( double x, double y )
2174 {
2175  QgsInternalGeometryEngine engine( *this );
2176 
2177  return engine.extrude( x, y );
2178 }
2179 
2180 QByteArray QgsGeometry::asWkb() const
2181 {
2182  return d->geometry ? d->geometry->asWkb() : QByteArray();
2183 }
2184 
2185 QVector<QgsGeometry> QgsGeometry::asGeometryCollection() const
2186 {
2187  QVector<QgsGeometry> geometryList;
2188  if ( !d->geometry )
2189  {
2190  return geometryList;
2191  }
2192 
2194  if ( gc )
2195  {
2196  int numGeom = gc->numGeometries();
2197  geometryList.reserve( numGeom );
2198  for ( int i = 0; i < numGeom; ++i )
2199  {
2200  geometryList.append( QgsGeometry( gc->geometryN( i )->clone() ) );
2201  }
2202  }
2203  else //a singlepart geometry
2204  {
2205  geometryList.append( *this );
2206  }
2207 
2208  return geometryList;
2209 }
2210 
2211 QPointF QgsGeometry::asQPointF() const
2212 {
2213  QgsPointXY point = asPoint();
2214  return point.toQPointF();
2215 }
2216 
2217 QPolygonF QgsGeometry::asQPolygonF() const
2218 {
2219  QPolygonF result;
2220  QgsPolylineXY polyline;
2222  if ( type == QgsWkbTypes::LineString || type == QgsWkbTypes::LineString25D )
2223  {
2224  polyline = asPolyline();
2225  }
2226  else if ( type == QgsWkbTypes::Polygon || type == QgsWkbTypes::Polygon25D )
2227  {
2228  QgsPolygonXY polygon = asPolygon();
2229  if ( polygon.empty() )
2230  return result;
2231  polyline = polygon.at( 0 );
2232  }
2233  else
2234  {
2235  return result;
2236  }
2237 
2238  result.reserve( polyline.count() );
2239  for ( const QgsPointXY &p : qgis::as_const( polyline ) )
2240  {
2241  result << p.toQPointF();
2242  }
2243  return result;
2244 }
2245 
2246 bool QgsGeometry::deleteRing( int ringNum, int partNum )
2247 {
2248  if ( !d->geometry )
2249  {
2250  return false;
2251  }
2252 
2253  detach();
2254  bool ok = QgsGeometryEditUtils::deleteRing( d->geometry.get(), ringNum, partNum );
2255  return ok;
2256 }
2257 
2258 bool QgsGeometry::deletePart( int partNum )
2259 {
2260  if ( !d->geometry )
2261  {
2262  return false;
2263  }
2264 
2265  if ( !isMultipart() && partNum < 1 )
2266  {
2267  set( nullptr );
2268  return true;
2269  }
2270 
2271  detach();
2272  bool ok = QgsGeometryEditUtils::deletePart( d->geometry.get(), partNum );
2273  return ok;
2274 }
2275 
2276 int QgsGeometry::avoidIntersections( const QList<QgsVectorLayer *> &avoidIntersectionsLayers, const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures )
2277 {
2278  if ( !d->geometry )
2279  {
2280  return 1;
2281  }
2282 
2283  std::unique_ptr< QgsAbstractGeometry > diffGeom = QgsGeometryEditUtils::avoidIntersections( *( d->geometry ), avoidIntersectionsLayers, ignoreFeatures );
2284  if ( diffGeom )
2285  {
2286  reset( std::move( diffGeom ) );
2287  }
2288  return 0;
2289 }
2290 
2291 
2293 {
2294  if ( !d->geometry )
2295  return QgsGeometry();
2296 
2297  mLastError.clear();
2298  std::unique_ptr< QgsAbstractGeometry > g( _qgis_lwgeom_make_valid( d->geometry.get(), mLastError ) );
2299 
2300  QgsGeometry result = QgsGeometry( std::move( g ) );
2301  result.mLastError = mLastError;
2302  return result;
2303 }
2304 
2305 
2306 void QgsGeometry::validateGeometry( QVector<QgsGeometry::Error> &errors, ValidationMethod method ) const
2307 {
2308  QgsGeometryValidator::validateGeometry( *this, errors, method );
2309 }
2310 
2312 {
2313  if ( !d->geometry )
2314  {
2315  return false;
2316  }
2317 
2318  QgsGeos geos( d->geometry.get() );
2319  mLastError.clear();
2320  return geos.isValid( &mLastError );
2321 }
2322 
2324 {
2325  if ( !d->geometry )
2326  return false;
2327 
2328  QgsGeos geos( d->geometry.get() );
2329  mLastError.clear();
2330  return geos.isSimple( &mLastError );
2331 }
2332 
2334 {
2335  if ( !d->geometry || !g.d->geometry )
2336  {
2337  return false;
2338  }
2339 
2340  QgsGeos geos( d->geometry.get() );
2341  mLastError.clear();
2342  return geos.isEqual( g.d->geometry.get(), &mLastError );
2343 }
2344 
2345 QgsGeometry QgsGeometry::unaryUnion( const QVector<QgsGeometry> &geometries )
2346 {
2347  QgsGeos geos( nullptr );
2348 
2349  QString error;
2350  std::unique_ptr< QgsAbstractGeometry > geom( geos.combine( geometries, &error ) );
2351  QgsGeometry result( std::move( geom ) );
2352  result.mLastError = error;
2353  return result;
2354 }
2355 
2356 QgsGeometry QgsGeometry::polygonize( const QVector<QgsGeometry> &geometryList )
2357 {
2358  QgsGeos geos( nullptr );
2359 
2360  QVector<const QgsAbstractGeometry *> geomV2List;
2361  for ( const QgsGeometry &g : geometryList )
2362  {
2363  if ( !( g.isNull() ) )
2364  {
2365  geomV2List.append( g.constGet() );
2366  }
2367  }
2368 
2369  QString error;
2370  QgsGeometry result = geos.polygonize( geomV2List, &error );
2371  result.mLastError = error;
2372  return result;
2373 }
2374 
2376 {
2378  {
2379  return;
2380  }
2381 
2382  std::unique_ptr< QgsAbstractGeometry > straightGeom( d->geometry->segmentize( tolerance, toleranceType ) );
2383  reset( std::move( straightGeom ) );
2384 }
2385 
2387 {
2388  if ( !d->geometry )
2389  {
2390  return false;
2391  }
2392 
2393  return d->geometry->hasCurvedSegments();
2394 }
2395 
2397 {
2398  if ( !d->geometry )
2399  {
2401  }
2402 
2403  detach();
2404  d->geometry->transform( ct, direction, transformZ );
2405  return QgsGeometry::Success;
2406 }
2407 
2408 QgsGeometry::OperationResult QgsGeometry::transform( const QTransform &ct, double zTranslate, double zScale, double mTranslate, double mScale )
2409 {
2410  if ( !d->geometry )
2411  {
2413  }
2414 
2415  detach();
2416  d->geometry->transform( ct, zTranslate, zScale, mTranslate, mScale );
2417  return QgsGeometry::Success;
2418 }
2419 
2421 {
2422  if ( d->geometry )
2423  {
2424  detach();
2425  d->geometry->transform( mtp.transform() );
2426  }
2427 }
2428 
2430 {
2431  if ( !d->geometry || rectangle.isNull() || rectangle.isEmpty() )
2432  {
2433  return QgsGeometry();
2434  }
2435 
2436  QgsGeos geos( d->geometry.get() );
2437  mLastError.clear();
2438  std::unique_ptr< QgsAbstractGeometry > resultGeom = geos.clip( rectangle, &mLastError );
2439  if ( !resultGeom )
2440  {
2441  QgsGeometry result;
2442  result.mLastError = mLastError;
2443  return result;
2444  }
2445  return QgsGeometry( std::move( resultGeom ) );
2446 }
2447 
2448 void QgsGeometry::draw( QPainter &p ) const
2449 {
2450  if ( d->geometry )
2451  {
2452  d->geometry->draw( p );
2453  }
2454 }
2455 
2456 static bool vertexIndexInfo( const QgsAbstractGeometry *g, int vertexIndex, int &partIndex, int &ringIndex, int &vertex )
2457 {
2458  if ( vertexIndex < 0 )
2459  return false; // clearly something wrong
2460 
2461  if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
2462  {
2463  partIndex = 0;
2464  int offset = 0;
2465  for ( int i = 0; i < geomCollection->numGeometries(); ++i )
2466  {
2467  const QgsAbstractGeometry *part = geomCollection->geometryN( i );
2468 
2469  // count total number of vertices in the part
2470  int numPoints = 0;
2471  for ( int k = 0; k < part->ringCount(); ++k )
2472  numPoints += part->vertexCount( 0, k );
2473 
2474  if ( vertexIndex < numPoints )
2475  {
2476  int nothing;
2477  return vertexIndexInfo( part, vertexIndex, nothing, ringIndex, vertex ); // set ring_index + index
2478  }
2479  vertexIndex -= numPoints;
2480  offset += numPoints;
2481  partIndex++;
2482  }
2483  }
2484  else if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
2485  {
2486  const QgsCurve *ring = curvePolygon->exteriorRing();
2487  if ( vertexIndex < ring->numPoints() )
2488  {
2489  partIndex = 0;
2490  ringIndex = 0;
2491  vertex = vertexIndex;
2492  return true;
2493  }
2494  vertexIndex -= ring->numPoints();
2495  ringIndex = 1;
2496  for ( int i = 0; i < curvePolygon->numInteriorRings(); ++i )
2497  {
2498  const QgsCurve *ring = curvePolygon->interiorRing( i );
2499  if ( vertexIndex < ring->numPoints() )
2500  {
2501  partIndex = 0;
2502  vertex = vertexIndex;
2503  return true;
2504  }
2505  vertexIndex -= ring->numPoints();
2506  ringIndex += 1;
2507  }
2508  }
2509  else if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
2510  {
2511  if ( vertexIndex < curve->numPoints() )
2512  {
2513  partIndex = 0;
2514  ringIndex = 0;
2515  vertex = vertexIndex;
2516  return true;
2517  }
2518  }
2519  else if ( qgsgeometry_cast<const QgsPoint *>( g ) )
2520  {
2521  if ( vertexIndex == 0 )
2522  {
2523  partIndex = 0;
2524  ringIndex = 0;
2525  vertex = 0;
2526  return true;
2527  }
2528  }
2529 
2530  return false;
2531 }
2532 
2534 {
2535  if ( !d->geometry )
2536  {
2537  return false;
2538  }
2539 
2540  id.type = QgsVertexId::SegmentVertex;
2541 
2542  bool res = vertexIndexInfo( d->geometry.get(), nr, id.part, id.ring, id.vertex );
2543  if ( !res )
2544  return false;
2545 
2546  // now let's find out if it is a straight or circular segment
2547  const QgsAbstractGeometry *g = d->geometry.get();
2548  if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
2549  {
2550  g = geomCollection->geometryN( id.part );
2551  }
2552 
2553  if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
2554  {
2555  g = id.ring == 0 ? curvePolygon->exteriorRing() : curvePolygon->interiorRing( id.ring - 1 );
2556  }
2557 
2558  if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
2559  {
2560  QgsPoint p;
2561  res = curve->pointAt( id.vertex, p, id.type );
2562  if ( !res )
2563  return false;
2564  }
2565 
2566  return true;
2567 }
2568 
2570 {
2571  if ( !d->geometry )
2572  {
2573  return -1;
2574  }
2575  return d->geometry->vertexNumberFromVertexId( id );
2576 }
2577 
2578 QString QgsGeometry::lastError() const
2579 {
2580  return mLastError;
2581 }
2582 
2583 void QgsGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
2584 {
2585  if ( !d->geometry )
2586  return;
2587 
2588  detach();
2589 
2590  d->geometry->filterVertices( filter );
2591 }
2592 
2593 void QgsGeometry::convertPointList( const QVector<QgsPointXY> &input, QgsPointSequence &output )
2594 {
2595  output.clear();
2596  for ( const QgsPointXY &p : input )
2597  {
2598  output.append( QgsPoint( p ) );
2599  }
2600 }
2601 
2602 void QgsGeometry::convertPointList( const QgsPointSequence &input, QVector<QgsPointXY> &output )
2603 {
2604  output.clear();
2605  for ( const QgsPoint &p : input )
2606  {
2607  output.append( QgsPointXY( p.x(), p.y() ) );
2608  }
2609 }
2610 
2611 QgsGeometry::operator bool() const
2612 {
2613  return d->geometry.get();
2614 }
2615 
2616 void QgsGeometry::convertToPolyline( const QgsPointSequence &input, QgsPolylineXY &output )
2617 {
2618  output.clear();
2619  output.resize( input.size() );
2620 
2621  for ( int i = 0; i < input.size(); ++i )
2622  {
2623  const QgsPoint &pt = input.at( i );
2624  output[i].setX( pt.x() );
2625  output[i].setY( pt.y() );
2626  }
2627 }
2628 
2629 void QgsGeometry::convertPolygon( const QgsPolygon &input, QgsPolygonXY &output )
2630 {
2631  output.clear();
2632  QgsCoordinateSequence coords = input.coordinateSequence();
2633  if ( coords.empty() )
2634  {
2635  return;
2636  }
2637  const QgsRingSequence &rings = coords[0];
2638  output.resize( rings.size() );
2639  for ( int i = 0; i < rings.size(); ++i )
2640  {
2641  convertToPolyline( rings[i], output[i] );
2642  }
2643 }
2644 
2646 {
2647  return QgsGeometry( qgis::make_unique< QgsPoint >( point.x(), point.y() ) );
2648 }
2649 
2650 QgsGeometry QgsGeometry::fromQPolygonF( const QPolygonF &polygon )
2651 {
2652  if ( polygon.isClosed() )
2653  {
2655  }
2656  else
2657  {
2659  }
2660 }
2661 
2663 {
2664  QgsPolygonXY result;
2665  result << createPolylineFromQPolygonF( polygon );
2666  return result;
2667 }
2668 
2670 {
2671  QgsPolylineXY result;
2672  result.reserve( polygon.count() );
2673  for ( const QPointF &p : polygon )
2674  {
2675  result.append( QgsPointXY( p ) );
2676  }
2677  return result;
2678 }
2679 
2680 bool QgsGeometry::compare( const QgsPolylineXY &p1, const QgsPolylineXY &p2, double epsilon )
2681 {
2682  if ( p1.count() != p2.count() )
2683  return false;
2684 
2685  for ( int i = 0; i < p1.count(); ++i )
2686  {
2687  if ( !p1.at( i ).compare( p2.at( i ), epsilon ) )
2688  return false;
2689  }
2690  return true;
2691 }
2692 
2693 bool QgsGeometry::compare( const QgsPolygonXY &p1, const QgsPolygonXY &p2, double epsilon )
2694 {
2695  if ( p1.count() != p2.count() )
2696  return false;
2697 
2698  for ( int i = 0; i < p1.count(); ++i )
2699  {
2700  if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
2701  return false;
2702  }
2703  return true;
2704 }
2705 
2706 
2707 bool QgsGeometry::compare( const QgsMultiPolygonXY &p1, const QgsMultiPolygonXY &p2, double epsilon )
2708 {
2709  if ( p1.count() != p2.count() )
2710  return false;
2711 
2712  for ( int i = 0; i < p1.count(); ++i )
2713  {
2714  if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
2715  return false;
2716  }
2717  return true;
2718 }
2719 
2720 QgsGeometry QgsGeometry::smooth( const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
2721 {
2722  if ( !d->geometry || d->geometry->isEmpty() )
2723  return QgsGeometry();
2724 
2725  QgsGeometry geom = *this;
2727  geom = QgsGeometry( d->geometry->segmentize() );
2728 
2729  switch ( QgsWkbTypes::flatType( geom.wkbType() ) )
2730  {
2731  case QgsWkbTypes::Point:
2733  //can't smooth a point based geometry
2734  return geom;
2735 
2737  {
2738  QgsLineString *lineString = static_cast< QgsLineString * >( d->geometry.get() );
2739  return QgsGeometry( smoothLine( *lineString, iterations, offset, minimumDistance, maxAngle ) );
2740  }
2741 
2743  {
2744  QgsMultiLineString *multiLine = static_cast< QgsMultiLineString * >( d->geometry.get() );
2745 
2746  std::unique_ptr< QgsMultiLineString > resultMultiline = qgis::make_unique< QgsMultiLineString> ();
2747  for ( int i = 0; i < multiLine->numGeometries(); ++i )
2748  {
2749  resultMultiline->addGeometry( smoothLine( *( static_cast< QgsLineString * >( multiLine->geometryN( i ) ) ), iterations, offset, minimumDistance, maxAngle ).release() );
2750  }
2751  return QgsGeometry( std::move( resultMultiline ) );
2752  }
2753 
2754  case QgsWkbTypes::Polygon:
2755  {
2756  QgsPolygon *poly = static_cast< QgsPolygon * >( d->geometry.get() );
2757  return QgsGeometry( smoothPolygon( *poly, iterations, offset, minimumDistance, maxAngle ) );
2758  }
2759 
2761  {
2762  QgsMultiPolygon *multiPoly = static_cast< QgsMultiPolygon * >( d->geometry.get() );
2763 
2764  std::unique_ptr< QgsMultiPolygon > resultMultiPoly = qgis::make_unique< QgsMultiPolygon >();
2765  for ( int i = 0; i < multiPoly->numGeometries(); ++i )
2766  {
2767  resultMultiPoly->addGeometry( smoothPolygon( *( static_cast< QgsPolygon * >( multiPoly->geometryN( i ) ) ), iterations, offset, minimumDistance, maxAngle ).release() );
2768  }
2769  return QgsGeometry( std::move( resultMultiPoly ) );
2770  }
2771 
2772  case QgsWkbTypes::Unknown:
2773  default:
2774  return QgsGeometry( *this );
2775  }
2776 }
2777 
2778 std::unique_ptr< QgsLineString > smoothCurve( const QgsLineString &line, const unsigned int iterations,
2779  const double offset, double squareDistThreshold, double maxAngleRads,
2780  bool isRing )
2781 {
2782  std::unique_ptr< QgsLineString > result = qgis::make_unique< QgsLineString >( line );
2783  QgsPointSequence outputLine;
2784  for ( unsigned int iteration = 0; iteration < iterations; ++iteration )
2785  {
2786  outputLine.resize( 0 );
2787  outputLine.reserve( 2 * ( result->numPoints() - 1 ) );
2788  bool skipFirst = false;
2789  bool skipLast = false;
2790  if ( isRing )
2791  {
2792  QgsPoint p1 = result->pointN( result->numPoints() - 2 );
2793  QgsPoint p2 = result->pointN( 0 );
2794  QgsPoint p3 = result->pointN( 1 );
2795  double angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
2796  p3.x(), p3.y() );
2797  angle = std::fabs( M_PI - angle );
2798  skipFirst = angle > maxAngleRads;
2799  }
2800  for ( int i = 0; i < result->numPoints() - 1; i++ )
2801  {
2802  QgsPoint p1 = result->pointN( i );
2803  QgsPoint p2 = result->pointN( i + 1 );
2804 
2805  double angle = M_PI;
2806  if ( i == 0 && isRing )
2807  {
2808  QgsPoint p3 = result->pointN( result->numPoints() - 2 );
2809  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
2810  p3.x(), p3.y() );
2811  }
2812  else if ( i < result->numPoints() - 2 )
2813  {
2814  QgsPoint p3 = result->pointN( i + 2 );
2815  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
2816  p3.x(), p3.y() );
2817  }
2818  else if ( i == result->numPoints() - 2 && isRing )
2819  {
2820  QgsPoint p3 = result->pointN( 1 );
2821  angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
2822  p3.x(), p3.y() );
2823  }
2824 
2825  skipLast = angle < M_PI - maxAngleRads || angle > M_PI + maxAngleRads;
2826 
2827  // don't apply distance threshold to first or last segment
2828  if ( i == 0 || i >= result->numPoints() - 2
2829  || QgsGeometryUtils::sqrDistance2D( p1, p2 ) > squareDistThreshold )
2830  {
2831  if ( !isRing )
2832  {
2833  if ( !skipFirst )
2834  outputLine << ( i == 0 ? result->pointN( i ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset ) );
2835  if ( !skipLast )
2836  outputLine << ( i == result->numPoints() - 2 ? result->pointN( i + 1 ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset ) );
2837  else
2838  outputLine << p2;
2839  }
2840  else
2841  {
2842  // ring
2843  if ( !skipFirst )
2844  outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset );
2845  else if ( i == 0 )
2846  outputLine << p1;
2847  if ( !skipLast )
2848  outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset );
2849  else
2850  outputLine << p2;
2851  }
2852  }
2853  skipFirst = skipLast;
2854  }
2855 
2856  if ( isRing && outputLine.at( 0 ) != outputLine.at( outputLine.count() - 1 ) )
2857  outputLine << outputLine.at( 0 );
2858 
2859  result->setPoints( outputLine );
2860  }
2861  return result;
2862 }
2863 
2864 std::unique_ptr<QgsLineString> QgsGeometry::smoothLine( const QgsLineString &line, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
2865 {
2866  double maxAngleRads = maxAngle * M_PI / 180.0;
2867  double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
2868  return smoothCurve( line, iterations, offset, squareDistThreshold, maxAngleRads, false );
2869 }
2870 
2871 std::unique_ptr<QgsPolygon> QgsGeometry::smoothPolygon( const QgsPolygon &polygon, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
2872 {
2873  double maxAngleRads = maxAngle * M_PI / 180.0;
2874  double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
2875  std::unique_ptr< QgsPolygon > resultPoly = qgis::make_unique< QgsPolygon >();
2876 
2877  resultPoly->setExteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.exteriorRing() ) ), iterations, offset,
2878  squareDistThreshold, maxAngleRads, true ).release() );
2879 
2880  for ( int i = 0; i < polygon.numInteriorRings(); ++i )
2881  {
2882  resultPoly->addInteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.interiorRing( i ) ) ), iterations, offset,
2883  squareDistThreshold, maxAngleRads, true ).release() );
2884  }
2885  return resultPoly;
2886 }
2887 
2888 QgsGeometry QgsGeometry::convertToPoint( bool destMultipart ) const
2889 {
2890  switch ( type() )
2891  {
2893  {
2894  bool srcIsMultipart = isMultipart();
2895 
2896  if ( ( destMultipart && srcIsMultipart ) ||
2897  ( !destMultipart && !srcIsMultipart ) )
2898  {
2899  // return a copy of the same geom
2900  return QgsGeometry( *this );
2901  }
2902  if ( destMultipart )
2903  {
2904  // layer is multipart => make a multipoint with a single point
2905  return fromMultiPointXY( QgsMultiPointXY() << asPoint() );
2906  }
2907  else
2908  {
2909  // destination is singlepart => make a single part if possible
2910  QgsMultiPointXY multiPoint = asMultiPoint();
2911  if ( multiPoint.count() == 1 )
2912  {
2913  return fromPointXY( multiPoint[0] );
2914  }
2915  }
2916  return QgsGeometry();
2917  }
2918 
2920  {
2921  // only possible if destination is multipart
2922  if ( !destMultipart )
2923  return QgsGeometry();
2924 
2925  // input geometry is multipart
2926  if ( isMultipart() )
2927  {
2928  const QgsMultiPolylineXY multiLine = asMultiPolyline();
2929  QgsMultiPointXY multiPoint;
2930  for ( const QgsPolylineXY &l : multiLine )
2931  for ( const QgsPointXY &p : l )
2932  multiPoint << p;
2933  return fromMultiPointXY( multiPoint );
2934  }
2935  // input geometry is not multipart: copy directly the line into a multipoint
2936  else
2937  {
2938  QgsPolylineXY line = asPolyline();
2939  if ( !line.isEmpty() )
2940  return fromMultiPointXY( line );
2941  }
2942  return QgsGeometry();
2943  }
2944 
2946  {
2947  // can only transform if destination is multipoint
2948  if ( !destMultipart )
2949  return QgsGeometry();
2950 
2951  // input geometry is multipart: make a multipoint from multipolygon
2952  if ( isMultipart() )
2953  {
2954  const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
2955  QgsMultiPointXY multiPoint;
2956  for ( const QgsPolygonXY &poly : multiPolygon )
2957  for ( const QgsPolylineXY &line : poly )
2958  for ( const QgsPointXY &pt : line )
2959  multiPoint << pt;
2960  return fromMultiPointXY( multiPoint );
2961  }
2962  // input geometry is not multipart: make a multipoint from polygon
2963  else
2964  {
2965  const QgsPolygonXY polygon = asPolygon();
2966  QgsMultiPointXY multiPoint;
2967  for ( const QgsPolylineXY &line : polygon )
2968  for ( const QgsPointXY &pt : line )
2969  multiPoint << pt;
2970  return fromMultiPointXY( multiPoint );
2971  }
2972  }
2973 
2974  default:
2975  return QgsGeometry();
2976  }
2977 }
2978 
2979 QgsGeometry QgsGeometry::convertToLine( bool destMultipart ) const
2980 {
2981  switch ( type() )
2982  {
2984  {
2985  if ( !isMultipart() )
2986  return QgsGeometry();
2987 
2988  QgsMultiPointXY multiPoint = asMultiPoint();
2989  if ( multiPoint.count() < 2 )
2990  return QgsGeometry();
2991 
2992  if ( destMultipart )
2993  return fromMultiPolylineXY( QgsMultiPolylineXY() << multiPoint );
2994  else
2995  return fromPolylineXY( multiPoint );
2996  }
2997 
2999  {
3000  bool srcIsMultipart = isMultipart();
3001 
3002  if ( ( destMultipart && srcIsMultipart ) ||
3003  ( !destMultipart && ! srcIsMultipart ) )
3004  {
3005  // return a copy of the same geom
3006  return QgsGeometry( *this );
3007  }
3008  if ( destMultipart )
3009  {
3010  // destination is multipart => makes a multipoint with a single line
3011  QgsPolylineXY line = asPolyline();
3012  if ( !line.isEmpty() )
3013  return fromMultiPolylineXY( QgsMultiPolylineXY() << line );
3014  }
3015  else
3016  {
3017  // destination is singlepart => make a single part if possible
3018  QgsMultiPolylineXY multiLine = asMultiPolyline();
3019  if ( multiLine.count() == 1 )
3020  return fromPolylineXY( multiLine[0] );
3021  }
3022  return QgsGeometry();
3023  }
3024 
3026  {
3027  // input geometry is multipolygon
3028  if ( isMultipart() )
3029  {
3030  const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3031  QgsMultiPolylineXY multiLine;
3032  for ( const QgsPolygonXY &poly : multiPolygon )
3033  for ( const QgsPolylineXY &line : poly )
3034  multiLine << line;
3035 
3036  if ( destMultipart )
3037  {
3038  // destination is multipart
3039  return fromMultiPolylineXY( multiLine );
3040  }
3041  else if ( multiLine.count() == 1 )
3042  {
3043  // destination is singlepart => make a single part if possible
3044  return fromPolylineXY( multiLine[0] );
3045  }
3046  }
3047  // input geometry is single polygon
3048  else
3049  {
3050  QgsPolygonXY polygon = asPolygon();
3051  // if polygon has rings
3052  if ( polygon.count() > 1 )
3053  {
3054  // cannot fit a polygon with rings in a single line layer
3055  // TODO: would it be better to remove rings?
3056  if ( destMultipart )
3057  {
3058  const QgsPolygonXY polygon = asPolygon();
3059  QgsMultiPolylineXY multiLine;
3060  multiLine.reserve( polygon.count() );
3061  for ( const QgsPolylineXY &line : polygon )
3062  multiLine << line;
3063  return fromMultiPolylineXY( multiLine );
3064  }
3065  }
3066  // no rings
3067  else if ( polygon.count() == 1 )
3068  {
3069  if ( destMultipart )
3070  {
3071  return fromMultiPolylineXY( polygon );
3072  }
3073  else
3074  {
3075  return fromPolylineXY( polygon[0] );
3076  }
3077  }
3078  }
3079  return QgsGeometry();
3080  }
3081 
3082  default:
3083  return QgsGeometry();
3084  }
3085 }
3086 
3087 QgsGeometry QgsGeometry::convertToPolygon( bool destMultipart ) const
3088 {
3089  switch ( type() )
3090  {
3092  {
3093  if ( !isMultipart() )
3094  return QgsGeometry();
3095 
3096  QgsMultiPointXY multiPoint = asMultiPoint();
3097  if ( multiPoint.count() < 3 )
3098  return QgsGeometry();
3099 
3100  if ( multiPoint.last() != multiPoint.first() )
3101  multiPoint << multiPoint.first();
3102 
3103  QgsPolygonXY polygon = QgsPolygonXY() << multiPoint;
3104  if ( destMultipart )
3105  return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3106  else
3107  return fromPolygonXY( polygon );
3108  }
3109 
3111  {
3112  // input geometry is multiline
3113  if ( isMultipart() )
3114  {
3115  QgsMultiPolylineXY multiLine = asMultiPolyline();
3116  QgsMultiPolygonXY multiPolygon;
3117  for ( QgsMultiPolylineXY::iterator multiLineIt = multiLine.begin(); multiLineIt != multiLine.end(); ++multiLineIt )
3118  {
3119  // do not create polygon for a 1 segment line
3120  if ( ( *multiLineIt ).count() < 3 )
3121  return QgsGeometry();
3122  if ( ( *multiLineIt ).count() == 3 && ( *multiLineIt ).first() == ( *multiLineIt ).last() )
3123  return QgsGeometry();
3124 
3125  // add closing node
3126  if ( ( *multiLineIt ).first() != ( *multiLineIt ).last() )
3127  *multiLineIt << ( *multiLineIt ).first();
3128  multiPolygon << ( QgsPolygonXY() << *multiLineIt );
3129  }
3130  // check that polygons were inserted
3131  if ( !multiPolygon.isEmpty() )
3132  {
3133  if ( destMultipart )
3134  {
3135  return fromMultiPolygonXY( multiPolygon );
3136  }
3137  else if ( multiPolygon.count() == 1 )
3138  {
3139  // destination is singlepart => make a single part if possible
3140  return fromPolygonXY( multiPolygon[0] );
3141  }
3142  }
3143  }
3144  // input geometry is single line
3145  else
3146  {
3147  QgsPolylineXY line = asPolyline();
3148 
3149  // do not create polygon for a 1 segment line
3150  if ( line.count() < 3 )
3151  return QgsGeometry();
3152  if ( line.count() == 3 && line.first() == line.last() )
3153  return QgsGeometry();
3154 
3155  // add closing node
3156  if ( line.first() != line.last() )
3157  line << line.first();
3158 
3159  // destination is multipart
3160  if ( destMultipart )
3161  {
3162  return fromMultiPolygonXY( QgsMultiPolygonXY() << ( QgsPolygonXY() << line ) );
3163  }
3164  else
3165  {
3166  return fromPolygonXY( QgsPolygonXY() << line );
3167  }
3168  }
3169  return QgsGeometry();
3170  }
3171 
3173  {
3174  bool srcIsMultipart = isMultipart();
3175 
3176  if ( ( destMultipart && srcIsMultipart ) ||
3177  ( !destMultipart && ! srcIsMultipart ) )
3178  {
3179  // return a copy of the same geom
3180  return QgsGeometry( *this );
3181  }
3182  if ( destMultipart )
3183  {
3184  // destination is multipart => makes a multipoint with a single polygon
3185  QgsPolygonXY polygon = asPolygon();
3186  if ( !polygon.isEmpty() )
3187  return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3188  }
3189  else
3190  {
3191  QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3192  if ( multiPolygon.count() == 1 )
3193  {
3194  // destination is singlepart => make a single part if possible
3195  return fromPolygonXY( multiPolygon[0] );
3196  }
3197  }
3198  return QgsGeometry();
3199  }
3200 
3201  default:
3202  return QgsGeometry();
3203  }
3204 }
3205 
3207 {
3208  return new QgsGeos( geometry );
3209 }
3210 
3211 QDataStream &operator<<( QDataStream &out, const QgsGeometry &geometry )
3212 {
3213  out << geometry.asWkb();
3214  return out;
3215 }
3216 
3217 QDataStream &operator>>( QDataStream &in, QgsGeometry &geometry )
3218 {
3219  QByteArray byteArray;
3220  in >> byteArray;
3221  if ( byteArray.isEmpty() )
3222  {
3223  geometry.set( nullptr );
3224  return in;
3225  }
3226 
3227  geometry.fromWkb( byteArray );
3228  return in;
3229 }
Geometry engine misses a method implemented or an error occurred in the geometry engine.
Definition: qgsgeometry.h:121
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.
bool convertGeometryCollectionToSubclass(QgsWkbTypes::GeometryType geomType)
Converts geometry collection to a the desired geometry type subclass (multi-point, multi-linestring or multi-polygon).
QgsGeometry taperedBuffer(double startWidth, double endWidth, int segments) const
Calculates a tapered width buffer for a (multi)curve geometry.
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:40
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)
Returns 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.
virtual void transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)=0
Transforms the geometry using a coordinate transform.
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.
QgsGeometry variableWidthBufferByM(int segments) const
Calculates a variable width buffer using the m-values from a (multi)line geometry.
static bool verticesAtDistance(const QgsAbstractGeometry &geometry, double distance, QgsVertexId &previousVertex, QgsVertexId &nextVertex)
Retrieves the vertices which are before and after the interpolated point at a specified distance alon...
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() )...
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
bool removeDuplicateNodes(double epsilon=4 *std::numeric_limits< double >::epsilon(), bool useZValues=false)
Removes duplicate nodes from the geometry, wherever removing the nodes does not result in a degenerat...
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:125
Nothing happened, without any error.
Definition: qgsgeometry.h:116
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)
Calculates the average angle (in radians) between the two linear segments from (x1, y1) to (x2, y2) and (x2, y2) to (x3, y3).
void filterVertices(const std::function< bool(const QgsPoint &) > &filter)
Filters the vertices from the geometry in place, removing any which do not return true for the filter...
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:586
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:62
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...
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:251
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.
const QgsCurve * interiorRing(int i) const
TransformDirection
Enum used to indicate the direction (forward or inverse) of the transform.
QVector< QgsPolylineXY > QgsPolygonXY
Polygon: first item of the list is outer ring, inner rings (if any) start from second item...
Definition: qgsgeometry.h:66
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:104
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:72
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.
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle...
double radius() const
Returns the radius of the circle.
Definition: qgscircle.h:221
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:891
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.
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:113
void convertToStraightSegment(double tolerance=M_PI/180., QgsAbstractGeometry::SegmentationToleranceType toleranceType=QgsAbstractGeometry::MaximumAngle)
Converts the geometry to straight line segments, if it is a curved geometry type. ...
double 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:83
bool deleteRing(int ringNum, int partNum=0)
Deletes a ring in polygon or multipolygon.
bool isGeosValid() const
Checks validity of the geometry using GEOS.
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:76
QgsMultiPolylineXY asMultiPolyline() const
Returns contents of the geometry as a multi linestring if wkbType is WKBMultiLineString, otherwise an empty list.
QVector< QgsGeometry > asGeometryCollection() const
Returns 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.h:148
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.
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.
QgsGeometry variableWidthBufferByM(int segments) const
Calculates a variable width buffer for a (multi)linestring geometry, where the width at each node is ...
Utility class for identifying a unique vertex within a geometry.
bool isEmpty() const
Returns true if the rectangle is empty.
Definition: qgsrectangle.h:419
QgsGeometry taperedBuffer(double startWidth, double endWidth, int segments) const
Calculates a variable width buffer ("tapered buffer") for a (multi)curve geometry.
Geometry collection.
QgsPolygonXY asPolygon() const
Returns contents of the geometry as a polygon if wkbType is WKBPolygon, otherwise an empty list...
static QgsGeometry fromQPointF(QPointF point)
Construct geometry from a QPointF.
virtual QgsPolygon * toPolygon(unsigned int segments=36) const
Returns a segmented polygon.
Definition: qgsellipse.cpp:223
QgsGeometry convexHull() const
Returns the smallest convex polygon that contains all the points in the geometry. ...
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:201
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.
QgsGeometry smooth(unsigned int iterations=1, double offset=0.25, double minimumDistance=-1.0, double maxAngle=180.0) const
Smooths a geometry by rounding off corners using the Chaikin algorithm.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
bool contains(const QgsPoint &point, double epsilon=1E-8) const
Returns true if the circle contains the point.
Definition: qgscircle.cpp:344
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:2217
QgsGeometry densifyByDistance(double distance) const
Densifies the geometry by adding regularly placed extra nodes inside each segment so that the maximum...
Method not implemented in geometry engine.
virtual double area() const
Returns the area of the geometry.
virtual int ringCount(int part=0) const =0
Returns the number of rings of which this geometry is built.
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
virtual QgsPolygon * toPolygon(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a new polygon geometry corresponding to a segmentized approximation of the curve...
static QgsPointXY interpolatePointOnLine(double x1, double y1, double x2, double y2, double fraction)
Interpolates the position of a point a fraction of the way along the line from (x1, y1) to (x2, y2).
QgsGeometry pointOnSurface() const
Returns a point guaranteed to lie on the surface of a geometry.
bool touches(const QgsGeometry &geometry) const
Test for if geometry touch another (uses GEOS)
Abstract base class for all geometries.
QgsCoordinateSequence coordinateSequence() const override
Retrieves the sequence of geometries, rings and nodes.
The vertex_iterator class provides STL-style iterator for vertices.
Does vector analysis using the geos library and handles import, export, exception handling*...
Definition: qgsgeos.h:103
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
static std::unique_ptr< QgsMultiLineString > fromMultiPolylineXY(const QgsMultiPolylineXY &multiline)
Construct geometry from a multipolyline.
QgsPoint project(double distance, double azimuth, double inclination=90.0) const
Returns a new point which correspond to this point projected by a specified distance with specified a...
Definition: qgspoint.cpp:631
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.
static QgsCircularString fromTwoPointsAndCenter(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &center, bool useShortestArc=true)
Creates a circular string with a single arc representing the curve from p1 to p2 with the specified c...
Contains geos related utilities and functions.
Definition: qgsgeos.h:41
void setX(double x)
Sets the point&#39;s x-coordinate.
Definition: qgspoint.h:213
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:176
QgsAbstractGeometry * combine(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the combination of this and geom.
Definition: qgsgeos.cpp:361
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:161
BufferSide
Side of line to buffer.
Definition: qgsgeometry.h:883
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:42
static double sqrDistance2D(const QgsPoint &pt1, const QgsPoint &pt2)
Returns the squared 2D distance between two points.
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
static std::unique_ptr< QgsAbstractGeometry > geomFromWkt(const QString &text)
Construct geometry from a WKT string.
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
double hausdorffDistance(const QgsGeometry &geom) const
Returns the Hausdorff distance between this geometry and geom.
QgsPointXY asPoint() const
Returns contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [0...
The base geometry on which the operation is done is invalid or empty.
Definition: qgsgeometry.h:117
Multi polygon geometry collection.
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:118
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.
static bool isCurvedType(Type type)
Returns true if the WKB type is a curved type or can contain curved geometries.
Definition: qgswkbtypes.h:606
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:341
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:43
QPointF asQPointF() const
Returns contents of the geometry as a QPointF if wkbType is WKBPoint, otherwise returns a null QPoint...
static QgsGeometry createWedgeBuffer(const QgsPoint &center, double azimuth, double angularWidth, double outerRadius, double innerRadius=0)
Creates a wedge shaped buffer from a center point.
ValidationMethod
Available methods for validating geometries.
Definition: qgsgeometry.h:1444
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.
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
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()).
Definition: qgsrectangle.h:429
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:166
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:171
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...
Circular string geometry type.
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:115
JoinStyle
Join styles for buffers.
Definition: qgsgeometry.h:900
const QgsCurve * exteriorRing() const
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.
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.
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:208
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...