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