QGIS API Documentation 3.36.0-Maidenhead (09951dc0acf)
Loading...
Searching...
No Matches
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
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 return QgsGeometry( point.clone() );
177}
178
180{
181 std::unique_ptr< QgsAbstractGeometry > geom = QgsGeometryFactory::fromPolylineXY( polyline );
182 if ( geom )
183 {
184 return QgsGeometry( std::move( geom ) );
185 }
186 return QgsGeometry();
187}
188
190{
191 return QgsGeometry( std::make_unique< QgsLineString >( polyline ) );
192}
193
195{
196 std::unique_ptr< QgsPolygon > geom = QgsGeometryFactory::fromPolygonXY( polygon );
197 if ( geom )
198 {
199 return QgsGeometry( std::move( geom ) );
200 }
201 return QgsGeometry();
202}
203
205{
206 std::unique_ptr< QgsMultiPoint > geom = QgsGeometryFactory::fromMultiPointXY( multipoint );
207 if ( geom )
208 {
209 return QgsGeometry( std::move( geom ) );
210 }
211 return QgsGeometry();
212}
213
215{
216 std::unique_ptr< QgsMultiLineString > geom = QgsGeometryFactory::fromMultiPolylineXY( multiline );
217 if ( geom )
218 {
219 return QgsGeometry( std::move( geom ) );
220 }
221 return QgsGeometry();
222}
223
225{
226 std::unique_ptr< QgsMultiPolygon > geom = QgsGeometryFactory::fromMultiPolygonXY( multipoly );
227 if ( geom )
228 {
229 return QgsGeometry( std::move( geom ) );
230 }
231 return QgsGeometry();
232}
233
235{
236 if ( rect.isNull() )
237 return QgsGeometry();
238
239 std::unique_ptr< QgsLineString > ext = std::make_unique< QgsLineString >(
240 QVector< double >() << rect.xMinimum()
241 << rect.xMaximum()
242 << rect.xMaximum()
243 << rect.xMinimum()
244 << rect.xMinimum(),
245 QVector< double >() << rect.yMinimum()
246 << rect.yMinimum()
247 << rect.yMaximum()
248 << rect.yMaximum()
249 << rect.yMinimum() );
250 std::unique_ptr< QgsPolygon > polygon = std::make_unique< QgsPolygon >();
251 polygon->setExteriorRing( ext.release() );
252 return QgsGeometry( std::move( polygon ) );
253}
254
256{
257 if ( box.is2d() )
258 {
259 return fromRect( box.toRectangle() );
260 }
261
262 std::unique_ptr< QgsMultiPolygon > multiPolygon = std::make_unique< QgsMultiPolygon >();
263
264 std::unique_ptr< QgsLineString > ext1 = std::make_unique< QgsLineString >(
265 QVector< double >() << box.xMinimum()
266 << box.xMinimum()
267 << box.xMaximum()
268 << box.xMaximum()
269 << box.xMinimum(),
270 QVector< double >() << box.yMinimum()
271 << box.yMaximum()
272 << box.yMaximum()
273 << box.yMinimum()
274 << box.yMinimum(),
275 QVector< double >() << box.zMinimum()
276 << box.zMinimum()
277 << box.zMinimum()
278 << box.zMinimum()
279 << box.zMinimum() );
280 std::unique_ptr< QgsPolygon > polygon1 = std::make_unique< QgsPolygon >( ext1.release() );
281 multiPolygon->addGeometry( polygon1.release() );
282
283 std::unique_ptr< QgsLineString > ext2 = std::make_unique< QgsLineString >(
284 QVector< double >() << box.xMinimum()
285 << box.xMinimum()
286 << box.xMinimum()
287 << box.xMinimum()
288 << box.xMinimum(),
289 QVector< double >() << box.yMinimum()
290 << box.yMaximum()
291 << box.yMaximum()
292 << box.yMinimum()
293 << box.yMinimum(),
294 QVector< double >() << box.zMinimum()
295 << box.zMinimum()
296 << box.zMaximum()
297 << box.zMaximum()
298 << box.zMinimum() );
299 std::unique_ptr< QgsPolygon > polygon2 = std::make_unique< QgsPolygon >( ext2.release() );
300 multiPolygon->addGeometry( polygon2.release() );
301
302 std::unique_ptr< QgsLineString > ext3 = std::make_unique< QgsLineString >(
303 QVector< double >() << box.xMinimum()
304 << box.xMaximum()
305 << box.xMaximum()
306 << box.xMinimum()
307 << box.xMinimum(),
308 QVector< double >() << box.yMinimum()
309 << box.yMinimum()
310 << box.yMinimum()
311 << box.yMinimum()
312 << box.yMinimum(),
313 QVector< double >() << box.zMinimum()
314 << box.zMinimum()
315 << box.zMaximum()
316 << box.zMaximum()
317 << box.zMinimum() );
318 std::unique_ptr< QgsPolygon > polygon3 = std::make_unique< QgsPolygon >( ext3.release() );
319 multiPolygon->addGeometry( polygon3.release() );
320
321 std::unique_ptr< QgsLineString > ext4 = std::make_unique< QgsLineString >(
322 QVector< double >() << box.xMaximum()
323 << box.xMaximum()
324 << box.xMinimum()
325 << box.xMinimum()
326 << box.xMaximum(),
327 QVector< double >() << box.yMaximum()
328 << box.yMinimum()
329 << box.yMinimum()
330 << box.yMaximum()
331 << box.yMaximum(),
332 QVector< double >() << box.zMaximum()
333 << box.zMaximum()
334 << box.zMaximum()
335 << box.zMaximum()
336 << box.zMaximum() );
337 std::unique_ptr< QgsPolygon > polygon4 = std::make_unique< QgsPolygon >( ext4.release() );
338 multiPolygon->addGeometry( polygon4.release() );
339
340 std::unique_ptr< QgsLineString > ext5 = std::make_unique< QgsLineString >(
341 QVector< double >() << box.xMaximum()
342 << box.xMaximum()
343 << box.xMaximum()
344 << box.xMaximum()
345 << box.xMaximum(),
346 QVector< double >() << box.yMaximum()
347 << box.yMinimum()
348 << box.yMinimum()
349 << box.yMaximum()
350 << box.yMaximum(),
351 QVector< double >() << box.zMaximum()
352 << box.zMaximum()
353 << box.zMinimum()
354 << box.zMinimum()
355 << box.zMaximum() );
356 std::unique_ptr< QgsPolygon > polygon5 = std::make_unique< QgsPolygon >( ext5.release() );
357 multiPolygon->addGeometry( polygon5.release() );
358
359 std::unique_ptr< QgsLineString > ext6 = std::make_unique< QgsLineString >(
360 QVector< double >() << box.xMaximum()
361 << box.xMaximum()
362 << box.xMinimum()
363 << box.xMinimum()
364 << box.xMaximum(),
365 QVector< double >() << box.yMaximum()
366 << box.yMaximum()
367 << box.yMaximum()
368 << box.yMaximum()
369 << box.yMaximum(),
370 QVector< double >() << box.zMaximum()
371 << box.zMinimum()
372 << box.zMinimum()
373 << box.zMaximum()
374 << box.zMaximum() );
375 std::unique_ptr< QgsPolygon > polygon6 = std::make_unique< QgsPolygon >( ext6.release() );
376 multiPolygon->addGeometry( polygon6.release() );
377
378 return QgsGeometry( std::move( multiPolygon ) );
379}
380
381QgsGeometry QgsGeometry::collectGeometry( const QVector< QgsGeometry > &geometries )
382{
383 QgsGeometry collected;
384
385 for ( const QgsGeometry &g : geometries )
386 {
387 if ( collected.isNull() )
388 {
389 collected = g;
390 collected.convertToMultiType();
391 }
392 else
393 {
394 if ( g.isMultipart() )
395 {
396 for ( auto p = g.const_parts_begin(); p != g.const_parts_end(); ++p )
397 {
398 collected.addPart( ( *p )->clone() );
399 }
400 }
401 else
402 {
403 collected.addPart( g );
404 }
405 }
406 }
407 return collected;
408}
409
410QgsGeometry QgsGeometry::createWedgeBuffer( const QgsPoint &center, const double azimuth, const double angularWidth, const double outerRadius, const double innerRadius )
411{
412 if ( std::abs( angularWidth ) >= 360.0 )
413 {
414 std::unique_ptr< QgsCompoundCurve > outerCc = std::make_unique< QgsCompoundCurve >();
415
416 QgsCircle outerCircle = QgsCircle( center, outerRadius );
417 outerCc->addCurve( outerCircle.toCircularString() );
418
419 std::unique_ptr< QgsCurvePolygon > cp = std::make_unique< QgsCurvePolygon >();
420 cp->setExteriorRing( outerCc.release() );
421
422 if ( !qgsDoubleNear( innerRadius, 0.0 ) && innerRadius > 0 )
423 {
424 std::unique_ptr< QgsCompoundCurve > innerCc = std::make_unique< QgsCompoundCurve >();
425
426 QgsCircle innerCircle = QgsCircle( center, innerRadius );
427 innerCc->addCurve( innerCircle.toCircularString() );
428
429 cp->setInteriorRings( { innerCc.release() } );
430 }
431
432 return QgsGeometry( std::move( cp ) );
433 }
434
435 std::unique_ptr< QgsCompoundCurve > wedge = std::make_unique< QgsCompoundCurve >();
436
437 const double startAngle = azimuth - angularWidth * 0.5;
438 const double endAngle = azimuth + angularWidth * 0.5;
439
440 const QgsPoint outerP1 = center.project( outerRadius, startAngle );
441 const QgsPoint outerP2 = center.project( outerRadius, endAngle );
442
443 const bool useShortestArc = angularWidth <= 180.0;
444
445 wedge->addCurve( new QgsCircularString( QgsCircularString::fromTwoPointsAndCenter( outerP1, outerP2, center, useShortestArc ) ) );
446
447 if ( !qgsDoubleNear( innerRadius, 0.0 ) && innerRadius > 0 )
448 {
449 const QgsPoint innerP1 = center.project( innerRadius, startAngle );
450 const QgsPoint innerP2 = center.project( innerRadius, endAngle );
451 wedge->addCurve( new QgsLineString( outerP2, innerP2 ) );
452 wedge->addCurve( new QgsCircularString( QgsCircularString::fromTwoPointsAndCenter( innerP2, innerP1, center, useShortestArc ) ) );
453 wedge->addCurve( new QgsLineString( innerP1, outerP1 ) );
454 }
455 else
456 {
457 wedge->addCurve( new QgsLineString( outerP2, center ) );
458 wedge->addCurve( new QgsLineString( center, outerP1 ) );
459 }
460
461 std::unique_ptr< QgsCurvePolygon > cp = std::make_unique< QgsCurvePolygon >();
462 cp->setExteriorRing( wedge.release() );
463 return QgsGeometry( std::move( cp ) );
464}
465
466void QgsGeometry::fromWkb( unsigned char *wkb, int length )
467{
468 QgsConstWkbPtr ptr( wkb, length );
469 reset( QgsGeometryFactory::geomFromWkb( ptr ) );
470 delete [] wkb;
471}
472
473void QgsGeometry::fromWkb( const QByteArray &wkb )
474{
475 QgsConstWkbPtr ptr( wkb );
476 reset( QgsGeometryFactory::geomFromWkb( ptr ) );
477}
478
480{
481 if ( !d->geometry )
482 {
484 }
485 else
486 {
487 return d->geometry->wkbType();
488 }
489}
490
491
493{
494 if ( !d->geometry )
495 {
497 }
498 return QgsWkbTypes::geometryType( d->geometry->wkbType() );
499}
500
502{
503 if ( !d->geometry )
504 {
505 return true;
506 }
507
508 return d->geometry->isEmpty();
509}
510
512{
513 if ( !d->geometry )
514 {
515 return false;
516 }
517 return QgsWkbTypes::isMultiType( d->geometry->wkbType() );
518}
519QgsPointXY QgsGeometry::closestVertex( const QgsPointXY &point, int &closestVertexIndex, int &previousVertexIndex, int &nextVertexIndex, double &sqrDist ) const
520{
521 if ( !d->geometry )
522 {
523 sqrDist = -1;
524 return QgsPointXY();
525 }
526
527 QgsPoint pt( point );
528 QgsVertexId id;
529
530 QgsPoint vp = QgsGeometryUtils::closestVertex( *( d->geometry ), pt, id );
531 if ( !id.isValid() )
532 {
533 sqrDist = -1;
534 return QgsPointXY();
535 }
536 sqrDist = QgsGeometryUtils::sqrDistance2D( pt, vp );
537
538 QgsVertexId prevVertex;
539 QgsVertexId nextVertex;
540 d->geometry->adjacentVertices( id, prevVertex, nextVertex );
541 closestVertexIndex = vertexNrFromVertexId( id );
542 previousVertexIndex = vertexNrFromVertexId( prevVertex );
543 nextVertexIndex = vertexNrFromVertexId( nextVertex );
544 return QgsPointXY( vp.x(), vp.y() );
545}
546
547double QgsGeometry::distanceToVertex( int vertex ) const
548{
549 if ( !d->geometry )
550 {
551 return -1;
552 }
553
554 QgsVertexId id;
555 if ( !vertexIdFromVertexNr( vertex, id ) )
556 {
557 return -1;
558 }
559
560 return QgsGeometryUtils::distanceToVertex( *( d->geometry ), id );
561}
562
563double QgsGeometry::angleAtVertex( int vertex ) const
564{
565 if ( !d->geometry )
566 {
567 return 0;
568 }
569
570 QgsVertexId v2;
571 if ( !vertexIdFromVertexNr( vertex, v2 ) )
572 {
573 return 0;
574 }
575
576 return d->geometry->vertexAngle( v2 );
577}
578
579void QgsGeometry::adjacentVertices( int atVertex, int &beforeVertex, int &afterVertex ) const
580{
581 if ( !d->geometry )
582 {
583 return;
584 }
585
586 QgsVertexId id;
587 if ( !vertexIdFromVertexNr( atVertex, id ) )
588 {
589 beforeVertex = -1;
590 afterVertex = -1;
591 return;
592 }
593
594 QgsVertexId beforeVertexId, afterVertexId;
595 d->geometry->adjacentVertices( id, beforeVertexId, afterVertexId );
596 beforeVertex = vertexNrFromVertexId( beforeVertexId );
597 afterVertex = vertexNrFromVertexId( afterVertexId );
598}
599
600bool QgsGeometry::moveVertex( double x, double y, int atVertex )
601{
602 if ( !d->geometry )
603 {
604 return false;
605 }
606
607 QgsVertexId id;
608 if ( !vertexIdFromVertexNr( atVertex, id ) )
609 {
610 return false;
611 }
612
613 detach();
614
615 return d->geometry->moveVertex( id, QgsPoint( x, y ) );
616}
617
618bool QgsGeometry::moveVertex( const QgsPoint &p, int atVertex )
619{
620 if ( !d->geometry )
621 {
622 return false;
623 }
624
625 QgsVertexId id;
626 if ( !vertexIdFromVertexNr( atVertex, id ) )
627 {
628 return false;
629 }
630
631 detach();
632
633 return d->geometry->moveVertex( id, p );
634}
635
636bool QgsGeometry::deleteVertex( int atVertex )
637{
638 if ( !d->geometry )
639 {
640 return false;
641 }
642
643 //maintain compatibility with < 2.10 API
645 {
646 detach();
647 //delete geometry instead of point
648 return static_cast< QgsGeometryCollection * >( d->geometry.get() )->removeGeometry( atVertex );
649 }
650
651 //if it is a point, set the geometry to nullptr
652 if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == Qgis::WkbType::Point )
653 {
654 reset( nullptr );
655 return true;
656 }
657
658 QgsVertexId id;
659 if ( !vertexIdFromVertexNr( atVertex, id ) )
660 {
661 return false;
662 }
663
664 detach();
665
666 return d->geometry->deleteVertex( id );
667}
668
670{
671
672 if ( !d->geometry )
673 return false;
674
675 QgsVertexId id;
676 if ( !vertexIdFromVertexNr( atVertex, id ) )
677 return false;
678
679 detach();
680
681 QgsAbstractGeometry *geom = d->geometry.get();
682
683 // If the geom is a collection, we get the concerned part, otherwise, the part is just the whole geom
684 QgsAbstractGeometry *part = nullptr;
685 QgsGeometryCollection *owningCollection = qgsgeometry_cast<QgsGeometryCollection *>( geom );
686 if ( owningCollection != nullptr )
687 part = owningCollection->geometryN( id.part );
688 else
689 part = geom;
690
691 // If the part is a polygon, we get the concerned ring, otherwise, the ring is just the whole part
692 QgsAbstractGeometry *ring = nullptr;
693 QgsCurvePolygon *owningPolygon = qgsgeometry_cast<QgsCurvePolygon *>( part );
694 if ( owningPolygon != nullptr )
695 ring = ( id.ring == 0 ) ? owningPolygon->exteriorRing() : owningPolygon->interiorRing( id.ring - 1 );
696 else
697 ring = part;
698
699 // If the ring is not a curve, we're probably on a point geometry
700 QgsCurve *curve = qgsgeometry_cast<QgsCurve *>( ring );
701 if ( curve == nullptr )
702 return false;
703
704 bool success = false;
705 QgsCompoundCurve *cpdCurve = qgsgeometry_cast<QgsCompoundCurve *>( curve );
706 if ( cpdCurve != nullptr )
707 {
708 // If the geom is a already compound curve, we convert inplace, and we're done
709 success = cpdCurve->toggleCircularAtVertex( id );
710 }
711 else
712 {
713 // TODO : move this block before the above, so we call toggleCircularAtVertex only in one place
714 // If the geom is a linestring or cirularstring, we create a compound curve
715 std::unique_ptr<QgsCompoundCurve> cpdCurve = std::make_unique<QgsCompoundCurve>();
716 cpdCurve->addCurve( curve->clone() );
717 success = cpdCurve->toggleCircularAtVertex( QgsVertexId( -1, -1, id.vertex ) );
718
719 // In that case, we must also reassign the instances
720 if ( success )
721 {
722 if ( owningPolygon == nullptr && owningCollection == nullptr )
723 {
724 // Standalone linestring
725 reset( std::make_unique<QgsCompoundCurve>( *cpdCurve ) ); // <- REVIEW PLZ
726 }
727 else if ( owningPolygon != nullptr )
728 {
729 // Replace the ring in the owning polygon
730 if ( id.ring == 0 )
731 {
732 owningPolygon->setExteriorRing( cpdCurve.release() );
733 }
734 else
735 {
736 owningPolygon->removeInteriorRing( id.ring - 1 );
737 owningPolygon->addInteriorRing( cpdCurve.release() );
738 }
739 }
740 else if ( owningCollection != nullptr )
741 {
742 // Replace the curve in the owning collection
743 owningCollection->removeGeometry( id.part );
744 owningCollection->insertGeometry( cpdCurve.release(), id.part );
745 }
746 }
747 }
748
749 return success;
750}
751
752bool QgsGeometry::insertVertex( double x, double y, int beforeVertex )
753{
754 if ( !d->geometry )
755 {
756 return false;
757 }
758
759 //maintain compatibility with < 2.10 API
761 {
762 detach();
763 //insert geometry instead of point
764 return static_cast< QgsGeometryCollection * >( d->geometry.get() )->insertGeometry( new QgsPoint( x, y ), beforeVertex );
765 }
766
767 QgsVertexId id;
768 if ( !vertexIdFromVertexNr( beforeVertex, id ) )
769 {
770 return false;
771 }
772
773 detach();
774
775 return d->geometry->insertVertex( id, QgsPoint( x, y ) );
776}
777
778bool QgsGeometry::insertVertex( const QgsPoint &point, int beforeVertex )
779{
780 if ( !d->geometry )
781 {
782 return false;
783 }
784
785 //maintain compatibility with < 2.10 API
787 {
788 detach();
789 //insert geometry instead of point
790 return static_cast< QgsGeometryCollection * >( d->geometry.get() )->insertGeometry( new QgsPoint( point ), beforeVertex );
791 }
792
793 QgsVertexId id;
794 if ( !vertexIdFromVertexNr( beforeVertex, id ) )
795 {
796 return false;
797 }
798
799 detach();
800
801 return d->geometry->insertVertex( id, point );
802}
803
804QgsPoint QgsGeometry::vertexAt( int atVertex ) const
805{
806 if ( !d->geometry )
807 {
808 return QgsPoint();
809 }
810
811 QgsVertexId vId;
812 ( void )vertexIdFromVertexNr( atVertex, vId );
813 if ( vId.vertex < 0 )
814 {
815 return QgsPoint();
816 }
817 return d->geometry->vertexAt( vId );
818}
819
820double QgsGeometry::sqrDistToVertexAt( QgsPointXY &point, int atVertex ) const
821{
822 QgsPointXY vertexPoint = vertexAt( atVertex );
823 return QgsGeometryUtils::sqrDistance2D( QgsPoint( vertexPoint ), QgsPoint( point ) );
824}
825
827{
828 // avoid calling geos for trivial point calculations
829 if ( d->geometry && QgsWkbTypes::flatType( d->geometry->wkbType() ) == Qgis::WkbType::Point )
830 {
831 return QgsGeometry( qgsgeometry_cast< const QgsPoint * >( d->geometry.get() )->clone() );
832 }
833
834 QgsGeos geos( d->geometry.get() );
835 mLastError.clear();
836 QgsGeometry result = geos.closestPoint( other );
837 result.mLastError = mLastError;
838 return result;
839}
840
842{
843 // avoid calling geos for trivial point-to-point line calculations
845 {
846 return QgsGeometry( std::make_unique< QgsLineString >( *qgsgeometry_cast< const QgsPoint * >( d->geometry.get() ), *qgsgeometry_cast< const QgsPoint * >( other.constGet() ) ) );
847 }
848
849 QgsGeos geos( d->geometry.get() );
850 mLastError.clear();
851 QgsGeometry result = geos.shortestLine( other, &mLastError );
852 result.mLastError = mLastError;
853 return result;
854}
855
856double QgsGeometry::closestVertexWithContext( const QgsPointXY &point, int &atVertex ) const
857{
858 if ( !d->geometry )
859 {
860 return -1;
861 }
862
863 QgsVertexId vId;
864 QgsPoint pt( point );
865 QgsPoint closestPoint = QgsGeometryUtils::closestVertex( *( d->geometry ), pt, vId );
866 if ( !vId.isValid() )
867 return -1;
868 atVertex = vertexNrFromVertexId( vId );
869 return QgsGeometryUtils::sqrDistance2D( closestPoint, pt );
870}
871
873 QgsPointXY &minDistPoint,
874 int &nextVertexIndex,
875 int *leftOrRightOfSegment,
876 double epsilon ) const
877{
878 if ( !d->geometry )
879 {
880 return -1;
881 }
882
883 QgsPoint segmentPt;
884 QgsVertexId vertexAfter;
885
886 double sqrDist = d->geometry->closestSegment( QgsPoint( point ), segmentPt, vertexAfter, leftOrRightOfSegment, epsilon );
887 if ( sqrDist < 0 )
888 return -1;
889
890 minDistPoint.setX( segmentPt.x() );
891 minDistPoint.setY( segmentPt.y() );
892 nextVertexIndex = vertexNrFromVertexId( vertexAfter );
893 return sqrDist;
894}
895
896Qgis::GeometryOperationResult QgsGeometry::addRing( const QVector<QgsPointXY> &ring )
897{
898 std::unique_ptr< QgsLineString > ringLine = std::make_unique< QgsLineString >( ring );
899 return addRing( ringLine.release() );
900}
901
903{
904 std::unique_ptr< QgsCurve > r( ring );
905 if ( !d->geometry )
906 {
908 }
909
910 detach();
911
912 return QgsGeometryEditUtils::addRing( d->geometry.get(), std::move( r ) );
913}
914
915Qgis::GeometryOperationResult QgsGeometry::addPart( const QVector<QgsPointXY> &points, Qgis::GeometryType geomType )
916{
918 convertPointList( points, l );
919 return addPart( l, geomType );
920}
921
923{
924 std::unique_ptr< QgsAbstractGeometry > partGeom;
925 if ( points.size() == 1 )
926 {
927 partGeom = std::make_unique< QgsPoint >( points[0] );
928 }
929 else if ( points.size() > 1 )
930 {
931 std::unique_ptr< QgsLineString > ringLine = std::make_unique< QgsLineString >();
932 ringLine->setPoints( points );
933 partGeom = std::move( ringLine );
934 }
935 return addPart( partGeom.release(), geomType );
936}
937
939{
940 std::unique_ptr< QgsAbstractGeometry > p( part );
941 if ( !d->geometry )
942 {
943 switch ( geomType )
944 {
946 reset( std::make_unique< QgsMultiPoint >() );
947 break;
949 reset( std::make_unique< QgsMultiLineString >() );
950 break;
952 reset( std::make_unique< QgsMultiPolygon >() );
953 break;
954 default:
955 reset( nullptr );
957 }
958 }
959 else
960 {
961 detach();
962 }
963
965 return QgsGeometryEditUtils::addPart( d->geometry.get(), std::move( p ) );
966}
967
969{
970 if ( !d->geometry )
971 {
973 }
974 if ( newPart.isNull() || !newPart.d->geometry )
975 {
977 }
978
979 return addPart( newPart.d->geometry->clone() );
980}
981
982QgsGeometry QgsGeometry::removeInteriorRings( double minimumRingArea ) const
983{
984 if ( !d->geometry || type() != Qgis::GeometryType::Polygon )
985 {
986 return QgsGeometry();
987 }
988
989 if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
990 {
991 const QVector<QgsGeometry> parts = asGeometryCollection();
992 QVector<QgsGeometry> results;
993 results.reserve( parts.count() );
994 for ( const QgsGeometry &part : parts )
995 {
996 QgsGeometry result = part.removeInteriorRings( minimumRingArea );
997 if ( !result.isNull() )
998 results << result;
999 }
1000 if ( results.isEmpty() )
1001 return QgsGeometry();
1002
1003 QgsGeometry first = results.takeAt( 0 );
1004 for ( const QgsGeometry &result : std::as_const( results ) )
1005 {
1006 first.addPart( result );
1007 }
1008 return first;
1009 }
1010 else
1011 {
1012 std::unique_ptr< QgsCurvePolygon > newPoly( static_cast< QgsCurvePolygon * >( d->geometry->clone() ) );
1013 newPoly->removeInteriorRings( minimumRingArea );
1014 return QgsGeometry( std::move( newPoly ) );
1015 }
1016}
1017
1018Qgis::GeometryOperationResult QgsGeometry::translate( double dx, double dy, double dz, double dm )
1019{
1020 if ( !d->geometry )
1021 {
1023 }
1024
1025 detach();
1026
1027 d->geometry->transform( QTransform::fromTranslate( dx, dy ), dz, 1.0, dm );
1029}
1030
1032{
1033 if ( !d->geometry )
1034 {
1036 }
1037
1038 detach();
1039
1040 QTransform t = QTransform::fromTranslate( center.x(), center.y() );
1041 t.rotate( -rotation );
1042 t.translate( -center.x(), -center.y() );
1043 d->geometry->transform( t );
1045}
1046
1047Qgis::GeometryOperationResult QgsGeometry::splitGeometry( const QVector<QgsPointXY> &splitLine, QVector<QgsGeometry> &newGeometries, bool topological, QVector<QgsPointXY> &topologyTestPoints, bool splitFeature )
1048{
1049 QgsPointSequence split, topology;
1050 convertPointList( splitLine, split );
1051 convertPointList( topologyTestPoints, topology );
1052 Qgis::GeometryOperationResult result = splitGeometry( split, newGeometries, topological, topology, splitFeature );
1053 convertPointList( topology, topologyTestPoints );
1054 return result;
1055}
1056Qgis::GeometryOperationResult QgsGeometry::splitGeometry( const QgsPointSequence &splitLine, QVector<QgsGeometry> &newGeometries, bool topological, QgsPointSequence &topologyTestPoints, bool splitFeature, bool skipIntersectionTest )
1057{
1058 if ( !d->geometry )
1059 {
1061 }
1062
1063 QVector<QgsGeometry > newGeoms;
1064 QgsLineString splitLineString( splitLine );
1065
1066 QgsGeos geos( d->geometry.get() );
1067 mLastError.clear();
1068 QgsGeometryEngine::EngineOperationResult result = geos.splitGeometry( splitLineString, newGeoms, topological, topologyTestPoints, &mLastError, skipIntersectionTest );
1069
1070 if ( result == QgsGeometryEngine::Success )
1071 {
1072 if ( splitFeature )
1073 *this = newGeoms.takeAt( 0 );
1074 newGeometries = newGeoms;
1075 }
1076
1077 switch ( result )
1078 {
1093 //default: do not implement default to handle properly all cases
1094 }
1095
1096 // this should never be reached
1097 Q_ASSERT( false );
1099}
1100
1101Qgis::GeometryOperationResult QgsGeometry::splitGeometry( const QgsCurve *curve, QVector<QgsGeometry> &newGeometries, bool preserveCircular, bool topological, QgsPointSequence &topologyTestPoints, bool splitFeature )
1102{
1103 std::unique_ptr<QgsLineString> segmentizedLine( curve->curveToLine() );
1104 QgsPointSequence points;
1105 segmentizedLine->points( points );
1106 Qgis::GeometryOperationResult result = splitGeometry( points, newGeometries, topological, topologyTestPoints, splitFeature );
1107
1109 {
1110 if ( preserveCircular )
1111 {
1112 for ( int i = 0; i < newGeometries.count(); ++i )
1113 newGeometries[i] = newGeometries[i].convertToCurves();
1114 *this = convertToCurves();
1115 }
1116 }
1117
1118 return result;
1119}
1120
1122{
1123 if ( !d->geometry )
1124 {
1126 }
1127
1128 QgsGeos geos( d->geometry.get() );
1130 mLastError.clear();
1131 std::unique_ptr< QgsAbstractGeometry > geom( geos.reshapeGeometry( reshapeLineString, &errorCode, &mLastError ) );
1132 if ( errorCode == QgsGeometryEngine::Success && geom )
1133 {
1134 reset( std::move( geom ) );
1136 }
1137
1138 switch ( errorCode )
1139 {
1150 case QgsGeometryEngine::SplitCannotSplitPoint: // should not happen
1154 }
1155
1156 // should not be reached
1158}
1159
1161{
1162 if ( !d->geometry || !other.d->geometry )
1163 {
1164 return 0;
1165 }
1166
1167 QgsGeos geos( d->geometry.get() );
1168
1169 mLastError.clear();
1170 std::unique_ptr< QgsAbstractGeometry > diffGeom( geos.intersection( other.constGet(), &mLastError ) );
1171 if ( !diffGeom )
1172 {
1173 return 1;
1174 }
1175
1176 reset( std::move( diffGeom ) );
1177 return 0;
1178}
1179
1181{
1182 if ( !d->geometry || other.isNull() )
1183 {
1184 return QgsGeometry();
1185 }
1186
1187 QgsGeos geos( d->geometry.get() );
1188
1189 mLastError.clear();
1190 std::unique_ptr< QgsAbstractGeometry > diffGeom( geos.intersection( other.constGet(), &mLastError ) );
1191 if ( !diffGeom )
1192 {
1193 QgsGeometry result;
1194 result.mLastError = mLastError;
1195 return result;
1196 }
1197
1198 return QgsGeometry( diffGeom.release() );
1199}
1200
1202{
1203 if ( d->geometry )
1204 {
1205 return d->geometry->boundingBox();
1206 }
1207 return QgsRectangle();
1208}
1209
1211{
1212 if ( d->geometry )
1213 {
1214 return d->geometry->boundingBox3D();
1215 }
1216 return QgsBox3D();
1217}
1218
1219
1220QgsGeometry QgsGeometry::orientedMinimumBoundingBox( double &area, double &angle, double &width, double &height ) const
1221{
1222 mLastError.clear();
1223 QgsInternalGeometryEngine engine( *this );
1224 const QgsGeometry res = engine.orientedMinimumBoundingBox( area, angle, width, height );
1225 if ( res.isNull() )
1226 mLastError = engine.lastError();
1227 return res;
1228}
1229
1231{
1232 double area, angle, width, height;
1233 return orientedMinimumBoundingBox( area, angle, width, height );
1234}
1235
1236static QgsCircle __recMinimalEnclosingCircle( QgsMultiPointXY points, QgsMultiPointXY boundary )
1237{
1238 auto l_boundary = boundary.length();
1239 QgsCircle circ_mec;
1240 if ( ( points.length() == 0 ) || ( l_boundary == 3 ) )
1241 {
1242 switch ( l_boundary )
1243 {
1244 case 0:
1245 circ_mec = QgsCircle();
1246 break;
1247 case 1:
1248 circ_mec = QgsCircle( QgsPoint( boundary.last() ), 0 );
1249 boundary.pop_back();
1250 break;
1251 case 2:
1252 {
1253 QgsPointXY p1 = boundary.last();
1254 boundary.pop_back();
1255 QgsPointXY p2 = boundary.last();
1256 boundary.pop_back();
1257 circ_mec = QgsCircle::from2Points( QgsPoint( p1 ), QgsPoint( p2 ) );
1258 }
1259 break;
1260 default:
1261 QgsPoint p1( boundary.at( 0 ) );
1262 QgsPoint p2( boundary.at( 1 ) );
1263 QgsPoint p3( boundary.at( 2 ) );
1264 circ_mec = QgsCircle::minimalCircleFrom3Points( p1, p2, p3 );
1265 break;
1266 }
1267 return circ_mec;
1268 }
1269 else
1270 {
1271 QgsPointXY pxy = points.last();
1272 points.pop_back();
1273 circ_mec = __recMinimalEnclosingCircle( points, boundary );
1274 QgsPoint p( pxy );
1275 if ( !circ_mec.contains( p ) )
1276 {
1277 boundary.append( pxy );
1278 circ_mec = __recMinimalEnclosingCircle( points, boundary );
1279 }
1280 }
1281 return circ_mec;
1282}
1283
1284QgsGeometry QgsGeometry::minimalEnclosingCircle( QgsPointXY &center, double &radius, unsigned int segments ) const
1285{
1286 center = QgsPointXY();
1287 radius = 0;
1288
1289 if ( isEmpty() )
1290 {
1291 return QgsGeometry();
1292 }
1293
1294 /* optimization */
1295 QgsGeometry hull = convexHull();
1296 if ( hull.isNull() )
1297 return QgsGeometry();
1298
1299 QgsMultiPointXY P = hull.convertToPoint( true ).asMultiPoint();
1301
1302 QgsCircle circ = __recMinimalEnclosingCircle( P, R );
1303 center = QgsPointXY( circ.center() );
1304 radius = circ.radius();
1305 QgsGeometry geom;
1306 geom.set( circ.toPolygon( segments ) );
1307 return geom;
1308
1309}
1310
1312{
1313 QgsPointXY center;
1314 double radius;
1315 return minimalEnclosingCircle( center, radius, segments );
1316
1317}
1318
1319QgsGeometry QgsGeometry::orthogonalize( double tolerance, int maxIterations, double angleThreshold ) const
1320{
1321 QgsInternalGeometryEngine engine( *this );
1322
1323 return engine.orthogonalize( tolerance, maxIterations, angleThreshold );
1324}
1325
1326QgsGeometry QgsGeometry::triangularWaves( double wavelength, double amplitude, bool strictWavelength ) const
1327{
1328 QgsInternalGeometryEngine engine( *this );
1329 return engine.triangularWaves( wavelength, amplitude, strictWavelength );
1330}
1331
1332QgsGeometry QgsGeometry::triangularWavesRandomized( double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed ) const
1333{
1334 QgsInternalGeometryEngine engine( *this );
1335 return engine.triangularWavesRandomized( minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, seed );
1336}
1337
1338QgsGeometry QgsGeometry::squareWaves( double wavelength, double amplitude, bool strictWavelength ) const
1339{
1340 QgsInternalGeometryEngine engine( *this );
1341 return engine.squareWaves( wavelength, amplitude, strictWavelength );
1342}
1343
1344QgsGeometry QgsGeometry::squareWavesRandomized( double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed ) const
1345{
1346 QgsInternalGeometryEngine engine( *this );
1347 return engine.squareWavesRandomized( minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, seed );
1348}
1349
1350QgsGeometry QgsGeometry::roundWaves( double wavelength, double amplitude, bool strictWavelength ) const
1351{
1352 QgsInternalGeometryEngine engine( *this );
1353 return engine.roundWaves( wavelength, amplitude, strictWavelength );
1354}
1355
1356QgsGeometry QgsGeometry::roundWavesRandomized( double minimumWavelength, double maximumWavelength, double minimumAmplitude, double maximumAmplitude, unsigned long seed ) const
1357{
1358 QgsInternalGeometryEngine engine( *this );
1359 return engine.roundWavesRandomized( minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, seed );
1360}
1361
1362QgsGeometry QgsGeometry::applyDashPattern( const QVector<double> &pattern, Qgis::DashPatternLineEndingRule startRule, Qgis::DashPatternLineEndingRule endRule, Qgis::DashPatternSizeAdjustment adjustment, double patternOffset ) const
1363{
1364 QgsInternalGeometryEngine engine( *this );
1365 return engine.applyDashPattern( pattern, startRule, endRule, adjustment, patternOffset );
1366}
1367
1368QgsGeometry QgsGeometry::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing ) const
1369{
1370 if ( !d->geometry )
1371 {
1372 return QgsGeometry();
1373 }
1374 return QgsGeometry( d->geometry->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing ) );
1375}
1376
1377bool QgsGeometry::removeDuplicateNodes( double epsilon, bool useZValues )
1378{
1379 if ( !d->geometry )
1380 return false;
1381
1382 detach();
1383 return d->geometry->removeDuplicateNodes( epsilon, useZValues );
1384}
1385
1387{
1388 // fast case, check bounding boxes
1389 if ( !boundingBoxIntersects( r ) )
1390 return false;
1391
1392 const Qgis::WkbType flatType { QgsWkbTypes::flatType( d->geometry->wkbType() ) };
1393 // optimise trivial case for point intersections -- the bounding box test has already given us the answer
1394 if ( flatType == Qgis::WkbType::Point )
1395 {
1396 return true;
1397 }
1398
1399 // Workaround for issue issue GH #51429
1400 // in case of multi polygon, intersection with an empty rect fails
1401 if ( flatType == Qgis::WkbType::MultiPolygon && r.isEmpty() )
1402 {
1403 const QgsPointXY center { r.xMinimum(), r.yMinimum() };
1404 return contains( QgsGeometry::fromPointXY( center ) );
1405 }
1406
1407 QgsGeometry g = fromRect( r );
1408 return intersects( g );
1409}
1410
1411bool QgsGeometry::intersects( const QgsGeometry &geometry ) const
1412{
1413 if ( !d->geometry || geometry.isNull() )
1414 {
1415 return false;
1416 }
1417
1418 QgsGeos geos( d->geometry.get() );
1419 mLastError.clear();
1420 return geos.intersects( geometry.d->geometry.get(), &mLastError );
1421}
1422
1424{
1425 if ( !d->geometry )
1426 {
1427 return false;
1428 }
1429
1430 return d->geometry->boundingBoxIntersects( rectangle );
1431}
1432
1434{
1435 if ( !d->geometry || geometry.isNull() )
1436 {
1437 return false;
1438 }
1439
1440 return d->geometry->boundingBoxIntersects( geometry.constGet()->boundingBox() );
1441}
1442
1443bool QgsGeometry::contains( const QgsPointXY *p ) const
1444{
1445 if ( !d->geometry || !p )
1446 {
1447 return false;
1448 }
1449
1450 QgsPoint pt( p->x(), p->y() );
1451 QgsGeos geos( d->geometry.get() );
1452 mLastError.clear();
1453 return geos.contains( &pt, &mLastError );
1454}
1455
1456bool QgsGeometry::contains( const QgsGeometry &geometry ) const
1457{
1458 if ( !d->geometry || geometry.isNull() )
1459 {
1460 return false;
1461 }
1462
1463 QgsGeos geos( d->geometry.get() );
1464 mLastError.clear();
1465 return geos.contains( geometry.d->geometry.get(), &mLastError );
1466}
1467
1468bool QgsGeometry::disjoint( const QgsGeometry &geometry ) const
1469{
1470 if ( !d->geometry || geometry.isNull() )
1471 {
1472 return false;
1473 }
1474
1475 QgsGeos geos( d->geometry.get() );
1476 mLastError.clear();
1477 return geos.disjoint( geometry.d->geometry.get(), &mLastError );
1478}
1479
1480bool QgsGeometry::equals( const QgsGeometry &geometry ) const
1481{
1482 if ( !d->geometry || geometry.isNull() )
1483 {
1484 return false;
1485 }
1486
1487 // fast check - are they shared copies of the same underlying geometry?
1488 if ( d == geometry.d )
1489 return true;
1490
1491 // fast check - distinct geometry types?
1492 if ( type() != geometry.type() )
1493 return false;
1494
1495 // slower check - actually test the geometries
1496 return *d->geometry == *geometry.d->geometry;
1497}
1498
1499bool QgsGeometry::touches( const QgsGeometry &geometry ) const
1500{
1501 if ( !d->geometry || geometry.isNull() )
1502 {
1503 return false;
1504 }
1505
1506 QgsGeos geos( d->geometry.get() );
1507 mLastError.clear();
1508 return geos.touches( geometry.d->geometry.get(), &mLastError );
1509}
1510
1511bool QgsGeometry::overlaps( const QgsGeometry &geometry ) const
1512{
1513 if ( !d->geometry || geometry.isNull() )
1514 {
1515 return false;
1516 }
1517
1518 QgsGeos geos( d->geometry.get() );
1519 mLastError.clear();
1520 return geos.overlaps( geometry.d->geometry.get(), &mLastError );
1521}
1522
1523bool QgsGeometry::within( const QgsGeometry &geometry ) const
1524{
1525 if ( !d->geometry || geometry.isNull() )
1526 {
1527 return false;
1528 }
1529
1530 QgsGeos geos( d->geometry.get() );
1531 mLastError.clear();
1532 return geos.within( geometry.d->geometry.get(), &mLastError );
1533}
1534
1535bool QgsGeometry::crosses( const QgsGeometry &geometry ) const
1536{
1537 if ( !d->geometry || geometry.isNull() )
1538 {
1539 return false;
1540 }
1541
1542 QgsGeos geos( d->geometry.get() );
1543 mLastError.clear();
1544 return geos.crosses( geometry.d->geometry.get(), &mLastError );
1545}
1546
1547QString QgsGeometry::asWkt( int precision ) const
1548{
1549 if ( !d->geometry )
1550 {
1551 return QString();
1552 }
1553 return d->geometry->asWkt( precision );
1554}
1555
1556QString QgsGeometry::asJson( int precision ) const
1557{
1558 return QString::fromStdString( asJsonObject( precision ).dump() );
1559}
1560
1562{
1563 if ( !d->geometry )
1564 {
1565 return nullptr;
1566 }
1567 return d->geometry->asJsonObject( precision );
1568
1569}
1570
1571QVector<QgsGeometry> QgsGeometry::coerceToType( const Qgis::WkbType type, double defaultZ, double defaultM ) const
1572{
1573 QVector< QgsGeometry > res;
1574 if ( isNull() )
1575 return res;
1576
1577 if ( wkbType() == type || type == Qgis::WkbType::Unknown )
1578 {
1579 res << *this;
1580 return res;
1581 }
1582
1584 {
1585 return res;
1586 }
1587
1588 QgsGeometry newGeom = *this;
1589
1590 // Curved -> straight
1592 {
1593 newGeom = QgsGeometry( d->geometry.get()->segmentize() );
1594 }
1595
1596 // polygon -> line
1598 newGeom.type() == Qgis::GeometryType::Polygon )
1599 {
1600 // boundary gives us a (multi)line string of exterior + interior rings
1601 newGeom = QgsGeometry( newGeom.constGet()->boundary() );
1602 }
1603 // line -> polygon
1605 newGeom.type() == Qgis::GeometryType::Line )
1606 {
1607 std::unique_ptr< QgsGeometryCollection > gc( QgsGeometryFactory::createCollectionOfType( type ) );
1608 const QgsGeometry source = newGeom;
1609 for ( auto part = source.const_parts_begin(); part != source.const_parts_end(); ++part )
1610 {
1611 std::unique_ptr< QgsAbstractGeometry > exterior( ( *part )->clone() );
1612 if ( QgsCurve *curve = qgsgeometry_cast< QgsCurve * >( exterior.get() ) )
1613 {
1615 {
1616 std::unique_ptr< QgsCurvePolygon > cp = std::make_unique< QgsCurvePolygon >();
1617 cp->setExteriorRing( curve );
1618 exterior.release();
1619 gc->addGeometry( cp.release() );
1620 }
1621 else
1622 {
1623 std::unique_ptr< QgsPolygon > p = std::make_unique< QgsPolygon >();
1624 p->setExteriorRing( qgsgeometry_cast< QgsLineString * >( curve ) );
1625 exterior.release();
1626 gc->addGeometry( p.release() );
1627 }
1628 }
1629 }
1630 newGeom = QgsGeometry( std::move( gc ) );
1631 }
1632
1633 // line/polygon -> points
1635 ( newGeom.type() == Qgis::GeometryType::Line ||
1636 newGeom.type() == Qgis::GeometryType::Polygon ) )
1637 {
1638 // lines/polygons to a point layer, extract all vertices
1639 std::unique_ptr< QgsMultiPoint > mp = std::make_unique< QgsMultiPoint >();
1640 const QgsGeometry source = newGeom;
1641 QSet< QgsPoint > added;
1642 for ( auto vertex = source.vertices_begin(); vertex != source.vertices_end(); ++vertex )
1643 {
1644 if ( added.contains( *vertex ) )
1645 continue; // avoid duplicate points, e.g. start/end of rings
1646 mp->addGeometry( ( *vertex ).clone() );
1647 added.insert( *vertex );
1648 }
1649 newGeom = QgsGeometry( std::move( mp ) );
1650 }
1651
1652 // Single -> multi
1653 if ( QgsWkbTypes::isMultiType( type ) && ! newGeom.isMultipart( ) )
1654 {
1655 newGeom.convertToMultiType();
1656 }
1657 // Drop Z/M
1658 if ( newGeom.constGet()->is3D() && ! QgsWkbTypes::hasZ( type ) )
1659 {
1660 newGeom.get()->dropZValue();
1661 }
1662 if ( newGeom.constGet()->isMeasure() && ! QgsWkbTypes::hasM( type ) )
1663 {
1664 newGeom.get()->dropMValue();
1665 }
1666 // Add Z/M back, set to 0
1667 if ( ! newGeom.constGet()->is3D() && QgsWkbTypes::hasZ( type ) )
1668 {
1669 newGeom.get()->addZValue( defaultZ );
1670 }
1671 if ( ! newGeom.constGet()->isMeasure() && QgsWkbTypes::hasM( type ) )
1672 {
1673 newGeom.get()->addMValue( defaultM );
1674 }
1675
1676 // Straight -> curve
1678 {
1679 newGeom.convertToCurvedMultiType();
1680 }
1681
1682 // Multi -> single
1683 if ( ! QgsWkbTypes::isMultiType( type ) && newGeom.isMultipart( ) )
1684 {
1685 const QgsGeometryCollection *parts( static_cast< const QgsGeometryCollection * >( newGeom.constGet() ) );
1686 res.reserve( parts->partCount() );
1687 for ( int i = 0; i < parts->partCount( ); i++ )
1688 {
1689 res << QgsGeometry( parts->geometryN( i )->clone() );
1690 }
1691 }
1692 else
1693 {
1694 res << newGeom;
1695 }
1696 return res;
1697}
1698
1699QgsGeometry QgsGeometry::convertToType( Qgis::GeometryType destType, bool destMultipart ) const
1700{
1701 switch ( destType )
1702 {
1704 return convertToPoint( destMultipart );
1705
1707 return convertToLine( destMultipart );
1708
1710 return convertToPolygon( destMultipart );
1711
1712 default:
1713 return QgsGeometry();
1714 }
1715}
1716
1718{
1719 if ( !d->geometry )
1720 {
1721 return false;
1722 }
1723
1724 if ( isMultipart() ) //already multitype, no need to convert
1725 {
1726 return true;
1727 }
1728
1729 std::unique_ptr< QgsAbstractGeometry >geom = QgsGeometryFactory::geomFromWkbType( QgsWkbTypes::multiType( d->geometry->wkbType() ) );
1730 QgsGeometryCollection *multiGeom = qgsgeometry_cast<QgsGeometryCollection *>( geom.get() );
1731 if ( !multiGeom )
1732 {
1733 return false;
1734 }
1735
1736 //try to avoid cloning existing geometry whenever we can
1737
1738 //want to see a magic trick?... gather round kiddies...
1739 detach(); // maybe a clone, hopefully not if we're the only ref to the private data
1740 // now we cheat a bit and steal the private geometry and add it direct to the multigeom
1741 // we can do this because we're the only ref to this geometry, guaranteed by the detach call above
1742 multiGeom->addGeometry( d->geometry.release() );
1743 // and replace it with the multi geometry.
1744 // TADA! a clone free conversion in some cases
1745 d->geometry = std::move( geom );
1746 return true;
1747}
1748
1750{
1751 if ( !d->geometry )
1752 {
1753 return false;
1754 }
1755
1756 switch ( QgsWkbTypes::flatType( d->geometry->wkbType() ) )
1757 {
1762 {
1763 return true;
1764 }
1765 default:
1766 break;
1767 }
1768
1769 std::unique_ptr< QgsAbstractGeometry >geom = QgsGeometryFactory::geomFromWkbType( QgsWkbTypes::curveType( QgsWkbTypes::multiType( d->geometry->wkbType() ) ) );
1770 QgsGeometryCollection *multiGeom = qgsgeometry_cast<QgsGeometryCollection *>( geom.get() );
1771 if ( !multiGeom )
1772 {
1773 return false;
1774 }
1775
1776 QgsGeometryCollection *sourceMultiGeom = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
1777 if ( sourceMultiGeom )
1778 {
1779 for ( int i = 0; i < sourceMultiGeom->numGeometries(); ++i )
1780 {
1781 if ( !multiGeom->addGeometry( sourceMultiGeom->geometryN( i )->clone() ) )
1782 return false;
1783 }
1784 }
1785 else
1786 {
1787 if ( !multiGeom->addGeometry( d->geometry->clone() ) )
1788 return false;
1789 }
1790
1791 reset( std::move( geom ) );
1792 return true;
1793}
1794
1796{
1797 if ( !d->geometry )
1798 {
1799 return false;
1800 }
1801
1802 if ( !isMultipart() ) //already single part, no need to convert
1803 {
1804 return true;
1805 }
1806
1807 QgsGeometryCollection *multiGeom = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
1808 if ( !multiGeom || multiGeom->partCount() < 1 )
1809 return false;
1810
1811 std::unique_ptr< QgsAbstractGeometry > firstPart( multiGeom->geometryN( 0 )->clone() );
1812 reset( std::move( firstPart ) );
1813 return true;
1814}
1815
1816
1818{
1819 const QgsGeometryCollection *origGeom = qgsgeometry_cast<const QgsGeometryCollection *>( constGet() );
1820 if ( !origGeom )
1821 return false;
1822
1823 std::unique_ptr<QgsGeometryCollection> resGeom;
1824 switch ( geomType )
1825 {
1827 resGeom = std::make_unique<QgsMultiPoint>();
1828 break;
1830 resGeom = std::make_unique<QgsMultiLineString>();
1831 break;
1833 resGeom = std::make_unique<QgsMultiPolygon>();
1834 break;
1835 default:
1836 break;
1837 }
1838 if ( !resGeom )
1839 return false;
1840
1841 resGeom->reserve( origGeom->numGeometries() );
1842 for ( int i = 0; i < origGeom->numGeometries(); ++i )
1843 {
1844 const QgsAbstractGeometry *g = origGeom->geometryN( i );
1845 if ( QgsWkbTypes::geometryType( g->wkbType() ) == geomType )
1846 resGeom->addGeometry( g->clone() );
1847 }
1848
1849 set( resGeom.release() );
1850 return true;
1851}
1852
1853
1855{
1856 if ( !d->geometry )
1857 {
1858 return QgsPointXY();
1859 }
1860 if ( QgsPoint *pt = qgsgeometry_cast<QgsPoint *>( d->geometry->simplifiedTypeRef() ) )
1861 {
1862 return QgsPointXY( pt->x(), pt->y() );
1863 }
1864 else
1865 {
1866 return QgsPointXY();
1867 }
1868}
1869
1871{
1872 QgsPolylineXY polyLine;
1873 if ( !d->geometry )
1874 {
1875 return polyLine;
1876 }
1877
1878 bool doSegmentation = ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == Qgis::WkbType::CompoundCurve
1880 std::unique_ptr< QgsLineString > segmentizedLine;
1881 QgsLineString *line = nullptr;
1882 if ( doSegmentation )
1883 {
1884 QgsCurve *curve = qgsgeometry_cast<QgsCurve *>( d->geometry.get() );
1885 if ( !curve )
1886 {
1887 return polyLine;
1888 }
1889 segmentizedLine.reset( curve->curveToLine() );
1890 line = segmentizedLine.get();
1891 }
1892 else
1893 {
1894 line = qgsgeometry_cast<QgsLineString *>( d->geometry.get() );
1895 if ( !line )
1896 {
1897 return polyLine;
1898 }
1899 }
1900
1901 int nVertices = line->numPoints();
1902 polyLine.resize( nVertices );
1903 QgsPointXY *data = polyLine.data();
1904 const double *xData = line->xData();
1905 const double *yData = line->yData();
1906 for ( int i = 0; i < nVertices; ++i )
1907 {
1908 data->setX( *xData++ );
1909 data->setY( *yData++ );
1910 data++;
1911 }
1912
1913 return polyLine;
1914}
1915
1917{
1918 if ( !d->geometry )
1919 return QgsPolygonXY();
1920
1921 bool doSegmentation = ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == Qgis::WkbType::CurvePolygon );
1922
1923 QgsPolygon *p = nullptr;
1924 std::unique_ptr< QgsPolygon > segmentized;
1925 if ( doSegmentation )
1926 {
1927 QgsCurvePolygon *curvePoly = qgsgeometry_cast<QgsCurvePolygon *>( d->geometry.get() );
1928 if ( !curvePoly )
1929 {
1930 return QgsPolygonXY();
1931 }
1932 segmentized.reset( curvePoly->toPolygon() );
1933 p = segmentized.get();
1934 }
1935 else
1936 {
1937 p = qgsgeometry_cast<QgsPolygon *>( d->geometry.get() );
1938 }
1939
1940 if ( !p )
1941 {
1942 return QgsPolygonXY();
1943 }
1944
1945 QgsPolygonXY polygon;
1946 convertPolygon( *p, polygon );
1947
1948 return polygon;
1949}
1950
1952{
1953 if ( !d->geometry || QgsWkbTypes::flatType( d->geometry->wkbType() ) != Qgis::WkbType::MultiPoint )
1954 {
1955 return QgsMultiPointXY();
1956 }
1957
1958 const QgsMultiPoint *mp = qgsgeometry_cast<QgsMultiPoint *>( d->geometry.get() );
1959 if ( !mp )
1960 {
1961 return QgsMultiPointXY();
1962 }
1963
1964 int nPoints = mp->numGeometries();
1965 QgsMultiPointXY multiPoint( nPoints );
1966 for ( int i = 0; i < nPoints; ++i )
1967 {
1968 const QgsPoint *pt = mp->pointN( i );
1969 multiPoint[i].setX( pt->x() );
1970 multiPoint[i].setY( pt->y() );
1971 }
1972 return multiPoint;
1973}
1974
1976{
1977 if ( !d->geometry )
1978 {
1979 return QgsMultiPolylineXY();
1980 }
1981
1982 QgsGeometryCollection *geomCollection = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
1983 if ( !geomCollection )
1984 {
1985 return QgsMultiPolylineXY();
1986 }
1987
1988 int nLines = geomCollection->numGeometries();
1989 if ( nLines < 1 )
1990 {
1991 return QgsMultiPolylineXY();
1992 }
1993
1995 mpl.reserve( nLines );
1996 for ( int i = 0; i < nLines; ++i )
1997 {
1998 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( geomCollection->geometryN( i ) );
1999 std::unique_ptr< QgsLineString > segmentized;
2000 if ( !line )
2001 {
2002 const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( geomCollection->geometryN( i ) );
2003 if ( !curve )
2004 {
2005 continue;
2006 }
2007 segmentized.reset( curve->curveToLine() );
2008 line = segmentized.get();
2009 }
2010
2011 QgsPolylineXY polyLine;
2012 int nVertices = line->numPoints();
2013 polyLine.resize( nVertices );
2014 QgsPointXY *data = polyLine.data();
2015 const double *xData = line->xData();
2016 const double *yData = line->yData();
2017 for ( int i = 0; i < nVertices; ++i )
2018 {
2019 data->setX( *xData++ );
2020 data->setY( *yData++ );
2021 data++;
2022 }
2023 mpl.append( polyLine );
2024 }
2025 return mpl;
2026}
2027
2029{
2030 if ( !d->geometry )
2031 {
2032 return QgsMultiPolygonXY();
2033 }
2034
2035 const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( d->geometry.get() );
2036 if ( !geomCollection )
2037 {
2038 return QgsMultiPolygonXY();
2039 }
2040
2041 const int nPolygons = geomCollection->numGeometries();
2042 if ( nPolygons < 1 )
2043 {
2044 return QgsMultiPolygonXY();
2045 }
2046
2048 mp.reserve( nPolygons );
2049 for ( int i = 0; i < nPolygons; ++i )
2050 {
2051 const QgsPolygon *polygon = qgsgeometry_cast<const QgsPolygon *>( geomCollection->geometryN( i ) );
2052 if ( !polygon )
2053 {
2054 const QgsCurvePolygon *cPolygon = qgsgeometry_cast<const QgsCurvePolygon *>( geomCollection->geometryN( i ) );
2055 if ( cPolygon )
2056 {
2057 polygon = cPolygon->toPolygon();
2058 }
2059 else
2060 {
2061 continue;
2062 }
2063 }
2064
2065 QgsPolygonXY poly;
2066 convertPolygon( *polygon, poly );
2067 mp.push_back( poly );
2068 }
2069 return mp;
2070}
2071
2072double QgsGeometry::area() const
2073{
2074 if ( !d->geometry )
2075 {
2076 return -1.0;
2077 }
2078
2079 return d->geometry->area();
2080}
2081
2083{
2084 if ( !d->geometry )
2085 {
2086 return -1.0;
2087 }
2088
2089 switch ( QgsWkbTypes::geometryType( d->geometry->wkbType() ) )
2090 {
2092 return 0.0;
2093
2095 return d->geometry->length();
2096
2098 return d->geometry->perimeter();
2099
2102 return d->geometry->length();
2103 }
2104 return -1;
2105}
2106
2107double QgsGeometry::distance( const QgsGeometry &geom ) const
2108{
2109 if ( !d->geometry || !geom.d->geometry )
2110 {
2111 return -1.0;
2112 }
2113
2114 // avoid calling geos for trivial point-to-point distance calculations
2116 {
2117 return qgsgeometry_cast< const QgsPoint * >( d->geometry.get() )->distance( *qgsgeometry_cast< const QgsPoint * >( geom.constGet() ) );
2118 }
2119
2120 QgsGeos g( d->geometry.get() );
2121 mLastError.clear();
2122 return g.distance( geom.d->geometry.get(), &mLastError );
2123}
2124
2126{
2127 if ( !d->geometry || !geom.d->geometry )
2128 {
2129 return -1.0;
2130 }
2131
2132 QgsGeos g( d->geometry.get() );
2133 mLastError.clear();
2134 return g.hausdorffDistance( geom.d->geometry.get(), &mLastError );
2135}
2136
2137double QgsGeometry::hausdorffDistanceDensify( const QgsGeometry &geom, double densifyFraction ) const
2138{
2139 if ( !d->geometry || !geom.d->geometry )
2140 {
2141 return -1.0;
2142 }
2143
2144 QgsGeos g( d->geometry.get() );
2145 mLastError.clear();
2146 return g.hausdorffDistanceDensify( geom.d->geometry.get(), densifyFraction, &mLastError );
2147}
2148
2149
2151{
2152 if ( !d->geometry || !geom.d->geometry )
2153 {
2154 return -1.0;
2155 }
2156
2157 QgsGeos g( d->geometry.get() );
2158 mLastError.clear();
2159 return g.frechetDistance( geom.d->geometry.get(), &mLastError );
2160}
2161
2162double QgsGeometry::frechetDistanceDensify( const QgsGeometry &geom, double densifyFraction ) const
2163{
2164 if ( !d->geometry || !geom.d->geometry )
2165 {
2166 return -1.0;
2167 }
2168
2169 QgsGeos g( d->geometry.get() );
2170 mLastError.clear();
2171 return g.frechetDistanceDensify( geom.d->geometry.get(), densifyFraction, &mLastError );
2172}
2173
2175{
2176 if ( !d->geometry || d->geometry.get()->isEmpty() )
2178 return d->geometry->vertices_begin();
2179}
2180
2182{
2183 if ( !d->geometry || d->geometry.get()->isEmpty() )
2185 return d->geometry->vertices_end();
2186}
2187
2189{
2190 if ( !d->geometry || d->geometry.get()->isEmpty() )
2191 return QgsVertexIterator();
2192 return QgsVertexIterator( d->geometry.get() );
2193}
2194
2196{
2197 if ( !d->geometry )
2199
2200 detach();
2201 return d->geometry->parts_begin();
2202}
2203
2205{
2206 if ( !d->geometry )
2208 return d->geometry->parts_end();
2209}
2210
2212{
2213 if ( !d->geometry )
2215 return d->geometry->const_parts_begin();
2216}
2217
2219{
2220 if ( !d->geometry )
2222 return d->geometry->const_parts_end();
2223}
2224
2226{
2227 if ( !d->geometry )
2228 return QgsGeometryPartIterator();
2229
2230 detach();
2231 return QgsGeometryPartIterator( d->geometry.get() );
2232}
2233
2235{
2236 if ( !d->geometry )
2238
2239 return QgsGeometryConstPartIterator( d->geometry.get() );
2240}
2241
2242QgsGeometry QgsGeometry::buffer( double distance, int segments ) const
2243{
2244 if ( !d->geometry )
2245 {
2246 return QgsGeometry();
2247 }
2248
2249 QgsGeos g( d->geometry.get() );
2250 mLastError.clear();
2251 std::unique_ptr<QgsAbstractGeometry> geom( g.buffer( distance, segments, &mLastError ) );
2252 if ( !geom )
2253 {
2254 QgsGeometry result;
2255 result.mLastError = mLastError;
2256 return result;
2257 }
2258 return QgsGeometry( std::move( geom ) );
2259}
2260
2261QgsGeometry QgsGeometry::buffer( double distance, int segments, Qgis::EndCapStyle endCapStyle, Qgis::JoinStyle joinStyle, double miterLimit ) const
2262{
2263 if ( !d->geometry )
2264 {
2265 return QgsGeometry();
2266 }
2267
2268 QgsGeos g( d->geometry.get() );
2269 mLastError.clear();
2270 QgsAbstractGeometry *geom = g.buffer( distance, segments, endCapStyle, joinStyle, miterLimit, &mLastError );
2271 if ( !geom )
2272 {
2273 QgsGeometry result;
2274 result.mLastError = mLastError;
2275 return result;
2276 }
2277 return QgsGeometry( geom );
2278}
2279
2280QgsGeometry QgsGeometry::offsetCurve( double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit ) const
2281{
2282 if ( !d->geometry || type() != Qgis::GeometryType::Line )
2283 {
2284 return QgsGeometry();
2285 }
2286
2287 if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
2288 {
2289 const QVector<QgsGeometry> parts = asGeometryCollection();
2290 QVector<QgsGeometry> results;
2291 results.reserve( parts.count() );
2292 for ( const QgsGeometry &part : parts )
2293 {
2294 QgsGeometry result = part.offsetCurve( distance, segments, joinStyle, miterLimit );
2295 if ( !result.isNull() )
2296 results << result;
2297 }
2298 if ( results.isEmpty() )
2299 return QgsGeometry();
2300
2301 QgsGeometry first = results.takeAt( 0 );
2302 for ( const QgsGeometry &result : std::as_const( results ) )
2303 {
2304 first.addPart( result );
2305 }
2306 return first;
2307 }
2308 else
2309 {
2310 QgsGeos geos( d->geometry.get() );
2311 mLastError.clear();
2312
2313 // GEOS can flip the curve orientation in some circumstances. So record previous orientation and correct if required
2314 const Qgis::AngularDirection prevOrientation = qgsgeometry_cast< const QgsCurve * >( d->geometry.get() )->orientation();
2315
2316 std::unique_ptr< QgsAbstractGeometry > offsetGeom( geos.offsetCurve( distance, segments, joinStyle, miterLimit, &mLastError ) );
2317 if ( !offsetGeom )
2318 {
2319 QgsGeometry result;
2320 result.mLastError = mLastError;
2321 return result;
2322 }
2323
2324 if ( const QgsCurve *offsetCurve = qgsgeometry_cast< const QgsCurve * >( offsetGeom.get() ) )
2325 {
2326 const Qgis::AngularDirection newOrientation = offsetCurve->orientation();
2327 if ( newOrientation != prevOrientation )
2328 {
2329 // GEOS has flipped line orientation, flip it back
2330 std::unique_ptr< QgsAbstractGeometry > flipped( offsetCurve->reversed() );
2331 offsetGeom = std::move( flipped );
2332 }
2333 }
2334 return QgsGeometry( std::move( offsetGeom ) );
2335 }
2336}
2337
2338QgsGeometry QgsGeometry::singleSidedBuffer( double distance, int segments, Qgis::BufferSide side, Qgis::JoinStyle joinStyle, double miterLimit ) const
2339{
2340 if ( !d->geometry || type() != Qgis::GeometryType::Line )
2341 {
2342 return QgsGeometry();
2343 }
2344
2345 if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
2346 {
2347 const QVector<QgsGeometry> parts = asGeometryCollection();
2348 QVector<QgsGeometry> results;
2349 results.reserve( parts.count() );
2350 for ( const QgsGeometry &part : parts )
2351 {
2352 QgsGeometry result = part.singleSidedBuffer( distance, segments, side, joinStyle, miterLimit );
2353 if ( !result.isNull() )
2354 results << result;
2355 }
2356 if ( results.isEmpty() )
2357 return QgsGeometry();
2358
2359 QgsGeometry first = results.takeAt( 0 );
2360 for ( const QgsGeometry &result : std::as_const( results ) )
2361 {
2362 first.addPart( result );
2363 }
2364 return first;
2365 }
2366 else
2367 {
2368 QgsGeos geos( d->geometry.get() );
2369 mLastError.clear();
2370 std::unique_ptr< QgsAbstractGeometry > bufferGeom = geos.singleSidedBuffer( distance, segments, side,
2371 joinStyle, miterLimit, &mLastError );
2372 if ( !bufferGeom )
2373 {
2374 QgsGeometry result;
2375 result.mLastError = mLastError;
2376 return result;
2377 }
2378 return QgsGeometry( std::move( bufferGeom ) );
2379 }
2380}
2381
2382QgsGeometry QgsGeometry::taperedBuffer( double startWidth, double endWidth, int segments ) const
2383{
2384 QgsInternalGeometryEngine engine( *this );
2385
2386 return engine.taperedBuffer( startWidth, endWidth, segments );
2387}
2388
2390{
2391 QgsInternalGeometryEngine engine( *this );
2392
2393 return engine.variableWidthBufferByM( segments );
2394}
2395
2396QgsGeometry QgsGeometry::extendLine( double startDistance, double endDistance ) const
2397{
2398 if ( !d->geometry || type() != Qgis::GeometryType::Line )
2399 {
2400 return QgsGeometry();
2401 }
2402
2403 if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
2404 {
2405 const QVector<QgsGeometry> parts = asGeometryCollection();
2406 QVector<QgsGeometry> results;
2407 results.reserve( parts.count() );
2408 for ( const QgsGeometry &part : parts )
2409 {
2410 QgsGeometry result = part.extendLine( startDistance, endDistance );
2411 if ( !result.isNull() )
2412 results << result;
2413 }
2414 if ( results.isEmpty() )
2415 return QgsGeometry();
2416
2417 QgsGeometry first = results.takeAt( 0 );
2418 for ( const QgsGeometry &result : std::as_const( results ) )
2419 {
2420 first.addPart( result );
2421 }
2422 return first;
2423 }
2424 else
2425 {
2426 QgsLineString *line = qgsgeometry_cast< QgsLineString * >( d->geometry.get() );
2427 if ( !line )
2428 return QgsGeometry();
2429
2430 std::unique_ptr< QgsLineString > newLine( line->clone() );
2431 newLine->extend( startDistance, endDistance );
2432 return QgsGeometry( std::move( newLine ) );
2433 }
2434}
2435
2436QgsGeometry QgsGeometry::simplify( double tolerance ) const
2437{
2438 if ( !d->geometry )
2439 {
2440 return QgsGeometry();
2441 }
2442
2443 QgsGeos geos( d->geometry.get() );
2444 mLastError.clear();
2445 std::unique_ptr< QgsAbstractGeometry > simplifiedGeom( geos.simplify( tolerance, &mLastError ) );
2446 if ( !simplifiedGeom )
2447 {
2448 QgsGeometry result;
2449 result.mLastError = mLastError;
2450 return result;
2451 }
2452 return QgsGeometry( std::move( simplifiedGeom ) );
2453}
2454
2455QgsGeometry QgsGeometry::densifyByCount( int extraNodesPerSegment ) const
2456{
2457 QgsInternalGeometryEngine engine( *this );
2458
2459 return engine.densifyByCount( extraNodesPerSegment );
2460}
2461
2463{
2464 QgsInternalGeometryEngine engine( *this );
2465
2466 return engine.densifyByDistance( distance );
2467}
2468
2469QgsGeometry QgsGeometry::convertToCurves( double distanceTolerance, double angleTolerance ) const
2470{
2471 QgsInternalGeometryEngine engine( *this );
2472
2473 return engine.convertToCurves( distanceTolerance, angleTolerance );
2474}
2475
2477{
2478 if ( !d->geometry )
2479 {
2480 return QgsGeometry();
2481 }
2482
2483 // avoid calling geos for trivial point centroids
2484 if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == Qgis::WkbType::Point )
2485 {
2486 QgsGeometry c = *this;
2487 c.get()->dropZValue();
2488 c.get()->dropMValue();
2489 return c;
2490 }
2491
2492 QgsGeos geos( d->geometry.get() );
2493
2494 mLastError.clear();
2495 QgsGeometry result( geos.centroid( &mLastError ) );
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
2509 mLastError.clear();
2510 QgsGeometry result( geos.pointOnSurface( &mLastError ) );
2511 result.mLastError = mLastError;
2512 return result;
2513}
2514
2515QgsGeometry QgsGeometry::poleOfInaccessibility( double precision, double *distanceToBoundary ) const
2516{
2517 QgsInternalGeometryEngine engine( *this );
2518
2519 return engine.poleOfInaccessibility( precision, distanceToBoundary );
2520}
2521
2522QgsGeometry QgsGeometry::largestEmptyCircle( double tolerance, const QgsGeometry &boundary ) const
2523{
2524 if ( !d->geometry )
2525 {
2526 return QgsGeometry();
2527 }
2528
2529 QgsGeos geos( d->geometry.get() );
2530
2531 mLastError.clear();
2532 QgsGeometry result( geos.largestEmptyCircle( tolerance, boundary.constGet(), &mLastError ) );
2533 result.mLastError = mLastError;
2534 return result;
2535}
2536
2538{
2539 if ( !d->geometry )
2540 {
2541 return QgsGeometry();
2542 }
2543
2544 QgsGeos geos( d->geometry.get() );
2545
2546 mLastError.clear();
2547 QgsGeometry result( geos.minimumWidth( &mLastError ) );
2548 result.mLastError = mLastError;
2549 return result;
2550}
2551
2553{
2554 if ( !d->geometry )
2555 {
2556 return std::numeric_limits< double >::quiet_NaN();
2557 }
2558
2559 QgsGeos geos( d->geometry.get() );
2560
2561 mLastError.clear();
2562 return geos.minimumClearance( &mLastError );
2563}
2564
2566{
2567 if ( !d->geometry )
2568 {
2569 return QgsGeometry();
2570 }
2571
2572 QgsGeos geos( d->geometry.get() );
2573
2574 mLastError.clear();
2575 QgsGeometry result( geos.minimumClearanceLine( &mLastError ) );
2576 result.mLastError = mLastError;
2577 return result;
2578}
2579
2581{
2582 if ( !d->geometry )
2583 {
2584 return QgsGeometry();
2585 }
2586 QgsGeos geos( d->geometry.get() );
2587 mLastError.clear();
2588 std::unique_ptr< QgsAbstractGeometry > cHull( geos.convexHull( &mLastError ) );
2589 if ( !cHull )
2590 {
2591 QgsGeometry geom;
2592 geom.mLastError = mLastError;
2593 return geom;
2594 }
2595 return QgsGeometry( std::move( cHull ) );
2596}
2597
2598QgsGeometry QgsGeometry::concaveHull( double targetPercent, bool allowHoles ) const
2599{
2600 if ( !d->geometry )
2601 {
2602 return QgsGeometry();
2603 }
2604 QgsGeos geos( d->geometry.get() );
2605 mLastError.clear();
2606 std::unique_ptr< QgsAbstractGeometry > concaveHull( geos.concaveHull( targetPercent, allowHoles, &mLastError ) );
2607 if ( !concaveHull )
2608 {
2609 QgsGeometry geom;
2610 geom.mLastError = mLastError;
2611 return geom;
2612 }
2613 return QgsGeometry( std::move( concaveHull ) );
2614}
2615
2616QgsGeometry QgsGeometry::voronoiDiagram( const QgsGeometry &extent, double tolerance, bool edgesOnly ) const
2617{
2618 if ( !d->geometry )
2619 {
2620 return QgsGeometry();
2621 }
2622
2623 QgsGeos geos( d->geometry.get() );
2624 mLastError.clear();
2625 QgsGeometry result = geos.voronoiDiagram( extent.constGet(), tolerance, edgesOnly, &mLastError );
2626 result.mLastError = mLastError;
2627 return result;
2628}
2629
2630QgsGeometry QgsGeometry::delaunayTriangulation( double tolerance, bool edgesOnly ) const
2631{
2632 if ( !d->geometry )
2633 {
2634 return QgsGeometry();
2635 }
2636
2637 QgsGeos geos( d->geometry.get() );
2638 mLastError.clear();
2639 QgsGeometry result = geos.delaunayTriangulation( tolerance, edgesOnly );
2640 result.mLastError = mLastError;
2641 return result;
2642}
2643
2645{
2646 if ( !d->geometry )
2647 {
2648 return QgsGeometry();
2649 }
2650
2651 QgsGeos geos( d->geometry.get() );
2652 mLastError.clear();
2653 QgsGeometry result( geos.constrainedDelaunayTriangulation() );
2654 result.mLastError = mLastError;
2655 return result;
2656}
2657
2659{
2660 if ( !d->geometry )
2661 {
2662 return QgsGeometry();
2663 }
2664
2668 return QgsGeometry();
2669
2670 QgsGeos geos( d->geometry.get() );
2671 mLastError.clear();
2672 const QgsGeometry result = QgsGeometry( geos.unionCoverage( &mLastError ) );
2673 result.mLastError = mLastError;
2674 return result;
2675}
2676
2678{
2679 if ( !d->geometry )
2680 {
2682 }
2683
2684 QgsGeos geos( d->geometry.get() );
2685 mLastError.clear();
2686 std::unique_ptr< QgsAbstractGeometry > invalidEdgesGeom;
2687
2688 const Qgis::CoverageValidityResult result = geos.validateCoverage( gapWidth, invalidEdges ? &invalidEdgesGeom : nullptr, &mLastError );
2689
2690 if ( invalidEdges && invalidEdgesGeom )
2691 *invalidEdges = QgsGeometry( std::move( invalidEdgesGeom ) );
2692
2693 return result;
2694}
2695
2696QgsGeometry QgsGeometry::simplifyCoverageVW( double tolerance, bool preserveBoundary ) const
2697{
2698 if ( !d->geometry )
2699 {
2700 return QgsGeometry();
2701 }
2702
2703 QgsGeos geos( d->geometry.get() );
2704 mLastError.clear();
2705 QgsGeometry result( geos.simplifyCoverageVW( tolerance, preserveBoundary, &mLastError ) );
2706 result.mLastError = mLastError;
2707 return result;
2708}
2709
2711{
2712 if ( !d->geometry )
2713 {
2714 return QgsGeometry();
2715 }
2716
2717 QgsGeos geos( d->geometry.get() );
2718 mLastError.clear();
2719 QgsGeometry result( geos.node( &mLastError ) );
2720 result.mLastError = mLastError;
2721 return result;
2722}
2723
2725{
2726 if ( !d->geometry )
2727 {
2728 return QgsGeometry();
2729 }
2730
2731 QgsGeos geos( d->geometry.get() );
2732 mLastError.clear();
2733 QgsGeometry result( geos.sharedPaths( other.constGet(), &mLastError ) );
2734 result.mLastError = mLastError;
2735 return result;
2736}
2737
2738QgsGeometry QgsGeometry::subdivide( int maxNodes, const QgsGeometryParameters &parameters ) const
2739{
2740 if ( !d->geometry )
2741 {
2742 return QgsGeometry();
2743 }
2744
2745 const QgsAbstractGeometry *geom = d->geometry.get();
2746 std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
2747 if ( QgsWkbTypes::isCurvedType( d->geometry->wkbType() ) )
2748 {
2749 segmentizedCopy.reset( d->geometry->segmentize() );
2750 geom = segmentizedCopy.get();
2751 }
2752
2753 QgsGeos geos( geom );
2754 mLastError.clear();
2755 std::unique_ptr< QgsAbstractGeometry > result( geos.subdivide( maxNodes, &mLastError, parameters ) );
2756 if ( !result )
2757 {
2758 QgsGeometry geom;
2759 geom.mLastError = mLastError;
2760 return geom;
2761 }
2762 return QgsGeometry( std::move( result ) );
2763}
2764
2766{
2767 if ( !d->geometry )
2768 {
2769 return QgsGeometry();
2770 }
2771
2772 QgsGeometry line = *this;
2774 return QgsGeometry();
2775 else if ( type() == Qgis::GeometryType::Polygon )
2776 {
2777 line = QgsGeometry( d->geometry->boundary() );
2778 }
2779
2780 const QgsCurve *curve = nullptr;
2781 if ( line.isMultipart() )
2782 {
2783 // if multi part, iterate through parts to find target part
2784 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( line.constGet() );
2785 for ( int part = 0; part < collection->numGeometries(); ++part )
2786 {
2787 const QgsCurve *candidate = qgsgeometry_cast< const QgsCurve * >( collection->geometryN( part ) );
2788 if ( !candidate )
2789 continue;
2790 const double candidateLength = candidate->length();
2791 if ( candidateLength >= distance )
2792 {
2793 curve = candidate;
2794 break;
2795 }
2796
2797 distance -= candidateLength;
2798 }
2799 }
2800 else
2801 {
2802 curve = qgsgeometry_cast< const QgsCurve * >( line.constGet() );
2803 }
2804 if ( !curve )
2805 return QgsGeometry();
2806
2807 std::unique_ptr< QgsPoint > result( curve->interpolatePoint( distance ) );
2808 if ( !result )
2809 {
2810 return QgsGeometry();
2811 }
2812 return QgsGeometry( std::move( result ) );
2813}
2814
2815double QgsGeometry::lineLocatePoint( const QgsGeometry &point ) const
2816{
2817 if ( type() != Qgis::GeometryType::Line )
2818 return -1;
2819
2821 return -1;
2822
2823 QgsGeometry segmentized = *this;
2825 {
2826 segmentized = QgsGeometry( static_cast< QgsCurve * >( d->geometry.get() )->segmentize() );
2827 }
2828
2829 QgsGeos geos( d->geometry.get() );
2830 mLastError.clear();
2831 return geos.lineLocatePoint( *( static_cast< QgsPoint * >( point.d->geometry.get() ) ), &mLastError );
2832}
2833
2834double QgsGeometry::interpolateAngle( double distance ) const
2835{
2836 if ( !d->geometry || d->geometry->isEmpty() )
2837 return 0.0;
2838
2839 const QgsAbstractGeometry *geom = d->geometry->simplifiedTypeRef();
2841 return 0.0;
2842
2843 // always operate on segmentized geometries
2844 QgsGeometry segmentized = *this;
2845 if ( QgsWkbTypes::isCurvedType( geom->wkbType() ) )
2846 {
2847 segmentized = QgsGeometry( static_cast< const QgsCurve * >( geom )->segmentize() );
2848 }
2849
2850 QgsVertexId previous;
2851 QgsVertexId next;
2852 if ( !QgsGeometryUtils::verticesAtDistance( *segmentized.constGet(), distance, previous, next ) )
2853 return 0.0;
2854
2855 if ( previous == next )
2856 {
2857 // distance coincided exactly with a vertex
2858 QgsVertexId v2 = previous;
2859 QgsVertexId v1;
2860 QgsVertexId v3;
2861 segmentized.constGet()->adjacentVertices( v2, v1, v3 );
2862 if ( v1.isValid() && v3.isValid() )
2863 {
2864 QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
2865 QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
2866 QgsPoint p3 = segmentized.constGet()->vertexAt( v3 );
2867 double angle1 = QgsGeometryUtilsBase::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2868 double angle2 = QgsGeometryUtilsBase::lineAngle( p2.x(), p2.y(), p3.x(), p3.y() );
2869 return QgsGeometryUtilsBase::averageAngle( angle1, angle2 );
2870 }
2871 else if ( v3.isValid() )
2872 {
2873 QgsPoint p1 = segmentized.constGet()->vertexAt( v2 );
2874 QgsPoint p2 = segmentized.constGet()->vertexAt( v3 );
2875 return QgsGeometryUtilsBase::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2876 }
2877 else
2878 {
2879 QgsPoint p1 = segmentized.constGet()->vertexAt( v1 );
2880 QgsPoint p2 = segmentized.constGet()->vertexAt( v2 );
2881 return QgsGeometryUtilsBase::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2882 }
2883 }
2884 else
2885 {
2886 QgsPoint p1 = segmentized.constGet()->vertexAt( previous );
2887 QgsPoint p2 = segmentized.constGet()->vertexAt( next );
2888 return QgsGeometryUtilsBase::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
2889 }
2890}
2891
2893{
2894 if ( !d->geometry || geometry.isNull() )
2895 {
2896 return QgsGeometry();
2897 }
2898
2899 QgsGeos geos( d->geometry.get() );
2900
2901 mLastError.clear();
2902 std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.intersection( geometry.d->geometry.get(), &mLastError, parameters ) );
2903
2904 if ( !resultGeom )
2905 {
2906 QgsGeometry geom;
2907 geom.mLastError = mLastError;
2908 return geom;
2909 }
2910
2911 return QgsGeometry( std::move( resultGeom ) );
2912}
2913
2914QgsGeometry QgsGeometry::combine( const QgsGeometry &geometry, const QgsGeometryParameters &parameters ) const
2915{
2916 if ( !d->geometry || geometry.isNull() )
2917 {
2918 return QgsGeometry();
2919 }
2920
2921 QgsGeos geos( d->geometry.get() );
2922 mLastError.clear();
2923 std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.combine( geometry.d->geometry.get(), &mLastError, parameters ) );
2924 if ( !resultGeom )
2925 {
2926 QgsGeometry geom;
2927 geom.mLastError = mLastError;
2928 return geom;
2929 }
2930 return QgsGeometry( std::move( resultGeom ) );
2931}
2932
2934{
2935 if ( !d->geometry )
2936 {
2937 return QgsGeometry();
2938 }
2939
2941 {
2942 // special case - a single linestring was passed
2943 return QgsGeometry( *this );
2944 }
2945
2946 QgsGeos geos( d->geometry.get() );
2947 mLastError.clear();
2948 QgsGeometry result = geos.mergeLines( &mLastError );
2949 result.mLastError = mLastError;
2950 return result;
2951}
2952
2954{
2955 if ( !d->geometry || geometry.isNull() )
2956 {
2957 return QgsGeometry();
2958 }
2959
2960 QgsGeos geos( d->geometry.get() );
2961
2962 mLastError.clear();
2963 std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.difference( geometry.d->geometry.get(), &mLastError, parameters ) );
2964 if ( !resultGeom )
2965 {
2966 QgsGeometry geom;
2967 geom.mLastError = mLastError;
2968 return geom;
2969 }
2970 return QgsGeometry( std::move( resultGeom ) );
2971}
2972
2974{
2975 if ( !d->geometry || geometry.isNull() )
2976 {
2977 return QgsGeometry();
2978 }
2979
2980 QgsGeos geos( d->geometry.get() );
2981
2982 mLastError.clear();
2983 std::unique_ptr< QgsAbstractGeometry > resultGeom( geos.symDifference( geometry.d->geometry.get(), &mLastError, parameters ) );
2984 if ( !resultGeom )
2985 {
2986 QgsGeometry geom;
2987 geom.mLastError = mLastError;
2988 return geom;
2989 }
2990 return QgsGeometry( std::move( resultGeom ) );
2991}
2992
2994{
2995 QgsInternalGeometryEngine engine( *this );
2996
2997 return engine.extrude( x, y );
2998}
2999
3001
3002QVector<QgsPointXY> QgsGeometry::randomPointsInPolygon( int count, const std::function< bool( const QgsPointXY & ) > &acceptPoint, unsigned long seed, QgsFeedback *feedback, int maxTriesPerPoint ) const
3003{
3005 return QVector< QgsPointXY >();
3006
3007 QgsInternalGeometryEngine engine( *this );
3008 const QVector<QgsPointXY> res = engine.randomPointsInPolygon( count, acceptPoint, seed, feedback, maxTriesPerPoint );
3009 mLastError = engine.lastError();
3010 return res;
3011}
3012
3013QVector<QgsPointXY> QgsGeometry::randomPointsInPolygon( int count, unsigned long seed, QgsFeedback *feedback ) const
3014{
3016 return QVector< QgsPointXY >();
3017
3018 QgsInternalGeometryEngine engine( *this );
3019 const QVector<QgsPointXY> res = engine.randomPointsInPolygon( count, []( const QgsPointXY & ) { return true; }, seed, feedback, 0 );
3020 mLastError = engine.lastError();
3021 return res;
3022}
3024
3025int QgsGeometry::wkbSize( QgsAbstractGeometry::WkbFlags flags ) const
3026{
3027 return d->geometry ? d->geometry->wkbSize( flags ) : 0;
3028}
3029
3030QByteArray QgsGeometry::asWkb( QgsAbstractGeometry::WkbFlags flags ) const
3031{
3032 return d->geometry ? d->geometry->asWkb( flags ) : QByteArray();
3033}
3034
3035QVector<QgsGeometry> QgsGeometry::asGeometryCollection() const
3036{
3037 QVector<QgsGeometry> geometryList;
3038 if ( !d->geometry )
3039 {
3040 return geometryList;
3041 }
3042
3043 QgsGeometryCollection *gc = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
3044 if ( gc )
3045 {
3046 int numGeom = gc->numGeometries();
3047 geometryList.reserve( numGeom );
3048 for ( int i = 0; i < numGeom; ++i )
3049 {
3050 geometryList.append( QgsGeometry( gc->geometryN( i )->clone() ) );
3051 }
3052 }
3053 else //a singlepart geometry
3054 {
3055 geometryList.append( *this );
3056 }
3057
3058 return geometryList;
3059}
3060
3062{
3063 QgsPointXY point = asPoint();
3064 return point.toQPointF();
3065}
3066
3068{
3069 const QgsAbstractGeometry *part = constGet();
3070
3071 // if a geometry collection, get first part only
3072 if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection *>( part ) )
3073 {
3074 if ( collection->numGeometries() > 0 )
3075 part = collection->geometryN( 0 );
3076 else
3077 return QPolygonF();
3078 }
3079
3080 if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( part ) )
3081 return curve->asQPolygonF();
3082 else if ( const QgsCurvePolygon *polygon = qgsgeometry_cast< const QgsCurvePolygon * >( part ) )
3083 return polygon->exteriorRing() ? polygon->exteriorRing()->asQPolygonF() : QPolygonF();
3084 return QPolygonF();
3085}
3086
3087bool QgsGeometry::deleteRing( int ringNum, int partNum )
3088{
3089 if ( !d->geometry )
3090 {
3091 return false;
3092 }
3093
3094 detach();
3095 bool ok = QgsGeometryEditUtils::deleteRing( d->geometry.get(), ringNum, partNum );
3096 return ok;
3097}
3098
3099bool QgsGeometry::deletePart( int partNum )
3100{
3101 if ( !d->geometry )
3102 {
3103 return false;
3104 }
3105
3106 if ( !isMultipart() && partNum < 1 )
3107 {
3108 set( nullptr );
3109 return true;
3110 }
3111
3112 detach();
3113 bool ok = QgsGeometryEditUtils::deletePart( d->geometry.get(), partNum );
3114 return ok;
3115}
3116
3117Qgis::GeometryOperationResult QgsGeometry::avoidIntersectionsV2( const QList<QgsVectorLayer *> &avoidIntersectionsLayers, const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures )
3118{
3119 if ( !d->geometry )
3120 {
3122 }
3123
3124 Qgis::WkbType geomTypeBeforeModification = wkbType();
3125
3126 bool haveInvalidGeometry = false;
3127 bool geomModified = false;
3128
3129 std::unique_ptr< QgsAbstractGeometry > diffGeom = QgsGeometryEditUtils::avoidIntersections( *( d->geometry ), avoidIntersectionsLayers, haveInvalidGeometry, ignoreFeatures );
3130 if ( diffGeom )
3131 {
3132 reset( std::move( diffGeom ) );
3133 geomModified = true;
3134 }
3135
3136 if ( geomTypeBeforeModification != wkbType() )
3138 if ( haveInvalidGeometry )
3140 if ( !geomModified )
3142
3144}
3145
3177
3179{
3180 if ( !d->geometry )
3181 return QgsGeometry();
3182
3183 mLastError.clear();
3184 QgsGeos geos( d->geometry.get() );
3185 std::unique_ptr< QgsAbstractGeometry > g( geos.makeValid( method, keepCollapsed, &mLastError ) );
3186
3187 QgsGeometry result = QgsGeometry( std::move( g ) );
3188 result.mLastError = mLastError;
3189 return result;
3190}
3191
3196
3198{
3199 if ( !d->geometry )
3200 {
3202 }
3203
3204 if ( isMultipart() )
3205 {
3206 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( d->geometry.get() );
3207 const QgsAbstractGeometry *g = collection->geometryN( 0 );
3208 if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( g ) )
3209 {
3210 return cp->exteriorRing() ? cp->exteriorRing()->orientation() : Qgis::AngularDirection::NoOrientation;
3211 }
3212 }
3213 else
3214 {
3215 if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( d->geometry.get() ) )
3216 {
3217 return cp->exteriorRing() ? cp->exteriorRing()->orientation() : Qgis::AngularDirection::NoOrientation;
3218 }
3219 }
3220
3222
3223}
3224
3226{
3227 if ( !d->geometry )
3228 return QgsGeometry();
3229
3230 if ( isMultipart() )
3231 {
3232 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( d->geometry.get() );
3233 std::unique_ptr< QgsGeometryCollection > newCollection( collection->createEmptyWithSameType() );
3234 newCollection->reserve( collection->numGeometries() );
3235 for ( int i = 0; i < collection->numGeometries(); ++i )
3236 {
3237 const QgsAbstractGeometry *g = collection->geometryN( i );
3238 if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( g ) )
3239 {
3240 std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
3241 corrected->forceClockwise();
3242 newCollection->addGeometry( corrected.release() );
3243 }
3244 else
3245 {
3246 newCollection->addGeometry( g->clone() );
3247 }
3248 }
3249 return QgsGeometry( std::move( newCollection ) );
3250 }
3251 else
3252 {
3253 if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( d->geometry.get() ) )
3254 {
3255 std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
3256 corrected->forceClockwise();
3257 return QgsGeometry( std::move( corrected ) );
3258 }
3259 else
3260 {
3261 // not a curve polygon, so return unchanged
3262 return *this;
3263 }
3264 }
3265}
3266
3268{
3269 if ( !d->geometry )
3270 return QgsGeometry();
3271
3272 if ( isMultipart() )
3273 {
3274 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( d->geometry.get() );
3275 std::unique_ptr< QgsGeometryCollection > newCollection( collection->createEmptyWithSameType() );
3276 newCollection->reserve( collection->numGeometries() );
3277 for ( int i = 0; i < collection->numGeometries(); ++i )
3278 {
3279 const QgsAbstractGeometry *g = collection->geometryN( i );
3280 if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( g ) )
3281 {
3282 std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
3283 corrected->forceCounterClockwise();
3284 newCollection->addGeometry( corrected.release() );
3285 }
3286 else
3287 {
3288 newCollection->addGeometry( g->clone() );
3289 }
3290 }
3291 return QgsGeometry( std::move( newCollection ) );
3292 }
3293 else
3294 {
3295 if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( d->geometry.get() ) )
3296 {
3297 std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
3298 corrected->forceCounterClockwise();
3299 return QgsGeometry( std::move( corrected ) );
3300 }
3301 else
3302 {
3303 // not a curve polygon, so return unchanged
3304 return *this;
3305 }
3306 }
3307}
3308
3309
3310void QgsGeometry::validateGeometry( QVector<QgsGeometry::Error> &errors, const Qgis::GeometryValidationEngine method, const Qgis::GeometryValidityFlags flags ) const
3311{
3312 errors.clear();
3313 if ( !d->geometry )
3314 return;
3315
3316 // avoid expensive calcs for trivial point geometries
3318 {
3319 return;
3320 }
3321
3322 switch ( method )
3323 {
3325 QgsGeometryValidator::validateGeometry( *this, errors, method );
3326 return;
3327
3329 {
3330 QgsGeos geos( d->geometry.get() );
3331 QString error;
3332 QgsGeometry errorLoc;
3333 if ( !geos.isValid( &error, flags & Qgis::GeometryValidityFlag::AllowSelfTouchingHoles, &errorLoc ) )
3334 {
3335 if ( errorLoc.isNull() )
3336 {
3337 errors.append( QgsGeometry::Error( error ) );
3338 }
3339 else
3340 {
3341 const QgsPointXY point = errorLoc.asPoint();
3342 errors.append( QgsGeometry::Error( error, point ) );
3343 }
3344 return;
3345 }
3346 }
3347 }
3348}
3349
3351{
3352 if ( !d->geometry )
3353 {
3354 return;
3355 }
3356
3357 detach();
3358 d->geometry->normalize();
3359}
3360
3361bool QgsGeometry::isGeosValid( Qgis::GeometryValidityFlags flags ) const
3362{
3363 if ( !d->geometry )
3364 {
3365 return false;
3366 }
3367
3368 return d->geometry->isValid( mLastError, flags );
3369}
3370
3372{
3373 if ( !d->geometry )
3374 return false;
3375
3376 QgsGeos geos( d->geometry.get() );
3377 mLastError.clear();
3378 return geos.isSimple( &mLastError );
3379}
3380
3381bool QgsGeometry::isAxisParallelRectangle( double maximumDeviation, bool simpleRectanglesOnly ) const
3382{
3383 if ( !d->geometry )
3384 return false;
3385
3386 QgsInternalGeometryEngine engine( *this );
3387 return engine.isAxisParallelRectangle( maximumDeviation, simpleRectanglesOnly );
3388}
3389
3391{
3392 if ( !d->geometry || !g.d->geometry )
3393 {
3394 return false;
3395 }
3396
3397 // fast check - are they shared copies of the same underlying geometry?
3398 if ( d == g.d )
3399 return true;
3400
3401 // fast check - distinct geometry types?
3402 if ( type() != g.type() )
3403 return false;
3404
3405 // avoid calling geos for trivial point case
3406 if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == Qgis::WkbType::Point
3407 && QgsWkbTypes::flatType( g.d->geometry->wkbType() ) == Qgis::WkbType::Point )
3408 {
3409 return equals( g );
3410 }
3411
3412 // another nice fast check upfront -- if the bounding boxes aren't equal, the geometries themselves can't be equal!
3413 if ( d->geometry->boundingBox() != g.d->geometry->boundingBox() )
3414 return false;
3415
3416 QgsGeos geos( d->geometry.get() );
3417 mLastError.clear();
3418 return geos.isEqual( g.d->geometry.get(), &mLastError );
3419}
3420
3421QgsGeometry QgsGeometry::unaryUnion( const QVector<QgsGeometry> &geometries, const QgsGeometryParameters &parameters )
3422{
3423 QgsGeos geos( nullptr );
3424
3425 QString error;
3426 std::unique_ptr< QgsAbstractGeometry > geom( geos.combine( geometries, &error, parameters ) );
3427 QgsGeometry result( std::move( geom ) );
3428 result.mLastError = error;
3429 return result;
3430}
3431
3432QgsGeometry QgsGeometry::polygonize( const QVector<QgsGeometry> &geometryList )
3433{
3434 QVector<const QgsAbstractGeometry *> geomV2List;
3435 for ( const QgsGeometry &g : geometryList )
3436 {
3437 if ( !( g.isNull() ) )
3438 {
3439 geomV2List.append( g.constGet() );
3440 }
3441 }
3442
3443 QString error;
3444 QgsGeometry result = QgsGeos::polygonize( geomV2List, &error );
3445 result.mLastError = error;
3446 return result;
3447}
3448
3450{
3452 {
3453 return;
3454 }
3455
3456 std::unique_ptr< QgsAbstractGeometry > straightGeom( d->geometry->segmentize( tolerance, toleranceType ) );
3457 reset( std::move( straightGeom ) );
3458}
3459
3461{
3462 if ( !d->geometry )
3463 {
3464 return false;
3465 }
3466
3467 return d->geometry->hasCurvedSegments();
3468}
3469
3471{
3472 if ( !d->geometry )
3473 {
3475 }
3476
3477 detach();
3478 d->geometry->transform( ct, direction, transformZ );
3480}
3481
3482Qgis::GeometryOperationResult QgsGeometry::transform( const QTransform &ct, double zTranslate, double zScale, double mTranslate, double mScale )
3483{
3484 if ( !d->geometry )
3485 {
3487 }
3488
3489 detach();
3490 d->geometry->transform( ct, zTranslate, zScale, mTranslate, mScale );
3492}
3493
3495{
3496 if ( d->geometry )
3497 {
3498 detach();
3499 d->geometry->transform( mtp.transform() );
3500 }
3501}
3502
3504{
3505 if ( !d->geometry || rectangle.isNull() || rectangle.isEmpty() )
3506 {
3507 return QgsGeometry();
3508 }
3509
3510 QgsGeos geos( d->geometry.get() );
3511 mLastError.clear();
3512 std::unique_ptr< QgsAbstractGeometry > resultGeom = geos.clip( rectangle, &mLastError );
3513 if ( !resultGeom )
3514 {
3515 QgsGeometry result;
3516 result.mLastError = mLastError;
3517 return result;
3518 }
3519 return QgsGeometry( std::move( resultGeom ) );
3520}
3521
3522void QgsGeometry::draw( QPainter &p ) const
3523{
3524 if ( d->geometry )
3525 {
3526 d->geometry->draw( p );
3527 }
3528}
3529
3530static bool vertexIndexInfo( const QgsAbstractGeometry *g, int vertexIndex, int &partIndex, int &ringIndex, int &vertex )
3531{
3532 if ( vertexIndex < 0 )
3533 return false; // clearly something wrong
3534
3535 if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
3536 {
3537 partIndex = 0;
3538 for ( int i = 0; i < geomCollection->numGeometries(); ++i )
3539 {
3540 const QgsAbstractGeometry *part = geomCollection->geometryN( i );
3541
3542 // count total number of vertices in the part
3543 int numPoints = 0;
3544 for ( int k = 0; k < part->ringCount(); ++k )
3545 numPoints += part->vertexCount( 0, k );
3546
3547 if ( vertexIndex < numPoints )
3548 {
3549 int nothing;
3550 return vertexIndexInfo( part, vertexIndex, nothing, ringIndex, vertex ); // set ring_index + index
3551 }
3552 vertexIndex -= numPoints;
3553 partIndex++;
3554 }
3555 }
3556 else if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
3557 {
3558 const QgsCurve *ring = curvePolygon->exteriorRing();
3559 if ( vertexIndex < ring->numPoints() )
3560 {
3561 partIndex = 0;
3562 ringIndex = 0;
3563 vertex = vertexIndex;
3564 return true;
3565 }
3566 vertexIndex -= ring->numPoints();
3567 ringIndex = 1;
3568 for ( int i = 0; i < curvePolygon->numInteriorRings(); ++i )
3569 {
3570 const QgsCurve *ring = curvePolygon->interiorRing( i );
3571 if ( vertexIndex < ring->numPoints() )
3572 {
3573 partIndex = 0;
3574 vertex = vertexIndex;
3575 return true;
3576 }
3577 vertexIndex -= ring->numPoints();
3578 ringIndex += 1;
3579 }
3580 }
3581 else if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
3582 {
3583 if ( vertexIndex < curve->numPoints() )
3584 {
3585 partIndex = 0;
3586 ringIndex = 0;
3587 vertex = vertexIndex;
3588 return true;
3589 }
3590 }
3591 else if ( qgsgeometry_cast<const QgsPoint *>( g ) )
3592 {
3593 if ( vertexIndex == 0 )
3594 {
3595 partIndex = 0;
3596 ringIndex = 0;
3597 vertex = 0;
3598 return true;
3599 }
3600 }
3601
3602 return false;
3603}
3604
3606{
3607 if ( !d->geometry )
3608 {
3609 return false;
3610 }
3611
3612 id.type = Qgis::VertexType::Segment;
3613
3614 bool res = vertexIndexInfo( d->geometry.get(), nr, id.part, id.ring, id.vertex );
3615 if ( !res )
3616 return false;
3617
3618 // now let's find out if it is a straight or circular segment
3619 const QgsAbstractGeometry *g = d->geometry.get();
3620 if ( const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( g ) )
3621 {
3622 g = geomCollection->geometryN( id.part );
3623 }
3624
3625 if ( const QgsCurvePolygon *curvePolygon = qgsgeometry_cast<const QgsCurvePolygon *>( g ) )
3626 {
3627 g = id.ring == 0 ? curvePolygon->exteriorRing() : curvePolygon->interiorRing( id.ring - 1 );
3628 }
3629
3630 if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( g ) )
3631 {
3632 QgsPoint p;
3633 res = curve->pointAt( id.vertex, p, id.type );
3634 if ( !res )
3635 return false;
3636 }
3637
3638 return true;
3639}
3640
3642{
3643 if ( !d->geometry )
3644 {
3645 return -1;
3646 }
3647 return d->geometry->vertexNumberFromVertexId( id );
3648}
3649
3651{
3652 return mLastError;
3653}
3654
3655void QgsGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
3656{
3657 if ( !d->geometry )
3658 return;
3659
3660 detach();
3661
3662 d->geometry->filterVertices( filter );
3663}
3664
3665void QgsGeometry::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
3666{
3667 if ( !d->geometry )
3668 return;
3669
3670 detach();
3671
3672 d->geometry->transformVertices( transform );
3673}
3674
3675void QgsGeometry::convertPointList( const QVector<QgsPointXY> &input, QgsPointSequence &output )
3676{
3677 output.clear();
3678 for ( const QgsPointXY &p : input )
3679 {
3680 output.append( QgsPoint( p ) );
3681 }
3682}
3683
3684void QgsGeometry::convertPointList( const QgsPointSequence &input, QVector<QgsPointXY> &output )
3685{
3686 output.clear();
3687 for ( const QgsPoint &p : input )
3688 {
3689 output.append( QgsPointXY( p.x(), p.y() ) );
3690 }
3691}
3692
3693void QgsGeometry::convertPolygon( const QgsPolygon &input, QgsPolygonXY &output )
3694{
3695 output.clear();
3696
3697 auto convertRing = []( const QgsCurve * ring ) -> QgsPolylineXY
3698 {
3699 QgsPolylineXY res;
3700 bool doSegmentation = ( QgsWkbTypes::flatType( ring->wkbType() ) == Qgis::WkbType::CompoundCurve
3702 std::unique_ptr< QgsLineString > segmentizedLine;
3703 const QgsLineString *line = nullptr;
3704 if ( doSegmentation )
3705 {
3706 segmentizedLine.reset( ring->curveToLine() );
3707 line = segmentizedLine.get();
3708 }
3709 else
3710 {
3711 line = qgsgeometry_cast<const QgsLineString *>( ring );
3712 if ( !line )
3713 {
3714 return res;
3715 }
3716 }
3717
3718 int nVertices = line->numPoints();
3719 res.resize( nVertices );
3720 QgsPointXY *data = res.data();
3721 const double *xData = line->xData();
3722 const double *yData = line->yData();
3723 for ( int i = 0; i < nVertices; ++i )
3724 {
3725 data->setX( *xData++ );
3726 data->setY( *yData++ );
3727 data++;
3728 }
3729 return res;
3730 };
3731
3732 if ( const QgsCurve *exterior = input.exteriorRing() )
3733 {
3734 output.push_back( convertRing( exterior ) );
3735 }
3736
3737 const int interiorRingCount = input.numInteriorRings();
3738 output.reserve( output.size() + interiorRingCount );
3739 for ( int n = 0; n < interiorRingCount; ++n )
3740 {
3741 output.push_back( convertRing( input.interiorRing( n ) ) );
3742 }
3743}
3744
3746{
3747 return QgsGeometry( std::make_unique< QgsPoint >( point.x(), point.y() ) );
3748}
3749
3750QgsGeometry QgsGeometry::fromQPolygonF( const QPolygonF &polygon )
3751{
3752 std::unique_ptr < QgsLineString > ring( QgsLineString::fromQPolygonF( polygon ) );
3753
3754 if ( polygon.isClosed() )
3755 {
3756 std::unique_ptr< QgsPolygon > poly = std::make_unique< QgsPolygon >();
3757 poly->setExteriorRing( ring.release() );
3758 return QgsGeometry( std::move( poly ) );
3759 }
3760 else
3761 {
3762 return QgsGeometry( std::move( ring ) );
3763 }
3764}
3765
3767{
3769 QgsPolygonXY result;
3770 result << createPolylineFromQPolygonF( polygon );
3771 return result;
3773}
3774
3776{
3777 QgsPolylineXY result;
3778 result.reserve( polygon.count() );
3779 for ( const QPointF &p : polygon )
3780 {
3781 result.append( QgsPointXY( p ) );
3782 }
3783 return result;
3784}
3785
3786bool QgsGeometry::compare( const QgsPolylineXY &p1, const QgsPolylineXY &p2, double epsilon )
3787{
3788 if ( p1.count() != p2.count() )
3789 return false;
3790
3791 for ( int i = 0; i < p1.count(); ++i )
3792 {
3793 if ( !p1.at( i ).compare( p2.at( i ), epsilon ) )
3794 return false;
3795 }
3796 return true;
3797}
3798
3799bool QgsGeometry::compare( const QgsPolygonXY &p1, const QgsPolygonXY &p2, double epsilon )
3800{
3801 if ( p1.count() != p2.count() )
3802 return false;
3803
3804 for ( int i = 0; i < p1.count(); ++i )
3805 {
3806 if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
3807 return false;
3808 }
3809 return true;
3810}
3811
3812
3813bool QgsGeometry::compare( const QgsMultiPolygonXY &p1, const QgsMultiPolygonXY &p2, double epsilon )
3814{
3815 if ( p1.count() != p2.count() )
3816 return false;
3817
3818 for ( int i = 0; i < p1.count(); ++i )
3819 {
3820 if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) )
3821 return false;
3822 }
3823 return true;
3824}
3825
3826QgsGeometry QgsGeometry::smooth( const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3827{
3828 if ( !d->geometry || d->geometry->isEmpty() )
3829 return QgsGeometry();
3830
3831 QgsGeometry geom = *this;
3833 geom = QgsGeometry( d->geometry->segmentize() );
3834
3835 switch ( QgsWkbTypes::flatType( geom.wkbType() ) )
3836 {
3839 //can't smooth a point based geometry
3840 return geom;
3841
3843 {
3844 const QgsLineString *lineString = qgsgeometry_cast< const QgsLineString * >( geom.constGet() );
3845 return QgsGeometry( smoothLine( *lineString, iterations, offset, minimumDistance, maxAngle ) );
3846 }
3847
3849 {
3850 const QgsMultiLineString *multiLine = qgsgeometry_cast< const QgsMultiLineString * >( geom.constGet() );
3851
3852 std::unique_ptr< QgsMultiLineString > resultMultiline = std::make_unique< QgsMultiLineString> ();
3853 resultMultiline->reserve( multiLine->numGeometries() );
3854 for ( int i = 0; i < multiLine->numGeometries(); ++i )
3855 {
3856 resultMultiline->addGeometry( smoothLine( *( multiLine->lineStringN( i ) ), iterations, offset, minimumDistance, maxAngle ).release() );
3857 }
3858 return QgsGeometry( std::move( resultMultiline ) );
3859 }
3860
3862 {
3863 const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon * >( geom.constGet() );
3864 return QgsGeometry( smoothPolygon( *poly, iterations, offset, minimumDistance, maxAngle ) );
3865 }
3866
3868 {
3869 const QgsMultiPolygon *multiPoly = qgsgeometry_cast< const QgsMultiPolygon * >( geom.constGet() );
3870
3871 std::unique_ptr< QgsMultiPolygon > resultMultiPoly = std::make_unique< QgsMultiPolygon >();
3872 resultMultiPoly->reserve( multiPoly->numGeometries() );
3873 for ( int i = 0; i < multiPoly->numGeometries(); ++i )
3874 {
3875 resultMultiPoly->addGeometry( smoothPolygon( *( multiPoly->polygonN( i ) ), iterations, offset, minimumDistance, maxAngle ).release() );
3876 }
3877 return QgsGeometry( std::move( resultMultiPoly ) );
3878 }
3879
3881 default:
3882 return QgsGeometry( *this );
3883 }
3884}
3885
3886std::unique_ptr< QgsLineString > smoothCurve( const QgsLineString &line, const unsigned int iterations,
3887 const double offset, double squareDistThreshold, double maxAngleRads,
3888 bool isRing )
3889{
3890 std::unique_ptr< QgsLineString > result = std::make_unique< QgsLineString >( line );
3891 QgsPointSequence outputLine;
3892 for ( unsigned int iteration = 0; iteration < iterations; ++iteration )
3893 {
3894 outputLine.resize( 0 );
3895 outputLine.reserve( 2 * ( result->numPoints() - 1 ) );
3896 bool skipFirst = false;
3897 bool skipLast = false;
3898 if ( isRing )
3899 {
3900 QgsPoint p1 = result->pointN( result->numPoints() - 2 );
3901 QgsPoint p2 = result->pointN( 0 );
3902 QgsPoint p3 = result->pointN( 1 );
3903 double angle = QgsGeometryUtilsBase::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3904 p3.x(), p3.y() );
3905 angle = std::fabs( M_PI - angle );
3906 skipFirst = angle > maxAngleRads;
3907 }
3908 for ( int i = 0; i < result->numPoints() - 1; i++ )
3909 {
3910 QgsPoint p1 = result->pointN( i );
3911 QgsPoint p2 = result->pointN( i + 1 );
3912
3913 double angle = M_PI;
3914 if ( i == 0 && isRing )
3915 {
3916 QgsPoint p3 = result->pointN( result->numPoints() - 2 );
3917 angle = QgsGeometryUtilsBase::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3918 p3.x(), p3.y() );
3919 }
3920 else if ( i < result->numPoints() - 2 )
3921 {
3922 QgsPoint p3 = result->pointN( i + 2 );
3923 angle = QgsGeometryUtilsBase::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3924 p3.x(), p3.y() );
3925 }
3926 else if ( i == result->numPoints() - 2 && isRing )
3927 {
3928 QgsPoint p3 = result->pointN( 1 );
3929 angle = QgsGeometryUtilsBase::angleBetweenThreePoints( p1.x(), p1.y(), p2.x(), p2.y(),
3930 p3.x(), p3.y() );
3931 }
3932
3933 skipLast = angle < M_PI - maxAngleRads || angle > M_PI + maxAngleRads;
3934
3935 // don't apply distance threshold to first or last segment
3936 if ( i == 0 || i >= result->numPoints() - 2
3937 || QgsGeometryUtils::sqrDistance2D( p1, p2 ) > squareDistThreshold )
3938 {
3939 if ( !isRing )
3940 {
3941 if ( !skipFirst )
3942 outputLine << ( i == 0 ? result->pointN( i ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset ) );
3943 if ( !skipLast )
3944 outputLine << ( i == result->numPoints() - 2 ? result->pointN( i + 1 ) : QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset ) );
3945 else
3946 outputLine << p2;
3947 }
3948 else
3949 {
3950 // ring
3951 if ( !skipFirst )
3952 outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, offset );
3953 else if ( i == 0 )
3954 outputLine << p1;
3955 if ( !skipLast )
3956 outputLine << QgsGeometryUtils::interpolatePointOnLine( p1, p2, 1.0 - offset );
3957 else
3958 outputLine << p2;
3959 }
3960 }
3961 skipFirst = skipLast;
3962 }
3963
3964 if ( isRing && outputLine.at( 0 ) != outputLine.at( outputLine.count() - 1 ) )
3965 outputLine << outputLine.at( 0 );
3966
3967 result->setPoints( outputLine );
3968 }
3969 return result;
3970}
3971
3972std::unique_ptr<QgsLineString> QgsGeometry::smoothLine( const QgsLineString &line, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3973{
3974 double maxAngleRads = maxAngle * M_PI / 180.0;
3975 double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
3976 return smoothCurve( line, iterations, offset, squareDistThreshold, maxAngleRads, false );
3977}
3978
3979std::unique_ptr<QgsPolygon> QgsGeometry::smoothPolygon( const QgsPolygon &polygon, const unsigned int iterations, const double offset, double minimumDistance, double maxAngle ) const
3980{
3981 double maxAngleRads = maxAngle * M_PI / 180.0;
3982 double squareDistThreshold = minimumDistance > 0 ? minimumDistance * minimumDistance : -1;
3983 std::unique_ptr< QgsPolygon > resultPoly = std::make_unique< QgsPolygon >();
3984
3985 resultPoly->setExteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.exteriorRing() ) ), iterations, offset,
3986 squareDistThreshold, maxAngleRads, true ).release() );
3987
3988 for ( int i = 0; i < polygon.numInteriorRings(); ++i )
3989 {
3990 resultPoly->addInteriorRing( smoothCurve( *( static_cast< const QgsLineString *>( polygon.interiorRing( i ) ) ), iterations, offset,
3991 squareDistThreshold, maxAngleRads, true ).release() );
3992 }
3993 return resultPoly;
3994}
3995
3996QgsGeometry QgsGeometry::convertToPoint( bool destMultipart ) const
3997{
3998 switch ( type() )
3999 {
4001 {
4002 bool srcIsMultipart = isMultipart();
4003
4004 if ( ( destMultipart && srcIsMultipart ) ||
4005 ( !destMultipart && !srcIsMultipart ) )
4006 {
4007 // return a copy of the same geom
4008 return QgsGeometry( *this );
4009 }
4010 if ( destMultipart )
4011 {
4012 // layer is multipart => make a multipoint with a single point
4013 return fromMultiPointXY( QgsMultiPointXY() << asPoint() );
4014 }
4015 else
4016 {
4017 // destination is singlepart => make a single part if possible
4018 QgsMultiPointXY multiPoint = asMultiPoint();
4019 if ( multiPoint.count() == 1 )
4020 {
4021 return fromPointXY( multiPoint[0] );
4022 }
4023 }
4024 return QgsGeometry();
4025 }
4026
4028 {
4029 // only possible if destination is multipart
4030 if ( !destMultipart )
4031 return QgsGeometry();
4032
4033 // input geometry is multipart
4034 if ( isMultipart() )
4035 {
4036 const QgsMultiPolylineXY multiLine = asMultiPolyline();
4037 QgsMultiPointXY multiPoint;
4038 for ( const QgsPolylineXY &l : multiLine )
4039 for ( const QgsPointXY &p : l )
4040 multiPoint << p;
4041 return fromMultiPointXY( multiPoint );
4042 }
4043 // input geometry is not multipart: copy directly the line into a multipoint
4044 else
4045 {
4046 QgsPolylineXY line = asPolyline();
4047 if ( !line.isEmpty() )
4048 return fromMultiPointXY( line );
4049 }
4050 return QgsGeometry();
4051 }
4052
4054 {
4055 // can only transform if destination is multipoint
4056 if ( !destMultipart )
4057 return QgsGeometry();
4058
4059 // input geometry is multipart: make a multipoint from multipolygon
4060 if ( isMultipart() )
4061 {
4062 const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
4063 QgsMultiPointXY multiPoint;
4064 for ( const QgsPolygonXY &poly : multiPolygon )
4065 for ( const QgsPolylineXY &line : poly )
4066 for ( const QgsPointXY &pt : line )
4067 multiPoint << pt;
4068 return fromMultiPointXY( multiPoint );
4069 }
4070 // input geometry is not multipart: make a multipoint from polygon
4071 else
4072 {
4073 const QgsPolygonXY polygon = asPolygon();
4074 QgsMultiPointXY multiPoint;
4075 for ( const QgsPolylineXY &line : polygon )
4076 for ( const QgsPointXY &pt : line )
4077 multiPoint << pt;
4078 return fromMultiPointXY( multiPoint );
4079 }
4080 }
4081
4082 default:
4083 return QgsGeometry();
4084 }
4085}
4086
4087QgsGeometry QgsGeometry::convertToLine( bool destMultipart ) const
4088{
4089 switch ( type() )
4090 {
4092 {
4093 if ( !isMultipart() )
4094 return QgsGeometry();
4095
4096 QgsMultiPointXY multiPoint = asMultiPoint();
4097 if ( multiPoint.count() < 2 )
4098 return QgsGeometry();
4099
4100 if ( destMultipart )
4101 return fromMultiPolylineXY( QgsMultiPolylineXY() << multiPoint );
4102 else
4103 return fromPolylineXY( multiPoint );
4104 }
4105
4107 {
4108 bool srcIsMultipart = isMultipart();
4109
4110 if ( ( destMultipart && srcIsMultipart ) ||
4111 ( !destMultipart && ! srcIsMultipart ) )
4112 {
4113 // return a copy of the same geom
4114 return QgsGeometry( *this );
4115 }
4116 if ( destMultipart )
4117 {
4118 // destination is multipart => makes a multipoint with a single line
4119 QgsPolylineXY line = asPolyline();
4120 if ( !line.isEmpty() )
4121 return fromMultiPolylineXY( QgsMultiPolylineXY() << line );
4122 }
4123 else
4124 {
4125 // destination is singlepart => make a single part if possible
4126 QgsMultiPolylineXY multiLine = asMultiPolyline();
4127 if ( multiLine.count() == 1 )
4128 return fromPolylineXY( multiLine[0] );
4129 }
4130 return QgsGeometry();
4131 }
4132
4134 {
4135 // input geometry is multipolygon
4136 if ( isMultipart() )
4137 {
4138 const QgsMultiPolygonXY multiPolygon = asMultiPolygon();
4139 QgsMultiPolylineXY multiLine;
4140 for ( const QgsPolygonXY &poly : multiPolygon )
4141 for ( const QgsPolylineXY &line : poly )
4142 multiLine << line;
4143
4144 if ( destMultipart )
4145 {
4146 // destination is multipart
4147 return fromMultiPolylineXY( multiLine );
4148 }
4149 else if ( multiLine.count() == 1 )
4150 {
4151 // destination is singlepart => make a single part if possible
4152 return fromPolylineXY( multiLine[0] );
4153 }
4154 }
4155 // input geometry is single polygon
4156 else
4157 {
4158 QgsPolygonXY polygon = asPolygon();
4159 // if polygon has rings
4160 if ( polygon.count() > 1 )
4161 {
4162 // cannot fit a polygon with rings in a single line layer
4163 // TODO: would it be better to remove rings?
4164 if ( destMultipart )
4165 {
4166 const QgsPolygonXY polygon = asPolygon();
4167 QgsMultiPolylineXY multiLine;
4168 multiLine.reserve( polygon.count() );
4169 for ( const QgsPolylineXY &line : polygon )
4170 multiLine << line;
4171 return fromMultiPolylineXY( multiLine );
4172 }
4173 }
4174 // no rings
4175 else if ( polygon.count() == 1 )
4176 {
4177 if ( destMultipart )
4178 {
4179 return fromMultiPolylineXY( polygon );
4180 }
4181 else
4182 {
4183 return fromPolylineXY( polygon[0] );
4184 }
4185 }
4186 }
4187 return QgsGeometry();
4188 }
4189
4190 default:
4191 return QgsGeometry();
4192 }
4193}
4194
4195QgsGeometry QgsGeometry::convertToPolygon( bool destMultipart ) const
4196{
4197 switch ( type() )
4198 {
4200 {
4201 if ( !isMultipart() )
4202 return QgsGeometry();
4203
4204 QgsMultiPointXY multiPoint = asMultiPoint();
4205 if ( multiPoint.count() < 3 )
4206 return QgsGeometry();
4207
4208 if ( multiPoint.last() != multiPoint.first() )
4209 multiPoint << multiPoint.first();
4210
4211 QgsPolygonXY polygon = QgsPolygonXY() << multiPoint;
4212 if ( destMultipart )
4213 return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
4214 else
4215 return fromPolygonXY( polygon );
4216 }
4217
4219 {
4220 // input geometry is multiline
4221 if ( isMultipart() )
4222 {
4223 QgsMultiPolylineXY multiLine = asMultiPolyline();
4224 QgsMultiPolygonXY multiPolygon;
4225 for ( QgsMultiPolylineXY::iterator multiLineIt = multiLine.begin(); multiLineIt != multiLine.end(); ++multiLineIt )
4226 {
4227 // do not create polygon for a 1 segment line
4228 if ( ( *multiLineIt ).count() < 3 )
4229 return QgsGeometry();
4230 if ( ( *multiLineIt ).count() == 3 && ( *multiLineIt ).first() == ( *multiLineIt ).last() )
4231 return QgsGeometry();
4232
4233 // add closing node
4234 if ( ( *multiLineIt ).first() != ( *multiLineIt ).last() )
4235 *multiLineIt << ( *multiLineIt ).first();
4236 multiPolygon << ( QgsPolygonXY() << *multiLineIt );
4237 }
4238 // check that polygons were inserted
4239 if ( !multiPolygon.isEmpty() )
4240 {
4241 if ( destMultipart )
4242 {
4243 return fromMultiPolygonXY( multiPolygon );
4244 }
4245 else if ( multiPolygon.count() == 1 )
4246 {
4247 // destination is singlepart => make a single part if possible
4248 return fromPolygonXY( multiPolygon[0] );
4249 }
4250 }
4251 }
4252 // input geometry is single line
4253 else
4254 {
4255 QgsPolylineXY line = asPolyline();
4256
4257 // do not create polygon for a 1 segment line
4258 if ( line.count() < 3 )
4259 return QgsGeometry();
4260 if ( line.count() == 3 && line.first() == line.last() )
4261 return QgsGeometry();
4262
4263 // add closing node
4264 if ( line.first() != line.last() )
4265 line << line.first();
4266
4267 // destination is multipart
4268 if ( destMultipart )
4269 {
4270 return fromMultiPolygonXY( QgsMultiPolygonXY() << ( QgsPolygonXY() << line ) );
4271 }
4272 else
4273 {
4274 return fromPolygonXY( QgsPolygonXY() << line );
4275 }
4276 }
4277 return QgsGeometry();
4278 }
4279
4281 {
4282 bool srcIsMultipart = isMultipart();
4283
4284 if ( ( destMultipart && srcIsMultipart ) ||
4285 ( !destMultipart && ! srcIsMultipart ) )
4286 {
4287 // return a copy of the same geom
4288 return QgsGeometry( *this );
4289 }
4290 if ( destMultipart )
4291 {
4292 // destination is multipart => makes a multipoint with a single polygon
4293 QgsPolygonXY polygon = asPolygon();
4294 if ( !polygon.isEmpty() )
4295 return fromMultiPolygonXY( QgsMultiPolygonXY() << polygon );
4296 }
4297 else
4298 {
4299 QgsMultiPolygonXY multiPolygon = asMultiPolygon();
4300 if ( multiPolygon.count() == 1 )
4301 {
4302 // destination is singlepart => make a single part if possible
4303 return fromPolygonXY( multiPolygon[0] );
4304 }
4305 }
4306 return QgsGeometry();
4307 }
4308
4309 default:
4310 return QgsGeometry();
4311 }
4312}
4313
4315{
4316 return new QgsGeos( geometry, precision );
4317}
4318
4319QDataStream &operator<<( QDataStream &out, const QgsGeometry &geometry )
4320{
4321 out << geometry.asWkb();
4322 return out;
4323}
4324
4325QDataStream &operator>>( QDataStream &in, QgsGeometry &geometry )
4326{
4327 QByteArray byteArray;
4328 in >> byteArray;
4329 if ( byteArray.isEmpty() )
4330 {
4331 geometry.set( nullptr );
4332 return in;
4333 }
4334
4335 geometry.fromWkb( byteArray );
4336 return in;
4337}
4338
4339
4341{
4342 return mMessage;
4343}
4344
4346{
4347 return mLocation;
4348}
4349
4351{
4352 return mHasLocation;
4353}
@ AllowSelfTouchingHoles
Indicates that self-touching holes are permitted. OGC validity states that self-touching holes are NO...
BufferSide
Side of line to buffer.
Definition qgis.h:1650
DashPatternSizeAdjustment
Dash pattern size adjustment options.
Definition qgis.h:2653
AngularDirection
Angular directions.
Definition qgis.h:2768
@ NoOrientation
Unknown orientation or sentinel value.
GeometryOperationResult
Success or failure of a geometry operation.
Definition qgis.h:1596
@ AddPartSelectedGeometryNotFound
The selected geometry cannot be found.
@ InvalidInputGeometryType
The input geometry (ring, part, split line, etc.) has not the correct geometry type.
@ Success
Operation succeeded.
@ SelectionIsEmpty
No features were selected.
@ GeometryTypeHasChanged
Operation has changed geometry type.
@ AddRingNotInExistingFeature
The input ring doesn't have any existing ring to fit into.
@ AddRingCrossesExistingRings
The input ring crosses existing rings (it is not disjoint)
@ AddPartNotMultiGeometry
The source geometry is not multi.
@ AddRingNotClosed
The input ring is not closed.
@ SelectionIsGreaterThanOne
More than one features were selected.
@ 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.
@ LayerNotEditable
Cannot edit layer.
@ AddRingNotValid
The input ring is not valid.
@ Segment
The actual start or end point of a segment.
GeometryValidationEngine
Available engines for validating geometries.
Definition qgis.h:1638
@ QgisInternal
Use internal QgsGeometryValidator method.
@ Geos
Use GEOS validation methods.
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
Definition qgis.h:255
@ Polygon
Polygons.
@ Unknown
Unknown types.
@ Null
No geometry.
JoinStyle
Join styles for buffers.
Definition qgis.h:1675
EndCapStyle
End cap styles for buffers.
Definition qgis.h:1662
CoverageValidityResult
Coverage validity results.
Definition qgis.h:1688
@ Error
An exception occurred while determining validity.
DashPatternLineEndingRule
Dash pattern line ending rules.
Definition qgis.h:2638
MakeValidMethod
Algorithms to use when repairing invalid geometries.
Definition qgis.h:1701
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:182
@ 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:2169
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.
virtual int vertexCount(int part=0, int ring=0) const =0
Returns the number of vertices of which this geometry is built.
bool isMeasure() const
Returns true if the geometry contains m values.
virtual QgsRectangle boundingBox() const
Returns the minimal bounding box for the geometry.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
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.
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
virtual double length() const
Returns the planar, 2-dimensional length of the geometry.
virtual bool dropZValue()=0
Drops any z-dimensions which exist in the geometry.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
A 3-dimensional box composed of x, y, z coordinates.
Definition qgsbox3d.h:43
double yMaximum() const
Returns the maximum y value.
Definition qgsbox3d.h:197
double xMinimum() const
Returns the minimum x value.
Definition qgsbox3d.h:162
double zMaximum() const
Returns the maximum z value.
Definition qgsbox3d.h:225
double xMaximum() const
Returns the maximum x value.
Definition qgsbox3d.h:169
QgsRectangle toRectangle() const
Converts the box to a 2D rectangle.
Definition qgsbox3d.h:338
bool is2d() const
Returns true if the box can be considered a 2-dimensional box, i.e.
Definition qgsbox3d.cpp:122
double zMinimum() const
Returns the minimum z value.
Definition qgsbox3d.h:218
double yMinimum() const
Returns the minimum y value.
Definition qgsbox3d.h:190
Circle geometry type.
Definition qgscircle.h:43
static QgsCircle from2Points(const QgsPoint &pt1, const QgsPoint &pt2)
Constructs a circle by 2 points on the circle.
Definition qgscircle.cpp:38
double radius() const
Returns the radius of the circle.
Definition qgscircle.h:310
bool contains(const QgsPoint &point, double epsilon=1E-8) const
Returns true if the circle contains the point.
QgsCircularString * toCircularString(bool oriented=false) const
Returns a circular string from the circle.
static QgsCircle minimalCircleFrom3Points(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double epsilon=1E-8)
Constructs the smallest circle from 3 points.
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.
int numInteriorRings() const
Returns the number of interior rings contained with the curve polygon.
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
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
Retrieves an interior ring from the curve polygon.
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)
bool removeInteriorRing(int ringIndex)
Removes an interior ring from the polygon.
Abstract base class for curved geometry type.
Definition qgscurve.h:35
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.
virtual QgsPolygon * toPolygon(unsigned int segments=36) const
Returns a segmented polygon.
QgsPoint center() const
Returns the center point.
Definition qgsellipse.h:120
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
virtual bool insertGeometry(QgsAbstractGeometry *g, int index)
Inserts a geometry before a specified index and takes ownership.
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.
int numGeometries() const
Returns the number of geometries within the collection.
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.
Java-style iterator for traversal of parts of a geometry.
static double angleBetweenThreePoints(double x1, double y1, double x2, double y2, double x3, double y3)
Calculates the angle between the lines AB and BC, where AB and BC described by points a,...
static double lineAngle(double x1, double y1, double x2, double y2)
Calculates the direction of line joining two points in radians, clockwise from the north direction.
static double averageAngle(double x1, double y1, double x2, double y2, double x3, double y3)
Calculates the average angle (in radians) between the two linear segments from (x1,...
static QgsPointXY interpolatePointOnLine(double x1, double y1, double x2, double y2, double fraction)
Interpolates the position of a point a fraction of the way along the line from (x1,...
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 QgsPoint closestVertex(const QgsAbstractGeometry &geom, const QgsPoint &pt, QgsVertexId &id)
Returns the closest vertex to a geometry for a specified point.
static Q_DECL_DEPRECATED double sqrDistance2D(double x1, double y1, double x2, double y2)
Returns the squared 2D distance between (x1, y1) and (x2, y2).
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.
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.
QPolygonF asQPolygonF() const
Returns contents of the geometry as a QPolygonF.
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.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
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.
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 ...
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 fromQPointF(QPointF point)
Construct geometry from a QPointF.
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 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.
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 minimumWidth() const
Returns a linestring geometry which represents the minimum diameter of the geometry.
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...
Qgis::CoverageValidityResult validateCoverage(double gapWidth, QgsGeometry *invalidEdges=nullptr) const
Analyze a coverage (represented as a collection of polygonal geometry with exactly matching edge geom...
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...
QgsGeometry simplifyCoverageVW(double tolerance, bool preserveBoundary) const
Operates on a coverage (represented as a list of polygonal geometry with exactly matching edge geomet...
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.
QgsGeometry makeValid(Qgis::MakeValidMethod method=Qgis::MakeValidMethod::Linework, bool keepCollapsed=false) const
Attempts to make an invalid geometry valid without losing vertices.
double frechetDistance(const QgsGeometry &geom) const
Returns the Fréchet distance between this geometry and geom, restricted to discrete points for both g...
QString lastError() const
Returns an error string referring to the last error encountered either when this geometry was created...
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 ...
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
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()
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.
void mapToPixel(const QgsMapToPixel &mtp)
Transforms the geometry from map units to pixels in place.
static QgsGeometry fromMultiPointXY(const QgsMultiPointXY &multipoint)
Creates a new geometry from a QgsMultiPointXY object.
QgsGeometry singleSidedBuffer(double distance, int segments, Qgis::BufferSide side, Qgis::JoinStyle joinStyle=Qgis::JoinStyle::Round, double miterLimit=2.0) const
Returns a single sided buffer for a (multi)line geometry.
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
QgsBox3D boundingBox3D() const
Returns the 3D bounding box of the geometry.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
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.
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 QgsGeometry fromPointXY(const QgsPointXY &point)
Creates a new geometry from a QgsPointXY object.
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
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.
Qgis::GeometryOperationResult avoidIntersectionsV2(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.
bool within(const QgsGeometry &geometry) const
Returns true if the geometry is completely within another geometry.
QPointF asQPointF() const
Returns contents of the geometry as a QPointF if wkbType is WKBPoint, otherwise returns a null QPoint...
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.
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
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.
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...
Qgis::AngularDirection polygonOrientation() const
Returns the orientation of the polygon.
double hausdorffDistance(const QgsGeometry &geom) const
Returns the Hausdorff distance between this geometry and geom.
QgsGeometry largestEmptyCircle(double tolerance, const QgsGeometry &boundary=QgsGeometry()) const
Constructs the Largest Empty Circle for a set of obstacle geometries, up to a specified tolerance.
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.
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 concaveHull(double targetPercent, bool allowHoles=false) const
Returns a possibly concave polygon that contains all the points in the geometry.
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 minimumClearanceLine() const
Returns a LineString whose endpoints define the minimum clearance of a geometry.
QgsGeometry sharedPaths(const QgsGeometry &other) const
Find paths shared between the two given lineal geometries (this and other).
virtual ~QgsGeometry()
static QgsGeometry fromPolygonXY(const QgsPolygonXY &polygon)
Creates a new geometry from a QgsPolygonXY.
double sqrDistToVertexAt(QgsPointXY &point, int atVertex) const
Returns the squared Cartesian distance between the given point to the given vertex index (vertex at t...
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.
double frechetDistanceDensify(const QgsGeometry &geom, double densifyFraction) const
Returns the Fréchet distance between this geometry and geom, restricted to discrete points for both g...
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const
Export the geometry to WKB.
QgsGeometry unionCoverage() const
Optimized union algorithm for polygonal inputs that are correctly noded and do not overlap.
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.
double minimumClearance() const
Computes the minimum clearance of a 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.
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.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry, double precision=0.0)
Creates and returns a new geometry engine representing the specified geometry using precision on a gr...
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.
Qgis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
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...
QgsGeometry()
Constructor.
QgsGeometry constrainedDelaunayTriangulation() const
Returns a constrained Delaunay triangulation for the vertices of the geometry.
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.
static QgsGeometry fromBox3D(const QgsBox3D &box)
Creates a new geometry from a QgsBox3D object.
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.
static QgsGeometry fromPoint(const QgsPoint &point)
Creates a new geometry from a QgsPoint object.
bool overlaps(const QgsGeometry &geometry) const
Returns true if the geometry overlaps another geometry.
Q_DECL_DEPRECATED 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:98
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:1876
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:2976
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...
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.
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
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.
QgsPointXY transform(const QgsPointXY &p) const
Transforms a point p from map (world) coordinates to device coordinates.
Multi line string geometry collection.
QgsLineString * lineStringN(int index)
Returns the line string with the specified index.
Multi point geometry collection.
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:60
void setY(double y)
Sets the y value of the point.
Definition qgspointxy.h:130
double y
Definition qgspointxy.h:64
double x
Definition qgspointxy.h:63
void setX(double x)
Sets the x value of the point.
Definition qgspointxy.h:120
QPointF toQPointF() const
Converts a point to a QPointF.
Definition qgspointxy.h:166
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:49
void setX(double x)
Sets the point's x-coordinate.
Definition qgspoint.h:332
QgsPoint * clone() const override
Clones the geometry by performing a deep copy.
Definition qgspoint.cpp:105
double x
Definition qgspoint.h:52
QgsPoint project(double distance, double azimuth, double inclination=90.0) const
Returns a new point which corresponds to this point projected by a specified distance with specified ...
Definition qgspoint.cpp:701
double y
Definition qgspoint.h:53
Polygon geometry type.
Definition qgspolygon.h:33
A rectangle specified with double values.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double xMaximum() const
Returns the x maximum value (right side of rectangle).
bool isNull() const
Test if the rectangle is null (holding no spatial information).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
bool isEmpty() const
Returns true if the rectangle has no area.
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)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
static bool isMultiType(Qgis::WkbType type)
Returns true if the WKB type is a multi type.
static bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
static bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
static Qgis::WkbType multiType(Qgis::WkbType type)
Returns the multi type for a WKB type.
static bool isCurvedType(Qgis::WkbType type)
Returns true if the WKB type is a curved type or can contain curved geometries.
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
static Qgis::WkbType curveType(Qgis::WkbType type)
Returns the curve type for a WKB type.
Contains geos related utilities and functions.
Definition qgsgeos.h:36
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:5713
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:5712
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:5144
QVector< QgsPoint > QgsPointSequence
Q_GLOBAL_STATIC_WITH_ARGS(PalPropertyList, palHiddenProperties,({ static_cast< int >(QgsPalLayerSettings::Property::PositionX), static_cast< int >(QgsPalLayerSettings::Property::PositionY), static_cast< int >(QgsPalLayerSettings::Property::Show), static_cast< int >(QgsPalLayerSettings::Property::LabelRotation), static_cast< int >(QgsPalLayerSettings::Property::Family), static_cast< int >(QgsPalLayerSettings::Property::FontStyle), static_cast< int >(QgsPalLayerSettings::Property::Size), static_cast< int >(QgsPalLayerSettings::Property::Bold), static_cast< int >(QgsPalLayerSettings::Property::Italic), static_cast< int >(QgsPalLayerSettings::Property::Underline), static_cast< int >(QgsPalLayerSettings::Property::Color), static_cast< int >(QgsPalLayerSettings::Property::Strikeout), static_cast< int >(QgsPalLayerSettings::Property::MultiLineAlignment), static_cast< int >(QgsPalLayerSettings::Property::BufferSize), static_cast< int >(QgsPalLayerSettings::Property::BufferDraw), static_cast< int >(QgsPalLayerSettings::Property::BufferColor), static_cast< int >(QgsPalLayerSettings::Property::LabelDistance), static_cast< int >(QgsPalLayerSettings::Property::Hali), static_cast< int >(QgsPalLayerSettings::Property::Vali), static_cast< int >(QgsPalLayerSettings::Property::ScaleVisibility), static_cast< int >(QgsPalLayerSettings::Property::MinScale), static_cast< int >(QgsPalLayerSettings::Property::MaxScale), static_cast< int >(QgsPalLayerSettings::Property::AlwaysShow), static_cast< int >(QgsPalLayerSettings::Property::CalloutDraw), static_cast< int >(QgsPalLayerSettings::Property::LabelAllParts) })) Q_GLOBAL_STATIC_WITH_ARGS(SymbolPropertyList
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)
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:74
QVector< QgsPolylineXY > QgsMultiPolylineXY
A collection of QgsPolylines that share a common collection of attributes.
Definition qgsgeometry.h:84
QVector< QgsPointXY > QgsMultiPointXY
A collection of QgsPoints that share a common collection of attributes.
Definition qgsgeometry.h:80
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
Definition qgsgeometry.h:62
QVector< QgsPolygonXY > QgsMultiPolygonXY
A collection of QgsPolygons that share a common collection of attributes.
Definition qgsgeometry.h:91
QgsPointSequence QgsPolyline
Polyline as represented as a vector of points.
Definition qgsgeometry.h:70
int precision
std::unique_ptr< QgsAbstractGeometry > geometry
QgsGeometryPrivate(std::unique_ptr< QgsAbstractGeometry > geometry)
Utility class for identifying a unique vertex within a geometry.
Definition qgsvertexid.h:30
int vertex
Vertex number.
Definition qgsvertexid.h:94
bool isValid() const
Returns true if the vertex id is valid.
Definition qgsvertexid.h:45