QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsgeometrycollection.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsgeometrycollection.cpp
3 -------------------------------------------------------------------
4Date : 28 Oct 2014
5Copyright : (C) 2014 by Marco Hugentobler
6email : marco.hugentobler at sourcepole dot com
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
17#include "qgsapplication.h"
18#include "qgsbox3d.h"
19#include "qgsgeometryfactory.h"
20#include "qgsgeometryutils.h"
21#include "qgscircularstring.h"
22#include "qgscompoundcurve.h"
23#include "qgslinestring.h"
24#include "qgsmultilinestring.h"
25#include "qgspoint.h"
26#include "qgsmultipoint.h"
27#include "qgspolygon.h"
28#include "qgsmultipolygon.h"
29#include "qgswkbptr.h"
30#include "qgsgeos.h"
31#include "qgsfeedback.h"
32
33#include <nlohmann/json.hpp>
34#include <memory>
35
37{
39}
40
43 mBoundingBox( c.mBoundingBox ),
44 mHasCachedValidity( c.mHasCachedValidity ),
45 mValidityFailureReason( c.mValidityFailureReason )
46{
47 int nGeoms = c.mGeometries.size();
48 mGeometries.resize( nGeoms );
49 for ( int i = 0; i < nGeoms; ++i )
50 {
51 mGeometries[i] = c.mGeometries.at( i )->clone();
52 }
53}
54
56{
57 if ( &c != this )
58 {
59 clearCache();
61 int nGeoms = c.mGeometries.size();
62 mGeometries.resize( nGeoms );
63 for ( int i = 0; i < nGeoms; ++i )
64 {
65 mGeometries[i] = c.mGeometries.at( i )->clone();
66 }
67 }
68 return *this;
69}
70
72{
73 clear();
74}
75
77{
78 auto result = std::make_unique< QgsGeometryCollection >();
79 result->mWkbType = mWkbType;
80 return result.release();
81}
82
84{
85 return new QgsGeometryCollection( *this );
86}
87
89{
90 qDeleteAll( mGeometries );
91 mGeometries.clear();
92 clearCache(); //set bounding box invalid
93}
94
95QgsGeometryCollection *QgsGeometryCollection::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing ) const
96{
97 std::unique_ptr<QgsGeometryCollection> result;
98
99 for ( auto geom : mGeometries )
100 {
101 std::unique_ptr<QgsAbstractGeometry> gridified { geom->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing ) };
102 if ( gridified )
103 {
104 if ( !result )
105 result = std::unique_ptr<QgsGeometryCollection> { createEmptyWithSameType() };
106
107 result->mGeometries.append( gridified.release() );
108 }
109 }
110
111 return result.release();
112}
113
114bool QgsGeometryCollection::removeDuplicateNodes( double epsilon, bool useZValues )
115{
116 bool result = false;
117 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
118 {
119 if ( geom->removeDuplicateNodes( epsilon, useZValues ) ) result = true;
120 }
121 return result;
122}
123
125{
126 return nullptr;
127}
128
129void QgsGeometryCollection::adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex ) const
130{
131 if ( vertex.part < 0 || vertex.part >= mGeometries.count() )
132 {
133 previousVertex = QgsVertexId();
135 return;
136 }
137
138 mGeometries.at( vertex.part )->adjacentVertices( vertex, previousVertex, nextVertex );
139}
140
142{
143 if ( id.part < 0 || id.part >= mGeometries.count() )
144 return -1;
145
146 int number = 0;
147 int part = 0;
148 for ( QgsAbstractGeometry *geometry : mGeometries )
149 {
150 if ( part == id.part )
151 {
152 int partNumber = geometry->vertexNumberFromVertexId( QgsVertexId( 0, id.ring, id.vertex ) );
153 if ( partNumber == -1 )
154 return -1;
155 return number + partNumber;
156 }
157 else
158 {
159 number += geometry->nCoordinates();
160 }
161
162 part++;
163 }
164 return -1; // should not happen
165}
166
168{
169 if ( mGeometries.empty() )
170 return false;
171
172 // if we already have the bounding box calculated, then this check is trivial!
173 if ( !mBoundingBox.isNull() )
174 {
175 return mBoundingBox.intersects( box3d );
176 }
177
178 // otherwise loop through each member geometry and test the bounding box intersection.
179 // This gives us a chance to use optimisations which may be present on the individual
180 // geometry subclasses, and at worst it will cause a calculation of the bounding box
181 // of each individual member geometry which we would have to do anyway... (and these
182 // bounding boxes are cached, so would be reused without additional expense)
183 for ( const QgsAbstractGeometry *geometry : mGeometries )
184 {
185 if ( geometry->boundingBoxIntersects( box3d ) )
186 return true;
187 }
188
189 // even if we don't intersect the bounding box of any member geometries, we may still intersect the
190 // bounding box of the overall collection.
191 // so here we fall back to the non-optimised base class check which has to first calculate
192 // the overall bounding box of the collection..
194}
195
197{
198 mGeometries.reserve( size );
199}
200
202{
203 clearCache();
204 return mGeometries.value( n );
205}
206
208{
209 if ( mGeometries.isEmpty() )
210 return true;
211
212 for ( QgsAbstractGeometry *geometry : mGeometries )
213 {
214 if ( !geometry->isEmpty() )
215 return false;
216 }
217 return true;
218}
219
221{
222 if ( !g )
223 {
224 return false;
225 }
226
227 mGeometries.append( g );
228 clearCache(); //set bounding box invalid
229 return true;
230}
231
233{
234 if ( !g )
235 {
236 return false;
237 }
238
239 index = std::min( static_cast<int>( mGeometries.count() ), index );
240
241 mGeometries.insert( index, g );
242 clearCache(); //set bounding box invalid
243 return true;
244}
245
247{
248 if ( nr >= mGeometries.size() || nr < 0 )
249 {
250 return false;
251 }
252 delete mGeometries.at( nr );
253 mGeometries.remove( nr );
254 clearCache(); //set bounding box invalid
255 return true;
256}
257
259{
260 for ( QgsAbstractGeometry *geometry : std::as_const( mGeometries ) )
261 {
262 geometry->normalize();
263 }
264 std::sort( mGeometries.begin(), mGeometries.end(), []( const QgsAbstractGeometry * a, const QgsAbstractGeometry * b )
265 {
266 return a->compareTo( b ) > 0;
267 } );
268}
269
271{
272 int maxDim = 0;
273 QVector< QgsAbstractGeometry * >::const_iterator it = mGeometries.constBegin();
274 for ( ; it != mGeometries.constEnd(); ++it )
275 {
276 int dim = ( *it )->dimension();
277 if ( dim > maxDim )
278 {
279 maxDim = dim;
280 }
281 }
282 return maxDim;
283}
284
286{
287 return QStringLiteral( "GeometryCollection" );
288}
289
291{
292 for ( QgsAbstractGeometry *g : std::as_const( mGeometries ) )
293 {
294 g->transform( ct, d, transformZ );
295 }
296 clearCache(); //set bounding box invalid
297}
298
299void QgsGeometryCollection::transform( const QTransform &t, double zTranslate, double zScale, double mTranslate, double mScale )
300{
301 for ( QgsAbstractGeometry *g : std::as_const( mGeometries ) )
302 {
303 g->transform( t, zTranslate, zScale, mTranslate, mScale );
304 }
305 clearCache(); //set bounding box invalid
306}
307
308void QgsGeometryCollection::draw( QPainter &p ) const
309{
310 QVector< QgsAbstractGeometry * >::const_iterator it = mGeometries.constBegin();
311 for ( ; it != mGeometries.constEnd(); ++it )
312 {
313 ( *it )->draw( p );
314 }
315}
316
318{
319 QPainterPath p;
320 for ( const QgsAbstractGeometry *geom : mGeometries )
321 {
322 QPainterPath partPath = geom->asQPainterPath();
323 if ( !partPath.isEmpty() )
324 p.addPath( partPath );
325 }
326 return p;
327}
328
330{
331 if ( !wkbPtr )
332 {
333 return false;
334 }
335
338 return false;
339
341
342 int nGeometries = 0;
343 wkbPtr >> nGeometries;
344
345 QVector<QgsAbstractGeometry *> geometryListBackup = mGeometries;
346 mGeometries.clear();
347 mGeometries.reserve( nGeometries );
348 for ( int i = 0; i < nGeometries; ++i )
349 {
350 std::unique_ptr< QgsAbstractGeometry > geom( QgsGeometryFactory::geomFromWkb( wkbPtr ) ); // also updates wkbPtr
351 if ( geom )
352 {
353 if ( !addGeometry( geom.release() ) )
354 {
355 qDeleteAll( mGeometries );
356 mGeometries = geometryListBackup;
357 return false;
358 }
359 }
360 }
361 qDeleteAll( geometryListBackup );
362
363 clearCache(); //set bounding box invalid
364
365 return true;
366}
367
368bool QgsGeometryCollection::fromWkt( const QString &wkt )
369{
370 return fromCollectionWkt( wkt, QVector<QgsAbstractGeometry *>() << new QgsPoint << new QgsLineString << new QgsPolygon
372 << new QgsCurvePolygon
375 << new QgsMultiCurve << new QgsMultiSurface, QStringLiteral( "GeometryCollection" ) );
376}
377
379{
380 int binarySize = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
381 for ( const QgsAbstractGeometry *geom : mGeometries )
382 {
383 if ( geom )
384 {
385 binarySize += geom->wkbSize( flags );
386 }
387 }
388
389 return binarySize;
390}
391
392QByteArray QgsGeometryCollection::asWkb( WkbFlags flags ) const
393{
394 int countNonNull = 0;
395 for ( const QgsAbstractGeometry *geom : mGeometries )
396 {
397 if ( geom )
398 {
399 countNonNull ++;
400 }
401 }
402
403 QByteArray wkbArray;
404 wkbArray.resize( QgsGeometryCollection::wkbSize( flags ) );
405 QgsWkbPtr wkb( wkbArray );
406 wkb << static_cast<char>( QgsApplication::endian() );
407 wkb << static_cast<quint32>( wkbType() );
408 wkb << static_cast<quint32>( countNonNull );
409 for ( const QgsAbstractGeometry *geom : mGeometries )
410 {
411 if ( geom )
412 {
413 wkb << geom->asWkb( flags );
414 }
415 }
416 return wkbArray;
417}
418
420{
421 QString wkt = wktTypeStr();
422
423 if ( isEmpty() )
424 wkt += QLatin1String( " EMPTY" );
425 else
426 {
427 wkt += QLatin1String( " (" );
428 for ( const QgsAbstractGeometry *geom : mGeometries )
429 {
430 QString childWkt = geom->asWkt( precision );
431 if ( wktOmitChildType() )
432 {
433 childWkt = childWkt.mid( childWkt.indexOf( '(' ) );
434 }
435 wkt += childWkt + ',';
436 }
437 if ( wkt.endsWith( ',' ) )
438 {
439 wkt.chop( 1 ); // Remove last ','
440 }
441 wkt += ')';
442 }
443 return wkt;
444}
445
446QDomElement QgsGeometryCollection::asGml2( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
447{
448 QDomElement elemMultiGeometry = doc.createElementNS( ns, QStringLiteral( "MultiGeometry" ) );
449 for ( const QgsAbstractGeometry *geom : mGeometries )
450 {
451 QDomElement elemGeometryMember = doc.createElementNS( ns, QStringLiteral( "geometryMember" ) );
452 elemGeometryMember.appendChild( geom->asGml2( doc, precision, ns, axisOrder ) );
453 elemMultiGeometry.appendChild( elemGeometryMember );
454 }
455 return elemMultiGeometry;
456}
457
458QDomElement QgsGeometryCollection::asGml3( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
459{
460 QDomElement elemMultiGeometry = doc.createElementNS( ns, QStringLiteral( "MultiGeometry" ) );
461 for ( const QgsAbstractGeometry *geom : mGeometries )
462 {
463 QDomElement elemGeometryMember = doc.createElementNS( ns, QStringLiteral( "geometryMember" ) );
464 elemGeometryMember.appendChild( geom->asGml3( doc, precision, ns, axisOrder ) );
465 elemMultiGeometry.appendChild( elemGeometryMember );
466 }
467 return elemMultiGeometry;
468}
469
471{
472 json coordinates( json::array( ) );
473 for ( const QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
474 {
475 coordinates.push_back( geom->asJsonObject( precision ) );
476 }
477 return
478 {
479 { "type", "GeometryCollection" },
480 { "geometries", coordinates }
481 };
482}
483
485{
486 QString kml;
487 kml.append( QLatin1String( "<MultiGeometry>" ) );
488 const QVector< QgsAbstractGeometry * > &geometries = mGeometries;
489 for ( const QgsAbstractGeometry *geometry : geometries )
490 {
491 kml.append( geometry->asKml( precision ) );
492 }
493 kml.append( QLatin1String( "</MultiGeometry>" ) );
494 return kml;
495}
496
498{
499 if ( mBoundingBox.isNull() )
500 {
501 mBoundingBox = calculateBoundingBox3D();
502 }
503 return mBoundingBox;
504}
505
507{
508 if ( mGeometries.empty() )
509 {
510 return QgsBox3D();
511 }
512
513 QgsBox3D bbox = mGeometries.at( 0 )->boundingBox3D();
514 for ( int i = 1; i < mGeometries.size(); ++i )
515 {
516 if ( mGeometries.at( i )->isEmpty() )
517 continue;
518
519 QgsBox3D geomBox = mGeometries.at( i )->boundingBox3D();
520 bbox.combineWith( geomBox );
521 }
522 return bbox;
523}
524
526{
527 mBoundingBox = QgsBox3D();
528 mHasCachedValidity = false;
529 mValidityFailureReason.clear();
531}
532
534{
535 QgsCoordinateSequence sequence;
536 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
537 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
538 {
539 QgsCoordinateSequence geomCoords = ( *geomIt )->coordinateSequence();
540
541 QgsCoordinateSequence::const_iterator cIt = geomCoords.constBegin();
542 for ( ; cIt != geomCoords.constEnd(); ++cIt )
543 {
544 sequence.push_back( *cIt );
545 }
546 }
547
548 return sequence;
549}
550
552{
553 int count = 0;
554
555 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
556 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
557 {
558 count += ( *geomIt )->nCoordinates();
559 }
560
561 return count;
562}
563
564double QgsGeometryCollection::closestSegment( const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf, double epsilon ) const
565{
566 return QgsGeometryUtils::closestSegmentFromComponents( mGeometries, QgsGeometryUtils::Part, pt, segmentPt, vertexAfter, leftOf, epsilon );
567}
568
570{
571 if ( id.part < 0 )
572 {
573 id.part = 0;
574 id.ring = -1;
575 id.vertex = -1;
576 }
577 if ( mGeometries.isEmpty() )
578 {
579 return false;
580 }
581
582 if ( id.part >= mGeometries.count() )
583 return false;
584
585 QgsAbstractGeometry *geom = mGeometries.at( id.part );
586 if ( geom->nextVertex( id, vertex ) )
587 {
588 return true;
589 }
590 if ( ( id.part + 1 ) >= numGeometries() )
591 {
592 return false;
593 }
594 ++id.part;
595 id.ring = -1;
596 id.vertex = -1;
597 return mGeometries.at( id.part )->nextVertex( id, vertex );
598}
599
601{
602 if ( position.part >= mGeometries.size() )
603 {
604 return false;
605 }
606
607 bool success = mGeometries.at( position.part )->insertVertex( position, vertex );
608 if ( success )
609 {
610 clearCache(); //set bounding box invalid
611 }
612 return success;
613}
614
616{
617 if ( position.part < 0 || position.part >= mGeometries.size() )
618 {
619 return false;
620 }
621
622 bool success = mGeometries.at( position.part )->moveVertex( position, newPos );
623 if ( success )
624 {
625 clearCache(); //set bounding box invalid
626 }
627 return success;
628}
629
631{
632 if ( position.part < 0 || position.part >= mGeometries.size() )
633 {
634 return false;
635 }
636
637 QgsAbstractGeometry *geom = mGeometries.at( position.part );
638 if ( !geom )
639 {
640 return false;
641 }
642
643 bool success = geom->deleteVertex( position );
644
645 //remove geometry if no vertices left
646 if ( geom->isEmpty() )
647 {
648 removeGeometry( position.part );
649 }
650
651 if ( success )
652 {
653 clearCache(); //set bounding box invalid
654 }
655 return success;
656}
657
659{
660 double length = 0.0;
661 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
662 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
663 {
664 length += ( *geomIt )->length();
665 }
666 return length;
667}
668
670{
671 double area = 0.0;
672 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
673 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
674 {
675 area += ( *geomIt )->area();
676 }
677 return area;
678}
679
681{
682 double perimeter = 0.0;
683 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
684 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
685 {
686 perimeter += ( *geomIt )->perimeter();
687 }
688 return perimeter;
689}
690
691bool QgsGeometryCollection::fromCollectionWkt( const QString &wkt, const QVector<QgsAbstractGeometry *> &subtypes, const QString &defaultChildWkbType )
692{
693 clear();
694
695 QPair<Qgis::WkbType, QString> parts = QgsGeometryUtils::wktReadBlock( wkt );
696
698 {
699 qDeleteAll( subtypes );
700 return false;
701 }
702 mWkbType = parts.first;
703
704 QString secondWithoutParentheses = parts.second;
705 secondWithoutParentheses = secondWithoutParentheses.remove( '(' ).remove( ')' ).simplified().remove( ' ' );
706 if ( ( parts.second.compare( QLatin1String( "EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
707 secondWithoutParentheses.isEmpty() )
708 {
709 qDeleteAll( subtypes );
710 return true;
711 }
712
713 QString defChildWkbType = QStringLiteral( "%1%2%3 " ).arg( defaultChildWkbType, is3D() ? QStringLiteral( "Z" ) : QString(), isMeasure() ? QStringLiteral( "M" ) : QString() );
714
715 const QStringList blocks = QgsGeometryUtils::wktGetChildBlocks( parts.second, defChildWkbType );
716 for ( const QString &childWkt : blocks )
717 {
718 QPair<Qgis::WkbType, QString> childParts = QgsGeometryUtils::wktReadBlock( childWkt );
719
720 bool success = false;
721 for ( const QgsAbstractGeometry *geom : subtypes )
722 {
723 if ( QgsWkbTypes::flatType( childParts.first ) == QgsWkbTypes::flatType( geom->wkbType() ) )
724 {
725 mGeometries.append( geom->clone() );
726 if ( mGeometries.back()->fromWkt( childWkt ) )
727 {
728 success = true;
729 break;
730 }
731 }
732 }
733 if ( !success )
734 {
735 clear();
736 qDeleteAll( subtypes );
737 return false;
738 }
739 }
740 qDeleteAll( subtypes );
741
742 //scan through geometries and check if dimensionality of geometries is different to collection.
743 //if so, update the type dimensionality of the collection to match
744 bool hasZ = false;
745 bool hasM = false;
746 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
747 {
748 hasZ = hasZ || geom->is3D();
749 hasM = hasM || geom->isMeasure();
750 if ( hasZ && hasM )
751 break;
752 }
753 if ( hasZ )
754 addZValue( 0 );
755 if ( hasM )
756 addMValue( 0 );
757
758 return true;
759}
760
762{
763 QVector< QgsAbstractGeometry * >::const_iterator it = mGeometries.constBegin();
764 for ( ; it != mGeometries.constEnd(); ++it )
765 {
766 if ( ( *it )->hasCurvedSegments() )
767 {
768 return true;
769 }
770 }
771 return false;
772}
773
775{
776 std::unique_ptr< QgsAbstractGeometry > geom( QgsGeometryFactory::geomFromWkbType( QgsWkbTypes::linearType( mWkbType ) ) );
777 QgsGeometryCollection *geomCollection = qgsgeometry_cast<QgsGeometryCollection *>( geom.get() );
778 if ( !geomCollection )
779 {
780 return clone();
781 }
782
783 geomCollection->reserve( mGeometries.size() );
784 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
785 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
786 {
787 geomCollection->addGeometry( ( *geomIt )->segmentize( tolerance, toleranceType ) );
788 }
789 return geom.release();
790}
791
793{
794 if ( vertex.part < 0 || vertex.part >= mGeometries.size() )
795 {
796 return 0.0;
797 }
798
799 QgsAbstractGeometry *geom = mGeometries[vertex.part];
800 if ( !geom )
801 {
802 return 0.0;
803 }
804
805 return geom->vertexAngle( vertex );
806}
807
809{
810 if ( startVertex.part < 0 || startVertex.part >= mGeometries.size() )
811 {
812 return 0.0;
813 }
814
815 const QgsAbstractGeometry *geom = mGeometries[startVertex.part];
816 if ( !geom )
817 {
818 return 0.0;
819 }
820
821 return geom->segmentLength( startVertex );
822}
823
824int QgsGeometryCollection::vertexCount( int part, int ring ) const
825{
826 if ( part < 0 || part >= mGeometries.size() )
827 {
828 return 0;
829 }
830
831 return mGeometries[part]->vertexCount( 0, ring );
832}
833
835{
836 if ( part < 0 || part >= mGeometries.size() )
837 {
838 return 0;
839 }
840
841 return mGeometries[part]->ringCount();
842}
843
845{
846 return mGeometries.size();
847}
848
850{
851 if ( id.part < 0 || id.part >= mGeometries.size() )
852 {
853 return QgsPoint();
854 }
855
856 const QgsAbstractGeometry *geom = mGeometries[id.part];
857 if ( !geom )
858 {
859 return QgsPoint();
860 }
861
862 return geom->vertexAt( id );
863}
864
866{
867 if ( flags == 0 && mHasCachedValidity )
868 {
869 // use cached validity results
870 error = mValidityFailureReason;
871 return error.isEmpty();
872 }
873
874 QgsGeos geos( this, /* tolerance = */ 0, /* allowInvalidSubGeom = */ false );
875 bool res = geos.isValid( &error, flags & Qgis::GeometryValidityFlag::AllowSelfTouchingHoles, nullptr );
876 if ( flags == 0 )
877 {
878 mValidityFailureReason = !res ? error : QString();
879 mHasCachedValidity = true;
880 }
881 return res;
882}
883
885{
887 return false;
888
890
891 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
892 {
893 geom->addZValue( zValue );
894 }
895 clearCache();
896 return true;
897}
898
900{
902 return false;
903
905
906 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
907 {
908 geom->addMValue( mValue );
909 }
910 clearCache();
911 return true;
912}
913
914
916{
918 return false;
919
921 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
922 {
923 geom->dropZValue();
924 }
925 clearCache();
926 return true;
927}
928
930{
932 return false;
933
935 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
936 {
937 geom->dropMValue();
938 }
939 clearCache();
940 return true;
941}
942
943void QgsGeometryCollection::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
944{
945 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
946 {
947 if ( geom )
948 geom->filterVertices( filter );
949 }
950 clearCache();
951}
952
953void QgsGeometryCollection::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
954{
955 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
956 {
957 if ( geom )
958 geom->transformVertices( transform );
959 }
960 clearCache();
961}
962
964{
965 // be tolerant if caller passed a multi type as type argument
966 const Qgis::WkbType filterSinglePartType = useFlatType ? QgsWkbTypes::flatType( QgsWkbTypes::singleType( type ) ) : QgsWkbTypes::singleType( type );
967
968 std::unique_ptr< QgsGeometryCollection > res;
969 switch ( QgsWkbTypes::geometryType( type ) )
970 {
972 {
973 if ( useFlatType )
974 {
975 // potential shortcut if we're already a matching subclass of QgsGeometryCollection
976 if ( const QgsMultiPoint *mp = qgsgeometry_cast< const QgsMultiPoint *>( this ) )
977 return mp->clone();
978 }
979
980 res = std::make_unique< QgsMultiPoint >();
981 break;
982 }
984 {
985 if ( useFlatType )
986 {
987 // potential shortcut if we're already a matching subclass of QgsGeometryCollection
988 if ( const QgsMultiLineString *ml = qgsgeometry_cast< const QgsMultiLineString *>( this ) )
989 return ml->clone();
990 }
991
992 res = std::make_unique< QgsMultiLineString >();
993 break;
994 }
996 {
997 if ( useFlatType )
998 {
999 // potential shortcut if we're already a matching subclass of QgsGeometryCollection
1000 if ( const QgsMultiPolygon *mp = qgsgeometry_cast< const QgsMultiPolygon *>( this ) )
1001 return mp->clone();
1002 }
1003
1004 res = std::make_unique< QgsMultiPolygon>();
1005 break;
1006 }
1007
1010 return nullptr;
1011 }
1012
1013 // assume that the collection consists entirely of matching parts (ie optimize for a pessimistic scenario)
1014 res->reserve( mGeometries.size() );
1015
1016 for ( const QgsAbstractGeometry *part : mGeometries )
1017 {
1018 if ( !part )
1019 continue;
1020
1021 const QgsAbstractGeometry *simplifiedPartType = part->simplifiedTypeRef();
1022
1023 const Qgis::WkbType thisPartType = useFlatType ? QgsWkbTypes::flatType( simplifiedPartType->wkbType() ) : simplifiedPartType->wkbType();
1024 if ( thisPartType == filterSinglePartType )
1025 {
1026 res->addGeometry( part->clone() );
1027 }
1028 }
1029
1030 return res.release();
1031}
1032
1034{
1035 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
1036 {
1037 if ( geom )
1038 geom->swapXy();
1039 }
1040 clearCache();
1041}
1042
1044{
1045 std::unique_ptr< QgsGeometryCollection > newCollection( new QgsGeometryCollection() );
1046 newCollection->reserve( mGeometries.size() );
1047 for ( QgsAbstractGeometry *geom : mGeometries )
1048 {
1049 newCollection->addGeometry( geom->toCurveType() );
1050 }
1051 return newCollection.release();
1052}
1053
1055{
1056 if ( mGeometries.size() == 1 )
1057 return mGeometries.at( 0 )->simplifiedTypeRef();
1058 else
1059 return this;
1060}
1061
1063{
1064 if ( !transformer )
1065 return false;
1066
1067 bool res = true;
1068 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
1069 {
1070 if ( geom )
1071 res = geom->transform( transformer, feedback );
1072
1073 if ( feedback && feedback->isCanceled() )
1074 res = false;
1075
1076 if ( !res )
1077 break;
1078 }
1079 clearCache();
1080 return res;
1081}
1082
1084{
1085 return false;
1086}
1087
1089{
1090 return mGeometries.count();
1091}
1092
1094{
1095 if ( index < 0 || index >= mGeometries.count() )
1096 return nullptr;
1097
1098 return mGeometries.at( index );
1099}
1100
1102{
1103 const QgsGeometryCollection *otherCollection = qgsgeometry_cast<const QgsGeometryCollection *>( other );
1104 if ( !otherCollection )
1105 return -1;
1106
1107 int i = 0;
1108 int j = 0;
1109 while ( i < mGeometries.size() && j < otherCollection->mGeometries.size() )
1110 {
1111 const QgsAbstractGeometry *aGeom = mGeometries[i];
1112 const QgsAbstractGeometry *bGeom = otherCollection->mGeometries[j];
1113 const int comparison = aGeom->compareTo( bGeom );
1114 if ( comparison != 0 )
1115 {
1116 return comparison;
1117 }
1118 i++;
1119 j++;
1120 }
1121 if ( i < mGeometries.size() )
1122 {
1123 return 1;
1124 }
1125 if ( j < otherCollection->mGeometries.size() )
1126 {
1127 return -1;
1128 }
1129 return 0;
1130}
@ AllowSelfTouchingHoles
Indicates that self-touching holes are permitted. OGC validity states that self-touching holes are NO...
QFlags< GeometryValidityFlag > GeometryValidityFlags
Geometry validity flags.
Definition: qgis.h:1648
@ Polygon
Polygons.
@ Unknown
Unknown types.
@ Null
No geometry.
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition: qgis.h:182
@ GeometryCollection
GeometryCollection.
TransformDirection
Indicates the direction (forward or inverse) of a transform.
Definition: qgis.h:2191
An abstract base class for classes which transform geometries by transforming input points to output ...
Abstract base class for all geometries.
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
virtual double vertexAngle(QgsVertexId vertex) const =0
Returns approximate angle at a vertex.
virtual const QgsAbstractGeometry * simplifiedTypeRef() const
Returns a reference to the simplest lossless representation of this geometry, e.g.
bool isMeasure() const
Returns true if the geometry contains m values.
QFlags< WkbFlag > WkbFlags
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
AxisOrder
Axis order for GML generation.
QString wktTypeStr() const
Returns the WKT type string of the geometry.
virtual QgsPoint vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
virtual void clearCache() const
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
QgsAbstractGeometry & operator=(const QgsAbstractGeometry &geom)
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
virtual bool isEmpty() const
Returns true if the geometry is empty.
virtual bool boundingBoxIntersects(const QgsRectangle &rectangle) const
Returns true if the bounding box of this geometry intersects with a rectangle.
virtual bool deleteVertex(QgsVertexId position)=0
Deletes a vertex within the geometry.
virtual double segmentLength(QgsVertexId startVertex) const =0
Returns the length of the segment of the geometry which begins at startVertex.
virtual int compareTo(const QgsAbstractGeometry *other) const
Comparator for sorting of geometry.
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts of the geometry.
virtual bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const =0
Returns next vertex id and coordinates.
static endian_t endian()
Returns whether this machine uses big or little endian.
A 3-dimensional box composed of x, y, z coordinates.
Definition: qgsbox3d.h:43
bool intersects(const QgsBox3D &other) const
Returns true if box intersects with another box.
Definition: qgsbox3d.cpp:132
void combineWith(const QgsBox3D &box)
Expands the bbox so that it covers both the original rectangle and the given rectangle.
Definition: qgsbox3d.cpp:196
bool isNull() const
Test if the box is null (holding no spatial information).
Definition: qgsbox3d.cpp:289
Circular string geometry type.
Compound curve geometry type.
A const WKB pointer.
Definition: qgswkbptr.h:138
Qgis::WkbType readHeader() const
readHeader
Definition: qgswkbptr.cpp:55
Class for doing transforms between two map coordinate systems.
Curve polygon geometry type.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:44
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:53
Geometry collection.
QgsGeometryCollection * toCurveType() const override
Returns the geometry converted to the more generic curve type.
bool dropMValue() override
Drops any measure values which exist in the geometry.
QString asKml(int precision=17) const override
Returns a KML representation of the geometry.
double perimeter() const override
Returns the planar, 2-dimensional perimeter of the geometry.
QVector< QgsAbstractGeometry * > mGeometries
void draw(QPainter &p) const override
Draws the geometry using the specified QPainter.
json asJsonObject(int precision=17) const override
Returns a json object representation of the geometry.
QgsGeometryCollection * snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0) const override
Makes a new geometry with all the points or vertices snapped to the closest point of the grid.
bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) override
Transforms the geometry using a coordinate transform.
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
void clear() override
Clears the geometry, ie reset it to a null geometry.
void reserve(int size)
Attempts to allocate memory for at least size geometries.
QPainterPath asQPainterPath() const override
Returns the geometry represented as a QPainterPath.
QgsAbstractGeometry * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
int vertexCount(int part=0, int ring=0) const override
Returns the number of vertices of which this geometry is built.
QString geometryType() const override
Returns a unique string representing the geometry type.
QgsGeometryCollection & operator=(const QgsGeometryCollection &c)
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
void adjacentVertices(QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex) const override
Returns the vertices adjacent to a specified vertex within a geometry.
int wkbSize(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns the length of the QByteArray returned by asWkb()
virtual bool insertGeometry(QgsAbstractGeometry *g, int index)
Inserts a geometry before a specified index and takes ownership.
int vertexNumberFromVertexId(QgsVertexId id) const override
Returns the vertex number corresponding to a vertex id.
bool isEmpty() const override
Returns true if the geometry is empty.
QgsGeometryCollection()
Constructor for an empty geometry collection.
bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const override
Returns next vertex id and coordinates.
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
bool fromWkb(QgsConstWkbPtr &wkb) override
Sets the geometry from a WKB string.
QgsAbstractGeometry * boundary() const override
Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the...
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
double area() const override
Returns the planar, 2-dimensional area of the geometry.
bool removeDuplicateNodes(double epsilon=4 *std::numeric_limits< double >::epsilon(), bool useZValues=false) override
Removes duplicate nodes from the geometry, wherever removing the nodes does not result in a degenerat...
int ringCount(int part=0) const override
Returns the number of rings of which this geometry is built.
void normalize() final
Reorganizes the geometry into a normalized form (or "canonical" form).
QgsAbstractGeometry * childGeometry(int index) const override
Returns pointer to child geometry (for geometries with child geometries - i.e.
void transformVertices(const std::function< QgsPoint(const QgsPoint &) > &transform) override
Transforms the vertices from the geometry in place, applying the transform function to every vertex.
void filterVertices(const std::function< bool(const QgsPoint &) > &filter) override
Filters the vertices from the geometry in place, removing any which do not return true for the filter...
QDomElement asGml2(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML2 representation of the geometry.
bool moveVertex(QgsVertexId position, const QgsPoint &newPos) override
Moves a vertex within the geometry.
int nCoordinates() const override
Returns the number of nodes contained in the geometry.
QgsGeometryCollection * extractPartsByType(Qgis::WkbType type, bool useFlatType=true) const
Returns a new QgsGeometryCollection subclass which consists of the parts of this collection which mat...
QgsBox3D boundingBox3D() const override
Returns the 3D bounding box for the geometry.
QgsGeometryCollection * clone() const override
Clones the geometry by performing a deep copy.
int childCount() const override
Returns number of child geometries (for geometries with child geometries) or child points (for geomet...
bool hasCurvedSegments() const override
Returns true if the geometry contains curved segments.
bool insertVertex(QgsVertexId position, const QgsPoint &vertex) override
Inserts a vertex into the geometry.
double length() const override
Returns the planar, 2-dimensional length of the geometry.
int dimension() const override
Returns the inherent dimension of the geometry.
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
QgsPoint vertexAt(QgsVertexId id) const override
Returns the point corresponding to a specified vertex id.
virtual bool removeGeometry(int nr)
Removes a geometry from the collection.
void swapXy() override
Swaps the x and y coordinates from the geometry.
bool boundingBoxIntersects(const QgsBox3D &box3d) const override
Returns true if the bounding box of this geometry intersects with a box3d.
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.
QgsBox3D calculateBoundingBox3D() const override
Calculates the minimal 3D bounding box for the geometry.
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns a WKB representation of the geometry.
int partCount() const override
Returns count of parts contained in the geometry.
virtual bool wktOmitChildType() const
Returns whether child type names are omitted from Wkt representations of the collection.
bool fromCollectionWkt(const QString &wkt, const QVector< QgsAbstractGeometry * > &subtypes, const QString &defaultChildWkbType=QString())
Reads a collection from a WKT string.
QgsCoordinateSequence coordinateSequence() const override
Retrieves the sequence of geometries, rings and nodes.
int numGeometries() const
Returns the number of geometries within the collection.
double segmentLength(QgsVertexId startVertex) const override
Returns the length of the segment of the geometry which begins at startVertex.
QDomElement asGml3(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML3 representation of the geometry.
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
double vertexAngle(QgsVertexId vertex) const override
Returns approximate angle at a vertex.
int compareToSameClass(const QgsAbstractGeometry *other) const final
Compares to an other geometry of the same class, and returns a integer for sorting of the two geometr...
double closestSegment(const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf=nullptr, double epsilon=4 *std::numeric_limits< double >::epsilon()) const override
Searches for the closest segment of the geometry to a given point.
const QgsAbstractGeometry * simplifiedTypeRef() const override
Returns a reference to the simplest lossless representation of this geometry, e.g.
static std::unique_ptr< QgsAbstractGeometry > geomFromWkb(QgsConstWkbPtr &wkb)
Construct geometry from a WKB string.
static std::unique_ptr< QgsAbstractGeometry > geomFromWkbType(Qgis::WkbType t)
Returns empty geometry from wkb type.
static QStringList wktGetChildBlocks(const QString &wkt, const QString &defaultType=QString())
Parses a WKT string and returns of list of blocks contained in the WKT.
static QPair< Qgis::WkbType, QString > wktReadBlock(const QString &wkt)
Parses a WKT block of the format "TYPE( contents )" and returns a pair of geometry type to contents (...
static double closestSegmentFromComponents(T &container, ComponentType ctype, const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf, double epsilon)
Does vector analysis using the geos library and handles import, export, exception handling*.
Definition: qgsgeos.h:98
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:45
Multi curve geometry collection.
Definition: qgsmulticurve.h:29
Multi line string geometry collection.
Multi point geometry collection.
Definition: qgsmultipoint.h:29
Multi polygon geometry collection.
Multi surface geometry collection.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
Polygon geometry type.
Definition: qgspolygon.h:33
WKB pointer handler.
Definition: qgswkbptr.h:44
static Qgis::WkbType dropM(Qgis::WkbType type)
Drops the m dimension (if present) for a WKB type and returns the new type.
Definition: qgswkbtypes.h:1144
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...
Definition: qgswkbtypes.h:862
static Qgis::WkbType linearType(Qgis::WkbType type)
Returns the linear type for a WKB type.
Definition: qgswkbtypes.h:518
static Qgis::WkbType dropZ(Qgis::WkbType type)
Drops the z dimension (if present) for a WKB type and returns the new type.
Definition: qgswkbtypes.h:1127
static Qgis::WkbType addM(Qgis::WkbType type)
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1092
static Qgis::WkbType addZ(Qgis::WkbType type)
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1068
static Qgis::WkbType singleType(Qgis::WkbType type)
Returns the single type for a WKB type.
Definition: qgswkbtypes.h:53
static bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:973
static bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1023
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:628
double ANALYSIS_EXPORT leftOf(const QgsPoint &thepoint, const QgsPoint *p1, const QgsPoint *p2)
Returns whether 'thepoint' is left or right of the line from 'p1' to 'p2'. Negative values mean left ...
Definition: MathUtils.cpp:222
Contains geos related utilities and functions.
Definition: qgsgeos.h:36
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QVector< QgsRingSequence > QgsCoordinateSequence
int precision
Utility class for identifying a unique vertex within a geometry.
Definition: qgsvertexid.h:30
int part
Part number.
Definition: qgsvertexid.h:88