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