QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
qgsgeometry.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsgeometry.cpp - Geometry (stored as Open Geospatial Consortium WKB)
3 -------------------------------------------------------------------
4Date : 02 May 2005
5Copyright : (C) 2005 by Brendan Morley
6email : 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#include <nlohmann/json.hpp>
21#include <QCache>
22
23#include "qgis.h"
24#include "qgsgeometry.h"
26#include "qgsgeometryfactory.h"
27
28#include <geos_c.h>
29
30#include "qgsgeometryutils.h"
32#include "qgsgeos.h"
33#include "qgsmaptopixel.h"
34#include "qgspointxy.h"
35#include "qgsrectangle.h"
36
37#include "qgsvectorlayer.h"
39
40#include "qgsmultilinestring.h"
41#include "qgsmultipoint.h"
42#include "qgsmultipolygon.h"
43#include "qgspoint.h"
44#include "qgspolygon.h"
45#include "qgslinestring.h"
46#include "qgscircle.h"
47#include "qgscurve.h"
48
50{
52 QAtomicInt ref;
53 std::unique_ptr< QgsAbstractGeometry > geometry;
54};
55
57 : d( new QgsGeometryPrivate() )
58{
59}
60
62{
63 if ( !d->ref.deref() )
64 delete d;
65}
66
68 : d( new QgsGeometryPrivate() )
69{
70 d->geometry.reset( geom );
71 d->ref = QAtomicInt( 1 );
72}
73
74QgsGeometry::QgsGeometry( std::unique_ptr<QgsAbstractGeometry> geom )
75 : d( new QgsGeometryPrivate() )
76{
77 d->geometry = std::move( geom );
78 d->ref = QAtomicInt( 1 );
79}
80
82 : d( other.d )
83{
84 mLastError = other.mLastError;
85 d->ref.ref();
86}
87
89{
90 if ( this != &other )
91 {
92 if ( !d->ref.deref() )
93 {
94 delete d;
95 }
96
97 mLastError = other.mLastError;
98 d = other.d;
99 d->ref.ref();
100 }
101 return *this;
102}
103
104void QgsGeometry::detach()
105{
106 if ( d->ref <= 1 )
107 return;
108
109 std::unique_ptr< QgsAbstractGeometry > cGeom;
110 if ( d->geometry )
111 cGeom.reset( d->geometry->clone() );
112
113 reset( std::move( cGeom ) );
114}
115
116void QgsGeometry::reset( std::unique_ptr<QgsAbstractGeometry> newGeometry )
117{
118 if ( d->ref > 1 )
119 {
120 ( void )d->ref.deref();
121 d = new QgsGeometryPrivate();
122 }
123 d->geometry = std::move( newGeometry );
124}
125
127{
128 return d->geometry.get();
129}
130
132{
133 detach();
134 return d->geometry.get();
135}
136
138{
139 if ( d->geometry.get() == geometry )
140 {
141 return;
142 }
143
144 reset( std::unique_ptr< QgsAbstractGeometry >( geometry ) );
145}
146
148{
149 return !d->geometry;
150}
151
152typedef QCache< QString, QgsGeometry > WktCache;
153Q_GLOBAL_STATIC_WITH_ARGS( WktCache, sWktCache, ( 2000 ) ) // store up to 2000 geometries
154Q_GLOBAL_STATIC( QMutex, sWktMutex )
155
156QgsGeometry QgsGeometry::fromWkt( const QString &wkt )
157{
158 QMutexLocker lock( sWktMutex() );
159 if ( const QgsGeometry *cached = sWktCache()->object( wkt ) )
160 return *cached;
161 const QgsGeometry result( QgsGeometryFactory::geomFromWkt( wkt ) );
162 sWktCache()->insert( wkt, new QgsGeometry( result ), 1 );
163 return result;
164}
165
167{
168 std::unique_ptr< QgsAbstractGeometry > geom( QgsGeometryFactory::fromPointXY( point ) );
169 if ( geom )
170 {
171 return QgsGeometry( geom.release() );
172 }
173 return QgsGeometry();
174}
175
177{
178 std::unique_ptr< QgsAbstractGeometry > geom = QgsGeometryFactory::fromPolylineXY( polyline );
179 if ( geom )
180 {
181 return QgsGeometry( std::move( geom ) );
182 }
183 return QgsGeometry();
184}
185
187{
188 return QgsGeometry( std::make_unique< QgsLineString >( polyline ) );
189}
190
192{
193 std::unique_ptr< QgsPolygon > geom = QgsGeometryFactory::fromPolygonXY( polygon );
194 if ( geom )
195 {
196 return QgsGeometry( std::move( geom ) );
197 }
198 return QgsGeometry();
199}
200
202{
203 std::unique_ptr< QgsMultiPoint > geom = QgsGeometryFactory::fromMultiPointXY( multipoint );
204 if ( geom )
205 {
206 return QgsGeometry( std::move( geom ) );
207 }
208 return QgsGeometry();
209}
210
212{
213 std::unique_ptr< QgsMultiLineString > geom = QgsGeometryFactory::fromMultiPolylineXY( multiline );
214 if ( geom )
215 {
216 return QgsGeometry( std::move( geom ) );
217 }
218 return QgsGeometry();
219}
220
222{
223 std::unique_ptr< QgsMultiPolygon > geom = QgsGeometryFactory::fromMultiPolygonXY( multipoly );
224 if ( geom )
225 {
226 return QgsGeometry( std::move( geom ) );
227 }
228 return QgsGeometry();
229}
230
232{
233 std::unique_ptr< QgsLineString > ext = std::make_unique< QgsLineString >(
234 QVector< double >() << rect.xMinimum()
235 << rect.xMaximum()
236 << rect.xMaximum()
237 << rect.xMinimum()
238 << rect.xMinimum(),
239 QVector< double >() << rect.yMinimum()
240 << rect.yMinimum()
241 << rect.yMaximum()
242 << rect.yMaximum()
243 << rect.yMinimum() );
244 std::unique_ptr< QgsPolygon > polygon = std::make_unique< QgsPolygon >();
245 polygon->setExteriorRing( ext.release() );
246 return QgsGeometry( std::move( polygon ) );
247}
248
249QgsGeometry QgsGeometry::collectGeometry( const QVector< QgsGeometry > &geometries )
250{
251 QgsGeometry collected;
252
253 for ( const QgsGeometry &g : geometries )
254 {
255 if ( collected.isNull() )
256 {
257 collected = g;
258 collected.convertToMultiType();
259 }
260 else
261 {
262 if ( g.isMultipart() )
263 {
264 for ( auto p = g.const_parts_begin(); p != g.const_parts_end(); ++p )
265 {
266 collected.addPart( ( *p )->clone() );
267 }
268 }
269 else
270 {
271 collected.addPart( g );
272 }
273 }
274 }
275 return collected;
276}
277
278QgsGeometry QgsGeometry::createWedgeBuffer( const QgsPoint &center, const double azimuth, const double angularWidth, const double outerRadius, const double innerRadius )
279{
280 if ( std::abs( angularWidth ) >= 360.0 )
281 {
282 std::unique_ptr< QgsCompoundCurve > outerCc = std::make_unique< QgsCompoundCurve >();
283
284 QgsCircle outerCircle = QgsCircle( center, outerRadius );
285 outerCc->addCurve( outerCircle.toCircularString() );
286
287 std::unique_ptr< QgsCurvePolygon > cp = std::make_unique< QgsCurvePolygon >();
288 cp->setExteriorRing( outerCc.release() );
289
290 if ( !qgsDoubleNear( innerRadius, 0.0 ) && innerRadius > 0 )
291 {
292 std::unique_ptr< QgsCompoundCurve > innerCc = std::make_unique< QgsCompoundCurve >();
293
294 QgsCircle innerCircle = QgsCircle( center, innerRadius );
295 innerCc->addCurve( innerCircle.toCircularString() );
296
297 cp->setInteriorRings( { innerCc.release() } );
298 }
299
300 return QgsGeometry( std::move( cp ) );
301 }
302
303 std::unique_ptr< QgsCompoundCurve > wedge = std::make_unique< QgsCompoundCurve >();
304
305 const double startAngle = azimuth - angularWidth * 0.5;
306 const double endAngle = azimuth + angularWidth * 0.5;
307
308 const QgsPoint outerP1 = center.project( outerRadius, startAngle );
309 const QgsPoint outerP2 = center.project( outerRadius, endAngle );
310
311 const bool useShortestArc = angularWidth <= 180.0;
312
313 wedge->addCurve( new QgsCircularString( QgsCircularString::fromTwoPointsAndCenter( outerP1, outerP2, center, useShortestArc ) ) );
314
315 if ( !qgsDoubleNear( innerRadius, 0.0 ) && innerRadius > 0 )
316 {
317 const QgsPoint innerP1 = center.project( innerRadius, startAngle );
318 const QgsPoint innerP2 = center.project( innerRadius, endAngle );
319 wedge->addCurve( new QgsLineString( outerP2, innerP2 ) );
320 wedge->addCurve( new QgsCircularString( QgsCircularString::fromTwoPointsAndCenter( innerP2, innerP1, center, useShortestArc ) ) );
321 wedge->addCurve( new QgsLineString( innerP1, outerP1 ) );
322 }
323 else
324 {
325 wedge->addCurve( new QgsLineString( outerP2, center ) );
326 wedge->addCurve( new QgsLineString( center, outerP1 ) );
327 }
328
329 std::unique_ptr< QgsCurvePolygon > cp = std::make_unique< QgsCurvePolygon >();
330 cp->setExteriorRing( wedge.release() );
331 return QgsGeometry( std::move( cp ) );
332}
333
334void QgsGeometry::fromWkb( unsigned char *wkb, int length )
335{
336 QgsConstWkbPtr ptr( wkb, length );
337 reset( QgsGeometryFactory::geomFromWkb( ptr ) );
338 delete [] wkb;
339}
340
341void QgsGeometry::fromWkb( const QByteArray &wkb )
342{
343 QgsConstWkbPtr ptr( wkb );
344 reset( QgsGeometryFactory::geomFromWkb( ptr ) );
345}
346
348{
349 if ( !d->geometry )
350 {
352 }
353 else
354 {
355 return d->geometry->wkbType();
356 }
357}
358
359
361{
362 if ( !d->geometry )
363 {
364 return Qgis::GeometryType::Unknown;
365 }
366 return QgsWkbTypes::geometryType( d->geometry->wkbType() );
367}
368
370{
371 if ( !d->geometry )
372 {
373 return true;
374 }
375
376 return d->geometry->isEmpty();
377}
378
380{
381 if ( !d->geometry )
382 {
383 return false;
384 }
385 return QgsWkbTypes::isMultiType( d->geometry->wkbType() );
386}
387QgsPointXY QgsGeometry::closestVertex( const QgsPointXY &point, int &closestVertexIndex, int &previousVertexIndex, int &nextVertexIndex, double &sqrDist ) const
388{
389 if ( !d->geometry )
390 {
391 sqrDist = -1;
392 return QgsPointXY();
393 }
394
395 QgsPoint pt( point );
396 QgsVertexId id;
397
398 QgsPoint vp = QgsGeometryUtils::closestVertex( *( d->geometry ), pt, id );
399 if ( !id.isValid() )
400 {
401 sqrDist = -1;
402 return QgsPointXY();
403 }
404 sqrDist = QgsGeometryUtils::sqrDistance2D( pt, vp );
405
406 QgsVertexId prevVertex;
407 QgsVertexId nextVertex;
408 d->geometry->adjacentVertices( id, prevVertex, nextVertex );
409 closestVertexIndex = vertexNrFromVertexId( id );
410 previousVertexIndex = vertexNrFromVertexId( prevVertex );
411 nextVertexIndex = vertexNrFromVertexId( nextVertex );
412 return QgsPointXY( vp.x(), vp.y() );
413}
414
415double QgsGeometry::distanceToVertex( int vertex ) const
416{
417 if ( !d->geometry )
418 {
419 return -1;
420 }
421
422 QgsVertexId id;
423 if ( !vertexIdFromVertexNr( vertex, id ) )
424 {
425 return -1;
426 }
427
428 return QgsGeometryUtils::distanceToVertex( *( d->geometry ), id );
429}
430
431double QgsGeometry::angleAtVertex( int vertex ) const
432{
433 if ( !d->geometry )
434 {
435 return 0;
436 }
437
438 QgsVertexId v2;
439 if ( !vertexIdFromVertexNr( vertex, v2 ) )
440 {
441 return 0;
442 }
443
444 return d->geometry->vertexAngle( v2 );
445}
446
447void QgsGeometry::adjacentVertices( int atVertex, int &beforeVertex, int &afterVertex ) const
448{
449 if ( !d->geometry )
450 {
451 return;
452 }
453
454 QgsVertexId id;
455 if ( !vertexIdFromVertexNr( atVertex, id ) )
456 {
457 beforeVertex = -1;
458 afterVertex = -1;
459 return;
460 }
461
462 QgsVertexId beforeVertexId, afterVertexId;
463 d->geometry->adjacentVertices( id, beforeVertexId, afterVertexId );
464 beforeVertex = vertexNrFromVertexId( beforeVertexId );
465 afterVertex = vertexNrFromVertexId( afterVertexId );
466}
467
468bool QgsGeometry::moveVertex( double x, double y, int atVertex )
469{
470 if ( !d->geometry )
471 {
472 return false;
473 }
474
475 QgsVertexId id;
476 if ( !vertexIdFromVertexNr( atVertex, id ) )
477 {
478 return false;
479 }
480
481 detach();
482
483 return d->geometry->moveVertex( id, QgsPoint( x, y ) );
484}
485
486bool QgsGeometry::moveVertex( const QgsPoint &p, int atVertex )
487{
488 if ( !d->geometry )
489 {
490 return false;
491 }
492
493 QgsVertexId id;
494 if ( !vertexIdFromVertexNr( atVertex, id ) )
495 {
496 return false;
497 }
498
499 detach();
500
501 return d->geometry->moveVertex( id, p );
502}
503
504bool QgsGeometry::deleteVertex( int atVertex )
505{
506 if ( !d->geometry )
507 {
508 return false;
509 }
510
511 //maintain compatibility with < 2.10 API
513 {
514 detach();
515 //delete geometry instead of point
516 return static_cast< QgsGeometryCollection * >( d->geometry.get() )->removeGeometry( atVertex );
517 }
518
519 //if it is a point, set the geometry to nullptr
520 if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == Qgis::WkbType::Point )
521 {
522 reset( nullptr );
523 return true;
524 }
525
526 QgsVertexId id;
527 if ( !vertexIdFromVertexNr( atVertex, id ) )
528 {
529 return false;
530 }
531
532 detach();
533
534 return d->geometry->deleteVertex( id );
535}
536
538{
539
540 if ( !d->geometry )
541 return false;
542
543 QgsVertexId id;
544 if ( !vertexIdFromVertexNr( atVertex, id ) )
545 return false;
546
547 detach();
548
549 QgsAbstractGeometry *geom = d->geometry.get();
550
551 // If the geom is a collection, we get the concerned part, otherwise, the part is just the whole geom
552 QgsAbstractGeometry *part = nullptr;
553 QgsGeometryCollection *owningCollection = qgsgeometry_cast<QgsGeometryCollection *>( geom );
554 if ( owningCollection != nullptr )
555 part = owningCollection->geometryN( id.part );
556 else
557 part = geom;
558
559 // If the part is a polygon, we get the concerned ring, otherwise, the ring is just the whole part
560 QgsAbstractGeometry *ring = nullptr;
561 QgsCurvePolygon *owningPolygon = qgsgeometry_cast<QgsCurvePolygon *>( part );
562 if ( owningPolygon != nullptr )
563 ring = ( id.ring == 0 ) ? owningPolygon->exteriorRing() : owningPolygon->interiorRing( id.ring - 1 );
564 else
565 ring = part;
566
567 // If the ring is not a curve, we're probably on a point geometry
568 QgsCurve *curve = qgsgeometry_cast<QgsCurve *>( ring );
569 if ( curve == nullptr )
570 return false;
571
572 bool success = false;
573 QgsCompoundCurve *cpdCurve = qgsgeometry_cast<QgsCompoundCurve *>( curve );
574 if ( cpdCurve != nullptr )
575 {
576 // If the geom is a already compound curve, we convert inplace, and we're done
577 success = cpdCurve->toggleCircularAtVertex( id );
578 }
579 else
580 {
581 // TODO : move this block before the above, so we call toggleCircularAtVertex only in one place
582 // If the geom is a linestring or cirularstring, we create a compound curve
583 std::unique_ptr<QgsCompoundCurve> cpdCurve = std::make_unique<QgsCompoundCurve>();
584 cpdCurve->addCurve( curve->clone() );
585 success = cpdCurve->toggleCircularAtVertex( QgsVertexId( -1, -1, id.vertex ) );
586
587 // In that case, we must also reassign the instances
588 if ( success )
589 {
590 if ( owningPolygon == nullptr && owningCollection == nullptr )
591 {
592 // Standalone linestring
593 reset( std::make_unique<QgsCompoundCurve>( *cpdCurve ) ); // <- REVIEW PLZ
594 }
595 else if ( owningPolygon != nullptr )
596 {
597 // Replace the ring in the owning polygon
598 if ( id.ring == 0 )
599 {
600 owningPolygon->setExteriorRing( cpdCurve.release() );
601 }
602 else
603 {
604 owningPolygon->removeInteriorRing( id.ring - 1 );
605 owningPolygon->addInteriorRing( cpdCurve.release() );
606 }
607 }
608 else if ( owningCollection != nullptr )
609 {
610 // Replace the curve in the owning collection
611 owningCollection->removeGeometry( id.part );
612 owningCollection->insertGeometry( cpdCurve.release(), id.part );
613 }
614 }
615 }
616
617 return success;
618}
619
620bool QgsGeometry::insertVertex( double x, double y, int beforeVertex )
621{
622 if ( !d->geometry )
623 {
624 return false;
625 }
626
627 //maintain compatibility with < 2.10 API
629 {
630 detach();
631 //insert geometry instead of point
632 return static_cast< QgsGeometryCollection * >( d->geometry.get() )->insertGeometry( new QgsPoint( x, y ), beforeVertex );
633 }
634
635 QgsVertexId id;
636 if ( !vertexIdFromVertexNr( beforeVertex, id ) )
637 {
638 return false;
639 }
640
641 detach();
642
643 return d->geometry->insertVertex( id, QgsPoint( x, y ) );
644}
645
646bool QgsGeometry::insertVertex( const QgsPoint &point, int beforeVertex )
647{
648 if ( !d->geometry )
649 {
650 return false;
651 }
652
653 //maintain compatibility with < 2.10 API
655 {
656 detach();
657 //insert geometry instead of point
658 return static_cast< QgsGeometryCollection * >( d->geometry.get() )->insertGeometry( new QgsPoint( point ), beforeVertex );
659 }
660
661 QgsVertexId id;
662 if ( !vertexIdFromVertexNr( beforeVertex, id ) )
663 {
664 return false;
665 }
666
667 detach();
668
669 return d->geometry->insertVertex( id, point );
670}
671
672QgsPoint QgsGeometry::vertexAt( int atVertex ) const
673{
674 if ( !d->geometry )
675 {
676 return QgsPoint();
677 }
678
679 QgsVertexId vId;
680 ( void )vertexIdFromVertexNr( atVertex, vId );
681 if ( vId.vertex < 0 )
682 {
683 return QgsPoint();
684 }
685 return d->geometry->vertexAt( vId );
686}
687
688double QgsGeometry::sqrDistToVertexAt( QgsPointXY &point, int atVertex ) const
689{
690 QgsPointXY vertexPoint = vertexAt( atVertex );
691 return QgsGeometryUtils::sqrDistance2D( QgsPoint( vertexPoint ), QgsPoint( point ) );
692}
693
695{
696 // avoid calling geos for trivial point calculations
697 if ( d->geometry && QgsWkbTypes::flatType( d->geometry->wkbType() ) == Qgis::WkbType::Point )
698 {
699 return QgsGeometry( qgsgeometry_cast< const QgsPoint * >( d->geometry.get() )->clone() );
700 }
701
702 QgsGeos geos( d->geometry.get() );
703 mLastError.clear();
704 QgsGeometry result = geos.closestPoint( other );
705 result.mLastError = mLastError;
706 return result;
707}
708
710{
711 // avoid calling geos for trivial point-to-point line calculations
713 {
714 return QgsGeometry( std::make_unique< QgsLineString >( *qgsgeometry_cast< const QgsPoint * >( d->geometry.get() ), *qgsgeometry_cast< const QgsPoint * >( other.constGet() ) ) );
715 }
716
717 QgsGeos geos( d->geometry.get() );
718 mLastError.clear();
719 QgsGeometry result = geos.shortestLine( other, &mLastError );
720 result.mLastError = mLastError;
721 return result;
722}
723
724double QgsGeometry::closestVertexWithContext( const QgsPointXY &point, int &atVertex ) const
725{
726 if ( !d->geometry )
727 {
728 return -1;
729 }
730
731 QgsVertexId vId;
732 QgsPoint pt( point );
733 QgsPoint closestPoint = QgsGeometryUtils::closestVertex( *( d->geometry ), pt, vId );
734 if ( !vId.isValid() )
735 return -1;
736 atVertex = vertexNrFromVertexId( vId );
737 return QgsGeometryUtils::sqrDistance2D( closestPoint, pt );
738}
739
741 QgsPointXY &minDistPoint,
742 int &nextVertexIndex,
743 int *leftOrRightOfSegment,
744 double epsilon ) const
745{
746 if ( !d->geometry )
747 {
748 return -1;
749 }
750
751 QgsPoint segmentPt;
752 QgsVertexId vertexAfter;
753
754 double sqrDist = d->geometry->closestSegment( QgsPoint( point ), segmentPt, vertexAfter, leftOrRightOfSegment, epsilon );
755 if ( sqrDist < 0 )
756 return -1;
757
758 minDistPoint.setX( segmentPt.x() );
759 minDistPoint.setY( segmentPt.y() );
760 nextVertexIndex = vertexNrFromVertexId( vertexAfter );
761 return sqrDist;
762}
763
764Qgis::GeometryOperationResult QgsGeometry::addRing( const QVector<QgsPointXY> &ring )
765{
766 std::unique_ptr< QgsLineString > ringLine = std::make_unique< QgsLineString >( ring );
767 return addRing( ringLine.release() );
768}
769
771{
772 std::unique_ptr< QgsCurve > r( ring );
773 if ( !d->geometry )
774 {
776 }
777
778 detach();
779
780 return QgsGeometryEditUtils::addRing( d->geometry.get(), std::move( r ) );
781}
782
783Qgis::GeometryOperationResult QgsGeometry::addPart( const QVector<QgsPointXY> &points, Qgis::GeometryType geomType )
784{
786 convertPointList( points, l );
787 return addPart( l, geomType );
788}
789
791{
792 std::unique_ptr< QgsAbstractGeometry > partGeom;
793 if ( points.size() == 1 )
794 {
795 partGeom = std::make_unique< QgsPoint >( points[0] );
796 }
797 else if ( points.size() > 1 )
798 {
799 std::unique_ptr< QgsLineString > ringLine = std::make_unique< QgsLineString >();
800 ringLine->setPoints( points );
801 partGeom = std::move( ringLine );
802 }
803 return addPart( partGeom.release(), geomType );
804}
805
807{
808 std::unique_ptr< QgsAbstractGeometry > p( part );
809 if ( !d->geometry )
810 {
811 switch ( geomType )
812 {
813 case Qgis::GeometryType::Point:
814 reset( std::make_unique< QgsMultiPoint >() );
815 break;
816 case Qgis::GeometryType::Line:
817 reset( std::make_unique< QgsMultiLineString >() );
818 break;
819 case Qgis::GeometryType::Polygon:
820 reset( std::make_unique< QgsMultiPolygon >() );
821 break;
822 default:
823 reset( nullptr );
825 }
826 }
827 else
828 {
829 detach();
830 }
831
833 return QgsGeometryEditUtils::addPart( d->geometry.get(), std::move( p ) );
834}
835
837{
838 if ( !d->geometry )
839 {
841 }
842 if ( newPart.isNull() || !newPart.d->geometry )
843 {
845 }
846
847 return addPart( newPart.d->geometry->clone() );
848}
849
850QgsGeometry QgsGeometry::removeInteriorRings( double minimumRingArea ) const
851{
852 if ( !d->geometry || type() != Qgis::GeometryType::Polygon )
853 {
854 return QgsGeometry();
855 }
856
857 if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
858 {
859 const QVector<QgsGeometry> parts = asGeometryCollection();
860 QVector<QgsGeometry> results;
861 results.reserve( parts.count() );
862 for ( const QgsGeometry &part : parts )
863 {
864 QgsGeometry result = part.removeInteriorRings( minimumRingArea );
865 if ( !result.isNull() )
866 results << result;
867 }
868 if ( results.isEmpty() )
869 return QgsGeometry();
870
871 QgsGeometry first = results.takeAt( 0 );
872 for ( const QgsGeometry &result : std::as_const( results ) )
873 {
874 first.addPart( result );
875 }
876 return first;
877 }
878 else
879 {
880 std::unique_ptr< QgsCurvePolygon > newPoly( static_cast< QgsCurvePolygon * >( d->geometry->clone() ) );
881 newPoly->removeInteriorRings( minimumRingArea );
882 return QgsGeometry( std::move( newPoly ) );
883 }
884}
885
886Qgis::GeometryOperationResult QgsGeometry::translate( double dx, double dy, double dz, double dm )
887{
888 if ( !d->geometry )
889 {
891 }
892
893 detach();
894
895 d->geometry->transform( QTransform::fromTranslate( dx, dy ), dz, 1.0, dm );
897}
898
900{
901 if ( !d->geometry )
902 {
904 }
905
906 detach();
907
908 QTransform t = QTransform::fromTranslate( center.x(), center.y() );
909 t.rotate( -rotation );
910 t.translate( -center.x(), -center.y() );
911 d->geometry->transform( t );
913}
914
915Qgis::GeometryOperationResult QgsGeometry::splitGeometry( const QVector<QgsPointXY> &splitLine, QVector<QgsGeometry> &newGeometries, bool topological, QVector<QgsPointXY> &topologyTestPoints, bool splitFeature )
916{
917 QgsPointSequence split, topology;
918 convertPointList( splitLine, split );
919 convertPointList( topologyTestPoints, topology );
920 Qgis::GeometryOperationResult result = splitGeometry( split, newGeometries, topological, topology, splitFeature );
921 convertPointList( topology, topologyTestPoints );
922 return result;
923}
924Qgis::GeometryOperationResult QgsGeometry::splitGeometry( const QgsPointSequence &splitLine, QVector<QgsGeometry> &newGeometries, bool topological, QgsPointSequence &topologyTestPoints, bool splitFeature, bool skipIntersectionTest )
925{
926 if ( !d->geometry )
927 {
929 }
930
931 QVector<QgsGeometry > newGeoms;
932 QgsLineString splitLineString( splitLine );
933
934 QgsGeos geos( d->geometry.get() );
935 mLastError.clear();
936 QgsGeometryEngine::EngineOperationResult result = geos.splitGeometry( splitLineString, newGeoms, topological, topologyTestPoints, &mLastError, skipIntersectionTest );
937
938 if ( result == QgsGeometryEngine::Success )
939 {
940 if ( splitFeature )
941 *this = newGeoms.takeAt( 0 );
942 newGeometries = newGeoms;
943 }
944
945 switch ( result )
946 {
961 //default: do not implement default to handle properly all cases
962 }
963
964 // this should never be reached
965 Q_ASSERT( false );
967}
968
969Qgis::GeometryOperationResult QgsGeometry::splitGeometry( const QgsCurve *curve, QVector<QgsGeometry> &newGeometries, bool preserveCircular, bool topological, QgsPointSequence &topologyTestPoints, bool splitFeature )
970{
971 std::unique_ptr<QgsLineString> segmentizedLine( curve->curveToLine() );
972 QgsPointSequence points;
973 segmentizedLine->points( points );
974 Qgis::GeometryOperationResult result = splitGeometry( points, newGeometries, topological, topologyTestPoints, splitFeature );
975
977 {
978 if ( preserveCircular )
979 {
980 for ( int i = 0; i < newGeometries.count(); ++i )
981 newGeometries[i] = newGeometries[i].convertToCurves();
982 *this = convertToCurves();
983 }
984 }
985
986 return result;
987}
988
990{
991 if ( !d->geometry )
992 {
994 }
995
996 QgsGeos geos( d->geometry.get() );
998 mLastError.clear();
999 std::unique_ptr< QgsAbstractGeometry > geom( geos.reshapeGeometry( reshapeLineString, &errorCode, &mLastError ) );
1000 if ( errorCode == QgsGeometryEngine::Success && geom )
1001 {
1002 reset( std::move( geom ) );
1004 }
1005
1006 switch ( errorCode )
1007 {
1018 case QgsGeometryEngine::SplitCannotSplitPoint: // should not happen
1022 }
1023
1024 // should not be reached
1026}
1027
1029{
1030 if ( !d->geometry || !other.d->geometry )
1031 {
1032 return 0;
1033 }
1034
1035 QgsGeos geos( d->geometry.get() );
1036
1037 mLastError.clear();
1038 std::unique_ptr< QgsAbstractGeometry > diffGeom( geos.intersection( other.constGet(), &mLastError ) );
1039 if ( !diffGeom )
1040 {
1041 return 1;
1042 }
1043
1044 reset( std::move( diffGeom ) );
1045 return 0;
1046}
1047
1049{
1050 if ( !d->geometry || other.isNull() )
1051 {
1052 return QgsGeometry();
1053 }
1054
1055 QgsGeos geos( d->geometry.get() );
1056
1057 mLastError.clear();
1058 std::unique_ptr< QgsAbstractGeometry > diffGeom( geos.intersection( other.constGet(), &mLastError ) );
1059 if ( !diffGeom )
1060 {
1061 QgsGeometry result;
1062 result.mLastError = mLastError;
1063 return result;
1064 }
1065
1066 return QgsGeometry( diffGeom.release() );
1067}
1068
1070{
1071 if ( d->geometry )
1072 {
1073 return d->geometry->boundingBox();
1074 }
1075 return QgsRectangle();
1076}
1077
1078QgsGeometry QgsGeometry::orientedMinimumBoundingBox( double &area, double &angle, double &width, double &height ) const
1079{
1080 mLastError.clear();
1081 QgsInternalGeometryEngine engine( *this );
1082 const QgsGeometry res = engine.orientedMinimumBoundingBox( area, angle, width, height );
1083 if ( res.isNull() )
1084 mLastError = engine.lastError();
1085 return res;
1086}
1087
1089{
1090 double area, angle, width, height;
1091 return orientedMinimumBoundingBox( area, angle, width, height );
1092}
1093
1094static QgsCircle __recMinimalEnclosingCircle( QgsMultiPointXY points, QgsMultiPointXY boundary )
1095{
1096 auto l_boundary = boundary.length();
1097 QgsCircle circ_mec;
1098 if ( ( points.length() == 0 ) || ( l_boundary == 3 ) )
1099 {
1100 switch ( l_boundary )
1101 {
1102 case 0:
1103 circ_mec = QgsCircle();
1104 break;
1105 case 1:
1106 circ_mec = QgsCircle( QgsPoint( boundary.last() ), 0 );
1107 boundary.pop_back();
1108 break;
1109 case 2:
1110 {
1111 QgsPointXY p1 = boundary.last();
1112 boundary.pop_back();
1113 QgsPointXY p2 = boundary.last();
1114 boundary.pop_back();
1115 circ_mec = QgsCircle::from2Points( QgsPoint( p1 ), QgsPoint( p2 ) );
1116 }
1117 break;
1118 default:
1119 QgsPoint p1( boundary.at( 0 ) );
1120 QgsPoint p2( boundary.at( 1 ) );
1121 QgsPoint p3( boundary.at( 2 ) );
1122 circ_mec = QgsCircle::minimalCircleFrom3Points( p1, p2, p3 );
1123 break;
1124 }
1125 return circ_mec;
1126 }
1127 else
1128 {
1129 QgsPointXY pxy = points.last();
1130 points.pop_back();
1131 circ_mec = __recMinimalEnclosingCircle( points, boundary );
1132 QgsPoint p( pxy );
1133 if ( !circ_mec.contains( p ) )
1134 {
1135 boundary.append( pxy );
1136 circ_mec = __recMinimalEnclosingCircle( points, boundary );
1137 }
1138 }
1139 return circ_mec;
1140}
1141
1142QgsGeometry QgsGeometry::minimalEnclosingCircle( QgsPointXY &center, double &radius, unsigned int segments ) const
1143{
1144 center = QgsPointXY();
1145 radius = 0;
1146
1147 if ( isEmpty() )
1148 {
1149 return QgsGeometry();
1150 }
1151
1152 /* optimization */
1153 QgsGeometry hull = convexHull();
1154 if ( hull.isNull() )
1155 return QgsGeometry();
1156
1157 QgsMultiPointXY P = hull.convertToPoint( true ).asMultiPoint();
1159
1160 QgsCircle circ = __recMinimalEnclosingCircle( P, R );
1161 center = QgsPointXY( circ.center() );
1162 radius = circ.radius();
1163 QgsGeometry geom;
1164 geom.set( circ.toPolygon( segments ) );
1165 return geom;
1166
1167}
1168
1170{
1171 QgsPointXY center;
1172 double radius;
1173 return minimalEnclosingCircle( center, radius, segments );
1174
1175}
1176
1177QgsGeometry QgsGeometry::orthogonalize( double tolerance, int maxIterations, double angleThreshold ) const
1178{
1179 QgsInternalGeometryEngine engine( *this );
1180
1181 return engine.orthogonalize( tolerance, maxIterations, angleThreshold );
1182}
1183
1184QgsGeometry QgsGeometry::triangularWaves( double wavelength, double amplitude, bool strictWavelength ) const
1185{
1186 QgsInternalGeometryEngine engine( *this );
1187 return engine.triangularWaves( wavelength, amplitude, strictWavelength );
1188}
1189
1190QgsGeometry QgsGeometry::triangularWavesRandomized( double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed ) const
1191{
1192 QgsInternalGeometryEngine engine( *this );
1193 return engine.triangularWavesRandomized( minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, seed );
1194}
1195
1196QgsGeometry QgsGeometry::squareWaves( double wavelength, double amplitude, bool strictWavelength ) const
1197{
1198 QgsInternalGeometryEngine engine( *this );
1199 return engine.squareWaves( wavelength, amplitude, strictWavelength );
1200}
1201
1202QgsGeometry QgsGeometry::squareWavesRandomized( double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed ) const
1203{
1204 QgsInternalGeometryEngine engine( *this );
1205 return engine.squareWavesRandomized( minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, seed );
1206}
1207
1208QgsGeometry QgsGeometry::roundWaves( double wavelength, double amplitude, bool strictWavelength ) const
1209{
1210 QgsInternalGeometryEngine engine( *this );
1211 return engine.roundWaves( wavelength, amplitude, strictWavelength );
1212}
1213
1214QgsGeometry QgsGeometry::roundWavesRandomized( double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed ) const
1215{
1216 QgsInternalGeometryEngine engine( *this );
1217 return engine.roundWavesRandomized( minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, seed );
1218}
1219
1220QgsGeometry QgsGeometry::applyDashPattern( const QVector<double> &pattern, Qgis::DashPatternLineEndingRule startRule, Qgis::DashPatternLineEndingRule endRule, Qgis::DashPatternSizeAdjustment adjustment, double patternOffset ) const
1221{
1222 QgsInternalGeometryEngine engine( *this );
1223 return engine.applyDashPattern( pattern, startRule, endRule, adjustment, patternOffset );
1224}
1225
1226QgsGeometry QgsGeometry::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing ) const
1227{
1228 if ( !d->geometry )
1229 {
1230 return QgsGeometry();
1231 }
1232 return QgsGeometry( d->geometry->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing ) );
1233}
1234
1235bool QgsGeometry::removeDuplicateNodes( double epsilon, bool useZValues )
1236{
1237 if ( !d->geometry )
1238 return false;
1239
1240 detach();
1241 return d->geometry->removeDuplicateNodes( epsilon, useZValues );
1242}
1243
1245{
1246 // fast case, check bounding boxes
1247 if ( !boundingBoxIntersects( r ) )
1248 return false;
1249
1250 const Qgis::WkbType flatType { QgsWkbTypes::flatType( d->geometry->wkbType() ) };
1251 // optimise trivial case for point intersections -- the bounding box test has already given us the answer
1252 if ( flatType == Qgis::WkbType::Point )
1253 {
1254 return true;
1255 }
1256
1257 // Workaround for issue issue GH #51429
1258 // in case of multi polygon, intersection with an empty rect fails
1259 if ( flatType == Qgis::WkbType::MultiPolygon && r.isEmpty() )
1260 {
1261 const QgsPointXY center { r.xMinimum(), r.yMinimum() };
1262 return contains( QgsGeometry::fromPointXY( center ) );
1263 }
1264
1265 QgsGeometry g = fromRect( r );
1266 return intersects( g );
1267}
1268
1269bool QgsGeometry::intersects( const QgsGeometry &geometry ) const
1270{
1271 if ( !d->geometry || geometry.isNull() )
1272 {
1273 return false;
1274 }
1275
1276 QgsGeos geos( d->geometry.get() );
1277 mLastError.clear();
1278 return geos.intersects( geometry.d->geometry.get(), &mLastError );
1279}
1280
1282{
1283 if ( !d->geometry )
1284 {
1285 return false;
1286 }
1287
1288 return d->geometry->boundingBoxIntersects( rectangle );
1289}
1290
1292{
1293 if ( !d->geometry || geometry.isNull() )
1294 {
1295 return false;
1296 }
1297
1298 return d->geometry->boundingBoxIntersects( geometry.constGet()->boundingBox() );
1299}
1300
1301bool QgsGeometry::contains( const QgsPointXY *p ) const
1302{
1303 if ( !d->geometry || !p )
1304 {
1305 return false;
1306 }
1307
1308 QgsPoint pt( p->x(), p->y() );
1309 QgsGeos geos( d->geometry.get() );
1310 mLastError.clear();
1311 return geos.contains( &pt, &mLastError );
1312}
1313
1314bool QgsGeometry::contains( const QgsGeometry &geometry ) const
1315{
1316 if ( !d->geometry || geometry.isNull() )
1317 {
1318 return false;
1319 }
1320
1321 QgsGeos geos( d->geometry.get() );
1322 mLastError.clear();
1323 return geos.contains( geometry.d->geometry.get(), &mLastError );
1324}
1325
1326bool QgsGeometry::disjoint( const QgsGeometry &geometry ) const
1327{
1328 if ( !d->geometry || geometry.isNull() )
1329 {
1330 return false;
1331 }
1332
1333 QgsGeos geos( d->geometry.get() );
1334 mLastError.clear();
1335 return geos.disjoint( geometry.d->geometry.get(), &mLastError );
1336}
1337
1338bool QgsGeometry::equals( const QgsGeometry &geometry ) const
1339{
1340 if ( !d->geometry || geometry.isNull() )
1341 {
1342 return false;
1343 }
1344
1345 // fast check - are they shared copies of the same underlying geometry?
1346 if ( d == geometry.d )
1347 return true;
1348
1349 // fast check - distinct geometry types?
1350 if ( type() != geometry.type() )
1351 return false;
1352
1353 // slower check - actually test the geometries
1354 return *d->geometry == *geometry.d->geometry;
1355}
1356
1357bool QgsGeometry::touches( const QgsGeometry &geometry ) const
1358{
1359 if ( !d->geometry || geometry.isNull() )
1360 {
1361 return false;
1362 }
1363
1364 QgsGeos geos( d->geometry.get() );
1365 mLastError.clear();
1366 return geos.touches( geometry.d->geometry.get(), &mLastError );
1367}
1368
1369bool QgsGeometry::overlaps( const QgsGeometry &geometry ) const
1370{
1371 if ( !d->geometry || geometry.isNull() )
1372 {
1373 return false;
1374 }
1375
1376 QgsGeos geos( d->geometry.get() );
1377 mLastError.clear();
1378 return geos.overlaps( geometry.d->geometry.get(), &mLastError );
1379}
1380
1381bool QgsGeometry::within( const QgsGeometry &geometry ) const
1382{
1383 if ( !d->geometry || geometry.isNull() )
1384 {
1385 return false;
1386 }
1387
1388 QgsGeos geos( d->geometry.get() );
1389 mLastError.clear();
1390 return geos.within( geometry.d->geometry.get(), &mLastError );
1391}
1392
1393bool QgsGeometry::crosses( const QgsGeometry &geometry ) const
1394{
1395 if ( !d->geometry || geometry.isNull() )
1396 {
1397 return false;
1398 }
1399
1400 QgsGeos geos( d->geometry.get() );
1401 mLastError.clear();
1402 return geos.crosses( geometry.d->geometry.get(), &mLastError );
1403}
1404
1405QString QgsGeometry::asWkt( int precision ) const
1406{
1407 if ( !d->geometry )
1408 {
1409 return QString();
1410 }
1411 return d->geometry->asWkt( precision );
1412}
1413
1414QString QgsGeometry::asJson( int precision ) const
1415{
1416 return QString::fromStdString( asJsonObject( precision ).dump() );
1417}
1418
1420{
1421 if ( !d->geometry )
1422 {
1423 return nullptr;
1424 }
1425 return d->geometry->asJsonObject( precision );
1426
1427}
1428
1429QVector<QgsGeometry> QgsGeometry::coerceToType( const Qgis::WkbType type, double defaultZ, double defaultM ) const
1430{
1431 QVector< QgsGeometry > res;
1432 if ( isNull() )
1433 return res;
1434
1435 if ( wkbType() == type || type == Qgis::WkbType::Unknown )
1436 {
1437 res << *this;
1438 return res;
1439 }
1440
1442 {
1443 return res;
1444 }
1445
1446 QgsGeometry newGeom = *this;
1447
1448 // Curved -> straight
1450 {
1451 newGeom = QgsGeometry( d->geometry.get()->segmentize() );
1452 }
1453
1454 // polygon -> line
1455 if ( QgsWkbTypes::geometryType( type ) == Qgis::GeometryType::Line &&
1456 newGeom.type() == Qgis::GeometryType::Polygon )
1457 {
1458 // boundary gives us a (multi)line string of exterior + interior rings
1459 newGeom = QgsGeometry( newGeom.constGet()->boundary() );
1460 }
1461 // line -> polygon
1462 if ( QgsWkbTypes::geometryType( type ) == Qgis::GeometryType::Polygon &&
1463 newGeom.type() == Qgis::GeometryType::Line )
1464 {
1465 std::unique_ptr< QgsGeometryCollection > gc( QgsGeometryFactory::createCollectionOfType( type ) );
1466 const QgsGeometry source = newGeom;
1467 for ( auto part = source.const_parts_begin(); part != source.const_parts_end(); ++part )
1468 {
1469 std::unique_ptr< QgsAbstractGeometry > exterior( ( *part )->clone() );
1470 if ( QgsCurve *curve = qgsgeometry_cast< QgsCurve * >( exterior.get() ) )
1471 {
1473 {
1474 std::unique_ptr< QgsCurvePolygon > cp = std::make_unique< QgsCurvePolygon >();
1475 cp->setExteriorRing( curve );
1476 exterior.release();
1477 gc->addGeometry( cp.release() );
1478 }
1479 else
1480 {
1481 std::unique_ptr< QgsPolygon > p = std::make_unique< QgsPolygon >();
1482 p->setExteriorRing( qgsgeometry_cast< QgsLineString * >( curve ) );
1483 exterior.release();
1484 gc->addGeometry( p.release() );
1485 }
1486 }
1487 }
1488 newGeom = QgsGeometry( std::move( gc ) );
1489 }
1490
1491 // line/polygon -> points
1492 if ( QgsWkbTypes::geometryType( type ) == Qgis::GeometryType::Point &&
1493 ( newGeom.type() == Qgis::GeometryType::Line ||
1494 newGeom.type() == Qgis::GeometryType::Polygon ) )
1495 {
1496 // lines/polygons to a point layer, extract all vertices
1497 std::unique_ptr< QgsMultiPoint > mp = std::make_unique< QgsMultiPoint >();
1498 const QgsGeometry source = newGeom;
1499 QSet< QgsPoint > added;
1500 for ( auto vertex = source.vertices_begin(); vertex != source.vertices_end(); ++vertex )
1501 {
1502 if ( added.contains( *vertex ) )
1503 continue; // avoid duplicate points, e.g. start/end of rings
1504 mp->addGeometry( ( *vertex ).clone() );
1505 added.insert( *vertex );
1506 }
1507 newGeom = QgsGeometry( std::move( mp ) );
1508 }
1509
1510 // Single -> multi
1511 if ( QgsWkbTypes::isMultiType( type ) && ! newGeom.isMultipart( ) )
1512 {
1513 newGeom.convertToMultiType();
1514 }
1515 // Drop Z/M
1516 if ( newGeom.constGet()->is3D() && ! QgsWkbTypes::hasZ( type ) )
1517 {
1518 newGeom.get()->dropZValue();
1519 }
1520 if ( newGeom.constGet()->isMeasure() && ! QgsWkbTypes::hasM( type ) )
1521 {
1522 newGeom.get()->dropMValue();
1523 }
1524 // Add Z/M back, set to 0
1525 if ( ! newGeom.constGet()->is3D() && QgsWkbTypes::hasZ( type ) )
1526 {
1527 newGeom.get()->addZValue( defaultZ );
1528 }
1529 if ( ! newGeom.constGet()->isMeasure() && QgsWkbTypes::hasM( type ) )
1530 {
1531 newGeom.get()->addMValue( defaultM );
1532 }
1533
1534 // Straight -> curve
1536 {
1537 newGeom.convertToCurvedMultiType();
1538 }
1539
1540 // Multi -> single
1541 if ( ! QgsWkbTypes::isMultiType( type ) && newGeom.isMultipart( ) )
1542 {
1543 const QgsGeometryCollection *parts( static_cast< const QgsGeometryCollection * >( newGeom.constGet() ) );
1544 res.reserve( parts->partCount() );
1545 for ( int i = 0; i < parts->partCount( ); i++ )
1546 {
1547 res << QgsGeometry( parts->geometryN( i )->clone() );
1548 }
1549 }
1550 else
1551 {
1552 res << newGeom;
1553 }
1554 return res;
1555}
1556
1557QgsGeometry QgsGeometry::convertToType( Qgis::GeometryType destType, bool destMultipart ) const
1558{
1559 switch ( destType )
1560 {
1561 case Qgis::GeometryType::Point:
1562 return convertToPoint( destMultipart );
1563
1564 case Qgis::GeometryType::Line:
1565 return convertToLine( destMultipart );
1566
1567 case Qgis::GeometryType::Polygon:
1568 return convertToPolygon( destMultipart );
1569
1570 default:
1571 return QgsGeometry();
1572 }
1573}
1574
1576{
1577 if ( !d->geometry )
1578 {
1579 return false;
1580 }
1581
1582 if ( isMultipart() ) //already multitype, no need to convert
1583 {
1584 return true;
1585 }
1586
1587 std::unique_ptr< QgsAbstractGeometry >geom = QgsGeometryFactory::geomFromWkbType( QgsWkbTypes::multiType( d->geometry->wkbType() ) );
1588 QgsGeometryCollection *multiGeom = qgsgeometry_cast<QgsGeometryCollection *>( geom.get() );
1589 if ( !multiGeom )
1590 {
1591 return false;
1592 }
1593
1594 //try to avoid cloning existing geometry whenever we can
1595
1596 //want to see a magic trick?... gather round kiddies...
1597 detach(); // maybe a clone, hopefully not if we're the only ref to the private data
1598 // now we cheat a bit and steal the private geometry and add it direct to the multigeom
1599 // we can do this because we're the only ref to this geometry, guaranteed by the detach call above
1600 multiGeom->addGeometry( d->geometry.release() );
1601 // and replace it with the multi geometry.
1602 // TADA! a clone free conversion in some cases
1603 d->geometry = std::move( geom );
1604 return true;
1605}
1606
1608{
1609 if ( !d->geometry )
1610 {
1611 return false;
1612 }
1613
1614 switch ( QgsWkbTypes::flatType( d->geometry->wkbType() ) )
1615 {
1620 {
1621 return true;
1622 }
1623 default:
1624 break;
1625 }
1626
1627 std::unique_ptr< QgsAbstractGeometry >geom = QgsGeometryFactory::geomFromWkbType( QgsWkbTypes::curveType( QgsWkbTypes::multiType( d->geometry->wkbType() ) ) );
1628 QgsGeometryCollection *multiGeom = qgsgeometry_cast<QgsGeometryCollection *>( geom.get() );
1629 if ( !multiGeom )
1630 {
1631 return false;
1632 }
1633
1634 QgsGeometryCollection *sourceMultiGeom = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
1635 if ( sourceMultiGeom )
1636 {
1637 for ( int i = 0; i < sourceMultiGeom->numGeometries(); ++i )
1638 {
1639 if ( !multiGeom->addGeometry( sourceMultiGeom->geometryN( i )->clone() ) )
1640 return false;
1641 }
1642 }
1643 else
1644 {
1645 if ( !multiGeom->addGeometry( d->geometry->clone() ) )
1646 return false;
1647 }
1648
1649 reset( std::move( geom ) );
1650 return true;
1651}
1652
1654{
1655 if ( !d->geometry )
1656 {
1657 return false;
1658 }
1659
1660 if ( !isMultipart() ) //already single part, no need to convert
1661 {
1662 return true;
1663 }
1664
1665 QgsGeometryCollection *multiGeom = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
1666 if ( !multiGeom || multiGeom->partCount() < 1 )
1667 return false;
1668
1669 std::unique_ptr< QgsAbstractGeometry > firstPart( multiGeom->geometryN( 0 )->clone() );
1670 reset( std::move( firstPart ) );
1671 return true;
1672}
1673
1674
1676{
1677 const QgsGeometryCollection *origGeom = qgsgeometry_cast<const QgsGeometryCollection *>( constGet() );
1678 if ( !origGeom )
1679 return false;
1680
1681 std::unique_ptr<QgsGeometryCollection> resGeom;
1682 switch ( geomType )
1683 {
1684 case Qgis::GeometryType::Point:
1685 resGeom = std::make_unique<QgsMultiPoint>();
1686 break;
1687 case Qgis::GeometryType::Line:
1688 resGeom = std::make_unique<QgsMultiLineString>();
1689 break;
1690 case Qgis::GeometryType::Polygon:
1691 resGeom = std::make_unique<QgsMultiPolygon>();
1692 break;
1693 default:
1694 break;
1695 }
1696 if ( !resGeom )
1697 return false;
1698
1699 resGeom->reserve( origGeom->numGeometries() );
1700 for ( int i = 0; i < origGeom->numGeometries(); ++i )
1701 {
1702 const QgsAbstractGeometry *g = origGeom->geometryN( i );
1703 if ( QgsWkbTypes::geometryType( g->wkbType() ) == geomType )
1704 resGeom->addGeometry( g->clone() );
1705 }
1706
1707 set( resGeom.release() );
1708 return true;
1709}
1710
1711
1713{
1714 if ( !d->geometry )
1715 {
1716 return QgsPointXY();
1717 }
1718 if ( QgsPoint *pt = qgsgeometry_cast<QgsPoint *>( d->geometry->simplifiedTypeRef() ) )
1719 {
1720 return QgsPointXY( pt->x(), pt->y() );
1721 }
1722 else
1723 {
1724 return QgsPointXY();
1725 }
1726}
1727
1729{
1730 QgsPolylineXY polyLine;
1731 if ( !d->geometry )
1732 {
1733 return polyLine;
1734 }
1735
1736 bool doSegmentation = ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == Qgis::WkbType::CompoundCurve
1738 std::unique_ptr< QgsLineString > segmentizedLine;
1739 QgsLineString *line = nullptr;
1740 if ( doSegmentation )
1741 {
1742 QgsCurve *curve = qgsgeometry_cast<QgsCurve *>( d->geometry.get() );
1743 if ( !curve )
1744 {
1745 return polyLine;
1746 }
1747 segmentizedLine.reset( curve->curveToLine() );
1748 line = segmentizedLine.get();
1749 }
1750 else
1751 {
1752 line = qgsgeometry_cast<QgsLineString *>( d->geometry.get() );
1753 if ( !line )
1754 {
1755 return polyLine;
1756 }
1757 }
1758
1759 int nVertices = line->numPoints();
1760 polyLine.resize( nVertices );
1761 QgsPointXY *data = polyLine.data();
1762 const double *xData = line->xData();
1763 const double *yData = line->yData();
1764 for ( int i = 0; i < nVertices; ++i )
1765 {
1766 data->setX( *xData++ );
1767 data->setY( *yData++ );
1768 data++;
1769 }
1770
1771 return polyLine;
1772}
1773
1775{
1776 if ( !d->geometry )
1777 return QgsPolygonXY();
1778
1779 bool doSegmentation = ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == Qgis::WkbType::CurvePolygon );
1780
1781 QgsPolygon *p = nullptr;
1782 std::unique_ptr< QgsPolygon > segmentized;
1783 if ( doSegmentation )
1784 {
1785 QgsCurvePolygon *curvePoly = qgsgeometry_cast<QgsCurvePolygon *>( d->geometry.get() );
1786 if ( !curvePoly )
1787 {
1788 return QgsPolygonXY();
1789 }
1790 segmentized.reset( curvePoly->toPolygon() );
1791 p = segmentized.get();
1792 }
1793 else
1794 {
1795 p = qgsgeometry_cast<QgsPolygon *>( d->geometry.get() );
1796 }
1797
1798 if ( !p )
1799 {
1800 return QgsPolygonXY();
1801 }
1802
1803 QgsPolygonXY polygon;
1804 convertPolygon( *p, polygon );
1805
1806 return polygon;
1807}
1808
1810{
1811 if ( !d->geometry || QgsWkbTypes::flatType( d->geometry->wkbType() ) != Qgis::WkbType::MultiPoint )
1812 {
1813 return QgsMultiPointXY();
1814 }
1815
1816 const QgsMultiPoint *mp = qgsgeometry_cast<QgsMultiPoint *>( d->geometry.get() );
1817 if ( !mp )
1818 {
1819 return QgsMultiPointXY();
1820 }
1821
1822 int nPoints = mp->numGeometries();
1823 QgsMultiPointXY multiPoint( nPoints );
1824 for ( int i = 0; i < nPoints; ++i )
1825 {
1826 const QgsPoint *pt = mp->pointN( i );
1827 multiPoint[i].setX( pt->x() );
1828 multiPoint[i].setY( pt->y() );
1829 }
1830 return multiPoint;
1831}
1832
1834{
1835 if ( !d->geometry )
1836 {
1837 return QgsMultiPolylineXY();
1838 }
1839
1840 QgsGeometryCollection *geomCollection = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
1841 if ( !geomCollection )
1842 {
1843 return QgsMultiPolylineXY();
1844 }
1845
1846 int nLines = geomCollection->numGeometries();
1847 if ( nLines < 1 )
1848 {
1849 return QgsMultiPolylineXY();
1850 }
1851
1853 mpl.reserve( nLines );
1854 for ( int i = 0; i < nLines; ++i )
1855 {
1856 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( geomCollection->geometryN( i ) );
1857 std::unique_ptr< QgsLineString > segmentized;
1858 if ( !line )
1859 {
1860 const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( geomCollection->geometryN( i ) );
1861 if ( !curve )
1862 {
1863 continue;
1864 }
1865 segmentized.reset( curve->curveToLine() );
1866 line = segmentized.get();
1867 }
1868
1869 QgsPolylineXY polyLine;
1870 int nVertices = line->numPoints();
1871 polyLine.resize( nVertices );
1872 QgsPointXY *data = polyLine.data();
1873 const double *xData = line->xData();
1874 const double *yData = line->yData();
1875 for ( int i = 0; i < nVertices; ++i )
1876 {
1877 data->setX( *xData++ );
1878 data->setY( *yData++ );
1879 data++;
1880 }
1881 mpl.append( polyLine );
1882 }
1883 return mpl;
1884}
1885
1887{
1888 if ( !d->geometry )
1889 {
1890 return QgsMultiPolygonXY();
1891 }
1892
1893 const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( d->geometry.get() );
1894 if ( !geomCollection )
1895 {
1896 return QgsMultiPolygonXY();
1897 }
1898
1899 const int nPolygons = geomCollection->numGeometries();
1900 if ( nPolygons < 1 )
1901 {
1902 return QgsMultiPolygonXY();
1903 }
1904
1906 mp.reserve( nPolygons );
1907 for ( int i = 0; i < nPolygons; ++i )
1908 {
1909 const QgsPolygon *polygon = qgsgeometry_cast<const QgsPolygon *>( geomCollection->geometryN( i ) );
1910 if ( !polygon )
1911 {
1912 const QgsCurvePolygon *cPolygon = qgsgeometry_cast<const QgsCurvePolygon *>( geomCollection->geometryN( i ) );
1913 if ( cPolygon )
1914 {
1915 polygon = cPolygon->toPolygon();
1916 }
1917 else
1918 {
1919 continue;
1920 }
1921 }
1922
1923 QgsPolygonXY poly;
1924 convertPolygon( *polygon, poly );
1925 mp.push_back( poly );
1926 }
1927 return mp;
1928}
1929
1930double QgsGeometry::area() const
1931{
1932 if ( !d->geometry )
1933 {
1934 return -1.0;
1935 }
1936
1937 return d->geometry->area();
1938}
1939
1941{
1942 if ( !d->geometry )
1943 {
1944 return -1.0;
1945 }
1946
1947 switch ( QgsWkbTypes::geometryType( d->geometry->wkbType() ) )
1948 {
1949 case Qgis::GeometryType::Point:
1950 return 0.0;
1951
1952 case Qgis::GeometryType::Line:
1953 return d->geometry->length();
1954
1955 case Qgis::GeometryType::Polygon:
1956 return d->geometry->perimeter();
1957
1958 case Qgis::GeometryType::Unknown:
1959 case Qgis::GeometryType::Null:
1960 return d->geometry->length();
1961 }
1962 return -1;
1963}
1964
1965double QgsGeometry::distance( const QgsGeometry &geom ) const
1966{
1967 if ( !d->geometry || !geom.d->geometry )
1968 {
1969 return -1.0;
1970 }
1971
1972 // avoid calling geos for trivial point-to-point distance calculations
1974 {
1975 return qgsgeometry_cast< const QgsPoint * >( d->geometry.get() )->distance( *qgsgeometry_cast< const QgsPoint * >( geom.constGet() ) );
1976 }
1977
1978 QgsGeos g( d->geometry.get() );
1979 mLastError.clear();
1980 return g.distance( geom.d->geometry.get(), &mLastError );
1981}
1982
1984{
1985 if ( !d->geometry || !geom.d->geometry )
1986 {
1987 return -1.0;
1988 }
1989
1990 QgsGeos g( d->geometry.get() );
1991 mLastError.clear();
1992 return g.hausdorffDistance( geom.d->geometry.get(), &mLastError );
1993}
1994
1995double QgsGeometry::hausdorffDistanceDensify( const QgsGeometry &geom, double densifyFraction ) const
1996{
1997 if ( !d->geometry || !geom.d->geometry )
1998 {
1999 return -1.0;
2000 }
2001
2002 QgsGeos g( d->geometry.get() );
2003 mLastError.clear();
2004 return g.hausdorffDistanceDensify( geom.d->geometry.get(), densifyFraction, &mLastError );
2005}
2006
2007
2009{
2010 if ( !d->geometry || !geom.d->geometry )
2011 {
2012 return -1.0;
2013 }
2014
2015 QgsGeos g( d->geometry.get() );
2016 mLastError.clear();
2017 return g.frechetDistance( geom.d->geometry.get(), &mLastError );
2018}
2019
2020double QgsGeometry::frechetDistanceDensify( const QgsGeometry &geom, double densifyFraction ) const
2021{
2022 if ( !d->geometry || !geom.d->geometry )
2023 {
2024 return -1.0;
2025 }
2026
2027 QgsGeos g( d->geometry.get() );
2028 mLastError.clear();
2029 return g.frechetDistanceDensify( geom.d->geometry.get(), densifyFraction, &mLastError );
2030}
2031
2033{
2034 if ( !d->geometry || d->geometry.get()->isEmpty() )
2036 return d->geometry->vertices_begin();
2037}
2038
2040{
2041 if ( !d->geometry || d->geometry.get()->isEmpty() )
2043 return d->geometry->vertices_end();
2044}
2045
2047{
2048 if ( !d->geometry || d->geometry.get()->isEmpty() )
2049 return QgsVertexIterator();
2050 return QgsVertexIterator( d->geometry.get() );
2051}
2052
2054{
2055 if ( !d->geometry )
2057
2058 detach();
2059 return d->geometry->parts_begin();
2060}
2061
2063{
2064 if ( !d->geometry )
2066 return d->geometry->parts_end();
2067}
2068
2070{
2071 if ( !d->geometry )
2073 return d->geometry->const_parts_begin();
2074}
2075
2077{
2078 if ( !d->geometry )
2080 return d->geometry->const_parts_end();
2081}
2082
2084{
2085 if ( !d->geometry )
2086 return QgsGeometryPartIterator();
2087
2088 detach();
2089 return QgsGeometryPartIterator( d->geometry.get() );
2090}
2091
2093{
2094 if ( !d->geometry )
2096
2097 return QgsGeometryConstPartIterator( d->geometry.get() );
2098}
2099
2100QgsGeometry QgsGeometry::buffer( double distance, int segments ) const
2101{
2102 if ( !d->geometry )
2103 {
2104 return QgsGeometry();
2105 }
2106
2107 QgsGeos g( d->geometry.get() );
2108 mLastError.clear();
2109 std::unique_ptr<QgsAbstractGeometry> geom( g.buffer( distance, segments, &mLastError ) );
2110 if ( !geom )
2111 {
2112 QgsGeometry result;
2113 result.mLastError = mLastError;
2114 return result;
2115 }
2116 return QgsGeometry( std::move( geom ) );
2117}
2118
2119QgsGeometry QgsGeometry::buffer( double distance, int segments, Qgis::EndCapStyle endCapStyle, Qgis::JoinStyle joinStyle, double miterLimit ) const
2120{
2121 if ( !d->geometry )
2122 {
2123 return QgsGeometry();
2124 }
2125
2126 QgsGeos g( d->geometry.get() );
2127 mLastError.clear();
2128 QgsAbstractGeometry *geom = g.buffer( distance, segments, endCapStyle, joinStyle, miterLimit, &mLastError );
2129 if ( !geom )
2130 {
2131 QgsGeometry result;
2132 result.mLastError = mLastError;
2133 return result;
2134 }
2135 return QgsGeometry( geom );
2136}
2137
2138QgsGeometry QgsGeometry::offsetCurve( double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit ) const
2139{
2140 if ( !d->geometry || type() != Qgis::GeometryType::Line )
2141 {
2142 return QgsGeometry();
2143 }
2144
2145 if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
2146 {
2147 const QVector<QgsGeometry> parts = asGeometryCollection();
2148 QVector<QgsGeometry> results;
2149 results.reserve( parts.count() );
2150 for ( const QgsGeometry &part : parts )
2151 {
2152 QgsGeometry result = part.offsetCurve( distance, segments, joinStyle, miterLimit );
2153 if ( !result.isNull() )
2154 results << result;
2155 }
2156 if ( results.isEmpty() )
2157 return QgsGeometry();
2158
2159 QgsGeometry first = results.takeAt( 0 );
2160 for ( const QgsGeometry &result : std::as_const( results ) )
2161 {
2162 first.addPart( result );
2163 }
2164 return first;
2165 }
2166 else
2167 {
2168 QgsGeos geos( d->geometry.get() );
2169 mLastError.clear();
2170
2171 // GEOS can flip the curve orientation in some circumstances. So record previous orientation and correct if required
2172 const Qgis::AngularDirection prevOrientation = qgsgeometry_cast< const QgsCurve * >( d->geometry.get() )->orientation();
2173
2174 std::unique_ptr< QgsAbstractGeometry > offsetGeom( geos.offsetCurve( distance, segments, joinStyle, miterLimit, &mLastError ) );
2175 if ( !offsetGeom )
2176 {
2177 QgsGeometry result;
2178 result.mLastError = mLastError;
2179 return result;
2180 }
2181
2182 if ( const QgsCurve *offsetCurve = qgsgeometry_cast< const QgsCurve * >( offsetGeom.get() ) )
2183 {
2184 const Qgis::AngularDirection newOrientation = offsetCurve->orientation();
2185 if ( newOrientation != prevOrientation )
2186 {
2187 // GEOS has flipped line orientation, flip it back
2188 std::unique_ptr< QgsAbstractGeometry > flipped( offsetCurve->reversed() );
2189 offsetGeom = std::move( flipped );
2190 }
2191 }
2192 return QgsGeometry( std::move( offsetGeom ) );
2193 }
2194}
2195
2196QgsGeometry QgsGeometry::singleSidedBuffer( double distance, int segments, Qgis::BufferSide side, Qgis::JoinStyle joinStyle, double miterLimit ) const
2197{
2198 if ( !d->geometry || type() != Qgis::GeometryType::Line )
2199 {
2200 return QgsGeometry();
2201 }
2202
2203 if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
2204 {
2205 const QVector<QgsGeometry> parts = asGeometryCollection();
2206 QVector<QgsGeometry> results;
2207 results.reserve( parts.count() );
2208 for ( const QgsGeometry &part : parts )
2209 {
2210 QgsGeometry result = part.singleSidedBuffer( distance, segments, side, joinStyle, miterLimit );
2211 if ( !result.isNull() )
2212 results << result;
2213 }
2214 if ( results.isEmpty() )
2215 return QgsGeometry();
2216
2217 QgsGeometry first = results.takeAt( 0 );
2218 for ( const QgsGeometry &result : std::as_const( results ) )
2219 {
2220 first.addPart( result );
2221 }
2222 return first;
2223 }
2224 else
2225 {
2226 QgsGeos geos( d->geometry.get() );
2227 mLastError.clear();
2228 std::unique_ptr< QgsAbstractGeometry > bufferGeom = geos.singleSidedBuffer( distance, segments, side,
2229 joinStyle, miterLimit, &mLastError );
2230 if ( !bufferGeom )
2231 {
2232 QgsGeometry result;
2233 result.mLastError = mLastError;
2234 return result;
2235 }
2236 return QgsGeometry( std::move( bufferGeom ) );
2237 }
2238}
2239
2240QgsGeometry QgsGeometry::taperedBuffer( double startWidth, double endWidth, int segments ) const
2241{
2242 QgsInternalGeometryEngine engine( *this );
2243
2244 return engine.taperedBuffer( startWidth, endWidth, segments );
2245}
2246
2248{
2249 QgsInternalGeometryEngine engine( *this );
2250
2251 return engine.variableWidthBufferByM( segments );
2252}
2253
2254QgsGeometry QgsGeometry::extendLine( double startDistance, double endDistance ) const
2255{
2256 if ( !d->geometry || type() != Qgis::GeometryType::Line )
2257 {
2258 return QgsGeometry();
2259 }
2260
2261 if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
2262 {
2263 const QVector<QgsGeometry> parts = asGeometryCollection();
2264 QVector<QgsGeometry> results;
2265 results.reserve( parts.count() );
2266 for ( const QgsGeometry &part : parts )
2267 {
2268 QgsGeometry result = part.extendLine( startDistance, endDistance );
2269 if ( !result.isNull() )
2270 results << result;
2271 }
2272 if ( results.isEmpty() )
2273 return QgsGeometry();
2274
2275 QgsGeometry first = results.takeAt( 0 );
2276 for ( const QgsGeometry &result : std::as_const( results ) )
2277 {
2278 first.addPart( result );
2279 }
2280 return first;
2281 }
2282 else
2283 {
2284 QgsLineString *line = qgsgeometry_cast< QgsLineString * >( d->geometry.get() );
2285 if ( !line )
2286 return QgsGeometry();
2287
2288 std::unique_ptr< QgsLineString > newLine( line->clone() );
2289 newLine->extend( startDistance, endDistance );
2290 return QgsGeometry( std::move( newLine ) );
2291 }
2292}
2293
2294QgsGeometry QgsGeometry::simplify( double tolerance ) const
2295{
2296 if ( !d->geometry )
2297 {
2298 return QgsGeometry();
2299 }
2300
2301 QgsGeos geos( d->geometry.get() );
2302 mLastError.clear();
2303 std::unique_ptr< QgsAbstractGeometry > simplifiedGeom( geos.simplify( tolerance, &mLastError ) );
2304 if ( !simplifiedGeom )
2305 {
2306 QgsGeometry result;
2307 result.mLastError = mLastError;
2308 return result;
2309 }
2310 return QgsGeometry( std::move( simplifiedGeom ) );
2311}
2312
2313QgsGeometry QgsGeometry::densifyByCount( int extraNodesPerSegment ) const
2314{
2315 QgsInternalGeometryEngine engine( *this );
2316
2317 return engine.densifyByCount( extraNodesPerSegment );
2318}
2319
2321{
2322 QgsInternalGeometryEngine engine( *this );
2323
2324 return engine.densifyByDistance( distance );
2325}
2326
2327QgsGeometry QgsGeometry::convertToCurves( double distanceTolerance, double angleTolerance ) const
2328{
2329 QgsInternalGeometryEngine engine( *this );
2330
2331 return engine.convertToCurves( distanceTolerance, angleTolerance );
2332}
2333
2335{
2336 if ( !d->geometry )
2337 {
2338 return QgsGeometry();
2339 }
2340
2341 // avoid calling geos for trivial point centroids
2342 if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == Qgis::WkbType::Point )
2343 {
2344 QgsGeometry c = *this;
2345 c.get()->dropZValue();
2346 c.get()->dropMValue();
2347 return c;
2348 }
2349
2350 QgsGeos geos( d->geometry.get() );
2351
2352 mLastError.clear();
2353 QgsGeometry result( geos.centroid( &mLastError ) );
2354 result.mLastError = mLastError;
2355 return result;
2356}
2357
2359{
2360 if ( !d->geometry )
2361 {
2362 return QgsGeometry();
2363 }
2364
2365 QgsGeos geos( d->geometry.get() );
2366
2367 mLastError.clear();
2368 QgsGeometry result( geos.pointOnSurface( &mLastError ) );
2369 result.mLastError = mLastError;
2370 return result;
2371}
2372
2373QgsGeometry QgsGeometry::poleOfInaccessibility( double precision, double *distanceToBoundary ) const
2374{
2375 QgsInternalGeometryEngine engine( *this );
2376
2377 return engine.poleOfInaccessibility( precision, distanceToBoundary );
2378}
2379
2380QgsGeometry QgsGeometry::largestEmptyCircle( double tolerance, const QgsGeometry &boundary ) const
2381{
2382 if ( !d->geometry )
2383 {
2384 return QgsGeometry();
2385 }
2386
2387 QgsGeos geos( d->geometry.get() );
2388
2389 mLastError.clear();
2390 QgsGeometry result( geos.largestEmptyCircle( tolerance, boundary.constGet(), &mLastError ) );
2391 result.mLastError = mLastError;
2392 return result;
2393}
2394
2396{
2397 if ( !d->geometry )
2398 {
2399 return QgsGeometry();
2400 }
2401
2402 QgsGeos geos( d->geometry.get() );
2403
2404 mLastError.clear();
2405 QgsGeometry result( geos.minimumWidth( &mLastError ) );
2406 result.mLastError = mLastError;
2407 return result;
2408}
2409
2411{
2412 if ( !d->geometry )
2413 {
2414 return std::numeric_limits< double >::quiet_NaN();
2415 }
2416
2417 QgsGeos geos( d->geometry.get() );
2418
2419 mLastError.clear();
2420 return geos.minimumClearance( &mLastError );
2421}
2422
2424{
2425 if ( !d->geometry )
2426 {
2427 return QgsGeometry();
2428 }
2429
2430 QgsGeos geos( d->geometry.get() );
2431
2432 mLastError.clear();
2433 QgsGeometry result( geos.minimumClearanceLine( &mLastError ) );
2434 result.mLastError = mLastError;
2435 return result;
2436}
2437
2439{
2440 if ( !d->geometry )
2441 {
2442 return QgsGeometry();
2443 }
2444 QgsGeos geos( d->geometry.get() );
2445 mLastError.clear();
2446 std::unique_ptr< QgsAbstractGeometry > cHull( geos.convexHull( &mLastError ) );
2447 if ( !cHull )
2448 {
2449 QgsGeometry geom;
2450 geom.mLastError = mLastError;
2451 return geom;
2452 }
2453 return QgsGeometry( std::move( cHull ) );
2454}
2455
2456QgsGeometry QgsGeometry::concaveHull( double targetPercent, bool allowHoles ) const
2457{
2458 if ( !d->geometry )
2459 {
2460 return QgsGeometry();
2461 }
2462 QgsGeos geos( d->geometry.get() );
2463 mLastError.clear();
2464 std::unique_ptr< QgsAbstractGeometry > concaveHull( geos.concaveHull( targetPercent, allowHoles, &mLastError ) );
2465 if ( !concaveHull )
2466 {
2467 QgsGeometry geom;
2468 geom.mLastError = mLastError;
2469 return geom;
2470 }
2471 return QgsGeometry( std::move( concaveHull ) );
2472}
2473
2474QgsGeometry QgsGeometry::voronoiDiagram( const QgsGeometry &extent, double tolerance, bool edgesOnly ) const
2475{
2476 if ( !d->geometry )
2477 {
2478 return QgsGeometry();
2479 }
2480
2481 QgsGeos geos( d->geometry.get() );
2482 mLastError.clear();
2483 QgsGeometry result = geos.voronoiDiagram( extent.constGet(), tolerance, edgesOnly, &mLastError );
2484 result.mLastError = mLastError;
2485 return result;
2486}
2487
2488QgsGeometry QgsGeometry::delaunayTriangulation( double tolerance, bool edgesOnly ) const
2489{
2490 if ( !d->geometry )
2491 {
2492 return QgsGeometry();
2493 }
2494
2495 QgsGeos geos( d->geometry.get() );
2496 mLastError.clear();
2497 QgsGeometry result = geos.delaunayTriangulation( tolerance, edgesOnly );
2498 result.mLastError = mLastError;
2499 return result;
2500}
2501
2503{
2504 if ( !d->geometry )
2505 {
2506 return QgsGeometry();
2507 }
2508
2509 QgsGeos geos( d->geometry.get() );
2510 mLastError.clear();
2511 QgsGeometry result( geos.node( &mLastError ) );
2512 result.mLastError = mLastError;
2513 return result;
2514}
2515
2517{
2518 if ( !d->geometry )
2519 {
2520 return QgsGeometry();
2521 }
2522
2523 QgsGeos geos( d->geometry.get() );
2524 mLastError.clear();
2525 QgsGeometry result( geos.sharedPaths( other.constGet(), &mLastError ) );
2526 result.mLastError = mLastError;
2527 return result;
2528}
2529
2530QgsGeometry QgsGeometry::subdivide( int maxNodes, const QgsGeometryParameters &parameters ) const
2531{
2532 if ( !d->geometry )
2533 {
2534 return QgsGeometry();
2535 }
2536
2537 const QgsAbstractGeometry *geom = d->geometry.get();
2538 std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
2539 if ( QgsWkbTypes::isCurvedType( d->geometry->wkbType() ) )
2540 {
2541 segmentizedCopy.reset( d->geometry->segmentize() );
2542 geom = segmentizedCopy.get();
2543 }
2544
2545 QgsGeos geos( geom );
2546 mLastError.clear();
2547 std::unique_ptr< QgsAbstractGeometry > result( geos.subdivide( maxNodes, &mLastError, parameters ) );
2548 if ( !result )
2549 {
2550 QgsGeometry geom;
2551 geom.mLastError = mLastError;
2552 return geom;
2553 }
2554 return QgsGeometry( std::move( result ) );
2555}
2556
2558{
2559 if ( !d->geometry )
2560 {
2561 return QgsGeometry();
2562 }
2563
2564 QgsGeometry line = *this;
2565 if ( type() == Qgis::GeometryType::Point )
2566 return QgsGeometry();
2567 else if ( type() == Qgis::GeometryType::Polygon )
2568 {
2569 line = QgsGeometry( d->geometry->boundary() );
2570 }
2571
2572 const QgsCurve *curve = nullptr;
2573 if ( line.isMultipart() )
2574 {
2575 // if multi part, iterate through parts to find target part
2576 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( line.constGet() );
2577 for ( int part = 0; part < collection->numGeometries(); ++part )
2578 {
2579 const QgsCurve *candidate = qgsgeometry_cast< const QgsCurve * >( collection->geometryN( part ) );
2580 if ( !candidate )
2581 continue;
2582 const double candidateLength = candidate->length();
2583 if ( candidateLength >= distance )
2584 {
2585 curve = candidate;
2586 break;
2587 }
2588
2589 distance -= candidateLength;
2590 }
2591 }
2592 else
2593 {
2594 curve = qgsgeometry_cast< const QgsCurve * >( line.constGet() );
2595 }
2596 if ( !curve )
2597 return QgsGeometry();
2598
2599 std::unique_ptr< QgsPoint > result( curve->interpolatePoint( distance ) );
2600 if ( !result )
2601 {
2602 return QgsGeometry();
2603 }
2604 return QgsGeometry( std::move( result ) );
2605}
2606
2607double QgsGeometry::lineLocatePoint( const QgsGeometry &point ) const
2608{
2609 if ( type() != Qgis::GeometryType::Line )
2610 return -1;
2611
2613 return -1;
2614
2615 QgsGeometry segmentized = *this;
2617 {
2618 segmentized = QgsGeometry( static_cast< QgsCurve * >( d->geometry.get() )->segmentize() );
2619 }
2620
2621 QgsGeos geos( d->geometry.get() );
2622 mLastError.clear();
2623 return geos.lineLocatePoint( *( static_cast< QgsPoint * >( point.d->geometry.get() ) ), &mLastError );
2624}
2625
2626double QgsGeometry::interpolateAngle( double distance ) const
2627{
2628 if ( !d->geometry )
2629 return 0.0;
2630
2631 const QgsAbstractGeometry *geom = d->geometry->simplifiedTypeRef();
2632 if ( QgsWkbTypes::geometryType( geom->wkbType() ) == Qgis::GeometryType::Point )
2633 return 0.0;
2634
2635 // always operate on segmentized geometries
2636 QgsGeometry segmentized = *this;
2637 if ( QgsWkbTypes::isCurvedType( geom->wkbType() ) )
2638 {
2639 segmentized = QgsGeometry( static_cast< const QgsCurve * >( geom )->segmentize() );
2640 }
2641
2642 QgsVertexId previous;
2643 QgsVertexId next;
2644 if ( !QgsGeometryUtils::verticesAtDistance( *segmentized.constGet(), distance, previous, next ) )
2645 return 0.0;
2646
2647 if ( previous == next )
2648 {
2649 // distance coincided exactly with a vertex
2650 QgsVertexId v2 = previous;
2651 QgsVertexId v1;
2652 QgsVertexId v3;
2653 segmentized.constGet()->adjacentVertices( v2, v1, v3 );
2654 if ( v1.isValid() && v3.isValid() )
2655 {
2656 QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
2657 QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
2658 QgsPoint p3 = segmentized.constGet()->vertexAt( v3 );
2659 double angle1 = QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2660 double angle2 = QgsGeometryUtils::lineAngle( p2.x(), p2.y(), p3.x(), p3.y() );
2661 return QgsGeometryUtils::averageAngle( angle1, angle2 );
2662 }
2663 else if ( v3.isValid() )
2664 {
2665 QgsPoint p1 = segmentized.constGet()->vertexAt( v2 );
2666 QgsPoint p2 = segmentized.constGet()->vertexAt( v3 );
2667 return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2668 }
2669 else
2670 {
2671 QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
2672 QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
2673 return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2674 }
2675 }
2676 else
2677 {
2678 QgsPoint p1 = segmentized.constGet()->vertexAt( previous );
2679 QgsPoint p2 = segmentized.constGet()->vertexAt( next );
2680 return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2681 }
2682}
2683
2685{
2686 if ( !d->geometry || geometry.isNull() )
2687 {
2688 return QgsGeometry();
2689 }
2690
2691 QgsGeos geos( d->geometry.get() );
2692
2693 mLastError.clear();
2694 std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.intersection( geometry.d->geometry.get(), &mLastError, parameters ) );
2695
2696 if ( !resultGeom )
2697 {
2698 QgsGeometry geom;
2699 geom.mLastError = mLastError;
2700 return geom;
2701 }
2702
2703 return QgsGeometry( std::move( resultGeom ) );
2704}
2705
2706QgsGeometry QgsGeometry::combine( const QgsGeometry &geometry, const QgsGeometryParameters &parameters ) const
2707{
2708 if ( !d->geometry || geometry.isNull() )
2709 {
2710 return QgsGeometry();
2711 }
2712
2713 QgsGeos geos( d->geometry.get() );
2714 mLastError.clear();
2715 std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.combine( geometry.d->geometry.get(), &mLastError, parameters ) );
2716 if ( !resultGeom )
2717 {
2718 QgsGeometry geom;
2719 geom.mLastError = mLastError;
2720 return geom;
2721 }
2722 return QgsGeometry( std::move( resultGeom ) );
2723}
2724
2726{
2727 if ( !d->geometry )
2728 {
2729 return QgsGeometry();
2730 }
2731
2733 {
2734 // special case - a single linestring was passed
2735 return QgsGeometry( *this );
2736 }
2737
2738 QgsGeos geos( d->geometry.get() );
2739 mLastError.clear();
2740 QgsGeometry result = geos.mergeLines( &mLastError );
2741 result.mLastError = mLastError;
2742 return result;
2743}
2744
2746{
2747 if ( !d->geometry || geometry.isNull() )
2748 {
2749 return QgsGeometry();
2750 }
2751
2752 QgsGeos geos( d->geometry.get() );
2753
2754 mLastError.clear();
2755 std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.difference( geometry.d->geometry.get(), &mLastError, parameters ) );
2756 if ( !resultGeom )
2757 {
2758 QgsGeometry geom;
2759 geom.mLastError = mLastError;
2760 return geom;
2761 }
2762 return QgsGeometry( std::move( resultGeom ) );
2763}
2764
2766{
2767 if ( !d->geometry || geometry.isNull() )
2768 {
2769 return QgsGeometry();
2770 }
2771
2772 QgsGeos geos( d->geometry.get() );
2773
2774 mLastError.clear();
2775 std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.symDifference( geometry.d->geometry.get(), &mLastError, parameters ) );
2776 if ( !resultGeom )
2777 {
2778 QgsGeometry geom;
2779 geom.mLastError = mLastError;
2780 return geom;
2781 }
2782 return QgsGeometry( std::move( resultGeom ) );
2783}
2784
2786{
2787 QgsInternalGeometryEngine engine( *this );
2788
2789 return engine.extrude( x, y );
2790}
2791
2793
2794QVector<QgsPointXY> QgsGeometry::randomPointsInPolygon( int count, const std::function< bool( const QgsPointXY & ) > &acceptPoint, unsigned long seed, QgsFeedback *feedback, int maxTriesPerPoint ) const
2795{
2796 if ( type() != Qgis::GeometryType::Polygon )
2797 return QVector< QgsPointXY >();
2798
2799 return QgsInternalGeometryEngine::randomPointsInPolygon( *this, count, acceptPoint, seed, feedback, maxTriesPerPoint );
2800}
2801
2802QVector<QgsPointXY> QgsGeometry::randomPointsInPolygon( int count, unsigned long seed, QgsFeedback *feedback ) const
2803{
2804 if ( type() != Qgis::GeometryType::Polygon )
2805 return QVector< QgsPointXY >();
2806
2807 return QgsInternalGeometryEngine::randomPointsInPolygon( *this, count, []( const QgsPointXY & ) { return true; }, seed, feedback, 0 );
2808}
2810
2811int QgsGeometry::wkbSize( QgsAbstractGeometry::WkbFlags flags ) const
2812{
2813 return d->geometry ? d->geometry->wkbSize( flags ) : 0;
2814}
2815
2816QByteArray QgsGeometry::asWkb( QgsAbstractGeometry::WkbFlags flags ) const
2817{
2818 return d->geometry ? d->geometry->asWkb( flags ) : QByteArray();
2819}
2820
2821QVector<QgsGeometry> QgsGeometry::asGeometryCollection() const
2822{
2823 QVector<QgsGeometry> geometryList;
2824 if ( !d->geometry )
2825 {
2826 return geometryList;
2827 }
2828
2829 QgsGeometryCollection *gc = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
2830 if ( gc )
2831 {
2832 int numGeom = gc->numGeometries();
2833 geometryList.reserve( numGeom );
2834 for ( int i = 0; i < numGeom; ++i )
2835 {
2836 geometryList.append( QgsGeometry( gc->geometryN( i )->clone() ) );
2837 }
2838 }
2839 else //a singlepart geometry
2840 {
2841 geometryList.append( *this );
2842 }
2843
2844 return geometryList;
2845}
2846
2848{
2849 QgsPointXY point = asPoint();
2850 return point.toQPointF();
2851}
2852
2854{
2855 const QgsAbstractGeometry *part = constGet();
2856
2857 // if a geometry collection, get first part only
2858 if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection *>( part ) )
2859 {
2860 if ( collection->numGeometries() > 0 )
2861 part = collection->geometryN( 0 );
2862 else
2863 return QPolygonF();
2864 }
2865
2866 if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( part ) )
2867 return curve->asQPolygonF();
2868 else if ( const QgsCurvePolygon *polygon = qgsgeometry_cast< const QgsCurvePolygon * >( part ) )
2869 return polygon->exteriorRing() ? polygon->exteriorRing()->asQPolygonF() : QPolygonF();
2870 return QPolygonF();
2871}
2872
2873bool QgsGeometry::deleteRing( int ringNum, int partNum )
2874{
2875 if ( !d->geometry )
2876 {
2877 return false;
2878 }
2879
2880 detach();
2881 bool ok = QgsGeometryEditUtils::deleteRing( d->geometry.get(), ringNum, partNum );
2882 return ok;
2883}
2884
2885bool QgsGeometry::deletePart( int partNum )
2886{
2887 if ( !d->geometry )
2888 {
2889 return false;
2890 }
2891
2892 if ( !isMultipart() && partNum < 1 )
2893 {
2894 set( nullptr );
2895 return true;
2896 }
2897
2898 detach();
2899 bool ok = QgsGeometryEditUtils::deletePart( d->geometry.get(), partNum );
2900 return ok;
2901}
2902
2903int QgsGeometry::avoidIntersections( const QList<QgsVectorLayer *> &avoidIntersectionsLayers, const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures )
2904{
2905 if ( !d->geometry )
2906 {
2907 return 1;
2908 }
2909
2910 Qgis::WkbType geomTypeBeforeModification = wkbType();
2911
2912 bool haveInvalidGeometry = false;
2913 bool geomModified = false;
2914
2915 std::unique_ptr< QgsAbstractGeometry > diffGeom = QgsGeometryEditUtils::avoidIntersections( *( d->geometry ), avoidIntersectionsLayers, haveInvalidGeometry, ignoreFeatures );
2916 if ( diffGeom )
2917 {
2918 reset( std::move( diffGeom ) );
2919 geomModified = true;
2920 }
2921
2922 if ( geomTypeBeforeModification != wkbType() )
2923 return 2;
2924 if ( haveInvalidGeometry )
2925 return 3;
2926 if ( !geomModified )
2927 return 4;
2928
2929 return 0;
2930}
2931
2932
2934{
2935 if ( !d->geometry )
2936 return QgsGeometry();
2937
2938 mLastError.clear();
2939 QgsGeos geos( d->geometry.get() );
2940 std::unique_ptr< QgsAbstractGeometry > g( geos.makeValid( method, keepCollapsed, &mLastError ) );
2941
2942 QgsGeometry result = QgsGeometry( std::move( g ) );
2943 result.mLastError = mLastError;
2944 return result;
2945}
2946
2948{
2949 return forcePolygonClockwise();
2950}
2951
2953{
2954 if ( !d->geometry )
2955 return QgsGeometry();
2956
2957 if ( isMultipart() )
2958 {
2959 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( d->geometry.get() );
2960 std::unique_ptr< QgsGeometryCollection > newCollection( collection->createEmptyWithSameType() );
2961 newCollection->reserve( collection->numGeometries() );
2962 for ( int i = 0; i < collection->numGeometries(); ++i )
2963 {
2964 const QgsAbstractGeometry *g = collection->geometryN( i );
2965 if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( g ) )
2966 {
2967 std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2968 corrected->forceClockwise();
2969 newCollection->addGeometry( corrected.release() );
2970 }
2971 else
2972 {
2973 newCollection->addGeometry( g->clone() );
2974 }
2975 }
2976 return QgsGeometry( std::move( newCollection ) );
2977 }
2978 else
2979 {
2980 if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( d->geometry.get() ) )
2981 {
2982 std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2983 corrected->forceClockwise();
2984 return QgsGeometry( std::move( corrected ) );
2985 }
2986 else
2987 {
2988 // not a curve polygon, so return unchanged
2989 return *this;
2990 }
2991 }
2992}
2993
2995{
2996 if ( !d->geometry )
2997 return QgsGeometry();
2998
2999 if ( isMultipart() )
3000 {
3001 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( d->geometry.get() );
3002 std::unique_ptr< QgsGeometryCollection > newCollection( collection->createEmptyWithSameType() );
3003 newCollection->reserve( collection->numGeometries() );
3004 for ( int i = 0; i < collection->numGeometries(); ++i )
3005 {
3006 const QgsAbstractGeometry *g = collection->geometryN( i );
3007 if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( g ) )
3008 {
3009 std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
3010 corrected->forceCounterClockwise();
3011 newCollection->addGeometry( corrected.release() );
3012 }
3013 else
3014 {
3015 newCollection->addGeometry( g->clone() );
3016 }
3017 }
3018 return QgsGeometry( std::move( newCollection ) );
3019 }
3020 else
3021 {
3022 if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( d->geometry.get() ) )
3023 {
3024 std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
3025 corrected->forceCounterClockwise();
3026 return QgsGeometry( std::move( corrected ) );
3027 }
3028 else
3029 {
3030 // not a curve polygon, so return unchanged
3031 return *this;
3032 }
3033 }
3034}
3035
3036
3037void QgsGeometry::validateGeometry( QVector<QgsGeometry::Error> &errors, const Qgis::GeometryValidationEngine method, const Qgis::GeometryValidityFlags flags ) const
3038{
3039 errors.clear();
3040 if ( !d->geometry )
3041 return;
3042
3043 // avoid expensive calcs for trivial point geometries
3044 if ( QgsWkbTypes::geometryType( d->geometry->wkbType() ) == Qgis::GeometryType::Point )
3045 {
3046 return;
3047 }
3048
3049 switch ( method )
3050 {
3051 case Qgis::GeometryValidationEngine::QgisInternal:
3052 QgsGeometryValidator::validateGeometry( *this, errors, method );
3053 return;
3054
3055 case Qgis::GeometryValidationEngine::Geos:
3056 {
3057 QgsGeos geos( d->geometry.get() );
3058 QString error;
3059 QgsGeometry errorLoc;
3060 if ( !geos.isValid( &error, flags & Qgis::GeometryValidityFlag::AllowSelfTouchingHoles, &errorLoc ) )
3061 {
3062 if ( errorLoc.isNull() )
3063 {
3064 errors.append( QgsGeometry::Error( error ) );
3065 }
3066 else
3067 {
3068 const QgsPointXY point = errorLoc.asPoint();
3069 errors.append( QgsGeometry::Error( error, point ) );
3070 }
3071 return;
3072 }
3073 }
3074 }
3075}
3076
3078{
3079 if ( !d->geometry )
3080 {
3081 return;
3082 }
3083
3084 detach();
3085 d->geometry->normalize();
3086}
3087
3088bool QgsGeometry::isGeosValid( Qgis::GeometryValidityFlags flags ) const
3089{
3090 if ( !d->geometry )
3091 {
3092 return false;
3093 }
3094
3095 return d->geometry->isValid( mLastError, flags );
3096}
3097
3099{
3100 if ( !d->geometry )
3101 return false;
3102
3103 QgsGeos geos( d->geometry.get() );
3104 mLastError.clear();
3105 return geos.isSimple( &mLastError );
3106}
3107
3108bool QgsGeometry::isAxisParallelRectangle( double maximumDeviation, bool simpleRectanglesOnly ) const
3109{
3110 if ( !d->geometry )
3111 return false;
3112
3113 QgsInternalGeometryEngine engine( *this );
3114 return engine.isAxisParallelRectangle( maximumDeviation, simpleRectanglesOnly );
3115}
3116
3118{
3119 if ( !d->geometry || !g.d->geometry )
3120 {
3121 return false;
3122 }
3123
3124 // fast check - are they shared copies of the same underlying geometry?
3125 if ( d == g.d )
3126 return true;
3127
3128 // fast check - distinct geometry types?
3129 if ( type() != g.type() )
3130 return false;
3131
3132 // avoid calling geos for trivial point case
3133 if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == Qgis::WkbType::Point
3134 && QgsWkbTypes::flatType( g.d->geometry->wkbType() ) == Qgis::WkbType::Point )
3135 {
3136 return equals( g );
3137 }
3138
3139 // another nice fast check upfront -- if the bounding boxes aren't equal, the geometries themselves can't be equal!
3140 if ( d->geometry->boundingBox() != g.d->geometry->boundingBox() )
3141 return false;
3142
3143 QgsGeos geos( d->geometry.get() );
3144 mLastError.clear();
3145 return geos.isEqual( g.d->geometry.get(), &mLastError );
3146}
3147
3148QgsGeometry QgsGeometry::unaryUnion( const QVector<QgsGeometry> &geometries, const QgsGeometryParameters &parameters )
3149{
3150 QgsGeos geos( nullptr );
3151
3152 QString error;
3153 std::unique_ptr< QgsAbstractGeometry > geom( geos.combine( geometries, &error, parameters ) );
3154 QgsGeometry result( std::move( geom ) );
3155 result.mLastError = error;
3156 return result;
3157}
3158
3159QgsGeometry QgsGeometry::polygonize( const QVector<QgsGeometry> &geometryList )
3160{
3161 QVector<const QgsAbstractGeometry *> geomV2List;
3162 for ( const QgsGeometry &g : geometryList )
3163 {
3164 if ( !( g.isNull() ) )
3165 {
3166 geomV2List.append( g.constGet() );
3167 }
3168 }
3169
3170 QString error;
3171 QgsGeometry result = QgsGeos::polygonize( geomV2List, &error );
3172 result.mLastError = error;
3173 return result;
3174}
3175
3177{
3179 {
3180 return;
3181 }
3182
3183 std::unique_ptr< QgsAbstractGeometry > straightGeom( d->geometry->segmentize( tolerance, toleranceType ) );
3184 reset( std::move( straightGeom ) );
3185}
3186
3188{
3189 if ( !d->geometry )
3190 {
3191 return false;
3192 }
3193
3194 return d->geometry->hasCurvedSegments();
3195}
3196
3198{
3199 if ( !d->geometry )
3200 {
3202 }
3203
3204 detach();
3205 d->geometry->transform( ct, direction, transformZ );
3207}
3208
3209Qgis::GeometryOperationResult QgsGeometry::transform( const QTransform &ct, double zTranslate, double zScale, double mTranslate, double mScale )
3210{
3211 if ( !d->geometry )
3212 {
3214 }
3215
3216 detach();
3217 d->geometry->transform( ct, zTranslate, zScale, mTranslate, mScale );
3219}
3220
3222{
3223 if ( d->geometry )
3224 {
3225 detach();
3226 d->geometry->transform( mtp.transform() );
3227 }
3228}
3229
3231{
3232 if ( !d->geometry || rectangle.isNull() || rectangle.isEmpty() )
3233 {
3234 return QgsGeometry();
3235 }
3236
3237 QgsGeos geos( d->geometry.get() );
3238 mLastError.clear();
3239 std::unique_ptr< QgsAbstractGeometry > resultGeom = geos.clip( rectangle, &mLastError );
3240 if ( !resultGeom )
3241 {
3242 QgsGeometry result;
3243 result.mLastError = mLastError;
3244 return result;
3245 }
3246 return QgsGeometry( std::move( resultGeom ) );
3247}
3248
3249void QgsGeometry::draw( QPainter &p ) const
3250{
3251 if ( d->geometry )
3252 {
3253 d->geometry->draw( p );
3254 }
3255}
3256
3257static bool vertexIndexInfo( const QgsAbstractGeometry *g, int vertexIndex, int &partIndex, int &ringIndex, int &vertex )
3258{
3259 if ( vertexIndex < 0 )
3260 return false; // clearly something wrong
3261
3262 if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
3263 {
3264 partIndex = 0;
3265 for ( int i = 0; i < geomCollection->numGeometries(); ++i )
3266 {
3267 const QgsAbstractGeometry *part = geomCollection->geometryN( i );
3268
3269 // count total number of vertices in the part
3270 int numPoints = 0;
3271 for ( int k = 0; k < part->ringCount(); ++k )
3272 numPoints += part->vertexCount( 0, k );
3273
3274 if ( vertexIndex < numPoints )
3275 {
3276 int nothing;
3277 return vertexIndexInfo( part, vertexIndex, nothing, ringIndex, vertex ); // set ring_index + index
3278 }
3279 vertexIndex -= numPoints;
3280 partIndex++;
3281 }
3282 }
3283 else if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
3284 {
3285 const QgsCurve *ring = curvePolygon->exteriorRing();
3286 if ( vertexIndex < ring->numPoints() )
3287 {
3288 partIndex = 0;
3289 ringIndex = 0;
3290 vertex = vertexIndex;
3291 return true;
3292 }
3293 vertexIndex -= ring->numPoints();
3294 ringIndex = 1;
3295 for ( int i = 0; i < curvePolygon->numInteriorRings(); ++i )
3296 {
3297 const QgsCurve *ring = curvePolygon->interiorRing( i );
3298 if ( vertexIndex < ring->numPoints() )
3299 {
3300 partIndex = 0;
3301 vertex = vertexIndex;
3302 return true;
3303 }
3304 vertexIndex -= ring->numPoints();
3305 ringIndex += 1;
3306 }
3307 }
3308 else if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
3309 {
3310 if ( vertexIndex < curve->numPoints() )
3311 {
3312 partIndex = 0;
3313 ringIndex = 0;
3314 vertex = vertexIndex;
3315 return true;
3316 }
3317 }
3318 else if ( qgsgeometry_cast<const QgsPoint *>( g ) )
3319 {
3320 if ( vertexIndex == 0 )
3321 {
3322 partIndex = 0;
3323 ringIndex = 0;
3324 vertex = 0;
3325 return true;
3326 }
3327 }
3328
3329 return false;
3330}
3331
3333{
3334 if ( !d->geometry )
3335 {
3336 return false;
3337 }
3338
3339 id.type = Qgis::VertexType::Segment;
3340
3341 bool res = vertexIndexInfo( d->geometry.get(), nr, id.part, id.ring, id.vertex );
3342 if ( !res )
3343 return false;
3344
3345 // now let's find out if it is a straight or circular segment
3346 const QgsAbstractGeometry *g = d->geometry.get();
3347 if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
3348 {
3349 g = geomCollection->geometryN( id.part );
3350 }
3351
3352 if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
3353 {
3354 g = id.ring == 0 ? curvePolygon->exteriorRing() : curvePolygon->interiorRing( id.ring - 1 );
3355 }
3356
3357 if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
3358 {
3359 QgsPoint p;
3360 res = curve->pointAt( id.vertex, p, id.type );
3361 if ( !res )
3362 return false;
3363 }
3364
3365 return true;
3366}
3367
3369{
3370 if ( !d->geometry )
3371 {
3372 return -1;
3373 }
3374 return d->geometry->vertexNumberFromVertexId( id );
3375}
3376
3378{
3379 return mLastError;
3380}
3381
3382void QgsGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
3383{
3384 if ( !d->geometry )
3385 return;
3386
3387 detach();
3388
3389 d->geometry->filterVertices( filter );
3390}
3391
3392void QgsGeometry::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
3393{
3394 if ( !d->geometry )
3395 return;
3396
3397 detach();
3398
3399 d->geometry->transformVertices( transform );
3400}
3401
3402void QgsGeometry::convertPointList( const QVector<QgsPointXY> &input, QgsPointSequence &output )
3403{
3404 output.clear();
3405 for ( const QgsPointXY &p : input )
3406 {
3407 output.append( QgsPoint( p ) );
3408 }
3409}
3410
3411void QgsGeometry::convertPointList( const QgsPointSequence &input, QVector<QgsPointXY> &output )
3412{
3413 output.clear();
3414 for ( const QgsPoint &p : input )
3415 {
3416 output.append( QgsPointXY( p.x(), p.y() ) );
3417 }
3418}
3419
3420void QgsGeometry::convertPolygon( const QgsPolygon &input, QgsPolygonXY &output )
3421{
3422 output.clear();
3423
3424 auto convertRing = []( const QgsCurve * ring ) -> QgsPolylineXY
3425 {
3426 QgsPolylineXY res;
3427 bool doSegmentation = ( QgsWkbTypes::flatType( ring->wkbType() ) == Qgis::WkbType::CompoundCurve
3429 std::unique_ptr< QgsLineString > segmentizedLine;
3430 const QgsLineString *line = nullptr;
3431 if ( doSegmentation )
3432 {
3433 segmentizedLine.reset( ring->curveToLine() );
3434 line = segmentizedLine.get();
3435 }
3436 else
3437 {
3438 line = qgsgeometry_cast<const QgsLineString *>( ring );
3439 if ( !line )
3440 {
3441 return res;
3442 }
3443 }
3444
3445 int nVertices = line->numPoints();
3446 res.resize( nVertices );
3447 QgsPointXY *data = res.data();
3448 const double *xData = line->xData();
3449 const double *yData = line->yData();
3450 for ( int i = 0; i < nVertices; ++i )
3451 {
3452 data->setX( *xData++ );
3453 data->setY( *yData++ );
3454 data++;
3455 }
3456 return res;
3457 };
3458
3459 if ( const QgsCurve *exterior = input.exteriorRing() )
3460 {
3461 output.push_back( convertRing( exterior ) );
3462 }
3463
3464 const int interiorRingCount = input.numInteriorRings();
3465 output.reserve( output.size() + interiorRingCount );
3466 for ( int n = 0; n < interiorRingCount; ++n )
3467 {
3468 output.push_back( convertRing( input.interiorRing( n ) ) );
3469 }
3470}
3471
3473{
3474 return QgsGeometry( std::make_unique< QgsPoint >( point.x(), point.y() ) );
3475}
3476
3477QgsGeometry QgsGeometry::fromQPolygonF( const QPolygonF &polygon )
3478{
3479 std::unique_ptr < QgsLineString > ring( QgsLineString::fromQPolygonF( polygon ) );
3480
3481 if ( polygon.isClosed() )
3482 {
3483 std::unique_ptr< QgsPolygon > poly = std::make_unique< QgsPolygon >();
3484 poly->setExteriorRing( ring.release() );
3485 return QgsGeometry( std::move( poly ) );
3486 }
3487 else
3488 {
3489 return QgsGeometry( std::move( ring ) );
3490 }
3491}
3492
3494{
3496 QgsPolygonXY result;
3497 result << createPolylineFromQPolygonF( polygon );
3498 return result;
3500}
3501
3503{
3504 QgsPolylineXY result;
3505 result.reserve( polygon.count() );
3506 for ( const QPointF &p : polygon )
3507 {
3508 result.append( QgsPointXY( p ) );
3509 }
3510 return result;
3511}
3512
3513bool QgsGeometry::compare( const QgsPolylineXY &p1, const QgsPolylineXY &p2, double epsilon )
3514{
3515 if ( p1.count() != p2.count() )
3516 return false;
3517
3518 for ( int i = 0; i < p1.count(); ++i )
3519 {
3520 if ( !p1.at( i ).compare( p2.at( i ), epsilon ) )
3521 return false;
3522 }
3523 return true;
3524}
3525
3526bool QgsGeometry::compare( const QgsPolygonXY &p1, const QgsPolygonXY &p2, double epsilon )
3527{
3528 if ( p1.count() != p2.count() )
3529 return false;
3530
3531 for ( int i = 0; i < p1.count(); ++i )
3532 {
3533 if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
3534 return false;
3535 }
3536 return true;
3537}
3538
3539
3540bool QgsGeometry::compare( const QgsMultiPolygonXY &p1, const QgsMultiPolygonXY &p2, double epsilon )
3541{
3542 if ( p1.count() != p2.count() )
3543 return false;
3544
3545 for ( int i = 0; i < p1.count(); ++i )
3546 {
3547 if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
3548 return false;
3549 }
3550 return true;
3551}
3552
3553QgsGeometry QgsGeometry::smooth( const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3554{
3555 if ( !d->geometry || d->geometry->isEmpty() )
3556 return QgsGeometry();
3557
3558 QgsGeometry geom = *this;
3560 geom = QgsGeometry( d->geometry->segmentize() );
3561
3562 switch ( QgsWkbTypes::flatType( geom.wkbType() ) )
3563 {
3566 //can't smooth a point based geometry
3567 return geom;
3568
3570 {
3571 const QgsLineString *lineString = qgsgeometry_cast< const QgsLineString * >( geom.constGet() );
3572 return QgsGeometry( smoothLine( *lineString, iterations, offset, minimumDistance, maxAngle ) );
3573 }
3574
3576 {
3577 const QgsMultiLineString *multiLine = qgsgeometry_cast< const QgsMultiLineString * >( geom.constGet() );
3578
3579 std::unique_ptr< QgsMultiLineString > resultMultiline = std::make_unique< QgsMultiLineString> ();
3580 resultMultiline->reserve( multiLine->numGeometries() );
3581 for ( int i = 0; i < multiLine->numGeometries(); ++i )
3582 {
3583 resultMultiline->addGeometry( smoothLine( *( multiLine->lineStringN( i ) ), iterations, offset, minimumDistance, maxAngle ).release() );
3584 }
3585 return QgsGeometry( std::move( resultMultiline ) );
3586 }
3587
3589 {
3590 const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon * >( geom.constGet() );
3591 return QgsGeometry( smoothPolygon( *poly, iterations, offset, minimumDistance, maxAngle ) );
3592 }
3593
3595 {
3596 const QgsMultiPolygon *multiPoly = qgsgeometry_cast< const QgsMultiPolygon * >( geom.constGet() );
3597
3598 std::unique_ptr< QgsMultiPolygon > resultMultiPoly = std::make_unique< QgsMultiPolygon >();
3599 resultMultiPoly->reserve( multiPoly->numGeometries() );
3600 for ( int i = 0; i < multiPoly->numGeometries(); ++i )
3601 {
3602 resultMultiPoly->addGeometry( smoothPolygon( *( multiPoly->polygonN( i ) ), iterations, offset, minimumDistance, maxAngle ).release() );
3603 }
3604 return QgsGeometry( std::move( resultMultiPoly ) );
3605 }
3606
3608 default:
3609 return QgsGeometry( *this );
3610 }
3611}
3612
3613std::unique_ptr< QgsLineString > smoothCurve( const QgsLineString &line, const unsigned int iterations,
3614 const double offset, double squareDistThreshold, double maxAngleRads,
3615 bool isRing )
3616{
3617 std::unique_ptr< QgsLineString > result = std::make_unique< QgsLineString >( line );
3618 QgsPointSequence outputLine;
3619 for ( unsigned int iteration = 0; iteration < iterations; ++iteration )
3620 {
3621 outputLine.resize( 0 );
3622 outputLine.reserve( 2 * ( result->numPoints() - 1 ) );
3623 bool skipFirst = false;
3624 bool skipLast = false;
3625 if ( isRing )
3626 {
3627 QgsPoint p1 = result->pointN( result->numPoints() - 2 );
3628 QgsPoint p2 = result->pointN( 0 );
3629 QgsPoint p3 = result->pointN( 1 );
3630 double angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3631 p3.x(), p3.y() );
3632 angle = std::fabs( M_PI - angle );
3633 skipFirst = angle > maxAngleRads;
3634 }
3635 for ( int i = 0; i < result->numPoints() - 1; i++ )
3636 {
3637 QgsPoint p1 = result->pointN( i );
3638 QgsPoint p2 = result->pointN( i + 1 );
3639
3640 double angle = M_PI;
3641 if ( i == 0 && isRing )
3642 {
3643 QgsPoint p3 = result->pointN( result->numPoints() - 2 );
3644 angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3645 p3.x(), p3.y() );
3646 }
3647 else if ( i < result->numPoints() - 2 )
3648 {
3649 QgsPoint p3 = result->pointN( i + 2 );
3650 angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3651 p3.x(), p3.y() );
3652 }
3653 else if ( i == result->numPoints() - 2 && isRing )
3654 {
3655 QgsPoint p3 = result->pointN( 1 );
3656 angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3657 p3.x(), p3.y() );
3658 }
3659
3660 skipLast = angle < M_PI - maxAngleRads || angle > M_PI + maxAngleRads;
3661
3662 // don't apply distance threshold to first or last segment
3663 if ( i == 0 || i >= result->numPoints() - 2
3664 || QgsGeometryUtils::sqrDistance2D( p1, p2 ) > squareDistThreshold )
3665 {
3666 if ( !isRing )
3667 {
3668 if ( !skipFirst )
3669 outputLine << ( i == 0 ? result->pointN( i ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset ) );
3670 if ( !skipLast )
3671 outputLine << ( i == result->numPoints() - 2 ? result->pointN( i + 1 ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset ) );
3672 else
3673 outputLine << p2;
3674 }
3675 else
3676 {
3677 // ring
3678 if ( !skipFirst )
3679 outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset );
3680 else if ( i == 0 )
3681 outputLine << p1;
3682 if ( !skipLast )
3683 outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset );
3684 else
3685 outputLine << p2;
3686 }
3687 }
3688 skipFirst = skipLast;
3689 }
3690
3691 if ( isRing && outputLine.at( 0 ) != outputLine.at( outputLine.count() - 1 ) )
3692 outputLine << outputLine.at( 0 );
3693
3694 result->setPoints( outputLine );
3695 }
3696 return result;
3697}
3698
3699std::unique_ptr<QgsLineString> QgsGeometry::smoothLine( const QgsLineString &line, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3700{
3701 double maxAngleRads = maxAngle * M_PI / 180.0;
3702 double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
3703 return smoothCurve( line, iterations, offset, squareDistThreshold, maxAngleRads, false );
3704}
3705
3706std::unique_ptr<QgsPolygon> QgsGeometry::smoothPolygon( const QgsPolygon &polygon, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3707{
3708 double maxAngleRads = maxAngle * M_PI / 180.0;
3709 double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
3710 std::unique_ptr< QgsPolygon > resultPoly = std::make_unique< QgsPolygon >();
3711
3712 resultPoly->setExteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.exteriorRing() ) ), iterations, offset,
3713 squareDistThreshold, maxAngleRads, true ).release() );
3714
3715 for ( int i = 0; i < polygon.numInteriorRings(); ++i )
3716 {
3717 resultPoly->addInteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.interiorRing( i ) ) ), iterations, offset,
3718 squareDistThreshold, maxAngleRads, true ).release() );
3719 }
3720 return resultPoly;
3721}
3722
3723QgsGeometry QgsGeometry::convertToPoint( bool destMultipart ) const
3724{
3725 switch ( type() )
3726 {
3727 case Qgis::GeometryType::Point:
3728 {
3729 bool srcIsMultipart = isMultipart();
3730
3731 if ( ( destMultipart && srcIsMultipart ) ||
3732 ( !destMultipart && !srcIsMultipart ) )
3733 {
3734 // return a copy of the same geom
3735 return QgsGeometry( *this );
3736 }
3737 if ( destMultipart )
3738 {
3739 // layer is multipart => make a multipoint with a single point
3740 return fromMultiPointXY( QgsMultiPointXY() << asPoint() );
3741 }
3742 else
3743 {
3744 // destination is singlepart => make a single part if possible
3745 QgsMultiPointXY multiPoint = asMultiPoint();
3746 if ( multiPoint.count() == 1 )
3747 {
3748 return fromPointXY( multiPoint[0] );
3749 }
3750 }
3751 return QgsGeometry();
3752 }
3753
3754 case Qgis::GeometryType::Line:
3755 {
3756 // only possible if destination is multipart
3757 if ( !destMultipart )
3758 return QgsGeometry();
3759
3760 // input geometry is multipart
3761 if ( isMultipart() )
3762 {
3763 const QgsMultiPolylineXY multiLine = asMultiPolyline();
3764 QgsMultiPointXY multiPoint;
3765 for ( const QgsPolylineXY &l : multiLine )
3766 for ( const QgsPointXY &p : l )
3767 multiPoint << p;
3768 return fromMultiPointXY( multiPoint );
3769 }
3770 // input geometry is not multipart: copy directly the line into a multipoint
3771 else
3772 {
3773 QgsPolylineXY line = asPolyline();
3774 if ( !line.isEmpty() )
3775 return fromMultiPointXY( line );
3776 }
3777 return QgsGeometry();
3778 }
3779
3780 case Qgis::GeometryType::Polygon:
3781 {
3782 // can only transform if destination is multipoint
3783 if ( !destMultipart )
3784 return QgsGeometry();
3785
3786 // input geometry is multipart: make a multipoint from multipolygon
3787 if ( isMultipart() )
3788 {
3789 const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3790 QgsMultiPointXY multiPoint;
3791 for ( const QgsPolygonXY &poly : multiPolygon )
3792 for ( const QgsPolylineXY &line : poly )
3793 for ( const QgsPointXY &pt : line )
3794 multiPoint << pt;
3795 return fromMultiPointXY( multiPoint );
3796 }
3797 // input geometry is not multipart: make a multipoint from polygon
3798 else
3799 {
3800 const QgsPolygonXY polygon = asPolygon();
3801 QgsMultiPointXY multiPoint;
3802 for ( const QgsPolylineXY &line : polygon )
3803 for ( const QgsPointXY &pt : line )
3804 multiPoint << pt;
3805 return fromMultiPointXY( multiPoint );
3806 }
3807 }
3808
3809 default:
3810 return QgsGeometry();
3811 }
3812}
3813
3814QgsGeometry QgsGeometry::convertToLine( bool destMultipart ) const
3815{
3816 switch ( type() )
3817 {
3818 case Qgis::GeometryType::Point:
3819 {
3820 if ( !isMultipart() )
3821 return QgsGeometry();
3822
3823 QgsMultiPointXY multiPoint = asMultiPoint();
3824 if ( multiPoint.count() < 2 )
3825 return QgsGeometry();
3826
3827 if ( destMultipart )
3828 return fromMultiPolylineXY( QgsMultiPolylineXY() << multiPoint );
3829 else
3830 return fromPolylineXY( multiPoint );
3831 }
3832
3833 case Qgis::GeometryType::Line:
3834 {
3835 bool srcIsMultipart = isMultipart();
3836
3837 if ( ( destMultipart && srcIsMultipart ) ||
3838 ( !destMultipart && ! srcIsMultipart ) )
3839 {
3840 // return a copy of the same geom
3841 return QgsGeometry( *this );
3842 }
3843 if ( destMultipart )
3844 {
3845 // destination is multipart => makes a multipoint with a single line
3846 QgsPolylineXY line = asPolyline();
3847 if ( !line.isEmpty() )
3848 return fromMultiPolylineXY( QgsMultiPolylineXY() << line );
3849 }
3850 else
3851 {
3852 // destination is singlepart => make a single part if possible
3853 QgsMultiPolylineXY multiLine = asMultiPolyline();
3854 if ( multiLine.count() == 1 )
3855 return fromPolylineXY( multiLine[0] );
3856 }
3857 return QgsGeometry();
3858 }
3859
3860 case Qgis::GeometryType::Polygon:
3861 {
3862 // input geometry is multipolygon
3863 if ( isMultipart() )
3864 {
3865 const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3866 QgsMultiPolylineXY multiLine;
3867 for ( const QgsPolygonXY &poly : multiPolygon )
3868 for ( const QgsPolylineXY &line : poly )
3869 multiLine << line;
3870
3871 if ( destMultipart )
3872 {
3873 // destination is multipart
3874 return fromMultiPolylineXY( multiLine );
3875 }
3876 else if ( multiLine.count() == 1 )
3877 {
3878 // destination is singlepart => make a single part if possible
3879 return fromPolylineXY( multiLine[0] );
3880 }
3881 }
3882 // input geometry is single polygon
3883 else
3884 {
3885 QgsPolygonXY polygon = asPolygon();
3886 // if polygon has rings
3887 if ( polygon.count() > 1 )
3888 {
3889 // cannot fit a polygon with rings in a single line layer
3890 // TODO: would it be better to remove rings?
3891 if ( destMultipart )
3892 {
3893 const QgsPolygonXY polygon = asPolygon();
3894 QgsMultiPolylineXY multiLine;
3895 multiLine.reserve( polygon.count() );
3896 for ( const QgsPolylineXY &line : polygon )
3897 multiLine << line;
3898 return fromMultiPolylineXY( multiLine );
3899 }
3900 }
3901 // no rings
3902 else if ( polygon.count() == 1 )
3903 {
3904 if ( destMultipart )
3905 {
3906 return fromMultiPolylineXY( polygon );
3907 }
3908 else
3909 {
3910 return fromPolylineXY( polygon[0] );
3911 }
3912 }
3913 }
3914 return QgsGeometry();
3915 }
3916
3917 default:
3918 return QgsGeometry();
3919 }
3920}
3921
3922QgsGeometry QgsGeometry::convertToPolygon( bool destMultipart ) const
3923{
3924 switch ( type() )
3925 {
3926 case Qgis::GeometryType::Point:
3927 {
3928 if ( !isMultipart() )
3929 return QgsGeometry();
3930
3931 QgsMultiPointXY multiPoint = asMultiPoint();
3932 if ( multiPoint.count() < 3 )
3933 return QgsGeometry();
3934
3935 if ( multiPoint.last() != multiPoint.first() )
3936 multiPoint << multiPoint.first();
3937
3938 QgsPolygonXY polygon = QgsPolygonXY() << multiPoint;
3939 if ( destMultipart )
3940 return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3941 else
3942 return fromPolygonXY( polygon );
3943 }
3944
3945 case Qgis::GeometryType::Line:
3946 {
3947 // input geometry is multiline
3948 if ( isMultipart() )
3949 {
3950 QgsMultiPolylineXY multiLine = asMultiPolyline();
3951 QgsMultiPolygonXY multiPolygon;
3952 for ( QgsMultiPolylineXY::iterator multiLineIt = multiLine.begin(); multiLineIt != multiLine.end(); ++multiLineIt )
3953 {
3954 // do not create polygon for a 1 segment line
3955 if ( ( *multiLineIt ).count() < 3 )
3956 return QgsGeometry();
3957 if ( ( *multiLineIt ).count() == 3 && ( *multiLineIt ).first() == ( *multiLineIt ).last() )
3958 return QgsGeometry();
3959
3960 // add closing node
3961 if ( ( *multiLineIt ).first() != ( *multiLineIt ).last() )
3962 *multiLineIt << ( *multiLineIt ).first();
3963 multiPolygon << ( QgsPolygonXY() << *multiLineIt );
3964 }
3965 // check that polygons were inserted
3966 if ( !multiPolygon.isEmpty() )
3967 {
3968 if ( destMultipart )
3969 {
3970 return fromMultiPolygonXY( multiPolygon );
3971 }
3972 else if ( multiPolygon.count() == 1 )
3973 {
3974 // destination is singlepart => make a single part if possible
3975 return fromPolygonXY( multiPolygon[0] );
3976 }
3977 }
3978 }
3979 // input geometry is single line
3980 else
3981 {
3982 QgsPolylineXY line = asPolyline();
3983
3984 // do not create polygon for a 1 segment line
3985 if ( line.count() < 3 )
3986 return QgsGeometry();
3987 if ( line.count() == 3 && line.first() == line.last() )
3988 return QgsGeometry();
3989
3990 // add closing node
3991 if ( line.first() != line.last() )
3992 line << line.first();
3993
3994 // destination is multipart
3995 if ( destMultipart )
3996 {
3997 return fromMultiPolygonXY( QgsMultiPolygonXY() << ( QgsPolygonXY() << line ) );
3998 }
3999 else
4000 {
4001 return fromPolygonXY( QgsPolygonXY() << line );
4002 }
4003 }
4004 return QgsGeometry();
4005 }
4006
4007 case Qgis::GeometryType::Polygon:
4008 {
4009 bool srcIsMultipart = isMultipart();
4010
4011 if ( ( destMultipart && srcIsMultipart ) ||
4012 ( !destMultipart && ! srcIsMultipart ) )
4013 {
4014 // return a copy of the same geom
4015 return QgsGeometry( *this );
4016 }
4017 if ( destMultipart )
4018 {
4019 // destination is multipart => makes a multipoint with a single polygon
4020 QgsPolygonXY polygon = asPolygon();
4021 if ( !polygon.isEmpty() )
4022 return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
4023 }
4024 else
4025 {
4026 QgsMultiPolygonXY multiPolygon = asMultiPolygon();
4027 if ( multiPolygon.count() == 1 )
4028 {
4029 // destination is singlepart => make a single part if possible
4030 return fromPolygonXY( multiPolygon[0] );
4031 }
4032 }
4033 return QgsGeometry();
4034 }
4035
4036 default:
4037 return QgsGeometry();
4038 }
4039}
4040
4042{
4043 return new QgsGeos( geometry );
4044}
4045
4046QDataStream &operator<<( QDataStream &out, const QgsGeometry &geometry )
4047{
4048 out << geometry.asWkb();
4049 return out;
4050}
4051
4052QDataStream &operator>>( QDataStream &in, QgsGeometry &geometry )
4053{
4054 QByteArray byteArray;
4055 in >> byteArray;
4056 if ( byteArray.isEmpty() )
4057 {
4058 geometry.set( nullptr );
4059 return in;
4060 }
4061
4062 geometry.fromWkb( byteArray );
4063 return in;
4064}
4065
4066
4068{
4069 return mMessage;
4070}
4071
4073{
4074 return mLocation;
4075}
4076
4078{
4079 return mHasLocation;
4080}
4081
BufferSide
Side of line to buffer.
Definition: qgis.h:1319
DashPatternSizeAdjustment
Dash pattern size adjustment options.
Definition: qgis.h:2093
AngularDirection
Angular directions.
Definition: qgis.h:2193
GeometryOperationResult
Success or failure of a geometry operation.
Definition: qgis.h:1266
@ InvalidInputGeometryType
The input geometry (ring, part, split line, etc.) has not the correct geometry type.
@ Success
Operation succeeded.
@ AddPartNotMultiGeometry
The source geometry is not multi.
@ SplitCannotSplitPoint
Cannot split points.
@ GeometryEngineError
Geometry engine misses a method implemented or an error occurred in the geometry engine.
@ NothingHappened
Nothing happened, without any error.
@ InvalidBaseGeometry
The base geometry on which the operation is done is invalid or empty.
GeometryValidationEngine
Available engines for validating geometries.
Definition: qgis.h:1307
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
Definition: qgis.h:228
JoinStyle
Join styles for buffers.
Definition: qgis.h:1344
EndCapStyle
End cap styles for buffers.
Definition: qgis.h:1331
DashPatternLineEndingRule
Dash pattern line ending rules.
Definition: qgis.h:2078
MakeValidMethod
Algorithms to use when repairing invalid geometries.
Definition: qgis.h:1357
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition: qgis.h:155
@ CompoundCurve
CompoundCurve.
@ LineString
LineString.
@ MultiPoint
MultiPoint.
@ Polygon
Polygon.
@ MultiPolygon
MultiPolygon.
@ NoGeometry
No geometry.
@ MultiLineString
MultiLineString.
@ Unknown
Unknown.
@ CircularString
CircularString.
@ GeometryCollection
GeometryCollection.
@ MultiCurve
MultiCurve.
@ CurvePolygon
CurvePolygon.
@ MultiSurface
MultiSurface.
TransformDirection
Flags for raster layer temporal capabilities.
Definition: qgis.h:1631
The part_iterator class provides STL-style iterator for const references to geometry parts.
The part_iterator class provides STL-style iterator for geometry parts.
The vertex_iterator class provides STL-style iterator for vertices.
Abstract base class for all geometries.
virtual int ringCount(int part=0) const =0
Returns the number of rings of which this geometry is built.
virtual bool addZValue(double zValue=0)=0
Adds a z-dimension to the geometry, initialized to a preset value.
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
virtual QgsAbstractGeometry * boundary() const =0
Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the...
virtual bool dropMValue()=0
Drops any measure values which exist in the geometry.
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
virtual int vertexCount(int part=0, int ring=0) const =0
Returns the number of vertices of which this geometry is built.
virtual QgsRectangle boundingBox() const =0
Returns the minimal bounding box for the geometry.
virtual QgsPoint vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
virtual void adjacentVertices(QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex) const =0
Returns the vertices adjacent to a specified vertex within a geometry.
virtual bool addMValue(double mValue=0)=0
Adds a measure to the geometry, initialized to a preset value.
virtual double length() const
Returns the planar, 2-dimensional length of the geometry.
Qgis::WkbType wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
virtual bool dropZValue()=0
Drops any z-dimensions which exist in the geometry.
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
Circle geometry type.
Definition: qgscircle.h:44
double radius() const SIP_HOLDGIL
Returns the radius of the circle.
Definition: qgscircle.h:311
static QgsCircle from2Points(const QgsPoint &pt1, const QgsPoint &pt2) SIP_HOLDGIL
Constructs a circle by 2 points on the circle.
Definition: qgscircle.cpp:38
bool contains(const QgsPoint &point, double epsilon=1E-8) const
Returns true if the circle contains the point.
Definition: qgscircle.cpp:453
static QgsCircle minimalCircleFrom3Points(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double epsilon=1E-8) SIP_HOLDGIL
Constructs the smallest circle from 3 points.
Definition: qgscircle.cpp:326
QgsCircularString * toCircularString(bool oriented=false) const
Returns a circular string from the circle.
Definition: qgscircle.cpp:430
Circular string geometry type.
static QgsCircularString fromTwoPointsAndCenter(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &center, bool useShortestArc=true)
Creates a circular string with a single arc representing the curve from p1 to p2 with the specified c...
Compound curve geometry type.
bool toggleCircularAtVertex(QgsVertexId position)
Converts the vertex at the given position from/to circular.
A const WKB pointer.
Definition: qgswkbptr.h:141
Class for doing transforms between two map coordinate systems.
Curve polygon geometry type.
virtual QgsPolygon * toPolygon(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a new polygon geometry corresponding to a segmentized approximation of the curve.
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
virtual void setExteriorRing(QgsCurve *ring)
Sets the exterior ring of the polygon.
virtual void addInteriorRing(QgsCurve *ring)
Adds an interior ring to the geometry (takes ownership)
int numInteriorRings() const SIP_HOLDGIL
Returns the number of interior rings contained with the curve polygon.
bool removeInteriorRing(int ringIndex)
Removes an interior ring from the polygon.
Abstract base class for curved geometry type.
Definition: qgscurve.h:36
virtual int numPoints() const =0
Returns the number of points in the curve.
QgsCurve * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
Definition: qgscurve.cpp:175
virtual QgsPoint * interpolatePoint(double distance) const =0
Returns an interpolated point on the curve at the specified distance.
QgsCurve * clone() const override=0
Clones the geometry by performing a deep copy.
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.
QgsPoint center() const SIP_HOLDGIL
Returns the center point.
Definition: qgsellipse.h:121
virtual QgsPolygon * toPolygon(unsigned int segments=36) const
Returns a segmented polygon.
Definition: qgsellipse.cpp:224
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:45
Geometry collection.
virtual bool insertGeometry(QgsAbstractGeometry *g, int index)
Inserts a geometry before a specified index and takes ownership.
int numGeometries() const SIP_HOLDGIL
Returns the number of geometries within the collection.
virtual bool removeGeometry(int nr)
Removes a geometry from the collection.
QgsGeometryCollection * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
virtual bool addGeometry(QgsAbstractGeometry *g)
Adds a geometry and takes ownership. Returns true in case of success.
int partCount() const override
Returns count of parts contained in the geometry.
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
Java-style iterator for const traversal of parts of a geometry.
static Qgis::GeometryOperationResult addRing(QgsAbstractGeometry *geometry, std::unique_ptr< QgsCurve > ring)
Add an interior ring to a geometry.
static std::unique_ptr< QgsAbstractGeometry > avoidIntersections(const QgsAbstractGeometry &geom, const QList< QgsVectorLayer * > &avoidIntersectionsLayers, bool &haveInvalidGeometry, const QHash< QgsVectorLayer *, QSet< QgsFeatureId > > &ignoreFeatures=(QHash< QgsVectorLayer *, QSet< QgsFeatureId > >()))
Alters a geometry so that it avoids intersections with features from all open vector layers.
static bool deletePart(QgsAbstractGeometry *geom, int partNum)
Deletes a part from a geometry.
static bool deleteRing(QgsAbstractGeometry *geom, int ringNum, int partNum=0)
Deletes a ring from a geometry.
static Qgis::GeometryOperationResult addPart(QgsAbstractGeometry *geometry, std::unique_ptr< QgsAbstractGeometry > part)
Add a part to multi type geometry.
A geometry engine is a low-level representation of a QgsAbstractGeometry object, optimised for use wi...
EngineOperationResult
Success or failure of a geometry operation.
@ NothingHappened
Nothing happened, without any error.
@ InvalidBaseGeometry
The geometry on which the operation occurs is not valid.
@ InvalidInput
The input is not valid.
@ NodedGeometryError
Error occurred while creating a noded geometry.
@ EngineError
Error occurred in the geometry engine.
@ SplitCannotSplitPoint
Points cannot be split.
@ Success
Operation succeeded.
@ MethodNotImplemented
Method not implemented in geometry engine.
static std::unique_ptr< QgsMultiPolygon > fromMultiPolygonXY(const QgsMultiPolygonXY &multipoly)
Construct geometry from a multipolygon.
static std::unique_ptr< QgsAbstractGeometry > geomFromWkb(QgsConstWkbPtr &wkb)
Construct geometry from a WKB string.
static std::unique_ptr< QgsGeometryCollection > createCollectionOfType(Qgis::WkbType type)
Returns a new geometry collection matching a specified WKB type.
static std::unique_ptr< QgsAbstractGeometry > fromPolylineXY(const QgsPolylineXY &polyline)
Construct geometry from a polyline.
static std::unique_ptr< QgsMultiPoint > fromMultiPointXY(const QgsMultiPointXY &multipoint)
Construct geometry from a multipoint.
static std::unique_ptr< QgsAbstractGeometry > geomFromWkt(const QString &text)
Construct geometry from a WKT string.
static std::unique_ptr< QgsMultiLineString > fromMultiPolylineXY(const QgsMultiPolylineXY &multiline)
Construct geometry from a multipolyline.
static std::unique_ptr< QgsAbstractGeometry > fromPointXY(const QgsPointXY &point)
Construct geometry from a point.
static std::unique_ptr< QgsPolygon > fromPolygonXY(const QgsPolygonXY &polygon)
Construct geometry from a polygon.
static std::unique_ptr< QgsAbstractGeometry > geomFromWkbType(Qgis::WkbType t)
Returns empty geometry from wkb type.
Encapsulates parameters under which a geometry operation is performed.
Definition: qgsgeometry.h:111
Java-style iterator for traversal of parts of a geometry.
static double sqrDistance2D(const QgsPoint &pt1, const QgsPoint &pt2) SIP_HOLDGIL
Returns the squared 2D distance between two points.
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...
static double distanceToVertex(const QgsAbstractGeometry &geom, QgsVertexId id)
Returns the distance along a geometry from its first vertex to the specified vertex.
static double averageAngle(double x1, double y1, double x2, double y2, double x3, double y3) SIP_HOLDGIL
Calculates the average angle (in radians) between the two linear segments from (x1,...
static double lineAngle(double x1, double y1, double x2, double y2) SIP_HOLDGIL
Calculates the direction of line joining two points in radians, clockwise from the north direction.
static double angleBetweenThreePoints(double x1, double y1, double x2, double y2, double x3, double y3) SIP_HOLDGIL
Calculates the angle between the lines AB and BC, where AB and BC described by points a,...
static QgsPoint closestVertex(const QgsAbstractGeometry &geom, const QgsPoint &pt, QgsVertexId &id)
Returns the closest vertex to a geometry for a specified point.
static QgsPointXY interpolatePointOnLine(double x1, double y1, double x2, double y2, double fraction) SIP_HOLDGIL
Interpolates the position of a point a fraction of the way along the line from (x1,...
static void validateGeometry(const QgsGeometry &geometry, QVector< QgsGeometry::Error > &errors, Qgis::GeometryValidationEngine method=Qgis::GeometryValidationEngine::QgisInternal)
Validate geometry and produce a list of geometry errors.
A geometry error.
Definition: qgsgeometry.h:2494
bool hasWhere() const
true if the location available from
QgsPointXY where() const
The coordinates at which the error is located and should be visualized.
QString what() const
A human readable error message containing details about the error.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:164
QgsGeometry() SIP_HOLDGIL
Constructor.
Definition: qgsgeometry.cpp:56
bool deleteRing(int ringNum, int partNum=0)
Deletes a ring in polygon or multipolygon.
QVector< QgsPointXY > randomPointsInPolygon(int count, const std::function< bool(const QgsPointXY &) > &acceptPoint, unsigned long seed=0, QgsFeedback *feedback=nullptr, int maxTriesPerPoint=0) const
Returns a list of count random points generated inside a (multi)polygon geometry (if acceptPoint is s...
double hausdorffDistanceDensify(const QgsGeometry &geom, double densifyFraction) const
Returns the Hausdorff distance between this geometry and geom.
QgsGeometry densifyByCount(int extraNodesPerSegment) const
Returns a copy of the geometry which has been densified by adding the specified number of extra nodes...
QgsGeometry clipped(const QgsRectangle &rectangle)
Clips the geometry using the specified rectangle.
double lineLocatePoint(const QgsGeometry &point) const
Returns a distance representing the location along this linestring of the closest point on this lines...
QVector< QgsGeometry > coerceToType(Qgis::WkbType type, double defaultZ=0, double defaultM=0) const
Attempts to coerce this geometry into the specified destination type.
int makeDifferenceInPlace(const QgsGeometry &other)
Changes this geometry such that it does not intersect the other geometry.
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
void adjacentVertices(int atVertex, int &beforeVertex, int &afterVertex) const
Returns the indexes of the vertices before and after the given vertex index.
QgsMultiPolygonXY asMultiPolygon() const
Returns the contents of the geometry as a multi-polygon.
QgsGeometry difference(const QgsGeometry &geometry, const QgsGeometryParameters &parameters=QgsGeometryParameters()) const
Returns a geometry representing the points making up this geometry that do not make up other.
bool deleteVertex(int atVertex)
Deletes the vertex at the given position number and item (first number is index 0)
double length() const
Returns the planar, 2-dimensional length of geometry.
QgsGeometry offsetCurve(double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit) const
Returns an offset line at a given distance and side from an input line.
static bool compare(const QgsPolylineXY &p1, const QgsPolylineXY &p2, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compares two polylines for equality within a specified tolerance.
QgsVertexIterator vertices() const
Returns a read-only, Java-style iterator for traversal of vertices of all the geometry,...
QgsGeometry densifyByDistance(double distance) const
Densifies the geometry by adding regularly placed extra nodes inside each segment so that the maximum...
QgsGeometry poleOfInaccessibility(double precision, double *distanceToBoundary=nullptr) const
Calculates the approximate pole of inaccessibility for a surface, which is the most distant internal ...
QgsGeometry largestEmptyCircle(double tolerance, const QgsGeometry &boundary=QgsGeometry()) const SIP_THROW(QgsNotSupportedException)
Constructs the Largest Empty Circle for a set of obstacle geometries, up to a specified tolerance.
QgsAbstractGeometry::const_part_iterator const_parts_begin() const
Returns STL-style const iterator pointing to the first part of the geometry.
QgsGeometry squareWaves(double wavelength, double amplitude, bool strictWavelength=false) const
Constructs square waves along the boundary of the geometry, with the specified wavelength and amplitu...
static QgsGeometry polygonize(const QVector< QgsGeometry > &geometries)
Creates a GeometryCollection geometry containing possible polygons formed from the constituent linewo...
QgsGeometry triangularWaves(double wavelength, double amplitude, bool strictWavelength=false) const
Constructs triangular waves along the boundary of the geometry, with the specified wavelength and amp...
bool boundingBoxIntersects(const QgsRectangle &rectangle) const
Returns true if the bounding box of this geometry intersects with a rectangle.
bool vertexIdFromVertexNr(int number, QgsVertexId &id) const
Calculates the vertex ID from a vertex number.
QgsGeometry concaveHull(double targetPercent, bool allowHoles=false) const SIP_THROW(QgsNotSupportedException)
Returns a possibly concave polygon that contains all the points in the geometry.
QgsGeometry pointOnSurface() const
Returns a point guaranteed to lie on the surface of a geometry.
bool touches(const QgsGeometry &geometry) const
Returns true if the geometry touches another geometry.
static QgsGeometry fromQPointF(QPointF point) SIP_HOLDGIL
Construct geometry from a QPointF.
void transformVertices(const std::function< QgsPoint(const QgsPoint &) > &transform)
Transforms the vertices from the geometry in place, applying the transform function to every vertex.
QgsGeometry applyDashPattern(const QVector< double > &pattern, Qgis::DashPatternLineEndingRule startRule=Qgis::DashPatternLineEndingRule::NoRule, Qgis::DashPatternLineEndingRule endRule=Qgis::DashPatternLineEndingRule::NoRule, Qgis::DashPatternSizeAdjustment adjustment=Qgis::DashPatternSizeAdjustment::ScaleBothDashAndGap, double patternOffset=0) const
Applies a dash pattern to a geometry, returning a MultiLineString geometry which is the input geometr...
QgsGeometry roundWaves(double wavelength, double amplitude, bool strictWavelength=false) const
Constructs rounded (sine-like) waves along the boundary of the geometry, with the specified wavelengt...
QgsGeometry nearestPoint(const QgsGeometry &other) const
Returns the nearest (closest) point on this geometry to another geometry.
QgsGeometry makeDifference(const QgsGeometry &other) const
Returns the geometry formed by modifying this geometry such that it does not intersect the other geom...
static QgsGeometry collectGeometry(const QVector< QgsGeometry > &geometries)
Creates a new multipart geometry from a list of QgsGeometry objects.
static QgsGeometry fromMultiPolylineXY(const QgsMultiPolylineXY &multiline)
Creates a new geometry from a QgsMultiPolylineXY object.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
QgsGeometry convertToType(Qgis::GeometryType destType, bool destMultipart=false) const
Try to convert the geometry to the requested type.
QgsGeometry combine(const QgsGeometry &geometry, const QgsGeometryParameters &parameters=QgsGeometryParameters()) const
Returns a geometry representing all the points in this geometry and other (a union geometry operation...
bool isAxisParallelRectangle(double maximumDeviation, bool simpleRectanglesOnly=false) const
Returns true if the geometry is a polygon that is almost an axis-parallel rectangle.
static QgsGeometry fromQPolygonF(const QPolygonF &polygon)
Construct geometry from a QPolygonF.
QgsGeometry variableWidthBufferByM(int segments) const
Calculates a variable width buffer for a (multi)linestring geometry, where the width at each node is ...
static QgsGeometry fromPolylineXY(const QgsPolylineXY &polyline)
Creates a new LineString geometry from a list of QgsPointXY points.
QgsMultiPointXY asMultiPoint() const
Returns the contents of the geometry as a multi-point.
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
QgsPointXY closestVertex(const QgsPointXY &point, int &closestVertexIndex, int &previousVertexIndex, int &nextVertexIndex, double &sqrDist) const
Returns the vertex closest to the given point, the corresponding vertex index, squared distance snap ...
void normalize()
Reorganizes the geometry into a normalized form (or "canonical" form).
int wkbSize(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const
Returns the length of the QByteArray returned by asWkb()
QgsGeometry minimumWidth() const SIP_THROW(QgsNotSupportedException)
Returns a linestring geometry which represents the minimum diameter of the geometry.
QgsPolygonXY asPolygon() const
Returns the contents of the geometry as a polygon.
bool disjoint(const QgsGeometry &geometry) const
Returns true if the geometry is disjoint of another geometry.
QVector< QgsGeometry > asGeometryCollection() const
Returns contents of the geometry as a list of geometries.
QgsGeometry roundWavesRandomized(double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed=0) const
Constructs randomized rounded (sine-like) waves along the boundary of the geometry,...
double distance(const QgsGeometry &geom) const
Returns the minimum distance between this geometry and another geometry.
QgsGeometry interpolate(double distance) const
Returns an interpolated point on the geometry at the specified distance.
QgsGeometry extrude(double x, double y)
Returns an extruded version of this geometry.
static Q_DECL_DEPRECATED QgsPolylineXY createPolylineFromQPolygonF(const QPolygonF &polygon)
Creates a QgsPolylineXY from a QPolygonF.
Q_GADGET bool isNull
Definition: qgsgeometry.h:166
void mapToPixel(const QgsMapToPixel &mtp)
Transforms the geometry from map units to pixels in place.
Qgis::WkbType wkbType() const SIP_HOLDGIL
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
static QgsGeometry fromMultiPointXY(const QgsMultiPointXY &multipoint)
Creates a new geometry from a QgsMultiPointXY object.
QgsGeometry singleSidedBuffer(double distance, int segments, Qgis::BufferSide side, Qgis::JoinStyle joinStyle=Qgis::JoinStyle::Round, double miterLimit=2.0) const
Returns a single sided buffer for a (multi)line geometry.
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
double minimumClearance() const SIP_THROW(QgsNotSupportedException)
Computes the minimum clearance of a geometry.
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...
bool isMultipart() const SIP_HOLDGIL
Returns true if WKB of the geometry is of WKBMulti* type.
QgsGeometry subdivide(int maxNodes=256, const QgsGeometryParameters &parameters=QgsGeometryParameters()) const
Subdivides the geometry.
bool contains(const QgsPointXY *p) const
Returns true if the geometry contains the point p.
QgsPolylineXY asPolyline() const
Returns the contents of the geometry as a polyline.
QgsAbstractGeometry::part_iterator parts_begin()
Returns STL-style iterator pointing to the first part of the geometry.
QgsGeometry forceRHR() const
Forces geometries to respect the Right-Hand-Rule, in which the area that is bounded by a polygon is t...
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
QgsGeometry snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0) const
Returns a new geometry with all points or vertices snapped to the closest point of the grid.
QgsGeometry minimumClearanceLine() const SIP_THROW(QgsNotSupportedException)
Returns a LineString whose endpoints define the minimum clearance of a geometry.
virtual json asJsonObject(int precision=17) const
Exports the geometry to a json object.
void filterVertices(const std::function< bool(const QgsPoint &) > &filter)
Filters the vertices from the geometry in place, removing any which do not return true for the filter...
bool equals(const QgsGeometry &geometry) const
Test if this geometry is exactly equal to another geometry.
bool isGeosValid(Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const
Checks validity of the geometry using GEOS.
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...
static Q_DECL_DEPRECATED QgsPolygonXY createPolygonFromQPolygonF(const QPolygonF &polygon)
Creates a QgsPolygonXYfrom a QPolygonF.
bool convertToSingleType()
Converts multi type geometry into single type geometry e.g.
Qgis::GeometryOperationResult addRing(const QVector< QgsPointXY > &ring)
Adds a new ring to this geometry.
Qgis::GeometryType type
Definition: qgsgeometry.h:167
QPointF asQPointF() const SIP_HOLDGIL
Returns contents of the geometry as a QPointF if wkbType is WKBPoint, otherwise returns a null QPoint...
static QgsGeometry fromPointXY(const QgsPointXY &point) SIP_HOLDGIL
Creates a new geometry from a QgsPointXY object.
bool requiresConversionToStraightSegments() const
Returns true if the geometry is a curved geometry type which requires conversion to display as straig...
bool isSimple() const
Determines whether the geometry is simple (according to OGC definition), i.e.
static QgsGeometry fromPolyline(const QgsPolyline &polyline)
Creates a new LineString geometry from a list of QgsPoint points.
void validateGeometry(QVector< QgsGeometry::Error > &errors, Qgis::GeometryValidationEngine method=Qgis::GeometryValidationEngine::QgisInternal, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const
Validates geometry and produces a list of geometry errors.
QgsMultiPolylineXY asMultiPolyline() const
Returns the contents of the geometry as a multi-linestring.
QgsGeometry taperedBuffer(double startWidth, double endWidth, int segments) const
Calculates a variable width buffer ("tapered buffer") for a (multi)curve geometry.
bool within(const QgsGeometry &geometry) const
Returns true if the geometry is completely within another geometry.
double frechetDistanceDensify(const QgsGeometry &geom, double densifyFraction) const SIP_THROW(QgsNotSupportedException)
Returns the Fréchet distance between this geometry and geom, restricted to discrete points for both g...
void convertToStraightSegment(double tolerance=M_PI/180., QgsAbstractGeometry::SegmentationToleranceType toleranceType=QgsAbstractGeometry::MaximumAngle)
Converts the geometry to straight line segments, if it is a curved geometry type.
double area() const
Returns the planar, 2-dimensional area of the geometry.
QgsGeometry centroid() const
Returns the center of mass of a geometry.
bool crosses(const QgsGeometry &geometry) const
Returns true if the geometry crosses another geometry.
QgsGeometry & operator=(QgsGeometry const &rhs)
Creates a deep copy of the object.
Definition: qgsgeometry.cpp:88
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...
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine representing the specified geometry.
double hausdorffDistance(const QgsGeometry &geom) const
Returns the Hausdorff distance between this geometry and geom.
QString lastError() const SIP_HOLDGIL
Returns an error string referring to the last error encountered either when this geometry was created...
QgsGeometry makeValid(Qgis::MakeValidMethod method=Qgis::MakeValidMethod::Linework, bool keepCollapsed=false) const SIP_THROW(QgsNotSupportedException)
Attempts to make an invalid geometry valid without losing vertices.
Qgis::GeometryOperationResult addPart(const QVector< QgsPointXY > &points, Qgis::GeometryType geomType=Qgis::GeometryType::Unknown)
Adds a new part to a the geometry.
QgsGeometryPartIterator parts()
Returns Java-style iterator for traversal of parts of the geometry.
QPolygonF asQPolygonF() const SIP_HOLDGIL
Returns contents of the geometry as a QPolygonF.
QgsGeometry convertToCurves(double distanceTolerance=1e-8, double angleTolerance=1e-8) const
Attempts to convert a non-curved geometry into a curved geometry type (e.g.
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.
void set(QgsAbstractGeometry *geometry)
Sets the underlying geometry store.
QgsGeometry convexHull() const
Returns the smallest convex polygon that contains all the points in the geometry.
QgsGeometry sharedPaths(const QgsGeometry &other) const
Find paths shared between the two given lineal geometries (this and other).
virtual ~QgsGeometry()
Definition: qgsgeometry.cpp:61
static QgsGeometry fromPolygonXY(const QgsPolygonXY &polygon)
Creates a new geometry from a QgsPolygonXY.
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer's length.
QgsGeometry intersection(const QgsGeometry &geometry, const QgsGeometryParameters &parameters=QgsGeometryParameters()) const
Returns a geometry representing the points shared by this geometry and other.
QgsGeometry symDifference(const QgsGeometry &geometry, const QgsGeometryParameters &parameters=QgsGeometryParameters()) const
Returns a geometry representing the points making up this geometry that do not make up other.
QgsGeometry minimalEnclosingCircle(QgsPointXY &center, double &radius, unsigned int segments=36) const
Returns the minimal enclosing circle for the geometry.
QgsGeometry mergeLines() const
Merges any connected lines in a LineString/MultiLineString geometry and converts them to single line ...
static QgsGeometry fromMultiPolygonXY(const QgsMultiPolygonXY &multipoly)
Creates a new geometry from a QgsMultiPolygonXY.
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...
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
QgsGeometry node() const
Returns a (Multi)LineString representing the fully noded version of a collection of linestrings.
double distanceToVertex(int vertex) const
Returns the distance along this geometry from its first vertex to the specified vertex.
int vertexNrFromVertexId(QgsVertexId id) const
Returns the vertex number corresponding to a vertex id.
QgsAbstractGeometry::const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry.
bool removeDuplicateNodes(double epsilon=4 *std::numeric_limits< double >::epsilon(), bool useZValues=false)
Removes duplicate nodes from the geometry, wherever removing the nodes does not result in a degenerat...
bool convertGeometryCollectionToSubclass(Qgis::GeometryType geomType)
Converts geometry collection to a the desired geometry type subclass (multi-point,...
QgsAbstractGeometry::part_iterator parts_end()
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry.
QgsAbstractGeometry::vertex_iterator vertices_begin() const
Returns STL-style iterator pointing to the first vertex of the geometry.
QgsGeometry forcePolygonClockwise() const
Forces geometries to respect the exterior ring is clockwise, interior rings are counter-clockwise con...
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
QString asJson(int precision=17) const
Exports the geometry to a GeoJSON string.
static QgsGeometry createWedgeBuffer(const QgsPoint &center, double azimuth, double angularWidth, double outerRadius, double innerRadius=0)
Creates a wedge shaped buffer from a center point.
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const
Export the geometry to WKB.
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...
static QgsGeometry unaryUnion(const QVector< QgsGeometry > &geometries, const QgsGeometryParameters &parameters=QgsGeometryParameters())
Compute the unary union on a list of geometries.
bool convertToCurvedMultiType()
Converts a geometry into a multitype geometry of curve kind (when there is a corresponding curve type...
static void convertPointList(const QVector< QgsPointXY > &input, QgsPointSequence &output)
Upgrades a point list from QgsPointXY to QgsPoint.
QgsGeometry orientedMinimumBoundingBox() const
Returns the oriented minimum bounding box for the geometry, which is the smallest (by area) rotated r...
QgsGeometry triangularWavesRandomized(double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed=0) const
Constructs randomized triangular waves along the boundary of the geometry, with the specified wavelen...
QgsGeometry squareWavesRandomized(double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed=0) const
Constructs randomized square waves along the boundary of the geometry, with the specified wavelength ...
QgsGeometryConstPartIterator constParts() const
Returns Java-style iterator for traversal of parts of the geometry.
QgsGeometry simplify(double tolerance) const
Returns a simplified version of this geometry using a specified tolerance value.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Qgis::GeometryOperationResult rotate(double rotation, const QgsPointXY &center)
Rotate this geometry around the Z axis.
Qgis::GeometryOperationResult translate(double dx, double dy, double dz=0.0, double dm=0.0)
Translates this geometry by dx, dy, dz and dm.
double interpolateAngle(double distance) const
Returns the angle parallel to the linestring or polygon boundary at the specified distance along the ...
double angleAtVertex(int vertex) const
Returns the bisector angle for this geometry at the specified vertex.
Qgis::GeometryOperationResult reshapeGeometry(const QgsLineString &reshapeLineString)
Replaces a part of this geometry with another line.
double closestVertexWithContext(const QgsPointXY &point, int &atVertex) const
Searches for the closest vertex in this geometry to the given point.
QgsGeometry delaunayTriangulation(double tolerance=0.0, bool edgesOnly=false) const
Returns the Delaunay triangulation for the vertices of the geometry.
void draw(QPainter &p) const
Draws the geometry onto a QPainter.
double frechetDistance(const QgsGeometry &geom) const SIP_THROW(QgsNotSupportedException)
Returns the Fréchet distance between this geometry and geom, restricted to discrete points for both g...
QgsGeometry smooth(unsigned int iterations=1, double offset=0.25, double minimumDistance=-1.0, double maxAngle=180.0) const
Smooths a geometry by rounding off corners using the Chaikin algorithm.
QgsGeometry forcePolygonCounterClockwise() const
Forces geometries to respect the exterior ring is counter-clockwise, interior rings are clockwise con...
QString asWkt(int precision=17) const
Exports the geometry to WKT.
Q_DECL_DEPRECATED Qgis::GeometryOperationResult splitGeometry(const QVector< QgsPointXY > &splitLine, QVector< QgsGeometry > &newGeometries, bool topological, QVector< QgsPointXY > &topologyTestPoints, bool splitFeature=true)
Splits this geometry according to a given line.
bool toggleCircularAtVertex(int atVertex)
Converts the vertex at the given position from/to circular.
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...
bool isGeosEqual(const QgsGeometry &) const
Compares the geometry with another geometry using GEOS.
double closestSegmentWithContext(const QgsPointXY &point, QgsPointXY &minDistPoint, int &nextVertexIndex, int *leftOrRightOfSegment=nullptr, double epsilon=DEFAULT_SEGMENT_EPSILON) const
Searches for the closest segment of geometry to the given point.
bool intersects(const QgsRectangle &rectangle) const
Returns true if this geometry exactly intersects with a rectangle.
QgsAbstractGeometry::vertex_iterator vertices_end() const
Returns STL-style iterator pointing to the imaginary vertex after the last vertex of the geometry.
bool deletePart(int partNum)
Deletes part identified by the part number.
QgsGeometry removeInteriorRings(double minimumAllowedArea=-1) const
Removes the interior rings from a (multi)polygon geometry.
bool overlaps(const QgsGeometry &geometry) const
Returns true if the geometry overlaps another geometry.
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.
QgsGeometry shortestLine(const QgsGeometry &other) const
Returns the shortest line joining this geometry to another geometry.
Does vector analysis using the geos library and handles import, export, exception handling*.
Definition: qgsgeos.h:99
double hausdorffDistanceDensify(const QgsAbstractGeometry *geom, double densifyFraction, QString *errorMsg=nullptr) const
Returns the Hausdorff distance between this geometry and geom.
Definition: qgsgeos.cpp:660
double hausdorffDistance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const
Returns the Hausdorff distance between this geometry and geom.
Definition: qgsgeos.cpp:637
QgsAbstractGeometry * buffer(double distance, int segments, QString *errorMsg=nullptr) const override
Definition: qgsgeos.cpp:1865
double distance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculates the distance between this and geom.
Definition: qgsgeos.cpp:507
static QgsGeometry polygonize(const QVector< const QgsAbstractGeometry * > &geometries, QString *errorMsg=nullptr)
Creates a GeometryCollection geometry containing possible polygons formed from the constituent linewo...
Definition: qgsgeos.cpp:2874
double frechetDistance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const
Returns the Fréchet distance between this geometry and geom, restricted to discrete points for both g...
Definition: qgsgeos.cpp:683
double frechetDistanceDensify(const QgsAbstractGeometry *geom, double densifyFraction, QString *errorMsg=nullptr) const
Returns the Fréchet distance between this geometry and geom, restricted to discrete points for both g...
Definition: qgsgeos.cpp:706
This class offers geometry processing methods.
QgsGeometry triangularWavesRandomized(double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed=0) const
Constructs randomized triangular waves along the boundary of the geometry, with the specified wavelen...
QgsGeometry triangularWaves(double wavelength, double amplitude, bool strictWavelength=false) const
Constructs triangular waves along the boundary of the geometry, with the specified wavelength and amp...
QgsGeometry roundWaves(double wavelength, double amplitude, bool strictWavelength=false) const
Constructs rounded (sine-like) waves along the boundary of the geometry, with the specified wavelengt...
QgsGeometry poleOfInaccessibility(double precision, double *distanceFromBoundary=nullptr) const
Calculates the approximate pole of inaccessibility for a surface, which is the most distant internal ...
QgsGeometry squareWaves(double wavelength, double amplitude, bool strictWavelength=false) const
Constructs square waves along the boundary of the geometry, with the specified wavelength and amplitu...
QgsGeometry variableWidthBufferByM(int segments) const
Calculates a variable width buffer using the m-values from a (multi)line 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...
QgsGeometry roundWavesRandomized(double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed=0) const
Constructs randomized rounded (sine-like) waves along the boundary of the geometry,...
QgsGeometry orthogonalize(double tolerance=1.0E-8, int maxIterations=1000, double angleThreshold=15.0) const
Attempts to orthogonalize a line or polygon geometry by shifting vertices to make the geometries angl...
QString lastError() const
Returns an error string referring to the last error encountered.
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 densifyByDistance(double distance) const
Densifies the geometry by adding regularly placed extra nodes inside each segment so that the maximum...
QgsGeometry taperedBuffer(double startWidth, double endWidth, int segments) const
Calculates a tapered width buffer for a (multi)curve geometry.
QgsGeometry densifyByCount(int extraNodesPerSegment) const
Densifies the geometry by adding the specified number of extra nodes within each segment of the geome...
QgsGeometry applyDashPattern(const QVector< double > &pattern, Qgis::DashPatternLineEndingRule startRule=Qgis::DashPatternLineEndingRule::NoRule, Qgis::DashPatternLineEndingRule endRule=Qgis::DashPatternLineEndingRule::NoRule, Qgis::DashPatternSizeAdjustment adjustment=Qgis::DashPatternSizeAdjustment::ScaleBothDashAndGap, double patternOffset=0) const
Applies a dash pattern to a geometry, returning a MultiLineString geometry which is the input geometr...
static QVector< QgsPointXY > randomPointsInPolygon(const QgsGeometry &polygon, int count, const std::function< bool(const QgsPointXY &) > &acceptPoint, unsigned long seed=0, QgsFeedback *feedback=nullptr, int maxTriesPerPoint=0)
Returns a list of count random points generated inside a polygon geometry (if acceptPoint is specifie...
QgsGeometry squareWavesRandomized(double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed=0) const
Constructs randomized square waves along the boundary of the geometry, with the specified wavelength ...
QgsGeometry convertToCurves(double distanceTolerance, double angleTolerance) const
Attempts to convert a non-curved geometry into a curved geometry type (e.g.
bool isAxisParallelRectangle(double maximumDeviation, bool simpleRectanglesOnly=false) const
Returns true if the geometry is a polygon that is almost an axis-parallel rectangle.
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:45
const double * yData() const
Returns a const pointer to the y vertex data.
const double * xData() const
Returns a const pointer to the x vertex data.
int numPoints() const override SIP_HOLDGIL
Returns the number of points in the curve.
static QgsLineString * fromQPolygonF(const QPolygonF &polygon)
Returns a new linestring from a QPolygonF polygon input.
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:39
QgsPointXY transform(const QgsPointXY &p) const
Transforms a point p from map (world) coordinates to device coordinates.
Definition: qgsmaptopixel.h:90
Multi line string geometry collection.
QgsLineString * lineStringN(int index)
Returns the line string with the specified index.
Multi point geometry collection.
Definition: qgsmultipoint.h:30
QgsPoint * pointN(int index)
Returns the point with the specified index.
Multi polygon geometry collection.
QgsPolygon * polygonN(int index)
Returns the polygon with the specified index.
A class to represent a 2D point.
Definition: qgspointxy.h:59
void setX(double x) SIP_HOLDGIL
Sets the x value of the point.
Definition: qgspointxy.h:122
double y
Definition: qgspointxy.h:63
Q_GADGET double x
Definition: qgspointxy.h:62
void setY(double y) SIP_HOLDGIL
Sets the y value of the point.
Definition: qgspointxy.h:132
QPointF toQPointF() const
Converts a point to a QPointF.
Definition: qgspointxy.h:169
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
void setX(double x) SIP_HOLDGIL
Sets the point's x-coordinate.
Definition: qgspoint.h:280
QgsPoint project(double distance, double azimuth, double inclination=90.0) const SIP_HOLDGIL
Returns a new point which corresponds to this point projected by a specified distance with specified ...
Definition: qgspoint.cpp:735
Q_GADGET double x
Definition: qgspoint.h:52
double y
Definition: qgspoint.h:53
Polygon geometry type.
Definition: qgspolygon.h:34
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:183
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:479
bool isEmpty() const
Returns true if the rectangle is empty.
Definition: qgsrectangle.h:469
Represents a vector layer which manages a vector based data sets.
Java-style iterator for traversal of vertices of a geometry.
static Qgis::GeometryType geometryType(Qgis::WkbType type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:865
static bool isMultiType(Qgis::WkbType type) SIP_HOLDGIL
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:759
static bool hasZ(Qgis::WkbType type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:977
static bool isCurvedType(Qgis::WkbType type) SIP_HOLDGIL
Returns true if the WKB type is a curved type or can contain curved geometries.
Definition: qgswkbtypes.h:808
static Qgis::WkbType curveType(Qgis::WkbType type) SIP_HOLDGIL
Returns the curve type for a WKB type.
Definition: qgswkbtypes.h:378
static Qgis::WkbType multiType(Qgis::WkbType type) SIP_HOLDGIL
Returns the multi type for a WKB type.
Definition: qgswkbtypes.h:201
static bool hasM(Qgis::WkbType type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1027
static Qgis::WkbType flatType(Qgis::WkbType type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:629
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:786
Contains geos related utilities and functions.
Definition: qgsgeos.h:37
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:4093
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:4092
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:3509
QVector< QgsPoint > QgsPointSequence
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
QDataStream & operator<<(QDataStream &out, const QgsGeometry &geometry)
Writes the geometry to stream out. QGIS version compatibility is not guaranteed.
std::unique_ptr< QgsLineString > smoothCurve(const QgsLineString &line, const unsigned int iterations, const double offset, double squareDistThreshold, double maxAngleRads, bool isRing)
Q_GLOBAL_STATIC_WITH_ARGS(WktCache, sWktCache,(2000)) QgsGeometry QgsGeometry
QDataStream & operator>>(QDataStream &in, QgsGeometry &geometry)
Reads a geometry from stream in into geometry. QGIS version compatibility is not guaranteed.
QCache< QString, QgsGeometry > WktCache
QVector< QgsPolylineXY > QgsPolygonXY
Polygon: first item of the list is outer ring, inner rings (if any) start from second item.
Definition: qgsgeometry.h:76
QVector< QgsPolylineXY > QgsMultiPolylineXY
A collection of QgsPolylines that share a common collection of attributes.
Definition: qgsgeometry.h:86
QVector< QgsPointXY > QgsMultiPointXY
A collection of QgsPoints that share a common collection of attributes.
Definition: qgsgeometry.h:82
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
Definition: qgsgeometry.h:63
QVector< QgsPolygonXY > QgsMultiPolygonXY
A collection of QgsPolygons that share a common collection of attributes.
Definition: qgsgeometry.h:93
QgsPointSequence QgsPolyline
Polyline as represented as a vector of points.
Definition: qgsgeometry.h:72
int precision
std::unique_ptr< QgsAbstractGeometry > geometry
Definition: qgsgeometry.cpp:53
Utility class for identifying a unique vertex within a geometry.
Definition: qgsvertexid.h:31
int vertex
Vertex number.
Definition: qgsvertexid.h:95
bool isValid() const SIP_HOLDGIL
Returns true if the vertex id is valid.
Definition: qgsvertexid.h:46