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