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