QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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 std::unique_ptr< QgsAbstractGeometry > diffGeom = QgsGeometryEditUtils::avoidIntersections( *( d->geometry ), avoidIntersectionsLayers, haveInvalidGeometry, ignoreFeatures );
2854 if ( diffGeom )
2855 {
2856 reset( std::move( diffGeom ) );
2857 }
2858
2859 if ( geomTypeBeforeModification != wkbType() )
2860 return 2;
2861 if ( haveInvalidGeometry )
2862 return 4;
2863
2864 return 0;
2865}
2866
2867
2869{
2870 if ( !d->geometry )
2871 return QgsGeometry();
2872
2873 mLastError.clear();
2874 QgsGeos geos( d->geometry.get() );
2875 std::unique_ptr< QgsAbstractGeometry > g( geos.makeValid( method, keepCollapsed, &mLastError ) );
2876
2877 QgsGeometry result = QgsGeometry( std::move( g ) );
2878 result.mLastError = mLastError;
2879 return result;
2880}
2881
2883{
2884 return forcePolygonClockwise();
2885}
2886
2888{
2889 if ( !d->geometry )
2890 return QgsGeometry();
2891
2892 if ( isMultipart() )
2893 {
2894 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( d->geometry.get() );
2895 std::unique_ptr< QgsGeometryCollection > newCollection( collection->createEmptyWithSameType() );
2896 newCollection->reserve( collection->numGeometries() );
2897 for ( int i = 0; i < collection->numGeometries(); ++i )
2898 {
2899 const QgsAbstractGeometry *g = collection->geometryN( i );
2900 if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( g ) )
2901 {
2902 std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2903 corrected->forceClockwise();
2904 newCollection->addGeometry( corrected.release() );
2905 }
2906 else
2907 {
2908 newCollection->addGeometry( g->clone() );
2909 }
2910 }
2911 return QgsGeometry( std::move( newCollection ) );
2912 }
2913 else
2914 {
2915 if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( d->geometry.get() ) )
2916 {
2917 std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2918 corrected->forceClockwise();
2919 return QgsGeometry( std::move( corrected ) );
2920 }
2921 else
2922 {
2923 // not a curve polygon, so return unchanged
2924 return *this;
2925 }
2926 }
2927}
2928
2930{
2931 if ( !d->geometry )
2932 return QgsGeometry();
2933
2934 if ( isMultipart() )
2935 {
2936 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( d->geometry.get() );
2937 std::unique_ptr< QgsGeometryCollection > newCollection( collection->createEmptyWithSameType() );
2938 newCollection->reserve( collection->numGeometries() );
2939 for ( int i = 0; i < collection->numGeometries(); ++i )
2940 {
2941 const QgsAbstractGeometry *g = collection->geometryN( i );
2942 if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( g ) )
2943 {
2944 std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2945 corrected->forceCounterClockwise();
2946 newCollection->addGeometry( corrected.release() );
2947 }
2948 else
2949 {
2950 newCollection->addGeometry( g->clone() );
2951 }
2952 }
2953 return QgsGeometry( std::move( newCollection ) );
2954 }
2955 else
2956 {
2957 if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( d->geometry.get() ) )
2958 {
2959 std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2960 corrected->forceCounterClockwise();
2961 return QgsGeometry( std::move( corrected ) );
2962 }
2963 else
2964 {
2965 // not a curve polygon, so return unchanged
2966 return *this;
2967 }
2968 }
2969}
2970
2971
2972void QgsGeometry::validateGeometry( QVector<QgsGeometry::Error> &errors, const Qgis::GeometryValidationEngine method, const Qgis::GeometryValidityFlags flags ) const
2973{
2974 errors.clear();
2975 if ( !d->geometry )
2976 return;
2977
2978 // avoid expensive calcs for trivial point geometries
2980 {
2981 return;
2982 }
2983
2984 switch ( method )
2985 {
2986 case Qgis::GeometryValidationEngine::QgisInternal:
2987 QgsGeometryValidator::validateGeometry( *this, errors, method );
2988 return;
2989
2990 case Qgis::GeometryValidationEngine::Geos:
2991 {
2992 QgsGeos geos( d->geometry.get() );
2993 QString error;
2994 QgsGeometry errorLoc;
2995 if ( !geos.isValid( &error, flags & Qgis::GeometryValidityFlag::AllowSelfTouchingHoles, &errorLoc ) )
2996 {
2997 if ( errorLoc.isNull() )
2998 {
2999 errors.append( QgsGeometry::Error( error ) );
3000 }
3001 else
3002 {
3003 const QgsPointXY point = errorLoc.asPoint();
3004 errors.append( QgsGeometry::Error( error, point ) );
3005 }
3006 return;
3007 }
3008 }
3009 }
3010}
3011
3013{
3014 if ( !d->geometry )
3015 {
3016 return;
3017 }
3018
3019 detach();
3020 d->geometry->normalize();
3021}
3022
3023bool QgsGeometry::isGeosValid( Qgis::GeometryValidityFlags flags ) const
3024{
3025 if ( !d->geometry )
3026 {
3027 return false;
3028 }
3029
3030 return d->geometry->isValid( mLastError, flags );
3031}
3032
3034{
3035 if ( !d->geometry )
3036 return false;
3037
3038 QgsGeos geos( d->geometry.get() );
3039 mLastError.clear();
3040 return geos.isSimple( &mLastError );
3041}
3042
3043bool QgsGeometry::isAxisParallelRectangle( double maximumDeviation, bool simpleRectanglesOnly ) const
3044{
3045 if ( !d->geometry )
3046 return false;
3047
3048 QgsInternalGeometryEngine engine( *this );
3049 return engine.isAxisParallelRectangle( maximumDeviation, simpleRectanglesOnly );
3050}
3051
3053{
3054 if ( !d->geometry || !g.d->geometry )
3055 {
3056 return false;
3057 }
3058
3059 // fast check - are they shared copies of the same underlying geometry?
3060 if ( d == g.d )
3061 return true;
3062
3063 // fast check - distinct geometry types?
3064 if ( type() != g.type() )
3065 return false;
3066
3067 // avoid calling geos for trivial point case
3068 if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == QgsWkbTypes::Point
3069 && QgsWkbTypes::flatType( g.d->geometry->wkbType() ) == QgsWkbTypes::Point )
3070 {
3071 return equals( g );
3072 }
3073
3074 // another nice fast check upfront -- if the bounding boxes aren't equal, the geometries themselves can't be equal!
3075 if ( d->geometry->boundingBox() != g.d->geometry->boundingBox() )
3076 return false;
3077
3078 QgsGeos geos( d->geometry.get() );
3079 mLastError.clear();
3080 return geos.isEqual( g.d->geometry.get(), &mLastError );
3081}
3082
3083QgsGeometry QgsGeometry::unaryUnion( const QVector<QgsGeometry> &geometries, const QgsGeometryParameters &parameters )
3084{
3085 QgsGeos geos( nullptr );
3086
3087 QString error;
3088 std::unique_ptr< QgsAbstractGeometry > geom( geos.combine( geometries, &error, parameters ) );
3089 QgsGeometry result( std::move( geom ) );
3090 result.mLastError = error;
3091 return result;
3092}
3093
3094QgsGeometry QgsGeometry::polygonize( const QVector<QgsGeometry> &geometryList )
3095{
3096 QVector<const QgsAbstractGeometry *> geomV2List;
3097 for ( const QgsGeometry &g : geometryList )
3098 {
3099 if ( !( g.isNull() ) )
3100 {
3101 geomV2List.append( g.constGet() );
3102 }
3103 }
3104
3105 QString error;
3106 QgsGeometry result = QgsGeos::polygonize( geomV2List, &error );
3107 result.mLastError = error;
3108 return result;
3109}
3110
3112{
3114 {
3115 return;
3116 }
3117
3118 std::unique_ptr< QgsAbstractGeometry > straightGeom( d->geometry->segmentize( tolerance, toleranceType ) );
3119 reset( std::move( straightGeom ) );
3120}
3121
3123{
3124 if ( !d->geometry )
3125 {
3126 return false;
3127 }
3128
3129 return d->geometry->hasCurvedSegments();
3130}
3131
3133{
3134 if ( !d->geometry )
3135 {
3137 }
3138
3139 detach();
3140 d->geometry->transform( ct, direction, transformZ );
3142}
3143
3144Qgis::GeometryOperationResult QgsGeometry::transform( const QTransform &ct, double zTranslate, double zScale, double mTranslate, double mScale )
3145{
3146 if ( !d->geometry )
3147 {
3149 }
3150
3151 detach();
3152 d->geometry->transform( ct, zTranslate, zScale, mTranslate, mScale );
3154}
3155
3157{
3158 if ( d->geometry )
3159 {
3160 detach();
3161 d->geometry->transform( mtp.transform() );
3162 }
3163}
3164
3166{
3167 if ( !d->geometry || rectangle.isNull() || rectangle.isEmpty() )
3168 {
3169 return QgsGeometry();
3170 }
3171
3172 QgsGeos geos( d->geometry.get() );
3173 mLastError.clear();
3174 std::unique_ptr< QgsAbstractGeometry > resultGeom = geos.clip( rectangle, &mLastError );
3175 if ( !resultGeom )
3176 {
3177 QgsGeometry result;
3178 result.mLastError = mLastError;
3179 return result;
3180 }
3181 return QgsGeometry( std::move( resultGeom ) );
3182}
3183
3184void QgsGeometry::draw( QPainter &p ) const
3185{
3186 if ( d->geometry )
3187 {
3188 d->geometry->draw( p );
3189 }
3190}
3191
3192static bool vertexIndexInfo( const QgsAbstractGeometry *g, int vertexIndex, int &partIndex, int &ringIndex, int &vertex )
3193{
3194 if ( vertexIndex < 0 )
3195 return false; // clearly something wrong
3196
3197 if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
3198 {
3199 partIndex = 0;
3200 for ( int i = 0; i < geomCollection->numGeometries(); ++i )
3201 {
3202 const QgsAbstractGeometry *part = geomCollection->geometryN( i );
3203
3204 // count total number of vertices in the part
3205 int numPoints = 0;
3206 for ( int k = 0; k < part->ringCount(); ++k )
3207 numPoints += part->vertexCount( 0, k );
3208
3209 if ( vertexIndex < numPoints )
3210 {
3211 int nothing;
3212 return vertexIndexInfo( part, vertexIndex, nothing, ringIndex, vertex ); // set ring_index + index
3213 }
3214 vertexIndex -= numPoints;
3215 partIndex++;
3216 }
3217 }
3218 else if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
3219 {
3220 const QgsCurve *ring = curvePolygon->exteriorRing();
3221 if ( vertexIndex < ring->numPoints() )
3222 {
3223 partIndex = 0;
3224 ringIndex = 0;
3225 vertex = vertexIndex;
3226 return true;
3227 }
3228 vertexIndex -= ring->numPoints();
3229 ringIndex = 1;
3230 for ( int i = 0; i < curvePolygon->numInteriorRings(); ++i )
3231 {
3232 const QgsCurve *ring = curvePolygon->interiorRing( i );
3233 if ( vertexIndex < ring->numPoints() )
3234 {
3235 partIndex = 0;
3236 vertex = vertexIndex;
3237 return true;
3238 }
3239 vertexIndex -= ring->numPoints();
3240 ringIndex += 1;
3241 }
3242 }
3243 else if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
3244 {
3245 if ( vertexIndex < curve->numPoints() )
3246 {
3247 partIndex = 0;
3248 ringIndex = 0;
3249 vertex = vertexIndex;
3250 return true;
3251 }
3252 }
3253 else if ( qgsgeometry_cast<const QgsPoint *>( g ) )
3254 {
3255 if ( vertexIndex == 0 )
3256 {
3257 partIndex = 0;
3258 ringIndex = 0;
3259 vertex = 0;
3260 return true;
3261 }
3262 }
3263
3264 return false;
3265}
3266
3268{
3269 if ( !d->geometry )
3270 {
3271 return false;
3272 }
3273
3274 id.type = Qgis::VertexType::Segment;
3275
3276 bool res = vertexIndexInfo( d->geometry.get(), nr, id.part, id.ring, id.vertex );
3277 if ( !res )
3278 return false;
3279
3280 // now let's find out if it is a straight or circular segment
3281 const QgsAbstractGeometry *g = d->geometry.get();
3282 if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
3283 {
3284 g = geomCollection->geometryN( id.part );
3285 }
3286
3287 if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
3288 {
3289 g = id.ring == 0 ? curvePolygon->exteriorRing() : curvePolygon->interiorRing( id.ring - 1 );
3290 }
3291
3292 if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
3293 {
3294 QgsPoint p;
3295 res = curve->pointAt( id.vertex, p, id.type );
3296 if ( !res )
3297 return false;
3298 }
3299
3300 return true;
3301}
3302
3304{
3305 if ( !d->geometry )
3306 {
3307 return -1;
3308 }
3309 return d->geometry->vertexNumberFromVertexId( id );
3310}
3311
3313{
3314 return mLastError;
3315}
3316
3317void QgsGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
3318{
3319 if ( !d->geometry )
3320 return;
3321
3322 detach();
3323
3324 d->geometry->filterVertices( filter );
3325}
3326
3327void QgsGeometry::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
3328{
3329 if ( !d->geometry )
3330 return;
3331
3332 detach();
3333
3334 d->geometry->transformVertices( transform );
3335}
3336
3337void QgsGeometry::convertPointList( const QVector<QgsPointXY> &input, QgsPointSequence &output )
3338{
3339 output.clear();
3340 for ( const QgsPointXY &p : input )
3341 {
3342 output.append( QgsPoint( p ) );
3343 }
3344}
3345
3346void QgsGeometry::convertPointList( const QgsPointSequence &input, QVector<QgsPointXY> &output )
3347{
3348 output.clear();
3349 for ( const QgsPoint &p : input )
3350 {
3351 output.append( QgsPointXY( p.x(), p.y() ) );
3352 }
3353}
3354
3355void QgsGeometry::convertPolygon( const QgsPolygon &input, QgsPolygonXY &output )
3356{
3357 output.clear();
3358
3359 auto convertRing = []( const QgsCurve * ring ) -> QgsPolylineXY
3360 {
3361 QgsPolylineXY res;
3362 bool doSegmentation = ( QgsWkbTypes::flatType( ring->wkbType() ) == QgsWkbTypes::CompoundCurve
3364 std::unique_ptr< QgsLineString > segmentizedLine;
3365 const QgsLineString *line = nullptr;
3366 if ( doSegmentation )
3367 {
3368 segmentizedLine.reset( ring->curveToLine() );
3369 line = segmentizedLine.get();
3370 }
3371 else
3372 {
3373 line = qgsgeometry_cast<const QgsLineString *>( ring );
3374 if ( !line )
3375 {
3376 return res;
3377 }
3378 }
3379
3380 int nVertices = line->numPoints();
3381 res.resize( nVertices );
3382 QgsPointXY *data = res.data();
3383 const double *xData = line->xData();
3384 const double *yData = line->yData();
3385 for ( int i = 0; i < nVertices; ++i )
3386 {
3387 data->setX( *xData++ );
3388 data->setY( *yData++ );
3389 data++;
3390 }
3391 return res;
3392 };
3393
3394 if ( const QgsCurve *exterior = input.exteriorRing() )
3395 {
3396 output.push_back( convertRing( exterior ) );
3397 }
3398
3399 const int interiorRingCount = input.numInteriorRings();
3400 output.reserve( output.size() + interiorRingCount );
3401 for ( int n = 0; n < interiorRingCount; ++n )
3402 {
3403 output.push_back( convertRing( input.interiorRing( n ) ) );
3404 }
3405}
3406
3408{
3409 return QgsGeometry( std::make_unique< QgsPoint >( point.x(), point.y() ) );
3410}
3411
3412QgsGeometry QgsGeometry::fromQPolygonF( const QPolygonF &polygon )
3413{
3414 std::unique_ptr < QgsLineString > ring( QgsLineString::fromQPolygonF( polygon ) );
3415
3416 if ( polygon.isClosed() )
3417 {
3418 std::unique_ptr< QgsPolygon > poly = std::make_unique< QgsPolygon >();
3419 poly->setExteriorRing( ring.release() );
3420 return QgsGeometry( std::move( poly ) );
3421 }
3422 else
3423 {
3424 return QgsGeometry( std::move( ring ) );
3425 }
3426}
3427
3429{
3431 QgsPolygonXY result;
3432 result << createPolylineFromQPolygonF( polygon );
3433 return result;
3435}
3436
3438{
3439 QgsPolylineXY result;
3440 result.reserve( polygon.count() );
3441 for ( const QPointF &p : polygon )
3442 {
3443 result.append( QgsPointXY( p ) );
3444 }
3445 return result;
3446}
3447
3448bool QgsGeometry::compare( const QgsPolylineXY &p1, const QgsPolylineXY &p2, double epsilon )
3449{
3450 if ( p1.count() != p2.count() )
3451 return false;
3452
3453 for ( int i = 0; i < p1.count(); ++i )
3454 {
3455 if ( !p1.at( i ).compare( p2.at( i ), epsilon ) )
3456 return false;
3457 }
3458 return true;
3459}
3460
3461bool QgsGeometry::compare( const QgsPolygonXY &p1, const QgsPolygonXY &p2, double epsilon )
3462{
3463 if ( p1.count() != p2.count() )
3464 return false;
3465
3466 for ( int i = 0; i < p1.count(); ++i )
3467 {
3468 if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
3469 return false;
3470 }
3471 return true;
3472}
3473
3474
3475bool QgsGeometry::compare( const QgsMultiPolygonXY &p1, const QgsMultiPolygonXY &p2, double epsilon )
3476{
3477 if ( p1.count() != p2.count() )
3478 return false;
3479
3480 for ( int i = 0; i < p1.count(); ++i )
3481 {
3482 if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
3483 return false;
3484 }
3485 return true;
3486}
3487
3488QgsGeometry QgsGeometry::smooth( const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3489{
3490 if ( !d->geometry || d->geometry->isEmpty() )
3491 return QgsGeometry();
3492
3493 QgsGeometry geom = *this;
3495 geom = QgsGeometry( d->geometry->segmentize() );
3496
3497 switch ( QgsWkbTypes::flatType( geom.wkbType() ) )
3498 {
3499 case QgsWkbTypes::Point:
3501 //can't smooth a point based geometry
3502 return geom;
3503
3505 {
3506 const QgsLineString *lineString = qgsgeometry_cast< const QgsLineString * >( geom.constGet() );
3507 return QgsGeometry( smoothLine( *lineString, iterations, offset, minimumDistance, maxAngle ) );
3508 }
3509
3511 {
3512 const QgsMultiLineString *multiLine = qgsgeometry_cast< const QgsMultiLineString * >( geom.constGet() );
3513
3514 std::unique_ptr< QgsMultiLineString > resultMultiline = std::make_unique< QgsMultiLineString> ();
3515 resultMultiline->reserve( multiLine->numGeometries() );
3516 for ( int i = 0; i < multiLine->numGeometries(); ++i )
3517 {
3518 resultMultiline->addGeometry( smoothLine( *( multiLine->lineStringN( i ) ), iterations, offset, minimumDistance, maxAngle ).release() );
3519 }
3520 return QgsGeometry( std::move( resultMultiline ) );
3521 }
3522
3524 {
3525 const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon * >( geom.constGet() );
3526 return QgsGeometry( smoothPolygon( *poly, iterations, offset, minimumDistance, maxAngle ) );
3527 }
3528
3530 {
3531 const QgsMultiPolygon *multiPoly = qgsgeometry_cast< const QgsMultiPolygon * >( geom.constGet() );
3532
3533 std::unique_ptr< QgsMultiPolygon > resultMultiPoly = std::make_unique< QgsMultiPolygon >();
3534 resultMultiPoly->reserve( multiPoly->numGeometries() );
3535 for ( int i = 0; i < multiPoly->numGeometries(); ++i )
3536 {
3537 resultMultiPoly->addGeometry( smoothPolygon( *( multiPoly->polygonN( i ) ), iterations, offset, minimumDistance, maxAngle ).release() );
3538 }
3539 return QgsGeometry( std::move( resultMultiPoly ) );
3540 }
3541
3543 default:
3544 return QgsGeometry( *this );
3545 }
3546}
3547
3548std::unique_ptr< QgsLineString > smoothCurve( const QgsLineString &line, const unsigned int iterations,
3549 const double offset, double squareDistThreshold, double maxAngleRads,
3550 bool isRing )
3551{
3552 std::unique_ptr< QgsLineString > result = std::make_unique< QgsLineString >( line );
3553 QgsPointSequence outputLine;
3554 for ( unsigned int iteration = 0; iteration < iterations; ++iteration )
3555 {
3556 outputLine.resize( 0 );
3557 outputLine.reserve( 2 * ( result->numPoints() - 1 ) );
3558 bool skipFirst = false;
3559 bool skipLast = false;
3560 if ( isRing )
3561 {
3562 QgsPoint p1 = result->pointN( result->numPoints() - 2 );
3563 QgsPoint p2 = result->pointN( 0 );
3564 QgsPoint p3 = result->pointN( 1 );
3565 double angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3566 p3.x(), p3.y() );
3567 angle = std::fabs( M_PI - angle );
3568 skipFirst = angle > maxAngleRads;
3569 }
3570 for ( int i = 0; i < result->numPoints() - 1; i++ )
3571 {
3572 QgsPoint p1 = result->pointN( i );
3573 QgsPoint p2 = result->pointN( i + 1 );
3574
3575 double angle = M_PI;
3576 if ( i == 0 && isRing )
3577 {
3578 QgsPoint p3 = result->pointN( result->numPoints() - 2 );
3579 angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3580 p3.x(), p3.y() );
3581 }
3582 else if ( i < result->numPoints() - 2 )
3583 {
3584 QgsPoint p3 = result->pointN( i + 2 );
3585 angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3586 p3.x(), p3.y() );
3587 }
3588 else if ( i == result->numPoints() - 2 && isRing )
3589 {
3590 QgsPoint p3 = result->pointN( 1 );
3591 angle = QgsGeometryUtils::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3592 p3.x(), p3.y() );
3593 }
3594
3595 skipLast = angle < M_PI - maxAngleRads || angle > M_PI + maxAngleRads;
3596
3597 // don't apply distance threshold to first or last segment
3598 if ( i == 0 || i >= result->numPoints() - 2
3599 || QgsGeometryUtils::sqrDistance2D( p1, p2 ) > squareDistThreshold )
3600 {
3601 if ( !isRing )
3602 {
3603 if ( !skipFirst )
3604 outputLine << ( i == 0 ? result->pointN( i ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset ) );
3605 if ( !skipLast )
3606 outputLine << ( i == result->numPoints() - 2 ? result->pointN( i + 1 ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset ) );
3607 else
3608 outputLine << p2;
3609 }
3610 else
3611 {
3612 // ring
3613 if ( !skipFirst )
3614 outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset );
3615 else if ( i == 0 )
3616 outputLine << p1;
3617 if ( !skipLast )
3618 outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset );
3619 else
3620 outputLine << p2;
3621 }
3622 }
3623 skipFirst = skipLast;
3624 }
3625
3626 if ( isRing && outputLine.at( 0 ) != outputLine.at( outputLine.count() - 1 ) )
3627 outputLine << outputLine.at( 0 );
3628
3629 result->setPoints( outputLine );
3630 }
3631 return result;
3632}
3633
3634std::unique_ptr<QgsLineString> QgsGeometry::smoothLine( const QgsLineString &line, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3635{
3636 double maxAngleRads = maxAngle * M_PI / 180.0;
3637 double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
3638 return smoothCurve( line, iterations, offset, squareDistThreshold, maxAngleRads, false );
3639}
3640
3641std::unique_ptr<QgsPolygon> QgsGeometry::smoothPolygon( const QgsPolygon &polygon, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3642{
3643 double maxAngleRads = maxAngle * M_PI / 180.0;
3644 double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
3645 std::unique_ptr< QgsPolygon > resultPoly = std::make_unique< QgsPolygon >();
3646
3647 resultPoly->setExteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.exteriorRing() ) ), iterations, offset,
3648 squareDistThreshold, maxAngleRads, true ).release() );
3649
3650 for ( int i = 0; i < polygon.numInteriorRings(); ++i )
3651 {
3652 resultPoly->addInteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.interiorRing( i ) ) ), iterations, offset,
3653 squareDistThreshold, maxAngleRads, true ).release() );
3654 }
3655 return resultPoly;
3656}
3657
3658QgsGeometry QgsGeometry::convertToPoint( bool destMultipart ) const
3659{
3660 switch ( type() )
3661 {
3663 {
3664 bool srcIsMultipart = isMultipart();
3665
3666 if ( ( destMultipart && srcIsMultipart ) ||
3667 ( !destMultipart && !srcIsMultipart ) )
3668 {
3669 // return a copy of the same geom
3670 return QgsGeometry( *this );
3671 }
3672 if ( destMultipart )
3673 {
3674 // layer is multipart => make a multipoint with a single point
3675 return fromMultiPointXY( QgsMultiPointXY() << asPoint() );
3676 }
3677 else
3678 {
3679 // destination is singlepart => make a single part if possible
3680 QgsMultiPointXY multiPoint = asMultiPoint();
3681 if ( multiPoint.count() == 1 )
3682 {
3683 return fromPointXY( multiPoint[0] );
3684 }
3685 }
3686 return QgsGeometry();
3687 }
3688
3690 {
3691 // only possible if destination is multipart
3692 if ( !destMultipart )
3693 return QgsGeometry();
3694
3695 // input geometry is multipart
3696 if ( isMultipart() )
3697 {
3698 const QgsMultiPolylineXY multiLine = asMultiPolyline();
3699 QgsMultiPointXY multiPoint;
3700 for ( const QgsPolylineXY &l : multiLine )
3701 for ( const QgsPointXY &p : l )
3702 multiPoint << p;
3703 return fromMultiPointXY( multiPoint );
3704 }
3705 // input geometry is not multipart: copy directly the line into a multipoint
3706 else
3707 {
3708 QgsPolylineXY line = asPolyline();
3709 if ( !line.isEmpty() )
3710 return fromMultiPointXY( line );
3711 }
3712 return QgsGeometry();
3713 }
3714
3716 {
3717 // can only transform if destination is multipoint
3718 if ( !destMultipart )
3719 return QgsGeometry();
3720
3721 // input geometry is multipart: make a multipoint from multipolygon
3722 if ( isMultipart() )
3723 {
3724 const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3725 QgsMultiPointXY multiPoint;
3726 for ( const QgsPolygonXY &poly : multiPolygon )
3727 for ( const QgsPolylineXY &line : poly )
3728 for ( const QgsPointXY &pt : line )
3729 multiPoint << pt;
3730 return fromMultiPointXY( multiPoint );
3731 }
3732 // input geometry is not multipart: make a multipoint from polygon
3733 else
3734 {
3735 const QgsPolygonXY polygon = asPolygon();
3736 QgsMultiPointXY multiPoint;
3737 for ( const QgsPolylineXY &line : polygon )
3738 for ( const QgsPointXY &pt : line )
3739 multiPoint << pt;
3740 return fromMultiPointXY( multiPoint );
3741 }
3742 }
3743
3744 default:
3745 return QgsGeometry();
3746 }
3747}
3748
3749QgsGeometry QgsGeometry::convertToLine( bool destMultipart ) const
3750{
3751 switch ( type() )
3752 {
3754 {
3755 if ( !isMultipart() )
3756 return QgsGeometry();
3757
3758 QgsMultiPointXY multiPoint = asMultiPoint();
3759 if ( multiPoint.count() < 2 )
3760 return QgsGeometry();
3761
3762 if ( destMultipart )
3763 return fromMultiPolylineXY( QgsMultiPolylineXY() << multiPoint );
3764 else
3765 return fromPolylineXY( multiPoint );
3766 }
3767
3769 {
3770 bool srcIsMultipart = isMultipart();
3771
3772 if ( ( destMultipart && srcIsMultipart ) ||
3773 ( !destMultipart && ! srcIsMultipart ) )
3774 {
3775 // return a copy of the same geom
3776 return QgsGeometry( *this );
3777 }
3778 if ( destMultipart )
3779 {
3780 // destination is multipart => makes a multipoint with a single line
3781 QgsPolylineXY line = asPolyline();
3782 if ( !line.isEmpty() )
3783 return fromMultiPolylineXY( QgsMultiPolylineXY() << line );
3784 }
3785 else
3786 {
3787 // destination is singlepart => make a single part if possible
3788 QgsMultiPolylineXY multiLine = asMultiPolyline();
3789 if ( multiLine.count() == 1 )
3790 return fromPolylineXY( multiLine[0] );
3791 }
3792 return QgsGeometry();
3793 }
3794
3796 {
3797 // input geometry is multipolygon
3798 if ( isMultipart() )
3799 {
3800 const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3801 QgsMultiPolylineXY multiLine;
3802 for ( const QgsPolygonXY &poly : multiPolygon )
3803 for ( const QgsPolylineXY &line : poly )
3804 multiLine << line;
3805
3806 if ( destMultipart )
3807 {
3808 // destination is multipart
3809 return fromMultiPolylineXY( multiLine );
3810 }
3811 else if ( multiLine.count() == 1 )
3812 {
3813 // destination is singlepart => make a single part if possible
3814 return fromPolylineXY( multiLine[0] );
3815 }
3816 }
3817 // input geometry is single polygon
3818 else
3819 {
3820 QgsPolygonXY polygon = asPolygon();
3821 // if polygon has rings
3822 if ( polygon.count() > 1 )
3823 {
3824 // cannot fit a polygon with rings in a single line layer
3825 // TODO: would it be better to remove rings?
3826 if ( destMultipart )
3827 {
3828 const QgsPolygonXY polygon = asPolygon();
3829 QgsMultiPolylineXY multiLine;
3830 multiLine.reserve( polygon.count() );
3831 for ( const QgsPolylineXY &line : polygon )
3832 multiLine << line;
3833 return fromMultiPolylineXY( multiLine );
3834 }
3835 }
3836 // no rings
3837 else if ( polygon.count() == 1 )
3838 {
3839 if ( destMultipart )
3840 {
3841 return fromMultiPolylineXY( polygon );
3842 }
3843 else
3844 {
3845 return fromPolylineXY( polygon[0] );
3846 }
3847 }
3848 }
3849 return QgsGeometry();
3850 }
3851
3852 default:
3853 return QgsGeometry();
3854 }
3855}
3856
3857QgsGeometry QgsGeometry::convertToPolygon( bool destMultipart ) const
3858{
3859 switch ( type() )
3860 {
3862 {
3863 if ( !isMultipart() )
3864 return QgsGeometry();
3865
3866 QgsMultiPointXY multiPoint = asMultiPoint();
3867 if ( multiPoint.count() < 3 )
3868 return QgsGeometry();
3869
3870 if ( multiPoint.last() != multiPoint.first() )
3871 multiPoint << multiPoint.first();
3872
3873 QgsPolygonXY polygon = QgsPolygonXY() << multiPoint;
3874 if ( destMultipart )
3875 return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3876 else
3877 return fromPolygonXY( polygon );
3878 }
3879
3881 {
3882 // input geometry is multiline
3883 if ( isMultipart() )
3884 {
3885 QgsMultiPolylineXY multiLine = asMultiPolyline();
3886 QgsMultiPolygonXY multiPolygon;
3887 for ( QgsMultiPolylineXY::iterator multiLineIt = multiLine.begin(); multiLineIt != multiLine.end(); ++multiLineIt )
3888 {
3889 // do not create polygon for a 1 segment line
3890 if ( ( *multiLineIt ).count() < 3 )
3891 return QgsGeometry();
3892 if ( ( *multiLineIt ).count() == 3 && ( *multiLineIt ).first() == ( *multiLineIt ).last() )
3893 return QgsGeometry();
3894
3895 // add closing node
3896 if ( ( *multiLineIt ).first() != ( *multiLineIt ).last() )
3897 *multiLineIt << ( *multiLineIt ).first();
3898 multiPolygon << ( QgsPolygonXY() << *multiLineIt );
3899 }
3900 // check that polygons were inserted
3901 if ( !multiPolygon.isEmpty() )
3902 {
3903 if ( destMultipart )
3904 {
3905 return fromMultiPolygonXY( multiPolygon );
3906 }
3907 else if ( multiPolygon.count() == 1 )
3908 {
3909 // destination is singlepart => make a single part if possible
3910 return fromPolygonXY( multiPolygon[0] );
3911 }
3912 }
3913 }
3914 // input geometry is single line
3915 else
3916 {
3917 QgsPolylineXY line = asPolyline();
3918
3919 // do not create polygon for a 1 segment line
3920 if ( line.count() < 3 )
3921 return QgsGeometry();
3922 if ( line.count() == 3 && line.first() == line.last() )
3923 return QgsGeometry();
3924
3925 // add closing node
3926 if ( line.first() != line.last() )
3927 line << line.first();
3928
3929 // destination is multipart
3930 if ( destMultipart )
3931 {
3932 return fromMultiPolygonXY( QgsMultiPolygonXY() << ( QgsPolygonXY() << line ) );
3933 }
3934 else
3935 {
3936 return fromPolygonXY( QgsPolygonXY() << line );
3937 }
3938 }
3939 return QgsGeometry();
3940 }
3941
3943 {
3944 bool srcIsMultipart = isMultipart();
3945
3946 if ( ( destMultipart && srcIsMultipart ) ||
3947 ( !destMultipart && ! srcIsMultipart ) )
3948 {
3949 // return a copy of the same geom
3950 return QgsGeometry( *this );
3951 }
3952 if ( destMultipart )
3953 {
3954 // destination is multipart => makes a multipoint with a single polygon
3955 QgsPolygonXY polygon = asPolygon();
3956 if ( !polygon.isEmpty() )
3957 return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
3958 }
3959 else
3960 {
3961 QgsMultiPolygonXY multiPolygon = asMultiPolygon();
3962 if ( multiPolygon.count() == 1 )
3963 {
3964 // destination is singlepart => make a single part if possible
3965 return fromPolygonXY( multiPolygon[0] );
3966 }
3967 }
3968 return QgsGeometry();
3969 }
3970
3971 default:
3972 return QgsGeometry();
3973 }
3974}
3975
3977{
3978 return new QgsGeos( geometry );
3979}
3980
3981QDataStream &operator<<( QDataStream &out, const QgsGeometry &geometry )
3982{
3983 out << geometry.asWkb();
3984 return out;
3985}
3986
3987QDataStream &operator>>( QDataStream &in, QgsGeometry &geometry )
3988{
3989 QByteArray byteArray;
3990 in >> byteArray;
3991 if ( byteArray.isEmpty() )
3992 {
3993 geometry.set( nullptr );
3994 return in;
3995 }
3996
3997 geometry.fromWkb( byteArray );
3998 return in;
3999}
4000
4001
4003{
4004 return mMessage;
4005}
4006
4008{
4009 return mLocation;
4010}
4011
4013{
4014 return mHasLocation;
4015}
4016
BufferSide
Side of line to buffer.
Definition: qgis.h:1008
DashPatternSizeAdjustment
Dash pattern size adjustment options.
Definition: qgis.h:1716
AngularDirection
Angular directions.
Definition: qgis.h:1805
GeometryOperationResult
Success or failure of a geometry operation.
Definition: qgis.h:955
@ 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:996
JoinStyle
Join styles for buffers.
Definition: qgis.h:1033
EndCapStyle
End cap styles for buffers.
Definition: qgis.h:1020
DashPatternLineEndingRule
Dash pattern line ending rules.
Definition: qgis.h:1701
MakeValidMethod
Algorithms to use when repairing invalid geometries.
Definition: qgis.h:1046
TransformDirection
Flags for raster layer temporal capabilities.
Definition: qgis.h:1320
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:2476
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:3061
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:3060
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2527
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