QGIS API Documentation 3.29.0-Master (006c3c0232)
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 {
365 }
366 return static_cast< QgsWkbTypes::GeometryType >( 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() ) == QgsWkbTypes::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
591 if ( owningPolygon == nullptr && owningCollection == nullptr )
592 {
593 // Standalone linestring
594 reset( std::make_unique<QgsCompoundCurve>( *cpdCurve ) ); // <- REVIEW PLZ
595 }
596 else if ( owningPolygon != nullptr )
597 {
598 // Replace the ring in the owning polygon
599 if ( id.ring == 0 )
600 {
601 owningPolygon->setExteriorRing( cpdCurve.release() );
602 }
603 else
604 {
605 owningPolygon->removeInteriorRing( id.ring - 1 );
606 owningPolygon->addInteriorRing( cpdCurve.release() );
607 }
608 }
609 else if ( owningCollection != nullptr )
610 {
611 // Replace the curve in the owning collection
612 owningCollection->removeGeometry( id.part );
613 owningCollection->insertGeometry( cpdCurve.release(), id.part );
614 }
615 }
616 }
617
618 return success;
619}
620
621bool QgsGeometry::insertVertex( double x, double y, int beforeVertex )
622{
623 if ( !d->geometry )
624 {
625 return false;
626 }
627
628 //maintain compatibility with < 2.10 API
630 {
631 detach();
632 //insert geometry instead of point
633 return static_cast< QgsGeometryCollection * >( d->geometry.get() )->insertGeometry( new QgsPoint( x, y ), beforeVertex );
634 }
635
636 QgsVertexId id;
637 if ( !vertexIdFromVertexNr( beforeVertex, id ) )
638 {
639 return false;
640 }
641
642 detach();
643
644 return d->geometry->insertVertex( id, QgsPoint( x, y ) );
645}
646
647bool QgsGeometry::insertVertex( const QgsPoint &point, int beforeVertex )
648{
649 if ( !d->geometry )
650 {
651 return false;
652 }
653
654 //maintain compatibility with < 2.10 API
656 {
657 detach();
658 //insert geometry instead of point
659 return static_cast< QgsGeometryCollection * >( d->geometry.get() )->insertGeometry( new QgsPoint( point ), beforeVertex );
660 }
661
662 QgsVertexId id;
663 if ( !vertexIdFromVertexNr( beforeVertex, id ) )
664 {
665 return false;
666 }
667
668 detach();
669
670 return d->geometry->insertVertex( id, point );
671}
672
673QgsPoint QgsGeometry::vertexAt( int atVertex ) const
674{
675 if ( !d->geometry )
676 {
677 return QgsPoint();
678 }
679
680 QgsVertexId vId;
681 ( void )vertexIdFromVertexNr( atVertex, vId );
682 if ( vId.vertex < 0 )
683 {
684 return QgsPoint();
685 }
686 return d->geometry->vertexAt( vId );
687}
688
689double QgsGeometry::sqrDistToVertexAt( QgsPointXY &point, int atVertex ) const
690{
691 QgsPointXY vertexPoint = vertexAt( atVertex );
692 return QgsGeometryUtils::sqrDistance2D( QgsPoint( vertexPoint ), QgsPoint( point ) );
693}
694
696{
697 // avoid calling geos for trivial point calculations
698 if ( d->geometry && QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::Point )
699 {
700 return QgsGeometry( qgsgeometry_cast< const QgsPoint * >( d->geometry.get() )->clone() );
701 }
702
703 QgsGeos geos( d->geometry.get() );
704 mLastError.clear();
705 QgsGeometry result = geos.closestPoint( other );
706 result.mLastError = mLastError;
707 return result;
708}
709
711{
712 // avoid calling geos for trivial point-to-point line calculations
714 {
715 return QgsGeometry( std::make_unique< QgsLineString >( *qgsgeometry_cast< const QgsPoint * >( d->geometry.get() ), *qgsgeometry_cast< const QgsPoint * >( other.constGet() ) ) );
716 }
717
718 QgsGeos geos( d->geometry.get() );
719 mLastError.clear();
720 QgsGeometry result = geos.shortestLine( other, &mLastError );
721 result.mLastError = mLastError;
722 return result;
723}
724
725double QgsGeometry::closestVertexWithContext( const QgsPointXY &point, int &atVertex ) const
726{
727 if ( !d->geometry )
728 {
729 return -1;
730 }
731
732 QgsVertexId vId;
733 QgsPoint pt( point );
734 QgsPoint closestPoint = QgsGeometryUtils::closestVertex( *( d->geometry ), pt, vId );
735 if ( !vId.isValid() )
736 return -1;
737 atVertex = vertexNrFromVertexId( vId );
738 return QgsGeometryUtils::sqrDistance2D( closestPoint, pt );
739}
740
742 QgsPointXY &minDistPoint,
743 int &nextVertexIndex,
744 int *leftOrRightOfSegment,
745 double epsilon ) const
746{
747 if ( !d->geometry )
748 {
749 return -1;
750 }
751
752 QgsPoint segmentPt;
753 QgsVertexId vertexAfter;
754
755 double sqrDist = d->geometry->closestSegment( QgsPoint( point ), segmentPt, vertexAfter, leftOrRightOfSegment, epsilon );
756 if ( sqrDist < 0 )
757 return -1;
758
759 minDistPoint.setX( segmentPt.x() );
760 minDistPoint.setY( segmentPt.y() );
761 nextVertexIndex = vertexNrFromVertexId( vertexAfter );
762 return sqrDist;
763}
764
765Qgis::GeometryOperationResult QgsGeometry::addRing( const QVector<QgsPointXY> &ring )
766{
767 std::unique_ptr< QgsLineString > ringLine = std::make_unique< QgsLineString >( ring );
768 return addRing( ringLine.release() );
769}
770
772{
773 std::unique_ptr< QgsCurve > r( ring );
774 if ( !d->geometry )
775 {
777 }
778
779 detach();
780
781 return QgsGeometryEditUtils::addRing( d->geometry.get(), std::move( r ) );
782}
783
785{
787 convertPointList( points, l );
788 return addPart( l, geomType );
789}
790
792{
793 std::unique_ptr< QgsAbstractGeometry > partGeom;
794 if ( points.size() == 1 )
795 {
796 partGeom = std::make_unique< QgsPoint >( points[0] );
797 }
798 else if ( points.size() > 1 )
799 {
800 std::unique_ptr< QgsLineString > ringLine = std::make_unique< QgsLineString >();
801 ringLine->setPoints( points );
802 partGeom = std::move( ringLine );
803 }
804 return addPart( partGeom.release(), geomType );
805}
806
808{
809 std::unique_ptr< QgsAbstractGeometry > p( part );
810 if ( !d->geometry )
811 {
812 switch ( geomType )
813 {
815 reset( std::make_unique< QgsMultiPoint >() );
816 break;
818 reset( std::make_unique< QgsMultiLineString >() );
819 break;
821 reset( std::make_unique< QgsMultiPolygon >() );
822 break;
823 default:
824 reset( nullptr );
826 }
827 }
828 else
829 {
830 detach();
831 }
832
834 return QgsGeometryEditUtils::addPart( d->geometry.get(), std::move( p ) );
835}
836
838{
839 if ( !d->geometry )
840 {
842 }
843 if ( newPart.isNull() || !newPart.d->geometry )
844 {
846 }
847
848 return addPart( newPart.d->geometry->clone() );
849}
850
851QgsGeometry QgsGeometry::removeInteriorRings( double minimumRingArea ) const
852{
854 {
855 return QgsGeometry();
856 }
857
858 if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
859 {
860 const QVector<QgsGeometry> parts = asGeometryCollection();
861 QVector<QgsGeometry> results;
862 results.reserve( parts.count() );
863 for ( const QgsGeometry &part : parts )
864 {
865 QgsGeometry result = part.removeInteriorRings( minimumRingArea );
866 if ( !result.isNull() )
867 results << result;
868 }
869 if ( results.isEmpty() )
870 return QgsGeometry();
871
872 QgsGeometry first = results.takeAt( 0 );
873 for ( const QgsGeometry &result : std::as_const( results ) )
874 {
875 first.addPart( result );
876 }
877 return first;
878 }
879 else
880 {
881 std::unique_ptr< QgsCurvePolygon > newPoly( static_cast< QgsCurvePolygon * >( d->geometry->clone() ) );
882 newPoly->removeInteriorRings( minimumRingArea );
883 return QgsGeometry( std::move( newPoly ) );
884 }
885}
886
887Qgis::GeometryOperationResult QgsGeometry::translate( double dx, double dy, double dz, double dm )
888{
889 if ( !d->geometry )
890 {
892 }
893
894 detach();
895
896 d->geometry->transform( QTransform::fromTranslate( dx, dy ), dz, 1.0, dm );
898}
899
901{
902 if ( !d->geometry )
903 {
905 }
906
907 detach();
908
909 QTransform t = QTransform::fromTranslate( center.x(), center.y() );
910 t.rotate( -rotation );
911 t.translate( -center.x(), -center.y() );
912 d->geometry->transform( t );
914}
915
916Qgis::GeometryOperationResult QgsGeometry::splitGeometry( const QVector<QgsPointXY> &splitLine, QVector<QgsGeometry> &newGeometries, bool topological, QVector<QgsPointXY> &topologyTestPoints, bool splitFeature )
917{
918 QgsPointSequence split, topology;
919 convertPointList( splitLine, split );
920 convertPointList( topologyTestPoints, topology );
921 Qgis::GeometryOperationResult result = splitGeometry( split, newGeometries, topological, topology, splitFeature );
922 convertPointList( topology, topologyTestPoints );
923 return result;
924}
925Qgis::GeometryOperationResult QgsGeometry::splitGeometry( const QgsPointSequence &splitLine, QVector<QgsGeometry> &newGeometries, bool topological, QgsPointSequence &topologyTestPoints, bool splitFeature, bool skipIntersectionTest )
926{
927 if ( !d->geometry )
928 {
930 }
931
932 QVector<QgsGeometry > newGeoms;
933 QgsLineString splitLineString( splitLine );
934
935 QgsGeos geos( d->geometry.get() );
936 mLastError.clear();
937 QgsGeometryEngine::EngineOperationResult result = geos.splitGeometry( splitLineString, newGeoms, topological, topologyTestPoints, &mLastError, skipIntersectionTest );
938
939 if ( result == QgsGeometryEngine::Success )
940 {
941 if ( splitFeature )
942 *this = newGeoms.takeAt( 0 );
943 newGeometries = newGeoms;
944 }
945
946 switch ( result )
947 {
962 //default: do not implement default to handle properly all cases
963 }
964
965 // this should never be reached
966 Q_ASSERT( false );
968}
969
970Qgis::GeometryOperationResult QgsGeometry::splitGeometry( const QgsCurve *curve, QVector<QgsGeometry> &newGeometries, bool preserveCircular, bool topological, QgsPointSequence &topologyTestPoints, bool splitFeature )
971{
972 std::unique_ptr<QgsLineString> segmentizedLine( curve->curveToLine() );
973 QgsPointSequence points;
974 segmentizedLine->points( points );
975 Qgis::GeometryOperationResult result = splitGeometry( points, newGeometries, topological, topologyTestPoints, splitFeature );
976
978 {
979 if ( preserveCircular )
980 {
981 for ( int i = 0; i < newGeometries.count(); ++i )
982 newGeometries[i] = newGeometries[i].convertToCurves();
983 *this = convertToCurves();
984 }
985 }
986
987 return result;
988}
989
991{
992 if ( !d->geometry )
993 {
995 }
996
997 QgsGeos geos( d->geometry.get() );
999 mLastError.clear();
1000 std::unique_ptr< QgsAbstractGeometry > geom( geos.reshapeGeometry( reshapeLineString, &errorCode, &mLastError ) );
1001 if ( errorCode == QgsGeometryEngine::Success && geom )
1002 {
1003 reset( std::move( geom ) );
1005 }
1006
1007 switch ( errorCode )
1008 {
1019 case QgsGeometryEngine::SplitCannotSplitPoint: // should not happen
1023 }
1024
1025 // should not be reached
1027}
1028
1030{
1031 if ( !d->geometry || !other.d->geometry )
1032 {
1033 return 0;
1034 }
1035
1036 QgsGeos geos( d->geometry.get() );
1037
1038 mLastError.clear();
1039 std::unique_ptr< QgsAbstractGeometry > diffGeom( geos.intersection( other.constGet(), &mLastError ) );
1040 if ( !diffGeom )
1041 {
1042 return 1;
1043 }
1044
1045 reset( std::move( diffGeom ) );
1046 return 0;
1047}
1048
1050{
1051 if ( !d->geometry || other.isNull() )
1052 {
1053 return QgsGeometry();
1054 }
1055
1056 QgsGeos geos( d->geometry.get() );
1057
1058 mLastError.clear();
1059 std::unique_ptr< QgsAbstractGeometry > diffGeom( geos.intersection( other.constGet(), &mLastError ) );
1060 if ( !diffGeom )
1061 {
1062 QgsGeometry result;
1063 result.mLastError = mLastError;
1064 return result;
1065 }
1066
1067 return QgsGeometry( diffGeom.release() );
1068}
1069
1071{
1072 if ( d->geometry )
1073 {
1074 return d->geometry->boundingBox();
1075 }
1076 return QgsRectangle();
1077}
1078
1079QgsGeometry QgsGeometry::orientedMinimumBoundingBox( double &area, double &angle, double &width, double &height ) const
1080{
1081 mLastError.clear();
1082 QgsInternalGeometryEngine engine( *this );
1083 const QgsGeometry res = engine.orientedMinimumBoundingBox( area, angle, width, height );
1084 if ( res.isNull() )
1085 mLastError = engine.lastError();
1086 return res;
1087}
1088
1090{
1091 double area, angle, width, height;
1092 return orientedMinimumBoundingBox( area, angle, width, height );
1093}
1094
1095static QgsCircle __recMinimalEnclosingCircle( QgsMultiPointXY points, QgsMultiPointXY boundary )
1096{
1097 auto l_boundary = boundary.length();
1098 QgsCircle circ_mec;
1099 if ( ( points.length() == 0 ) || ( l_boundary == 3 ) )
1100 {
1101 switch ( l_boundary )
1102 {
1103 case 0:
1104 circ_mec = QgsCircle();
1105 break;
1106 case 1:
1107 circ_mec = QgsCircle( QgsPoint( boundary.last() ), 0 );
1108 boundary.pop_back();
1109 break;
1110 case 2:
1111 {
1112 QgsPointXY p1 = boundary.last();
1113 boundary.pop_back();
1114 QgsPointXY p2 = boundary.last();
1115 boundary.pop_back();
1116 circ_mec = QgsCircle::from2Points( QgsPoint( p1 ), QgsPoint( p2 ) );
1117 }
1118 break;
1119 default:
1120 QgsPoint p1( boundary.at( 0 ) );
1121 QgsPoint p2( boundary.at( 1 ) );
1122 QgsPoint p3( boundary.at( 2 ) );
1123 circ_mec = QgsCircle::minimalCircleFrom3Points( p1, p2, p3 );
1124 break;
1125 }
1126 return circ_mec;
1127 }
1128 else
1129 {
1130 QgsPointXY pxy = points.last();
1131 points.pop_back();
1132 circ_mec = __recMinimalEnclosingCircle( points, boundary );
1133 QgsPoint p( pxy );
1134 if ( !circ_mec.contains( p ) )
1135 {
1136 boundary.append( pxy );
1137 circ_mec = __recMinimalEnclosingCircle( points, boundary );
1138 }
1139 }
1140 return circ_mec;
1141}
1142
1143QgsGeometry QgsGeometry::minimalEnclosingCircle( QgsPointXY &center, double &radius, unsigned int segments ) const
1144{
1145 center = QgsPointXY();
1146 radius = 0;
1147
1148 if ( isEmpty() )
1149 {
1150 return QgsGeometry();
1151 }
1152
1153 /* optimization */
1154 QgsGeometry hull = convexHull();
1155 if ( hull.isNull() )
1156 return QgsGeometry();
1157
1158 QgsMultiPointXY P = hull.convertToPoint( true ).asMultiPoint();
1160
1161 QgsCircle circ = __recMinimalEnclosingCircle( P, R );
1162 center = QgsPointXY( circ.center() );
1163 radius = circ.radius();
1164 QgsGeometry geom;
1165 geom.set( circ.toPolygon( segments ) );
1166 return geom;
1167
1168}
1169
1171{
1172 QgsPointXY center;
1173 double radius;
1174 return minimalEnclosingCircle( center, radius, segments );
1175
1176}
1177
1178QgsGeometry QgsGeometry::orthogonalize( double tolerance, int maxIterations, double angleThreshold ) const
1179{
1180 QgsInternalGeometryEngine engine( *this );
1181
1182 return engine.orthogonalize( tolerance, maxIterations, angleThreshold );
1183}
1184
1185QgsGeometry QgsGeometry::triangularWaves( double wavelength, double amplitude, bool strictWavelength ) const
1186{
1187 QgsInternalGeometryEngine engine( *this );
1188 return engine.triangularWaves( wavelength, amplitude, strictWavelength );
1189}
1190
1191QgsGeometry QgsGeometry::triangularWavesRandomized( double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed ) const
1192{
1193 QgsInternalGeometryEngine engine( *this );
1194 return engine.triangularWavesRandomized( minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, seed );
1195}
1196
1197QgsGeometry QgsGeometry::squareWaves( double wavelength, double amplitude, bool strictWavelength ) const
1198{
1199 QgsInternalGeometryEngine engine( *this );
1200 return engine.squareWaves( wavelength, amplitude, strictWavelength );
1201}
1202
1203QgsGeometry QgsGeometry::squareWavesRandomized( double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed ) const
1204{
1205 QgsInternalGeometryEngine engine( *this );
1206 return engine.squareWavesRandomized( minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, seed );
1207}
1208
1209QgsGeometry QgsGeometry::roundWaves( double wavelength, double amplitude, bool strictWavelength ) const
1210{
1211 QgsInternalGeometryEngine engine( *this );
1212 return engine.roundWaves( wavelength, amplitude, strictWavelength );
1213}
1214
1215QgsGeometry QgsGeometry::roundWavesRandomized( double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed ) const
1216{
1217 QgsInternalGeometryEngine engine( *this );
1218 return engine.roundWavesRandomized( minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, seed );
1219}
1220
1221QgsGeometry QgsGeometry::applyDashPattern( const QVector<double> &pattern, Qgis::DashPatternLineEndingRule startRule, Qgis::DashPatternLineEndingRule endRule, Qgis::DashPatternSizeAdjustment adjustment, double patternOffset ) const
1222{
1223 QgsInternalGeometryEngine engine( *this );
1224 return engine.applyDashPattern( pattern, startRule, endRule, adjustment, patternOffset );
1225}
1226
1227QgsGeometry QgsGeometry::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing ) const
1228{
1229 if ( !d->geometry )
1230 {
1231 return QgsGeometry();
1232 }
1233 return QgsGeometry( d->geometry->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing ) );
1234}
1235
1236bool QgsGeometry::removeDuplicateNodes( double epsilon, bool useZValues )
1237{
1238 if ( !d->geometry )
1239 return false;
1240
1241 detach();
1242 return d->geometry->removeDuplicateNodes( epsilon, useZValues );
1243}
1244
1246{
1247 // fast case, check bounding boxes
1248 if ( !boundingBoxIntersects( r ) )
1249 return false;
1250
1251 // optimise trivial case for point intersections -- the bounding box test has already given us the answer
1252 if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::Point )
1253 {
1254 return true;
1255 }
1256
1257 QgsGeometry g = fromRect( r );
1258 return intersects( g );
1259}
1260
1261bool QgsGeometry::intersects( const QgsGeometry &geometry ) const
1262{
1263 if ( !d->geometry || geometry.isNull() )
1264 {
1265 return false;
1266 }
1267
1268 QgsGeos geos( d->geometry.get() );
1269 mLastError.clear();
1270 return geos.intersects( geometry.d->geometry.get(), &mLastError );
1271}
1272
1274{
1275 if ( !d->geometry )
1276 {
1277 return false;
1278 }
1279
1280 return d->geometry->boundingBoxIntersects( rectangle );
1281}
1282
1284{
1285 if ( !d->geometry || geometry.isNull() )
1286 {
1287 return false;
1288 }
1289
1290 return d->geometry->boundingBoxIntersects( geometry.constGet()->boundingBox() );
1291}
1292
1293bool QgsGeometry::contains( const QgsPointXY *p ) const
1294{
1295 if ( !d->geometry || !p )
1296 {
1297 return false;
1298 }
1299
1300 QgsPoint pt( p->x(), p->y() );
1301 QgsGeos geos( d->geometry.get() );
1302 mLastError.clear();
1303 return geos.contains( &pt, &mLastError );
1304}
1305
1306bool QgsGeometry::contains( const QgsGeometry &geometry ) const
1307{
1308 if ( !d->geometry || geometry.isNull() )
1309 {
1310 return false;
1311 }
1312
1313 QgsGeos geos( d->geometry.get() );
1314 mLastError.clear();
1315 return geos.contains( geometry.d->geometry.get(), &mLastError );
1316}
1317
1318bool QgsGeometry::disjoint( const QgsGeometry &geometry ) const
1319{
1320 if ( !d->geometry || geometry.isNull() )
1321 {
1322 return false;
1323 }
1324
1325 QgsGeos geos( d->geometry.get() );
1326 mLastError.clear();
1327 return geos.disjoint( geometry.d->geometry.get(), &mLastError );
1328}
1329
1330bool QgsGeometry::equals( const QgsGeometry &geometry ) const
1331{
1332 if ( !d->geometry || geometry.isNull() )
1333 {
1334 return false;
1335 }
1336
1337 // fast check - are they shared copies of the same underlying geometry?
1338 if ( d == geometry.d )
1339 return true;
1340
1341 // fast check - distinct geometry types?
1342 if ( type() != geometry.type() )
1343 return false;
1344
1345 // slower check - actually test the geometries
1346 return *d->geometry == *geometry.d->geometry;
1347}
1348
1349bool QgsGeometry::touches( const QgsGeometry &geometry ) const
1350{
1351 if ( !d->geometry || geometry.isNull() )
1352 {
1353 return false;
1354 }
1355
1356 QgsGeos geos( d->geometry.get() );
1357 mLastError.clear();
1358 return geos.touches( geometry.d->geometry.get(), &mLastError );
1359}
1360
1361bool QgsGeometry::overlaps( const QgsGeometry &geometry ) const
1362{
1363 if ( !d->geometry || geometry.isNull() )
1364 {
1365 return false;
1366 }
1367
1368 QgsGeos geos( d->geometry.get() );
1369 mLastError.clear();
1370 return geos.overlaps( geometry.d->geometry.get(), &mLastError );
1371}
1372
1373bool QgsGeometry::within( const QgsGeometry &geometry ) const
1374{
1375 if ( !d->geometry || geometry.isNull() )
1376 {
1377 return false;
1378 }
1379
1380 QgsGeos geos( d->geometry.get() );
1381 mLastError.clear();
1382 return geos.within( geometry.d->geometry.get(), &mLastError );
1383}
1384
1385bool QgsGeometry::crosses( const QgsGeometry &geometry ) const
1386{
1387 if ( !d->geometry || geometry.isNull() )
1388 {
1389 return false;
1390 }
1391
1392 QgsGeos geos( d->geometry.get() );
1393 mLastError.clear();
1394 return geos.crosses( geometry.d->geometry.get(), &mLastError );
1395}
1396
1397QString QgsGeometry::asWkt( int precision ) const
1398{
1399 if ( !d->geometry )
1400 {
1401 return QString();
1402 }
1403 return d->geometry->asWkt( precision );
1404}
1405
1406QString QgsGeometry::asJson( int precision ) const
1407{
1408 return QString::fromStdString( asJsonObject( precision ).dump() );
1409}
1410
1412{
1413 if ( !d->geometry )
1414 {
1415 return nullptr;
1416 }
1417 return d->geometry->asJsonObject( precision );
1418
1419}
1420
1421QVector<QgsGeometry> QgsGeometry::coerceToType( const QgsWkbTypes::Type type, double defaultZ, double defaultM ) const
1422{
1423 QVector< QgsGeometry > res;
1424 if ( isNull() )
1425 return res;
1426
1427 if ( wkbType() == type || type == QgsWkbTypes::Unknown )
1428 {
1429 res << *this;
1430 return res;
1431 }
1432
1434 {
1435 return res;
1436 }
1437
1438 QgsGeometry newGeom = *this;
1439
1440 // Curved -> straight
1442 {
1443 newGeom = QgsGeometry( d->geometry.get()->segmentize() );
1444 }
1445
1446 // polygon -> line
1448 newGeom.type() == QgsWkbTypes::PolygonGeometry )
1449 {
1450 // boundary gives us a (multi)line string of exterior + interior rings
1451 newGeom = QgsGeometry( newGeom.constGet()->boundary() );
1452 }
1453 // line -> polygon
1455 newGeom.type() == QgsWkbTypes::LineGeometry )
1456 {
1457 std::unique_ptr< QgsGeometryCollection > gc( QgsGeometryFactory::createCollectionOfType( type ) );
1458 const QgsGeometry source = newGeom;
1459 for ( auto part = source.const_parts_begin(); part != source.const_parts_end(); ++part )
1460 {
1461 std::unique_ptr< QgsAbstractGeometry > exterior( ( *part )->clone() );
1462 if ( QgsCurve *curve = qgsgeometry_cast< QgsCurve * >( exterior.get() ) )
1463 {
1465 {
1466 std::unique_ptr< QgsCurvePolygon > cp = std::make_unique< QgsCurvePolygon >();
1467 cp->setExteriorRing( curve );
1468 exterior.release();
1469 gc->addGeometry( cp.release() );
1470 }
1471 else
1472 {
1473 std::unique_ptr< QgsPolygon > p = std::make_unique< QgsPolygon >();
1474 p->setExteriorRing( qgsgeometry_cast< QgsLineString * >( curve ) );
1475 exterior.release();
1476 gc->addGeometry( p.release() );
1477 }
1478 }
1479 }
1480 newGeom = QgsGeometry( std::move( gc ) );
1481 }
1482
1483 // line/polygon -> points
1485 ( newGeom.type() == QgsWkbTypes::LineGeometry ||
1486 newGeom.type() == QgsWkbTypes::PolygonGeometry ) )
1487 {
1488 // lines/polygons to a point layer, extract all vertices
1489 std::unique_ptr< QgsMultiPoint > mp = std::make_unique< QgsMultiPoint >();
1490 const QgsGeometry source = newGeom;
1491 QSet< QgsPoint > added;
1492 for ( auto vertex = source.vertices_begin(); vertex != source.vertices_end(); ++vertex )
1493 {
1494 if ( added.contains( *vertex ) )
1495 continue; // avoid duplicate points, e.g. start/end of rings
1496 mp->addGeometry( ( *vertex ).clone() );
1497 added.insert( *vertex );
1498 }
1499 newGeom = QgsGeometry( std::move( mp ) );
1500 }
1501
1502 // Single -> multi
1503 if ( QgsWkbTypes::isMultiType( type ) && ! newGeom.isMultipart( ) )
1504 {
1505 newGeom.convertToMultiType();
1506 }
1507 // Drop Z/M
1508 if ( newGeom.constGet()->is3D() && ! QgsWkbTypes::hasZ( type ) )
1509 {
1510 newGeom.get()->dropZValue();
1511 }
1512 if ( newGeom.constGet()->isMeasure() && ! QgsWkbTypes::hasM( type ) )
1513 {
1514 newGeom.get()->dropMValue();
1515 }
1516 // Add Z/M back, set to 0
1517 if ( ! newGeom.constGet()->is3D() && QgsWkbTypes::hasZ( type ) )
1518 {
1519 newGeom.get()->addZValue( defaultZ );
1520 }
1521 if ( ! newGeom.constGet()->isMeasure() && QgsWkbTypes::hasM( type ) )
1522 {
1523 newGeom.get()->addMValue( defaultM );
1524 }
1525
1526 // Multi -> single
1527 if ( ! QgsWkbTypes::isMultiType( type ) && newGeom.isMultipart( ) )
1528 {
1529 const QgsGeometryCollection *parts( static_cast< const QgsGeometryCollection * >( newGeom.constGet() ) );
1530 res.reserve( parts->partCount() );
1531 for ( int i = 0; i < parts->partCount( ); i++ )
1532 {
1533 res << QgsGeometry( parts->geometryN( i )->clone() );
1534 }
1535 }
1536 else
1537 {
1538 res << newGeom;
1539 }
1540 return res;
1541}
1542
1544{
1545 switch ( destType )
1546 {
1548 return convertToPoint( destMultipart );
1549
1551 return convertToLine( destMultipart );
1552
1554 return convertToPolygon( destMultipart );
1555
1556 default:
1557 return QgsGeometry();
1558 }
1559}
1560
1562{
1563 if ( !d->geometry )
1564 {
1565 return false;
1566 }
1567
1568 if ( isMultipart() ) //already multitype, no need to convert
1569 {
1570 return true;
1571 }
1572
1573 std::unique_ptr< QgsAbstractGeometry >geom = QgsGeometryFactory::geomFromWkbType( QgsWkbTypes::multiType( d->geometry->wkbType() ) );
1574 QgsGeometryCollection *multiGeom = qgsgeometry_cast<QgsGeometryCollection *>( geom.get() );
1575 if ( !multiGeom )
1576 {
1577 return false;
1578 }
1579
1580 //try to avoid cloning existing geometry whenever we can
1581
1582 //want to see a magic trick?... gather round kiddies...
1583 detach(); // maybe a clone, hopefully not if we're the only ref to the private data
1584 // now we cheat a bit and steal the private geometry and add it direct to the multigeom
1585 // we can do this because we're the only ref to this geometry, guaranteed by the detach call above
1586 multiGeom->addGeometry( d->geometry.release() );
1587 // and replace it with the multi geometry.
1588 // TADA! a clone free conversion in some cases
1589 d->geometry = std::move( geom );
1590 return true;
1591}
1592
1594{
1595 if ( !d->geometry )
1596 {
1597 return false;
1598 }
1599
1600 if ( !isMultipart() ) //already single part, no need to convert
1601 {
1602 return true;
1603 }
1604
1605 QgsGeometryCollection *multiGeom = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
1606 if ( !multiGeom || multiGeom->partCount() < 1 )
1607 return false;
1608
1609 std::unique_ptr< QgsAbstractGeometry > firstPart( multiGeom->geometryN( 0 )->clone() );
1610 reset( std::move( firstPart ) );
1611 return true;
1612}
1613
1614
1616{
1617 const QgsGeometryCollection *origGeom = qgsgeometry_cast<const QgsGeometryCollection *>( constGet() );
1618 if ( !origGeom )
1619 return false;
1620
1621 std::unique_ptr<QgsGeometryCollection> resGeom;
1622 switch ( geomType )
1623 {
1625 resGeom = std::make_unique<QgsMultiPoint>();
1626 break;
1628 resGeom = std::make_unique<QgsMultiLineString>();
1629 break;
1631 resGeom = std::make_unique<QgsMultiPolygon>();
1632 break;
1633 default:
1634 break;
1635 }
1636 if ( !resGeom )
1637 return false;
1638
1639 resGeom->reserve( origGeom->numGeometries() );
1640 for ( int i = 0; i < origGeom->numGeometries(); ++i )
1641 {
1642 const QgsAbstractGeometry *g = origGeom->geometryN( i );
1643 if ( QgsWkbTypes::geometryType( g->wkbType() ) == geomType )
1644 resGeom->addGeometry( g->clone() );
1645 }
1646
1647 set( resGeom.release() );
1648 return true;
1649}
1650
1651
1653{
1654 if ( !d->geometry )
1655 {
1656 return QgsPointXY();
1657 }
1658 if ( QgsPoint *pt = qgsgeometry_cast<QgsPoint *>( d->geometry->simplifiedTypeRef() ) )
1659 {
1660 return QgsPointXY( pt->x(), pt->y() );
1661 }
1662 else
1663 {
1664 return QgsPointXY();
1665 }
1666}
1667
1669{
1670 QgsPolylineXY polyLine;
1671 if ( !d->geometry )
1672 {
1673 return polyLine;
1674 }
1675
1676 bool doSegmentation = ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::CompoundCurve
1678 std::unique_ptr< QgsLineString > segmentizedLine;
1679 QgsLineString *line = nullptr;
1680 if ( doSegmentation )
1681 {
1682 QgsCurve *curve = qgsgeometry_cast<QgsCurve *>( d->geometry.get() );
1683 if ( !curve )
1684 {
1685 return polyLine;
1686 }
1687 segmentizedLine.reset( curve->curveToLine() );
1688 line = segmentizedLine.get();
1689 }
1690 else
1691 {
1692 line = qgsgeometry_cast<QgsLineString *>( d->geometry.get() );
1693 if ( !line )
1694 {
1695 return polyLine;
1696 }
1697 }
1698
1699 int nVertices = line->numPoints();
1700 polyLine.resize( nVertices );
1701 QgsPointXY *data = polyLine.data();
1702 const double *xData = line->xData();
1703 const double *yData = line->yData();
1704 for ( int i = 0; i < nVertices; ++i )
1705 {
1706 data->setX( *xData++ );
1707 data->setY( *yData++ );
1708 data++;
1709 }
1710
1711 return polyLine;
1712}
1713
1715{
1716 if ( !d->geometry )
1717 return QgsPolygonXY();
1718
1719 bool doSegmentation = ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::CurvePolygon );
1720
1721 QgsPolygon *p = nullptr;
1722 std::unique_ptr< QgsPolygon > segmentized;
1723 if ( doSegmentation )
1724 {
1725 QgsCurvePolygon *curvePoly = qgsgeometry_cast<QgsCurvePolygon *>( d->geometry.get() );
1726 if ( !curvePoly )
1727 {
1728 return QgsPolygonXY();
1729 }
1730 segmentized.reset( curvePoly->toPolygon() );
1731 p = segmentized.get();
1732 }
1733 else
1734 {
1735 p = qgsgeometry_cast<QgsPolygon *>( d->geometry.get() );
1736 }
1737
1738 if ( !p )
1739 {
1740 return QgsPolygonXY();
1741 }
1742
1743 QgsPolygonXY polygon;
1744 convertPolygon( *p, polygon );
1745
1746 return polygon;
1747}
1748
1750{
1751 if ( !d->geometry || QgsWkbTypes::flatType( d->geometry->wkbType() ) != QgsWkbTypes::MultiPoint )
1752 {
1753 return QgsMultiPointXY();
1754 }
1755
1756 const QgsMultiPoint *mp = qgsgeometry_cast<QgsMultiPoint *>( d->geometry.get() );
1757 if ( !mp )
1758 {
1759 return QgsMultiPointXY();
1760 }
1761
1762 int nPoints = mp->numGeometries();
1763 QgsMultiPointXY multiPoint( nPoints );
1764 for ( int i = 0; i < nPoints; ++i )
1765 {
1766 const QgsPoint *pt = mp->pointN( i );
1767 multiPoint[i].setX( pt->x() );
1768 multiPoint[i].setY( pt->y() );
1769 }
1770 return multiPoint;
1771}
1772
1774{
1775 if ( !d->geometry )
1776 {
1777 return QgsMultiPolylineXY();
1778 }
1779
1780 QgsGeometryCollection *geomCollection = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
1781 if ( !geomCollection )
1782 {
1783 return QgsMultiPolylineXY();
1784 }
1785
1786 int nLines = geomCollection->numGeometries();
1787 if ( nLines < 1 )
1788 {
1789 return QgsMultiPolylineXY();
1790 }
1791
1793 mpl.reserve( nLines );
1794 for ( int i = 0; i < nLines; ++i )
1795 {
1796 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( geomCollection->geometryN( i ) );
1797 std::unique_ptr< QgsLineString > segmentized;
1798 if ( !line )
1799 {
1800 const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( geomCollection->geometryN( i ) );
1801 if ( !curve )
1802 {
1803 continue;
1804 }
1805 segmentized.reset( curve->curveToLine() );
1806 line = segmentized.get();
1807 }
1808
1809 QgsPolylineXY polyLine;
1810 int nVertices = line->numPoints();
1811 polyLine.resize( nVertices );
1812 QgsPointXY *data = polyLine.data();
1813 const double *xData = line->xData();
1814 const double *yData = line->yData();
1815 for ( int i = 0; i < nVertices; ++i )
1816 {
1817 data->setX( *xData++ );
1818 data->setY( *yData++ );
1819 data++;
1820 }
1821 mpl.append( polyLine );
1822 }
1823 return mpl;
1824}
1825
1827{
1828 if ( !d->geometry )
1829 {
1830 return QgsMultiPolygonXY();
1831 }
1832
1833 const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( d->geometry.get() );
1834 if ( !geomCollection )
1835 {
1836 return QgsMultiPolygonXY();
1837 }
1838
1839 const int nPolygons = geomCollection->numGeometries();
1840 if ( nPolygons < 1 )
1841 {
1842 return QgsMultiPolygonXY();
1843 }
1844
1846 mp.reserve( nPolygons );
1847 for ( int i = 0; i < nPolygons; ++i )
1848 {
1849 const QgsPolygon *polygon = qgsgeometry_cast<const QgsPolygon *>( geomCollection->geometryN( i ) );
1850 if ( !polygon )
1851 {
1852 const QgsCurvePolygon *cPolygon = qgsgeometry_cast<const QgsCurvePolygon *>( geomCollection->geometryN( i ) );
1853 if ( cPolygon )
1854 {
1855 polygon = cPolygon->toPolygon();
1856 }
1857 else
1858 {
1859 continue;
1860 }
1861 }
1862
1863 QgsPolygonXY poly;
1864 convertPolygon( *polygon, poly );
1865 mp.push_back( poly );
1866 }
1867 return mp;
1868}
1869
1870double QgsGeometry::area() const
1871{
1872 if ( !d->geometry )
1873 {
1874 return -1.0;
1875 }
1876
1877 return d->geometry->area();
1878}
1879
1881{
1882 if ( !d->geometry )
1883 {
1884 return -1.0;
1885 }
1886
1887 switch ( QgsWkbTypes::geometryType( d->geometry->wkbType() ) )
1888 {
1890 return 0.0;
1891
1893 return d->geometry->length();
1894
1896 return d->geometry->perimeter();
1897
1900 return d->geometry->length();
1901 }
1902 return -1;
1903}
1904
1905double QgsGeometry::distance( const QgsGeometry &geom ) const
1906{
1907 if ( !d->geometry || !geom.d->geometry )
1908 {
1909 return -1.0;
1910 }
1911
1912 // avoid calling geos for trivial point-to-point distance calculations
1914 {
1915 return qgsgeometry_cast< const QgsPoint * >( d->geometry.get() )->distance( *qgsgeometry_cast< const QgsPoint * >( geom.constGet() ) );
1916 }
1917
1918 QgsGeos g( d->geometry.get() );
1919 mLastError.clear();
1920 return g.distance( geom.d->geometry.get(), &mLastError );
1921}
1922
1924{
1925 if ( !d->geometry || !geom.d->geometry )
1926 {
1927 return -1.0;
1928 }
1929
1930 QgsGeos g( d->geometry.get() );
1931 mLastError.clear();
1932 return g.hausdorffDistance( geom.d->geometry.get(), &mLastError );
1933}
1934
1935double QgsGeometry::hausdorffDistanceDensify( const QgsGeometry &geom, double densifyFraction ) const
1936{
1937 if ( !d->geometry || !geom.d->geometry )
1938 {
1939 return -1.0;
1940 }
1941
1942 QgsGeos g( d->geometry.get() );
1943 mLastError.clear();
1944 return g.hausdorffDistanceDensify( geom.d->geometry.get(), densifyFraction, &mLastError );
1945}
1946
1947
1949{
1950 if ( !d->geometry || !geom.d->geometry )
1951 {
1952 return -1.0;
1953 }
1954
1955 QgsGeos g( d->geometry.get() );
1956 mLastError.clear();
1957 return g.frechetDistance( geom.d->geometry.get(), &mLastError );
1958}
1959
1960double QgsGeometry::frechetDistanceDensify( const QgsGeometry &geom, double densifyFraction ) const
1961{
1962 if ( !d->geometry || !geom.d->geometry )
1963 {
1964 return -1.0;
1965 }
1966
1967 QgsGeos g( d->geometry.get() );
1968 mLastError.clear();
1969 return g.frechetDistanceDensify( geom.d->geometry.get(), densifyFraction, &mLastError );
1970}
1971
1973{
1974 if ( !d->geometry || d->geometry.get()->isEmpty() )
1976 return d->geometry->vertices_begin();
1977}
1978
1980{
1981 if ( !d->geometry || d->geometry.get()->isEmpty() )
1983 return d->geometry->vertices_end();
1984}
1985
1987{
1988 if ( !d->geometry || d->geometry.get()->isEmpty() )
1989 return QgsVertexIterator();
1990 return QgsVertexIterator( d->geometry.get() );
1991}
1992
1994{
1995 if ( !d->geometry )
1997
1998 detach();
1999 return d->geometry->parts_begin();
2000}
2001
2003{
2004 if ( !d->geometry )
2006 return d->geometry->parts_end();
2007}
2008
2010{
2011 if ( !d->geometry )
2013 return d->geometry->const_parts_begin();
2014}
2015
2017{
2018 if ( !d->geometry )
2020 return d->geometry->const_parts_end();
2021}
2022
2024{
2025 if ( !d->geometry )
2026 return QgsGeometryPartIterator();
2027
2028 detach();
2029 return QgsGeometryPartIterator( d->geometry.get() );
2030}
2031
2033{
2034 if ( !d->geometry )
2036
2037 return QgsGeometryConstPartIterator( d->geometry.get() );
2038}
2039
2040QgsGeometry QgsGeometry::buffer( double distance, int segments ) const
2041{
2042 if ( !d->geometry )
2043 {
2044 return QgsGeometry();
2045 }
2046
2047 QgsGeos g( d->geometry.get() );
2048 mLastError.clear();
2049 std::unique_ptr<QgsAbstractGeometry> geom( g.buffer( distance, segments, &mLastError ) );
2050 if ( !geom )
2051 {
2052 QgsGeometry result;
2053 result.mLastError = mLastError;
2054 return result;
2055 }
2056 return QgsGeometry( std::move( geom ) );
2057}
2058
2059QgsGeometry QgsGeometry::buffer( double distance, int segments, Qgis::EndCapStyle endCapStyle, Qgis::JoinStyle joinStyle, double miterLimit ) const
2060{
2061 if ( !d->geometry )
2062 {
2063 return QgsGeometry();
2064 }
2065
2066 QgsGeos g( d->geometry.get() );
2067 mLastError.clear();
2068 QgsAbstractGeometry *geom = g.buffer( distance, segments, endCapStyle, joinStyle, miterLimit, &mLastError );
2069 if ( !geom )
2070 {
2071 QgsGeometry result;
2072 result.mLastError = mLastError;
2073 return result;
2074 }
2075 return QgsGeometry( geom );
2076}
2077
2078QgsGeometry QgsGeometry::offsetCurve( double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit ) const
2079{
2080 if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
2081 {
2082 return QgsGeometry();
2083 }
2084
2085 if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
2086 {
2087 const QVector<QgsGeometry> parts = asGeometryCollection();
2088 QVector<QgsGeometry> results;
2089 results.reserve( parts.count() );
2090 for ( const QgsGeometry &part : parts )
2091 {
2092 QgsGeometry result = part.offsetCurve( distance, segments, joinStyle, miterLimit );
2093 if ( !result.isNull() )
2094 results << result;
2095 }
2096 if ( results.isEmpty() )
2097 return QgsGeometry();
2098
2099 QgsGeometry first = results.takeAt( 0 );
2100 for ( const QgsGeometry &result : std::as_const( results ) )
2101 {
2102 first.addPart( result );
2103 }
2104 return first;
2105 }
2106 else
2107 {
2108 QgsGeos geos( d->geometry.get() );
2109 mLastError.clear();
2110
2111 // GEOS can flip the curve orientation in some circumstances. So record previous orientation and correct if required
2112 const Qgis::AngularDirection prevOrientation = qgsgeometry_cast< const QgsCurve * >( d->geometry.get() )->orientation();
2113
2114 std::unique_ptr< QgsAbstractGeometry > offsetGeom( geos.offsetCurve( distance, segments, joinStyle, miterLimit, &mLastError ) );
2115 if ( !offsetGeom )
2116 {
2117 QgsGeometry result;
2118 result.mLastError = mLastError;
2119 return result;
2120 }
2121
2122 if ( const QgsCurve *offsetCurve = qgsgeometry_cast< const QgsCurve * >( offsetGeom.get() ) )
2123 {
2124 const Qgis::AngularDirection newOrientation = offsetCurve->orientation();
2125 if ( newOrientation != prevOrientation )
2126 {
2127 // GEOS has flipped line orientation, flip it back
2128 std::unique_ptr< QgsAbstractGeometry > flipped( offsetCurve->reversed() );
2129 offsetGeom = std::move( flipped );
2130 }
2131 }
2132 return QgsGeometry( std::move( offsetGeom ) );
2133 }
2134}
2135
2136QgsGeometry QgsGeometry::singleSidedBuffer( double distance, int segments, Qgis::BufferSide side, Qgis::JoinStyle joinStyle, double miterLimit ) const
2137{
2138 if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
2139 {
2140 return QgsGeometry();
2141 }
2142
2143 if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
2144 {
2145 const QVector<QgsGeometry> parts = asGeometryCollection();
2146 QVector<QgsGeometry> results;
2147 results.reserve( parts.count() );
2148 for ( const QgsGeometry &part : parts )
2149 {
2150 QgsGeometry result = part.singleSidedBuffer( distance, segments, side, joinStyle, miterLimit );
2151 if ( !result.isNull() )
2152 results << result;
2153 }
2154 if ( results.isEmpty() )
2155 return QgsGeometry();
2156
2157 QgsGeometry first = results.takeAt( 0 );
2158 for ( const QgsGeometry &result : std::as_const( results ) )
2159 {
2160 first.addPart( result );
2161 }
2162 return first;
2163 }
2164 else
2165 {
2166 QgsGeos geos( d->geometry.get() );
2167 mLastError.clear();
2168 std::unique_ptr< QgsAbstractGeometry > bufferGeom = geos.singleSidedBuffer( distance, segments, side,
2169 joinStyle, miterLimit, &mLastError );
2170 if ( !bufferGeom )
2171 {
2172 QgsGeometry result;
2173 result.mLastError = mLastError;
2174 return result;
2175 }
2176 return QgsGeometry( std::move( bufferGeom ) );
2177 }
2178}
2179
2180QgsGeometry QgsGeometry::taperedBuffer( double startWidth, double endWidth, int segments ) const
2181{
2182 QgsInternalGeometryEngine engine( *this );
2183
2184 return engine.taperedBuffer( startWidth, endWidth, segments );
2185}
2186
2188{
2189 QgsInternalGeometryEngine engine( *this );
2190
2191 return engine.variableWidthBufferByM( segments );
2192}
2193
2194QgsGeometry QgsGeometry::extendLine( double startDistance, double endDistance ) const
2195{
2196 if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
2197 {
2198 return QgsGeometry();
2199 }
2200
2201 if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
2202 {
2203 const QVector<QgsGeometry> parts = asGeometryCollection();
2204 QVector<QgsGeometry> results;
2205 results.reserve( parts.count() );
2206 for ( const QgsGeometry &part : parts )
2207 {
2208 QgsGeometry result = part.extendLine( startDistance, endDistance );
2209 if ( !result.isNull() )
2210 results << result;
2211 }
2212 if ( results.isEmpty() )
2213 return QgsGeometry();
2214
2215 QgsGeometry first = results.takeAt( 0 );
2216 for ( const QgsGeometry &result : std::as_const( results ) )
2217 {
2218 first.addPart( result );
2219 }
2220 return first;
2221 }
2222 else
2223 {
2224 QgsLineString *line = qgsgeometry_cast< QgsLineString * >( d->geometry.get() );
2225 if ( !line )
2226 return QgsGeometry();
2227
2228 std::unique_ptr< QgsLineString > newLine( line->clone() );
2229 newLine->extend( startDistance, endDistance );
2230 return QgsGeometry( std::move( newLine ) );
2231 }
2232}
2233
2234QgsGeometry QgsGeometry::simplify( double tolerance ) const
2235{
2236 if ( !d->geometry )
2237 {
2238 return QgsGeometry();
2239 }
2240
2241 QgsGeos geos( d->geometry.get() );
2242 mLastError.clear();
2243 std::unique_ptr< QgsAbstractGeometry > simplifiedGeom( geos.simplify( tolerance, &mLastError ) );
2244 if ( !simplifiedGeom )
2245 {
2246 QgsGeometry result;
2247 result.mLastError = mLastError;
2248 return result;
2249 }
2250 return QgsGeometry( std::move( simplifiedGeom ) );
2251}
2252
2253QgsGeometry QgsGeometry::densifyByCount( int extraNodesPerSegment ) const
2254{
2255 QgsInternalGeometryEngine engine( *this );
2256
2257 return engine.densifyByCount( extraNodesPerSegment );
2258}
2259
2261{
2262 QgsInternalGeometryEngine engine( *this );
2263
2264 return engine.densifyByDistance( distance );
2265}
2266
2267QgsGeometry QgsGeometry::convertToCurves( double distanceTolerance, double angleTolerance ) const
2268{
2269 QgsInternalGeometryEngine engine( *this );
2270
2271 return engine.convertToCurves( distanceTolerance, angleTolerance );
2272}
2273
2275{
2276 if ( !d->geometry )
2277 {
2278 return QgsGeometry();
2279 }
2280
2281 // avoid calling geos for trivial point centroids
2282 if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::Point )
2283 {
2284 QgsGeometry c = *this;
2285 c.get()->dropZValue();
2286 c.get()->dropMValue();
2287 return c;
2288 }
2289
2290 QgsGeos geos( d->geometry.get() );
2291
2292 mLastError.clear();
2293 QgsGeometry result( geos.centroid( &mLastError ) );
2294 result.mLastError = mLastError;
2295 return result;
2296}
2297
2299{
2300 if ( !d->geometry )
2301 {
2302 return QgsGeometry();
2303 }
2304
2305 QgsGeos geos( d->geometry.get() );
2306
2307 mLastError.clear();
2308 QgsGeometry result( geos.pointOnSurface( &mLastError ) );
2309 result.mLastError = mLastError;
2310 return result;
2311}
2312
2313QgsGeometry QgsGeometry::poleOfInaccessibility( double precision, double *distanceToBoundary ) const
2314{
2315 QgsInternalGeometryEngine engine( *this );
2316
2317 return engine.poleOfInaccessibility( precision, distanceToBoundary );
2318}
2319
2320QgsGeometry QgsGeometry::largestEmptyCircle( double tolerance, const QgsGeometry &boundary ) const
2321{
2322 if ( !d->geometry )
2323 {
2324 return QgsGeometry();
2325 }
2326
2327 QgsGeos geos( d->geometry.get() );
2328
2329 mLastError.clear();
2330 QgsGeometry result( geos.largestEmptyCircle( tolerance, boundary.constGet(), &mLastError ) );
2331 result.mLastError = mLastError;
2332 return result;
2333}
2334
2336{
2337 if ( !d->geometry )
2338 {
2339 return QgsGeometry();
2340 }
2341
2342 QgsGeos geos( d->geometry.get() );
2343
2344 mLastError.clear();
2345 QgsGeometry result( geos.minimumWidth( &mLastError ) );
2346 result.mLastError = mLastError;
2347 return result;
2348}
2349
2351{
2352 if ( !d->geometry )
2353 {
2354 return std::numeric_limits< double >::quiet_NaN();
2355 }
2356
2357 QgsGeos geos( d->geometry.get() );
2358
2359 mLastError.clear();
2360 return geos.minimumClearance( &mLastError );
2361}
2362
2364{
2365 if ( !d->geometry )
2366 {
2367 return QgsGeometry();
2368 }
2369
2370 QgsGeos geos( d->geometry.get() );
2371
2372 mLastError.clear();
2373 QgsGeometry result( geos.minimumClearanceLine( &mLastError ) );
2374 result.mLastError = mLastError;
2375 return result;
2376}
2377
2379{
2380 if ( !d->geometry )
2381 {
2382 return QgsGeometry();
2383 }
2384 QgsGeos geos( d->geometry.get() );
2385 mLastError.clear();
2386 std::unique_ptr< QgsAbstractGeometry > cHull( geos.convexHull( &mLastError ) );
2387 if ( !cHull )
2388 {
2389 QgsGeometry geom;
2390 geom.mLastError = mLastError;
2391 return geom;
2392 }
2393 return QgsGeometry( std::move( cHull ) );
2394}
2395
2396QgsGeometry QgsGeometry::concaveHull( double targetPercent, bool allowHoles ) const
2397{
2398 if ( !d->geometry )
2399 {
2400 return QgsGeometry();
2401 }
2402 QgsGeos geos( d->geometry.get() );
2403 mLastError.clear();
2404 std::unique_ptr< QgsAbstractGeometry > concaveHull( geos.concaveHull( targetPercent, allowHoles, &mLastError ) );
2405 if ( !concaveHull )
2406 {
2407 QgsGeometry geom;
2408 geom.mLastError = mLastError;
2409 return geom;
2410 }
2411 return QgsGeometry( std::move( concaveHull ) );
2412}
2413
2414QgsGeometry QgsGeometry::voronoiDiagram( const QgsGeometry &extent, double tolerance, bool edgesOnly ) const
2415{
2416 if ( !d->geometry )
2417 {
2418 return QgsGeometry();
2419 }
2420
2421 QgsGeos geos( d->geometry.get() );
2422 mLastError.clear();
2423 QgsGeometry result = geos.voronoiDiagram( extent.constGet(), tolerance, edgesOnly, &mLastError );
2424 result.mLastError = mLastError;
2425 return result;
2426}
2427
2428QgsGeometry QgsGeometry::delaunayTriangulation( double tolerance, bool edgesOnly ) const
2429{
2430 if ( !d->geometry )
2431 {
2432 return QgsGeometry();
2433 }
2434
2435 QgsGeos geos( d->geometry.get() );
2436 mLastError.clear();
2437 QgsGeometry result = geos.delaunayTriangulation( tolerance, edgesOnly );
2438 result.mLastError = mLastError;
2439 return result;
2440}
2441
2443{
2444 if ( !d->geometry )
2445 {
2446 return QgsGeometry();
2447 }
2448
2449 QgsGeos geos( d->geometry.get() );
2450 mLastError.clear();
2451 QgsGeometry result( geos.node( &mLastError ) );
2452 result.mLastError = mLastError;
2453 return result;
2454}
2455
2457{
2458 if ( !d->geometry )
2459 {
2460 return QgsGeometry();
2461 }
2462
2463 QgsGeos geos( d->geometry.get() );
2464 mLastError.clear();
2465 QgsGeometry result( geos.sharedPaths( other.constGet(), &mLastError ) );
2466 result.mLastError = mLastError;
2467 return result;
2468}
2469
2470QgsGeometry QgsGeometry::subdivide( int maxNodes, const QgsGeometryParameters &parameters ) const
2471{
2472 if ( !d->geometry )
2473 {
2474 return QgsGeometry();
2475 }
2476
2477 const QgsAbstractGeometry *geom = d->geometry.get();
2478 std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
2479 if ( QgsWkbTypes::isCurvedType( d->geometry->wkbType() ) )
2480 {
2481 segmentizedCopy.reset( d->geometry->segmentize() );
2482 geom = segmentizedCopy.get();
2483 }
2484
2485 QgsGeos geos( geom );
2486 mLastError.clear();
2487 std::unique_ptr< QgsAbstractGeometry > result( geos.subdivide( maxNodes, &mLastError, parameters ) );
2488 if ( !result )
2489 {
2490 QgsGeometry geom;
2491 geom.mLastError = mLastError;
2492 return geom;
2493 }
2494 return QgsGeometry( std::move( result ) );
2495}
2496
2498{
2499 if ( !d->geometry )
2500 {
2501 return QgsGeometry();
2502 }
2503
2504 QgsGeometry line = *this;
2506 return QgsGeometry();
2507 else if ( type() == QgsWkbTypes::PolygonGeometry )
2508 {
2509 line = QgsGeometry( d->geometry->boundary() );
2510 }
2511
2512 const QgsCurve *curve = nullptr;
2513 if ( line.isMultipart() )
2514 {
2515 // if multi part, iterate through parts to find target part
2516 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( line.constGet() );
2517 for ( int part = 0; part < collection->numGeometries(); ++part )
2518 {
2519 const QgsCurve *candidate = qgsgeometry_cast< const QgsCurve * >( collection->geometryN( part ) );
2520 if ( !candidate )
2521 continue;
2522 const double candidateLength = candidate->length();
2523 if ( candidateLength >= distance )
2524 {
2525 curve = candidate;
2526 break;
2527 }
2528
2529 distance -= candidateLength;
2530 }
2531 }
2532 else
2533 {
2534 curve = qgsgeometry_cast< const QgsCurve * >( line.constGet() );
2535 }
2536 if ( !curve )
2537 return QgsGeometry();
2538
2539 std::unique_ptr< QgsPoint > result( curve->interpolatePoint( distance ) );
2540 if ( !result )
2541 {
2542 return QgsGeometry();
2543 }
2544 return QgsGeometry( std::move( result ) );
2545}
2546
2547double QgsGeometry::lineLocatePoint( const QgsGeometry &point ) const
2548{
2550 return -1;
2551
2553 return -1;
2554
2555 QgsGeometry segmentized = *this;
2557 {
2558 segmentized = QgsGeometry( static_cast< QgsCurve * >( d->geometry.get() )->segmentize() );
2559 }
2560
2561 QgsGeos geos( d->geometry.get() );
2562 mLastError.clear();
2563 return geos.lineLocatePoint( *( static_cast< QgsPoint * >( point.d->geometry.get() ) ), &mLastError );
2564}
2565
2566double QgsGeometry::interpolateAngle( double distance ) const
2567{
2568 if ( !d->geometry )
2569 return 0.0;
2570
2571 const QgsAbstractGeometry *geom = d->geometry->simplifiedTypeRef();
2573 return 0.0;
2574
2575 // always operate on segmentized geometries
2576 QgsGeometry segmentized = *this;
2577 if ( QgsWkbTypes::isCurvedType( geom->wkbType() ) )
2578 {
2579 segmentized = QgsGeometry( static_cast< const QgsCurve * >( geom )->segmentize() );
2580 }
2581
2582 QgsVertexId previous;
2583 QgsVertexId next;
2584 if ( !QgsGeometryUtils::verticesAtDistance( *segmentized.constGet(), distance, previous, next ) )
2585 return 0.0;
2586
2587 if ( previous == next )
2588 {
2589 // distance coincided exactly with a vertex
2590 QgsVertexId v2 = previous;
2591 QgsVertexId v1;
2592 QgsVertexId v3;
2593 segmentized.constGet()->adjacentVertices( v2, v1, v3 );
2594 if ( v1.isValid() && v3.isValid() )
2595 {
2596 QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
2597 QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
2598 QgsPoint p3 = segmentized.constGet()->vertexAt( v3 );
2599 double angle1 = QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2600 double angle2 = QgsGeometryUtils::lineAngle( p2.x(), p2.y(), p3.x(), p3.y() );
2601 return QgsGeometryUtils::averageAngle( angle1, angle2 );
2602 }
2603 else if ( v3.isValid() )
2604 {
2605 QgsPoint p1 = segmentized.constGet()->vertexAt( v2 );
2606 QgsPoint p2 = segmentized.constGet()->vertexAt( v3 );
2607 return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2608 }
2609 else
2610 {
2611 QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
2612 QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
2613 return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2614 }
2615 }
2616 else
2617 {
2618 QgsPoint p1 = segmentized.constGet()->vertexAt( previous );
2619 QgsPoint p2 = segmentized.constGet()->vertexAt( next );
2620 return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2621 }
2622}
2623
2625{
2626 if ( !d->geometry || geometry.isNull() )
2627 {
2628 return QgsGeometry();
2629 }
2630
2631 QgsGeos geos( d->geometry.get() );
2632
2633 mLastError.clear();
2634 std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.intersection( geometry.d->geometry.get(), &mLastError, parameters ) );
2635
2636 if ( !resultGeom )
2637 {
2638 QgsGeometry geom;
2639 geom.mLastError = mLastError;
2640 return geom;
2641 }
2642
2643 return QgsGeometry( std::move( resultGeom ) );
2644}
2645
2646QgsGeometry QgsGeometry::combine( const QgsGeometry &geometry, const QgsGeometryParameters &parameters ) const
2647{
2648 if ( !d->geometry || geometry.isNull() )
2649 {
2650 return QgsGeometry();
2651 }
2652
2653 QgsGeos geos( d->geometry.get() );
2654 mLastError.clear();
2655 std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.combine( geometry.d->geometry.get(), &mLastError, parameters ) );
2656 if ( !resultGeom )
2657 {
2658 QgsGeometry geom;
2659 geom.mLastError = mLastError;
2660 return geom;
2661 }
2662 return QgsGeometry( std::move( resultGeom ) );
2663}
2664
2666{
2667 if ( !d->geometry )
2668 {
2669 return QgsGeometry();
2670 }
2671
2672 if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::LineString )
2673 {
2674 // special case - a single linestring was passed
2675 return QgsGeometry( *this );
2676 }
2677
2678 QgsGeos geos( d->geometry.get() );
2679 mLastError.clear();
2680 QgsGeometry result = geos.mergeLines( &mLastError );
2681 result.mLastError = mLastError;
2682 return result;
2683}
2684
2686{
2687 if ( !d->geometry || geometry.isNull() )
2688 {
2689 return QgsGeometry();
2690 }
2691
2692 QgsGeos geos( d->geometry.get() );
2693
2694 mLastError.clear();
2695 std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.difference( geometry.d->geometry.get(), &mLastError, parameters ) );
2696 if ( !resultGeom )
2697 {
2698 QgsGeometry geom;
2699 geom.mLastError = mLastError;
2700 return geom;
2701 }
2702 return QgsGeometry( std::move( resultGeom ) );
2703}
2704
2706{
2707 if ( !d->geometry || geometry.isNull() )
2708 {
2709 return QgsGeometry();
2710 }
2711
2712 QgsGeos geos( d->geometry.get() );
2713
2714 mLastError.clear();
2715 std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.symDifference( 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 QgsInternalGeometryEngine engine( *this );
2728
2729 return engine.extrude( x, y );
2730}
2731
2733
2734QVector<QgsPointXY> QgsGeometry::randomPointsInPolygon( int count, const std::function< bool( const QgsPointXY & ) > &acceptPoint, unsigned long seed, QgsFeedback *feedback, int maxTriesPerPoint ) const
2735{
2737 return QVector< QgsPointXY >();
2738
2739 return QgsInternalGeometryEngine::randomPointsInPolygon( *this, count, acceptPoint, seed, feedback, maxTriesPerPoint );
2740}
2741
2742QVector<QgsPointXY> QgsGeometry::randomPointsInPolygon( int count, unsigned long seed, QgsFeedback *feedback ) const
2743{
2745 return QVector< QgsPointXY >();
2746
2747 return QgsInternalGeometryEngine::randomPointsInPolygon( *this, count, []( const QgsPointXY & ) { return true; }, seed, feedback, 0 );
2748}
2750
2751int QgsGeometry::wkbSize( QgsAbstractGeometry::WkbFlags flags ) const
2752{
2753 return d->geometry ? d->geometry->wkbSize( flags ) : 0;
2754}
2755
2756QByteArray QgsGeometry::asWkb( QgsAbstractGeometry::WkbFlags flags ) const
2757{
2758 return d->geometry ? d->geometry->asWkb( flags ) : QByteArray();
2759}
2760
2761QVector<QgsGeometry> QgsGeometry::asGeometryCollection() const
2762{
2763 QVector<QgsGeometry> geometryList;
2764 if ( !d->geometry )
2765 {
2766 return geometryList;
2767 }
2768
2769 QgsGeometryCollection *gc = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
2770 if ( gc )
2771 {
2772 int numGeom = gc->numGeometries();
2773 geometryList.reserve( numGeom );
2774 for ( int i = 0; i < numGeom; ++i )
2775 {
2776 geometryList.append( QgsGeometry( gc->geometryN( i )->clone() ) );
2777 }
2778 }
2779 else //a singlepart geometry
2780 {
2781 geometryList.append( *this );
2782 }
2783
2784 return geometryList;
2785}
2786
2788{
2789 QgsPointXY point = asPoint();
2790 return point.toQPointF();
2791}
2792
2794{
2795 const QgsAbstractGeometry *part = constGet();
2796
2797 // if a geometry collection, get first part only
2798 if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection *>( part ) )
2799 {
2800 if ( collection->numGeometries() > 0 )
2801 part = collection->geometryN( 0 );
2802 else
2803 return QPolygonF();
2804 }
2805
2806 if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( part ) )
2807 return curve->asQPolygonF();
2808 else if ( const QgsCurvePolygon *polygon = qgsgeometry_cast< const QgsCurvePolygon * >( part ) )
2809 return polygon->exteriorRing() ? polygon->exteriorRing()->asQPolygonF() : QPolygonF();
2810 return QPolygonF();
2811}
2812
2813bool QgsGeometry::deleteRing( int ringNum, int partNum )
2814{
2815 if ( !d->geometry )
2816 {
2817 return false;
2818 }
2819
2820 detach();
2821 bool ok = QgsGeometryEditUtils::deleteRing( d->geometry.get(), ringNum, partNum );
2822 return ok;
2823}
2824
2825bool QgsGeometry::deletePart( int partNum )
2826{
2827 if ( !d->geometry )
2828 {
2829 return false;
2830 }
2831
2832 if ( !isMultipart() && partNum < 1 )
2833 {
2834 set( nullptr );
2835 return true;
2836 }
2837
2838 detach();
2839 bool ok = QgsGeometryEditUtils::deletePart( d->geometry.get(), partNum );
2840 return ok;
2841}
2842
2843int QgsGeometry::avoidIntersections( const QList<QgsVectorLayer *> &avoidIntersectionsLayers, const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures )
2844{
2845 if ( !d->geometry )
2846 {
2847 return 1;
2848 }
2849
2850 QgsWkbTypes::Type geomTypeBeforeModification = wkbType();
2851
2852 bool haveInvalidGeometry = false;
2853 bool geomModified = false;
2854
2855 std::unique_ptr< QgsAbstractGeometry > diffGeom = QgsGeometryEditUtils::avoidIntersections( *( d->geometry ), avoidIntersectionsLayers, haveInvalidGeometry, ignoreFeatures );
2856 if ( diffGeom )
2857 {
2858 reset( std::move( diffGeom ) );
2859 geomModified = true;
2860 }
2861
2862 if ( geomTypeBeforeModification != wkbType() )
2863 return 2;
2864 if ( haveInvalidGeometry )
2865 return 3;
2866 if ( !geomModified )
2867 return 4;
2868
2869 return 0;
2870}
2871
2872
2874{
2875 if ( !d->geometry )
2876 return QgsGeometry();
2877
2878 mLastError.clear();
2879 QgsGeos geos( d->geometry.get() );
2880 std::unique_ptr< QgsAbstractGeometry > g( geos.makeValid( method, keepCollapsed, &mLastError ) );
2881
2882 QgsGeometry result = QgsGeometry( std::move( g ) );
2883 result.mLastError = mLastError;
2884 return result;
2885}
2886
2888{
2889 return forcePolygonClockwise();
2890}
2891
2893{
2894 if ( !d->geometry )
2895 return QgsGeometry();
2896
2897 if ( isMultipart() )
2898 {
2899 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( d->geometry.get() );
2900 std::unique_ptr< QgsGeometryCollection > newCollection( collection->createEmptyWithSameType() );
2901 newCollection->reserve( collection->numGeometries() );
2902 for ( int i = 0; i < collection->numGeometries(); ++i )
2903 {
2904 const QgsAbstractGeometry *g = collection->geometryN( i );
2905 if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( g ) )
2906 {
2907 std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2908 corrected->forceClockwise();
2909 newCollection->addGeometry( corrected.release() );
2910 }
2911 else
2912 {
2913 newCollection->addGeometry( g->clone() );
2914 }
2915 }
2916 return QgsGeometry( std::move( newCollection ) );
2917 }
2918 else
2919 {
2920 if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( d->geometry.get() ) )
2921 {
2922 std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2923 corrected->forceClockwise();
2924 return QgsGeometry( std::move( corrected ) );
2925 }
2926 else
2927 {
2928 // not a curve polygon, so return unchanged
2929 return *this;
2930 }
2931 }
2932}
2933
2935{
2936 if ( !d->geometry )
2937 return QgsGeometry();
2938
2939 if ( isMultipart() )
2940 {
2941 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( d->geometry.get() );
2942 std::unique_ptr< QgsGeometryCollection > newCollection( collection->createEmptyWithSameType() );
2943 newCollection->reserve( collection->numGeometries() );
2944 for ( int i = 0; i < collection->numGeometries(); ++i )
2945 {
2946 const QgsAbstractGeometry *g = collection->geometryN( i );
2947 if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( g ) )
2948 {
2949 std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2950 corrected->forceCounterClockwise();
2951 newCollection->addGeometry( corrected.release() );
2952 }
2953 else
2954 {
2955 newCollection->addGeometry( g->clone() );
2956 }
2957 }
2958 return QgsGeometry( std::move( newCollection ) );
2959 }
2960 else
2961 {
2962 if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( d->geometry.get() ) )
2963 {
2964 std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2965 corrected->forceCounterClockwise();
2966 return QgsGeometry( std::move( corrected ) );
2967 }
2968 else
2969 {
2970 // not a curve polygon, so return unchanged
2971 return *this;
2972 }
2973 }
2974}
2975
2976
2977void QgsGeometry::validateGeometry( QVector<QgsGeometry::Error> &errors, const Qgis::GeometryValidationEngine method, const Qgis::GeometryValidityFlags flags ) const
2978{
2979 errors.clear();
2980 if ( !d->geometry )
2981 return;
2982
2983 // avoid expensive calcs for trivial point geometries
2985 {
2986 return;
2987 }
2988
2989 switch ( method )
2990 {
2991 case Qgis::GeometryValidationEngine::QgisInternal:
2992 QgsGeometryValidator::validateGeometry( *this, errors, method );
2993 return;
2994
2995 case Qgis::GeometryValidationEngine::Geos:
2996 {
2997 QgsGeos geos( d->geometry.get() );
2998 QString error;
2999 QgsGeometry errorLoc;
3000 if ( !geos.isValid( &error, flags & Qgis::GeometryValidityFlag::AllowSelfTouchingHoles, &errorLoc ) )
3001 {
3002 if ( errorLoc.isNull() )
3003 {
3004 errors.append( QgsGeometry::Error( error ) );
3005 }
3006 else
3007 {
3008 const QgsPointXY point = errorLoc.asPoint();
3009 errors.append( QgsGeometry::Error( error, point ) );
3010 }
3011 return;
3012 }
3013 }
3014 }
3015}
3016
3018{
3019 if ( !d->geometry )
3020 {
3021 return;
3022 }
3023
3024 detach();
3025 d->geometry->normalize();
3026}
3027
3028bool QgsGeometry::isGeosValid( Qgis::GeometryValidityFlags flags ) const
3029{
3030 if ( !d->geometry )
3031 {
3032 return false;
3033 }
3034
3035 return d->geometry->isValid( mLastError, flags );
3036}
3037
3039{
3040 if ( !d->geometry )
3041 return false;
3042
3043 QgsGeos geos( d->geometry.get() );
3044 mLastError.clear();
3045 return geos.isSimple( &mLastError );
3046}
3047
3048bool QgsGeometry::isAxisParallelRectangle( double maximumDeviation, bool simpleRectanglesOnly ) const
3049{
3050 if ( !d->geometry )
3051 return false;
3052
3053 QgsInternalGeometryEngine engine( *this );
3054 return engine.isAxisParallelRectangle( maximumDeviation, simpleRectanglesOnly );
3055}
3056
3058{
3059 if ( !d->geometry || !g.d->geometry )
3060 {
3061 return false;
3062 }
3063
3064 // fast check - are they shared copies of the same underlying geometry?
3065 if ( d == g.d )
3066 return true;
3067
3068 // fast check - distinct geometry types?
3069 if ( type() != g.type() )
3070 return false;
3071
3072 // avoid calling geos for trivial point case
3073 if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::Point
3074 && QgsWkbTypes::flatType( g.d->geometry->wkbType() ) == QgsWkbTypes::Point )
3075 {
3076 return equals( g );
3077 }
3078
3079 // another nice fast check upfront -- if the bounding boxes aren't equal, the geometries themselves can't be equal!
3080 if ( d->geometry->boundingBox() != g.d->geometry->boundingBox() )
3081 return false;
3082
3083 QgsGeos geos( d->geometry.get() );
3084 mLastError.clear();
3085 return geos.isEqual( g.d->geometry.get(), &mLastError );
3086}
3087
3088QgsGeometry QgsGeometry::unaryUnion( const QVector<QgsGeometry> &geometries, const QgsGeometryParameters &parameters )
3089{
3090 QgsGeos geos( nullptr );
3091
3092 QString error;
3093 std::unique_ptr< QgsAbstractGeometry > geom( geos.combine( geometries, &error, parameters ) );
3094 QgsGeometry result( std::move( geom ) );
3095 result.mLastError = error;
3096 return result;
3097}
3098
3099QgsGeometry QgsGeometry::polygonize( const QVector<QgsGeometry> &geometryList )
3100{
3101 QVector<const QgsAbstractGeometry *> geomV2List;
3102 for ( const QgsGeometry &g : geometryList )
3103 {
3104 if ( !( g.isNull() ) )
3105 {
3106 geomV2List.append( g.constGet() );
3107 }
3108 }
3109
3110 QString error;
3111 QgsGeometry result = QgsGeos::polygonize( geomV2List, &error );
3112 result.mLastError = error;
3113 return result;
3114}
3115
3117{
3119 {
3120 return;
3121 }
3122
3123 std::unique_ptr< QgsAbstractGeometry > straightGeom( d->geometry->segmentize( tolerance, toleranceType ) );
3124 reset( std::move( straightGeom ) );
3125}
3126
3128{
3129 if ( !d->geometry )
3130 {
3131 return false;
3132 }
3133
3134 return d->geometry->hasCurvedSegments();
3135}
3136
3138{
3139 if ( !d->geometry )
3140 {
3142 }
3143
3144 detach();
3145 d->geometry->transform( ct, direction, transformZ );
3147}
3148
3149Qgis::GeometryOperationResult QgsGeometry::transform( const QTransform &ct, double zTranslate, double zScale, double mTranslate, double mScale )
3150{
3151 if ( !d->geometry )
3152 {
3154 }
3155
3156 detach();
3157 d->geometry->transform( ct, zTranslate, zScale, mTranslate, mScale );
3159}
3160
3162{
3163 if ( d->geometry )
3164 {
3165 detach();
3166 d->geometry->transform( mtp.transform() );
3167 }
3168}
3169
3171{
3172 if ( !d->geometry || rectangle.isNull() || rectangle.isEmpty() )
3173 {
3174 return QgsGeometry();
3175 }
3176
3177 QgsGeos geos( d->geometry.get() );
3178 mLastError.clear();
3179 std::unique_ptr< QgsAbstractGeometry > resultGeom = geos.clip( rectangle, &mLastError );
3180 if ( !resultGeom )
3181 {
3182 QgsGeometry result;
3183 result.mLastError = mLastError;
3184 return result;
3185 }
3186 return QgsGeometry( std::move( resultGeom ) );
3187}
3188
3189void QgsGeometry::draw( QPainter &p ) const
3190{
3191 if ( d->geometry )
3192 {
3193 d->geometry->draw( p );
3194 }
3195}
3196
3197static bool vertexIndexInfo( const QgsAbstractGeometry *g, int vertexIndex, int &partIndex, int &ringIndex, int &vertex )
3198{
3199 if ( vertexIndex < 0 )
3200 return false; // clearly something wrong
3201
3202 if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
3203 {
3204 partIndex = 0;
3205 for ( int i = 0; i < geomCollection->numGeometries(); ++i )
3206 {
3207 const QgsAbstractGeometry *part = geomCollection->geometryN( i );
3208
3209 // count total number of vertices in the part
3210 int numPoints = 0;
3211 for ( int k = 0; k < part->ringCount(); ++k )
3212 numPoints += part->vertexCount( 0, k );
3213
3214 if ( vertexIndex < numPoints )
3215 {
3216 int nothing;
3217 return vertexIndexInfo( part, vertexIndex, nothing, ringIndex, vertex ); // set ring_index + index
3218 }
3219 vertexIndex -= numPoints;
3220 partIndex++;
3221 }
3222 }
3223 else if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
3224 {
3225 const QgsCurve *ring = curvePolygon->exteriorRing();
3226 if ( vertexIndex < ring->numPoints() )
3227 {
3228 partIndex = 0;
3229 ringIndex = 0;
3230 vertex = vertexIndex;
3231 return true;
3232 }
3233 vertexIndex -= ring->numPoints();
3234 ringIndex = 1;
3235 for ( int i = 0; i < curvePolygon->numInteriorRings(); ++i )
3236 {
3237 const QgsCurve *ring = curvePolygon->interiorRing( i );
3238 if ( vertexIndex < ring->numPoints() )
3239 {
3240 partIndex = 0;
3241 vertex = vertexIndex;
3242 return true;
3243 }
3244 vertexIndex -= ring->numPoints();
3245 ringIndex += 1;
3246 }
3247 }
3248 else if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
3249 {
3250 if ( vertexIndex < curve->numPoints() )
3251 {
3252 partIndex = 0;
3253 ringIndex = 0;
3254 vertex = vertexIndex;
3255 return true;
3256 }
3257 }
3258 else if ( qgsgeometry_cast<const QgsPoint *>( g ) )
3259 {
3260 if ( vertexIndex == 0 )
3261 {
3262 partIndex = 0;
3263 ringIndex = 0;
3264 vertex = 0;
3265 return true;
3266 }
3267 }
3268
3269 return false;
3270}
3271
3273{
3274 if ( !d->geometry )
3275 {
3276 return false;
3277 }
3278
3279 id.type = Qgis::VertexType::Segment;
3280
3281 bool res = vertexIndexInfo( d->geometry.get(), nr, id.part, id.ring, id.vertex );
3282 if ( !res )
3283 return false;
3284
3285 // now let's find out if it is a straight or circular segment
3286 const QgsAbstractGeometry *g = d->geometry.get();
3287 if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
3288 {
3289 g = geomCollection->geometryN( id.part );
3290 }
3291
3292 if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
3293 {
3294 g = id.ring == 0 ? curvePolygon->exteriorRing() : curvePolygon->interiorRing( id.ring - 1 );
3295 }
3296
3297 if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
3298 {
3299 QgsPoint p;
3300 res = curve->pointAt( id.vertex, p, id.type );
3301 if ( !res )
3302 return false;
3303 }
3304
3305 return true;
3306}
3307
3309{
3310 if ( !d->geometry )
3311 {
3312 return -1;
3313 }
3314 return d->geometry->vertexNumberFromVertexId( id );
3315}
3316
3318{
3319 return mLastError;
3320}
3321
3322void QgsGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
3323{
3324 if ( !d->geometry )
3325 return;
3326
3327 detach();
3328
3329 d->geometry->filterVertices( filter );
3330}
3331
3332void QgsGeometry::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
3333{
3334 if ( !d->geometry )
3335 return;
3336
3337 detach();
3338
3339 d->geometry->transformVertices( transform );
3340}
3341
3342void QgsGeometry::convertPointList( const QVector<QgsPointXY> &input, QgsPointSequence &output )
3343{
3344 output.clear();
3345 for ( const QgsPointXY &p : input )
3346 {
3347 output.append( QgsPoint( p ) );
3348 }
3349}
3350
3351void QgsGeometry::convertPointList( const QgsPointSequence &input, QVector<QgsPointXY> &output )
3352{
3353 output.clear();
3354 for ( const QgsPoint &p : input )
3355 {
3356 output.append( QgsPointXY( p.x(), p.y() ) );
3357 }
3358}
3359
3360void QgsGeometry::convertPolygon( const QgsPolygon &input, QgsPolygonXY &output )
3361{
3362 output.clear();
3363
3364 auto convertRing = []( const QgsCurve * ring ) -> QgsPolylineXY
3365 {
3366 QgsPolylineXY res;
3367 bool doSegmentation = ( QgsWkbTypes::flatType( ring->wkbType() ) == QgsWkbTypes::CompoundCurve
3369 std::unique_ptr< QgsLineString > segmentizedLine;
3370 const QgsLineString *line = nullptr;
3371 if ( doSegmentation )
3372 {
3373 segmentizedLine.reset( ring->curveToLine() );
3374 line = segmentizedLine.get();
3375 }
3376 else
3377 {
3378 line = qgsgeometry_cast<const QgsLineString *>( ring );
3379 if ( !line )
3380 {
3381 return res;
3382 }
3383 }
3384
3385 int nVertices = line->numPoints();
3386 res.resize( nVertices );
3387 QgsPointXY *data = res.data();
3388 const double *xData = line->xData();
3389 const double *yData = line->yData();
3390 for ( int i = 0; i < nVertices; ++i )
3391 {
3392 data->setX( *xData++ );
3393 data->setY( *yData++ );
3394 data++;
3395 }
3396 return res;
3397 };
3398
3399 if ( const QgsCurve *exterior = input.exteriorRing() )
3400 {
3401 output.push_back( convertRing( exterior ) );
3402 }
3403
3404 const int interiorRingCount = input.numInteriorRings();
3405 output.reserve( output.size() + interiorRingCount );
3406 for ( int n = 0; n < interiorRingCount; ++n )
3407 {
3408 output.push_back( convertRing( input.interiorRing( n ) ) );
3409 }
3410}
3411
3413{
3414 return QgsGeometry( std::make_unique< QgsPoint >( point.x(), point.y() ) );
3415}
3416
3417QgsGeometry QgsGeometry::fromQPolygonF( const QPolygonF &polygon )
3418{
3419 std::unique_ptr < QgsLineString > ring( QgsLineString::fromQPolygonF( polygon ) );
3420
3421 if ( polygon.isClosed() )
3422 {
3423 std::unique_ptr< QgsPolygon > poly = std::make_unique< QgsPolygon >();
3424 poly->setExteriorRing( ring.release() );
3425 return QgsGeometry( std::move( poly ) );
3426 }
3427 else
3428 {
3429 return QgsGeometry( std::move( ring ) );
3430 }
3431}
3432
3434{
3436 QgsPolygonXY result;
3437 result << createPolylineFromQPolygonF( polygon );
3438 return result;
3440}
3441
3443{
3444 QgsPolylineXY result;
3445 result.reserve( polygon.count() );
3446 for ( const QPointF &p : polygon )
3447 {
3448 result.append( QgsPointXY( p ) );
3449 }
3450 return result;
3451}
3452
3453bool QgsGeometry::compare( const QgsPolylineXY &p1, const QgsPolylineXY &p2, double epsilon )
3454{
3455 if ( p1.count() != p2.count() )
3456 return false;
3457
3458 for ( int i = 0; i < p1.count(); ++i )
3459 {
3460 if ( !p1.at( i ).compare( p2.at( i ), epsilon ) )
3461 return false;
3462 }
3463 return true;
3464}
3465
3466bool QgsGeometry::compare( const QgsPolygonXY &p1, const QgsPolygonXY &p2, double epsilon )
3467{
3468 if ( p1.count() != p2.count() )
3469 return false;
3470
3471 for ( int i = 0; i < p1.count(); ++i )
3472 {
3473 if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
3474 return false;
3475 }
3476 return true;
3477}
3478
3479
3480bool QgsGeometry::compare( const QgsMultiPolygonXY &p1, const QgsMultiPolygonXY &p2, double epsilon )
3481{
3482 if ( p1.count() != p2.count() )
3483 return false;
3484
3485 for ( int i = 0; i < p1.count(); ++i )
3486 {
3487 if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
3488 return false;
3489 }
3490 return true;
3491}
3492
3493QgsGeometry QgsGeometry::smooth( const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3494{
3495 if ( !d->geometry || d->geometry->isEmpty() )
3496 return QgsGeometry();
3497
3498 QgsGeometry geom = *this;
3500 geom = QgsGeometry( d->geometry->segmentize() );
3501
3502 switch ( QgsWkbTypes::flatType( geom.wkbType() ) )
3503 {
3504 case QgsWkbTypes::Point:
3506 //can't smooth a point based geometry
3507 return geom;
3508
3510 {
3511 const QgsLineString *lineString = qgsgeometry_cast< const QgsLineString * >( geom.constGet() );
3512 return QgsGeometry( smoothLine( *lineString, iterations, offset, minimumDistance, maxAngle ) );
3513 }
3514
3516 {
3517 const QgsMultiLineString *multiLine = qgsgeometry_cast< const QgsMultiLineString * >( geom.constGet() );
3518
3519 std::unique_ptr< QgsMultiLineString > resultMultiline = std::make_unique< QgsMultiLineString> ();
3520 resultMultiline->reserve( multiLine->numGeometries() );
3521 for ( int i = 0; i < multiLine->numGeometries(); ++i )
3522 {
3523 resultMultiline->addGeometry( smoothLine( *( multiLine->lineStringN( i ) ), iterations, offset, minimumDistance, maxAngle ).release() );
3524 }
3525 return QgsGeometry( std::move( resultMultiline ) );
3526 }
3527
3529 {
3530 const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon * >( geom.constGet() );
3531 return QgsGeometry( smoothPolygon( *poly, iterations, offset, minimumDistance, maxAngle ) );
3532 }
3533
3535 {
3536 const QgsMultiPolygon *multiPoly = qgsgeometry_cast< const QgsMultiPolygon * >( geom.constGet() );
3537
3538 std::unique_ptr< QgsMultiPolygon > resultMultiPoly = std::make_unique< QgsMultiPolygon >();
3539 resultMultiPoly->reserve( multiPoly->numGeometries() );
3540 for ( int i = 0; i < multiPoly->numGeometries(); ++i )
3541 {
3542 resultMultiPoly->addGeometry( smoothPolygon( *( multiPoly->polygonN( i ) ), iterations, offset, minimumDistance, maxAngle ).release() );
3543 }
3544 return QgsGeometry( std::move( resultMultiPoly ) );
3545 }
3546
3548 default:
3549 return QgsGeometry( *this );
3550 }
3551}
3552
3553std::unique_ptr< QgsLineString > smoothCurve( const QgsLineString &line, const unsigned int iterations,
3554 const double offset, double squareDistThreshold, double maxAngleRads,
3555 bool isRing )
3556{
3557 std::unique_ptr< QgsLineString > result = std::make_unique< QgsLineString >( line );
3558 QgsPointSequence outputLine;
3559 for ( unsigned int iteration = 0; iteration < iterations; ++iteration )
3560 {
3561 outputLine.resize( 0 );
3562 outputLine.reserve( 2 * ( result->numPoints() - 1 ) );
3563 bool skipFirst = false;
3564 bool skipLast = false;
3565 if ( isRing )
3566 {
3567 QgsPoint p1 = result->pointN( result->numPoints() - 2 );
3568 QgsPoint p2 = result->pointN( 0 );
3569 QgsPoint p3 = result->pointN( 1 );
3570 double angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3571 p3.x(), p3.y() );
3572 angle = std::fabs( M_PI - angle );
3573 skipFirst = angle > maxAngleRads;
3574 }
3575 for ( int i = 0; i < result->numPoints() - 1; i++ )
3576 {
3577 QgsPoint p1 = result->pointN( i );
3578 QgsPoint p2 = result->pointN( i + 1 );
3579
3580 double angle = M_PI;
3581 if ( i == 0 && isRing )
3582 {
3583 QgsPoint p3 = result->pointN( result->numPoints() - 2 );
3584 angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3585 p3.x(), p3.y() );
3586 }
3587 else if ( i < result->numPoints() - 2 )
3588 {
3589 QgsPoint p3 = result->pointN( i + 2 );
3590 angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3591 p3.x(), p3.y() );
3592 }
3593 else if ( i == result->numPoints() - 2 && isRing )
3594 {
3595 QgsPoint p3 = result->pointN( 1 );
3596 angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3597 p3.x(), p3.y() );
3598 }
3599
3600 skipLast = angle < M_PI - maxAngleRads || angle > M_PI + maxAngleRads;
3601
3602 // don't apply distance threshold to first or last segment
3603 if ( i == 0 || i >= result->numPoints() - 2
3604 || QgsGeometryUtils::sqrDistance2D( p1, p2 ) > squareDistThreshold )
3605 {
3606 if ( !isRing )
3607 {
3608 if ( !skipFirst )
3609 outputLine << ( i == 0 ? result->pointN( i ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset ) );
3610 if ( !skipLast )
3611 outputLine << ( i == result->numPoints() - 2 ? result->pointN( i + 1 ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset ) );
3612 else
3613 outputLine << p2;
3614 }
3615 else
3616 {
3617 // ring
3618 if ( !skipFirst )
3619 outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset );
3620 else if ( i == 0 )
3621 outputLine << p1;
3622 if ( !skipLast )
3623 outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset );
3624 else
3625 outputLine << p2;
3626 }
3627 }
3628 skipFirst = skipLast;
3629 }
3630
3631 if ( isRing && outputLine.at( 0 ) != outputLine.at( outputLine.count() - 1 ) )
3632 outputLine << outputLine.at( 0 );
3633
3634 result->setPoints( outputLine );
3635 }
3636 return result;
3637}
3638
3639std::unique_ptr<QgsLineString> QgsGeometry::smoothLine( const QgsLineString &line, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3640{
3641 double maxAngleRads = maxAngle * M_PI / 180.0;
3642 double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
3643 return smoothCurve( line, iterations, offset, squareDistThreshold, maxAngleRads, false );
3644}
3645
3646std::unique_ptr<QgsPolygon> QgsGeometry::smoothPolygon( const QgsPolygon &polygon, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3647{
3648 double maxAngleRads = maxAngle * M_PI / 180.0;
3649 double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
3650 std::unique_ptr< QgsPolygon > resultPoly = std::make_unique< QgsPolygon >();
3651
3652 resultPoly->setExteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.exteriorRing() ) ), iterations, offset,
3653 squareDistThreshold, maxAngleRads, true ).release() );
3654
3655 for ( int i = 0; i < polygon.numInteriorRings(); ++i )
3656 {
3657 resultPoly->addInteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.interiorRing( i ) ) ), iterations, offset,
3658 squareDistThreshold, maxAngleRads, true ).release() );
3659 }
3660 return resultPoly;
3661}
3662
3663QgsGeometry QgsGeometry::convertToPoint( bool destMultipart ) const
3664{
3665 switch ( type() )
3666 {
3668 {
3669 bool srcIsMultipart = isMultipart();
3670
3671 if ( ( destMultipart && srcIsMultipart ) ||
3672 ( !destMultipart && !srcIsMultipart ) )
3673 {
3674 // return a copy of the same geom
3675 return QgsGeometry( *this );
3676 }
3677 if ( destMultipart )
3678 {
3679 // layer is multipart => make a multipoint with a single point
3680 return fromMultiPointXY( QgsMultiPointXY() << asPoint() );
3681 }
3682 else
3683 {
3684 // destination is singlepart => make a single part if possible
3685 QgsMultiPointXY multiPoint = asMultiPoint();
3686 if ( multiPoint.count() == 1 )
3687 {
3688 return fromPointXY( multiPoint[0] );
3689 }
3690 }
3691 return QgsGeometry();
3692 }
3693
3695 {
3696 // only possible if destination is multipart
3697 if ( !destMultipart )
3698 return QgsGeometry();
3699
3700 // input geometry is multipart
3701 if ( isMultipart() )
3702 {
3703 const QgsMultiPolylineXY multiLine = asMultiPolyline();
3704 QgsMultiPointXY multiPoint;
3705 for ( const QgsPolylineXY &l : multiLine )
3706 for ( const QgsPointXY &p : l )
3707 multiPoint << p;
3708 return fromMultiPointXY( multiPoint );
3709 }
3710 // input geometry is not multipart: copy directly the line into a multipoint
3711 else
3712 {
3713 QgsPolylineXY line = asPolyline();
3714 if ( !line.isEmpty() )
3715 return fromMultiPointXY( line );
3716 }
3717 return QgsGeometry();
3718 }
3719
3721 {
3722 // can only transform if destination is multipoint
3723 if ( !destMultipart )
3724 return QgsGeometry();
3725
3726 // input geometry is multipart: make a multipoint from multipolygon
3727 if ( isMultipart() )
3728 {
3729 const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3730 QgsMultiPointXY multiPoint;
3731 for ( const QgsPolygonXY &poly : multiPolygon )
3732 for ( const QgsPolylineXY &line : poly )
3733 for ( const QgsPointXY &pt : line )
3734 multiPoint << pt;
3735 return fromMultiPointXY( multiPoint );
3736 }
3737 // input geometry is not multipart: make a multipoint from polygon
3738 else
3739 {
3740 const QgsPolygonXY polygon = asPolygon();
3741 QgsMultiPointXY multiPoint;
3742 for ( const QgsPolylineXY &line : polygon )
3743 for ( const QgsPointXY &pt : line )
3744 multiPoint << pt;
3745 return fromMultiPointXY( multiPoint );
3746 }
3747 }
3748
3749 default:
3750 return QgsGeometry();
3751 }
3752}
3753
3754QgsGeometry QgsGeometry::convertToLine( bool destMultipart ) const
3755{
3756 switch ( type() )
3757 {
3759 {
3760 if ( !isMultipart() )
3761 return QgsGeometry();
3762
3763 QgsMultiPointXY multiPoint = asMultiPoint();
3764 if ( multiPoint.count() < 2 )
3765 return QgsGeometry();
3766
3767 if ( destMultipart )
3768 return fromMultiPolylineXY( QgsMultiPolylineXY() << multiPoint );
3769 else
3770 return fromPolylineXY( multiPoint );
3771 }
3772
3774 {
3775 bool srcIsMultipart = isMultipart();
3776
3777 if ( ( destMultipart && srcIsMultipart ) ||
3778 ( !destMultipart && ! srcIsMultipart ) )
3779 {
3780 // return a copy of the same geom
3781 return QgsGeometry( *this );
3782 }
3783 if ( destMultipart )
3784 {
3785 // destination is multipart => makes a multipoint with a single line
3786 QgsPolylineXY line = asPolyline();
3787 if ( !line.isEmpty() )
3788 return fromMultiPolylineXY( QgsMultiPolylineXY() << line );
3789 }
3790 else
3791 {
3792 // destination is singlepart => make a single part if possible
3793 QgsMultiPolylineXY multiLine = asMultiPolyline();
3794 if ( multiLine.count() == 1 )
3795 return fromPolylineXY( multiLine[0] );
3796 }
3797 return QgsGeometry();
3798 }
3799
3801 {
3802 // input geometry is multipolygon
3803 if ( isMultipart() )
3804 {
3805 const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3806 QgsMultiPolylineXY multiLine;
3807 for ( const QgsPolygonXY &poly : multiPolygon )
3808 for ( const QgsPolylineXY &line : poly )
3809 multiLine << line;
3810
3811 if ( destMultipart )
3812 {
3813 // destination is multipart
3814 return fromMultiPolylineXY( multiLine );
3815 }
3816 else if ( multiLine.count() == 1 )
3817 {
3818 // destination is singlepart => make a single part if possible
3819 return fromPolylineXY( multiLine[0] );
3820 }
3821 }
3822 // input geometry is single polygon
3823 else
3824 {
3825 QgsPolygonXY polygon = asPolygon();
3826 // if polygon has rings
3827 if ( polygon.count() > 1 )
3828 {
3829 // cannot fit a polygon with rings in a single line layer
3830 // TODO: would it be better to remove rings?
3831 if ( destMultipart )
3832 {
3833 const QgsPolygonXY polygon = asPolygon();
3834 QgsMultiPolylineXY multiLine;
3835 multiLine.reserve( polygon.count() );
3836 for ( const QgsPolylineXY &line : polygon )
3837 multiLine << line;
3838 return fromMultiPolylineXY( multiLine );
3839 }
3840 }
3841 // no rings
3842 else if ( polygon.count() == 1 )
3843 {
3844 if ( destMultipart )
3845 {
3846 return fromMultiPolylineXY( polygon );
3847 }
3848 else
3849 {
3850 return fromPolylineXY( polygon[0] );
3851 }
3852 }
3853 }
3854 return QgsGeometry();
3855 }
3856
3857 default:
3858 return QgsGeometry();
3859 }
3860}
3861
3862QgsGeometry QgsGeometry::convertToPolygon( bool destMultipart ) const
3863{
3864 switch ( type() )
3865 {
3867 {
3868 if ( !isMultipart() )
3869 return QgsGeometry();
3870
3871 QgsMultiPointXY multiPoint = asMultiPoint();
3872 if ( multiPoint.count() < 3 )
3873 return QgsGeometry();
3874
3875 if ( multiPoint.last() != multiPoint.first() )
3876 multiPoint << multiPoint.first();
3877
3878 QgsPolygonXY polygon = QgsPolygonXY() << multiPoint;
3879 if ( destMultipart )
3880 return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3881 else
3882 return fromPolygonXY( polygon );
3883 }
3884
3886 {
3887 // input geometry is multiline
3888 if ( isMultipart() )
3889 {
3890 QgsMultiPolylineXY multiLine = asMultiPolyline();
3891 QgsMultiPolygonXY multiPolygon;
3892 for ( QgsMultiPolylineXY::iterator multiLineIt = multiLine.begin(); multiLineIt != multiLine.end(); ++multiLineIt )
3893 {
3894 // do not create polygon for a 1 segment line
3895 if ( ( *multiLineIt ).count() < 3 )
3896 return QgsGeometry();
3897 if ( ( *multiLineIt ).count() == 3 && ( *multiLineIt ).first() == ( *multiLineIt ).last() )
3898 return QgsGeometry();
3899
3900 // add closing node
3901 if ( ( *multiLineIt ).first() != ( *multiLineIt ).last() )
3902 *multiLineIt << ( *multiLineIt ).first();
3903 multiPolygon << ( QgsPolygonXY() << *multiLineIt );
3904 }
3905 // check that polygons were inserted
3906 if ( !multiPolygon.isEmpty() )
3907 {
3908 if ( destMultipart )
3909 {
3910 return fromMultiPolygonXY( multiPolygon );
3911 }
3912 else if ( multiPolygon.count() == 1 )
3913 {
3914 // destination is singlepart => make a single part if possible
3915 return fromPolygonXY( multiPolygon[0] );
3916 }
3917 }
3918 }
3919 // input geometry is single line
3920 else
3921 {
3922 QgsPolylineXY line = asPolyline();
3923
3924 // do not create polygon for a 1 segment line
3925 if ( line.count() < 3 )
3926 return QgsGeometry();
3927 if ( line.count() == 3 && line.first() == line.last() )
3928 return QgsGeometry();
3929
3930 // add closing node
3931 if ( line.first() != line.last() )
3932 line << line.first();
3933
3934 // destination is multipart
3935 if ( destMultipart )
3936 {
3937 return fromMultiPolygonXY( QgsMultiPolygonXY() << ( QgsPolygonXY() << line ) );
3938 }
3939 else
3940 {
3941 return fromPolygonXY( QgsPolygonXY() << line );
3942 }
3943 }
3944 return QgsGeometry();
3945 }
3946
3948 {
3949 bool srcIsMultipart = isMultipart();
3950
3951 if ( ( destMultipart && srcIsMultipart ) ||
3952 ( !destMultipart && ! srcIsMultipart ) )
3953 {
3954 // return a copy of the same geom
3955 return QgsGeometry( *this );
3956 }
3957 if ( destMultipart )
3958 {
3959 // destination is multipart => makes a multipoint with a single polygon
3960 QgsPolygonXY polygon = asPolygon();
3961 if ( !polygon.isEmpty() )
3962 return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3963 }
3964 else
3965 {
3966 QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3967 if ( multiPolygon.count() == 1 )
3968 {
3969 // destination is singlepart => make a single part if possible
3970 return fromPolygonXY( multiPolygon[0] );
3971 }
3972 }
3973 return QgsGeometry();
3974 }
3975
3976 default:
3977 return QgsGeometry();
3978 }
3979}
3980
3982{
3983 return new QgsGeos( geometry );
3984}
3985
3986QDataStream &operator<<( QDataStream &out, const QgsGeometry &geometry )
3987{
3988 out << geometry.asWkb();
3989 return out;
3990}
3991
3992QDataStream &operator>>( QDataStream &in, QgsGeometry &geometry )
3993{
3994 QByteArray byteArray;
3995 in >> byteArray;
3996 if ( byteArray.isEmpty() )
3997 {
3998 geometry.set( nullptr );
3999 return in;
4000 }
4001
4002 geometry.fromWkb( byteArray );
4003 return in;
4004}
4005
4006
4008{
4009 return mMessage;
4010}
4011
4013{
4014 return mLocation;
4015}
4016
4018{
4019 return mHasLocation;
4020}
4021
BufferSide
Side of line to buffer.
Definition: qgis.h:1149
DashPatternSizeAdjustment
Dash pattern size adjustment options.
Definition: qgis.h:1923
AngularDirection
Angular directions.
Definition: qgis.h:2023
GeometryOperationResult
Success or failure of a geometry operation.
Definition: qgis.h:1096
@ 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:1137
JoinStyle
Join styles for buffers.
Definition: qgis.h:1174
EndCapStyle
End cap styles for buffers.
Definition: qgis.h:1161
DashPatternLineEndingRule
Dash pattern line ending rules.
Definition: qgis.h:1908
MakeValidMethod
Algorithms to use when repairing invalid geometries.
Definition: qgis.h:1187
TransformDirection
Flags for raster layer temporal capabilities.
Definition: qgis.h:1461
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.
QgsWkbTypes::Type 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:138
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< 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< QgsAbstractGeometry > geomFromWkbType(QgsWkbTypes::Type t)
Returns empty geometry from wkb type.
static std::unique_ptr< QgsMultiLineString > fromMultiPolylineXY(const QgsMultiPolylineXY &multiline)
Construct geometry from a multipolyline.
static std::unique_ptr< QgsGeometryCollection > createCollectionOfType(QgsWkbTypes::Type type)
Returns a new geometry collection matching a specified WKB type.
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.
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:2477
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...
int makeDifferenceInPlace(const QgsGeometry &other)
Changes this geometry such that it does not intersect the other geometry.
QVector< QgsGeometry > coerceToType(QgsWkbTypes::Type type, double defaultZ=0, double defaultM=0) const
Attempts to coerce this geometry into the specified destination type.
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.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
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 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 ...
Qgis::GeometryOperationResult addPart(const QVector< QgsPointXY > &points, QgsWkbTypes::GeometryType geomType=QgsWkbTypes::UnknownGeometry)
Adds a new part to a the geometry.
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.
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.
QgsGeometry convertToType(QgsWkbTypes::GeometryType destType, bool destMultipart=false) const
Try to convert the geometry to the requested type.
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.
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.
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:167
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.
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...
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.
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.
bool convertGeometryCollectionToSubclass(QgsWkbTypes::GeometryType geomType)
Converts geometry collection to a the desired geometry type subclass (multi-point,...
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:1861
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:2870
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 GeometryType geometryType(Type type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:968
static bool isMultiType(Type type) SIP_HOLDGIL
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:862
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:141
static bool hasM(Type type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1130
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
static bool isCurvedType(Type type) SIP_HOLDGIL
Returns true if the WKB type is a curved type or can contain curved geometries.
Definition: qgswkbtypes.h:911
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:732
static Type multiType(Type type) SIP_HOLDGIL
Returns the multi type for a WKB type.
Definition: qgswkbtypes.h:304
static bool hasZ(Type type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:1080
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:3499
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:3498
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2915
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