QGIS API Documentation 3.99.0-Master (a8882ad4560)
Loading...
Searching...
No Matches
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
18#include <memory>
19#include <nlohmann/json.hpp>
20
21#include "qgsapplication.h"
22#include "qgsbox3d.h"
23#include "qgsfeedback.h"
24#include "qgsgeometryfactory.h"
25#include "qgsgeometryutils.h"
26#include "qgsgeos.h"
27#include "qgslinestring.h"
28#include "qgsmultilinestring.h"
29#include "qgsmultipoint.h"
30#include "qgsmultipolygon.h"
31#include "qgspoint.h"
32#include "qgswkbptr.h"
33
38
41 mBoundingBox( c.mBoundingBox ),
42 mHasCachedValidity( c.mHasCachedValidity ),
43 mValidityFailureReason( c.mValidityFailureReason )
44{
45 int nGeoms = c.mGeometries.size();
46 mGeometries.resize( nGeoms );
47 for ( int i = 0; i < nGeoms; ++i )
48 {
49 mGeometries[i] = c.mGeometries.at( i )->clone();
50 }
51}
52
53// cppcheck-suppress operatorEqVarError
55{
56 if ( &c != this )
57 {
59 int nGeoms = c.mGeometries.size();
60 mGeometries.resize( nGeoms );
61 for ( int i = 0; i < nGeoms; ++i )
62 {
63 mGeometries[i] = c.mGeometries.at( i )->clone();
64 }
65 }
66 return *this;
67}
68
73
75{
76 auto result = std::make_unique< QgsGeometryCollection >();
77 result->mWkbType = mWkbType;
78 return result.release();
79}
80
85
87{
88 qDeleteAll( mGeometries );
89 mGeometries.clear();
90 clearCache(); //set bounding box invalid
91}
92
93QgsGeometryCollection *QgsGeometryCollection::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing, bool removeRedundantPoints ) const
94{
95 std::unique_ptr<QgsGeometryCollection> result;
96
97 for ( auto geom : mGeometries )
98 {
99 std::unique_ptr<QgsAbstractGeometry> gridified { geom->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing, removeRedundantPoints ) };
100 if ( gridified )
101 {
102 if ( !result )
103 result = std::unique_ptr<QgsGeometryCollection> { createEmptyWithSameType() };
104
105 result->mGeometries.append( gridified.release() );
106 }
107 }
108
109 return result.release();
110}
111
112bool QgsGeometryCollection::removeDuplicateNodes( double epsilon, bool useZValues )
113{
114 bool result = false;
115 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
116 {
117 if ( geom->removeDuplicateNodes( epsilon, useZValues ) ) result = true;
118 }
119 return result;
120}
121
123{
124 return nullptr;
125}
126
128{
129 if ( vertex.part < 0 || vertex.part >= mGeometries.count() )
130 {
131 previousVertex = QgsVertexId();
133 return;
134 }
135
136 mGeometries.at( vertex.part )->adjacentVertices( vertex, previousVertex, nextVertex );
137}
138
140{
141 if ( id.part < 0 || id.part >= mGeometries.count() )
142 return -1;
143
144 int number = 0;
145 int part = 0;
146 for ( QgsAbstractGeometry *geometry : mGeometries )
147 {
148 if ( part == id.part )
149 {
150 int partNumber = geometry->vertexNumberFromVertexId( QgsVertexId( 0, id.ring, id.vertex ) );
151 if ( partNumber == -1 )
152 return -1;
153 return number + partNumber;
154 }
155 else
156 {
157 number += geometry->nCoordinates();
158 }
159
160 part++;
161 }
162 return -1; // should not happen
163}
164
166{
167 if ( mGeometries.empty() )
168 return false;
169
170 // if we already have the bounding box calculated, then this check is trivial!
171 if ( !mBoundingBox.isNull() )
172 {
173 return mBoundingBox.intersects( box3d );
174 }
175
176 // otherwise loop through each member geometry and test the bounding box intersection.
177 // This gives us a chance to use optimisations which may be present on the individual
178 // geometry subclasses, and at worst it will cause a calculation of the bounding box
179 // of each individual member geometry which we would have to do anyway... (and these
180 // bounding boxes are cached, so would be reused without additional expense)
181 for ( const QgsAbstractGeometry *geometry : mGeometries )
182 {
183 if ( geometry->boundingBoxIntersects( box3d ) )
184 return true;
185 }
186
187 // even if we don't intersect the bounding box of any member geometries, we may still intersect the
188 // bounding box of the overall collection.
189 // so here we fall back to the non-optimised base class check which has to first calculate
190 // the overall bounding box of the collection..
192}
193
195{
196 mGeometries.reserve( size );
197}
198
200{
201 clearCache();
202 return mGeometries.value( n );
203}
204
206{
207 if ( mGeometries.isEmpty() )
208 return true;
209
210 for ( QgsAbstractGeometry *geometry : mGeometries )
211 {
212 if ( !geometry->isEmpty() )
213 return false;
214 }
215 return true;
216}
217
219{
220 if ( !g )
221 {
222 return false;
223 }
224
225 mGeometries.append( g );
226 clearCache(); //set bounding box invalid
227 return true;
228}
229
230bool QgsGeometryCollection::addGeometries( const QVector<QgsAbstractGeometry *> &geometries )
231{
232 mGeometries.append( geometries );
233 clearCache(); //set bounding box invalid
234 return true;
235}
236
238{
239 if ( !g )
240 {
241 return false;
242 }
243
244 index = std::min( static_cast<int>( mGeometries.count() ), index );
245
246 mGeometries.insert( index, g );
247 clearCache(); //set bounding box invalid
248 return true;
249}
250
252{
253 if ( nr >= mGeometries.size() || nr < 0 )
254 {
255 return false;
256 }
257 delete mGeometries.at( nr );
258 mGeometries.remove( nr );
259 clearCache(); //set bounding box invalid
260 return true;
261}
262
263QVector<QgsAbstractGeometry *> QgsGeometryCollection::takeGeometries()
264{
265 QVector< QgsAbstractGeometry * > results = mGeometries;
266 mGeometries.clear();
267 clearCache();
268 return results;
269}
270
272{
273 for ( QgsAbstractGeometry *geometry : std::as_const( mGeometries ) )
274 {
275 geometry->normalize();
276 }
277 std::sort( mGeometries.begin(), mGeometries.end(), []( const QgsAbstractGeometry * a, const QgsAbstractGeometry * b )
278 {
279 return a->compareTo( b ) > 0;
280 } );
281}
282
284{
285 int maxDim = 0;
286 QVector< QgsAbstractGeometry * >::const_iterator it = mGeometries.constBegin();
287 for ( ; it != mGeometries.constEnd(); ++it )
288 {
289 int dim = ( *it )->dimension();
290 if ( dim > maxDim )
291 {
292 maxDim = dim;
293 }
294 }
295 return maxDim;
296}
297
299{
300 return u"GeometryCollection"_s;
301}
302
304{
305 for ( QgsAbstractGeometry *g : std::as_const( mGeometries ) )
306 {
307 g->transform( ct, d, transformZ );
308 }
309 clearCache(); //set bounding box invalid
310}
311
312void QgsGeometryCollection::transform( const QTransform &t, double zTranslate, double zScale, double mTranslate, double mScale )
313{
314 for ( QgsAbstractGeometry *g : std::as_const( mGeometries ) )
315 {
316 g->transform( t, zTranslate, zScale, mTranslate, mScale );
317 }
318 clearCache(); //set bounding box invalid
319}
320
321void QgsGeometryCollection::draw( QPainter &p ) const
322{
323 QVector< QgsAbstractGeometry * >::const_iterator it = mGeometries.constBegin();
324 for ( ; it != mGeometries.constEnd(); ++it )
325 {
326 ( *it )->draw( p );
327 }
328}
329
331{
332 QPainterPath p;
333 for ( const QgsAbstractGeometry *geom : mGeometries )
334 {
335 QPainterPath partPath = geom->asQPainterPath();
336 if ( !partPath.isEmpty() )
337 p.addPath( partPath );
338 }
339 return p;
340}
341
343{
344 if ( !wkbPtr )
345 {
346 return false;
347 }
348
351 return false;
352
354
355 int nGeometries = 0;
356 wkbPtr >> nGeometries;
357
358 QVector<QgsAbstractGeometry *> geometryListBackup = mGeometries;
359 mGeometries.clear();
360 mGeometries.reserve( nGeometries );
361 for ( int i = 0; i < nGeometries; ++i )
362 {
363 std::unique_ptr< QgsAbstractGeometry > geom( QgsGeometryFactory::geomFromWkb( wkbPtr ) ); // also updates wkbPtr
364 if ( geom )
365 {
366 if ( !addGeometry( geom.release() ) )
367 {
368 qDeleteAll( mGeometries );
369 mGeometries = geometryListBackup;
370 return false;
371 }
372 }
373 }
374 qDeleteAll( geometryListBackup );
375
376 clearCache(); //set bounding box invalid
377
378 return true;
379}
380
401
403{
404 int binarySize = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
405 for ( const QgsAbstractGeometry *geom : mGeometries )
406 {
407 if ( geom )
408 {
409 binarySize += geom->wkbSize( flags );
410 }
411 }
412
413 return binarySize;
414}
415
416QByteArray QgsGeometryCollection::asWkb( WkbFlags flags ) const
417{
418 int countNonNull = 0;
419 for ( const QgsAbstractGeometry *geom : mGeometries )
420 {
421 if ( geom )
422 {
423 countNonNull ++;
424 }
425 }
426
427 QByteArray wkbArray;
428 wkbArray.resize( QgsGeometryCollection::wkbSize( flags ) );
429 QgsWkbPtr wkb( wkbArray );
430 wkb << static_cast<char>( QgsApplication::endian() );
431 wkb << static_cast<quint32>( wkbType() );
432 wkb << static_cast<quint32>( countNonNull );
433 for ( const QgsAbstractGeometry *geom : mGeometries )
434 {
435 if ( geom )
436 {
437 wkb << geom->asWkb( flags );
438 }
439 }
440 return wkbArray;
441}
442
443QString QgsGeometryCollection::asWkt( int precision ) const
444{
445 QString wkt = wktTypeStr();
446
447 if ( isEmpty() )
448 wkt += " EMPTY"_L1;
449 else
450 {
451 wkt += " ("_L1;
452 for ( const QgsAbstractGeometry *geom : mGeometries )
453 {
454 QString childWkt = geom->asWkt( precision );
455 if ( wktOmitChildType() )
456 {
457 childWkt = childWkt.mid( childWkt.indexOf( '(' ) );
458 }
459 wkt += childWkt + ',';
460 }
461 if ( wkt.endsWith( ',' ) )
462 {
463 wkt.chop( 1 ); // Remove last ','
464 }
465 wkt += ')';
466 }
467 return wkt;
468}
469
470QDomElement QgsGeometryCollection::asGml2( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
471{
472 QDomElement elemMultiGeometry = doc.createElementNS( ns, u"MultiGeometry"_s );
473 for ( const QgsAbstractGeometry *geom : mGeometries )
474 {
475 QDomElement elemGeometryMember = doc.createElementNS( ns, u"geometryMember"_s );
476 elemGeometryMember.appendChild( geom->asGml2( doc, precision, ns, axisOrder ) );
477 elemMultiGeometry.appendChild( elemGeometryMember );
478 }
479 return elemMultiGeometry;
480}
481
482QDomElement QgsGeometryCollection::asGml3( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
483{
484 QDomElement elemMultiGeometry = doc.createElementNS( ns, u"MultiGeometry"_s );
485 for ( const QgsAbstractGeometry *geom : mGeometries )
486 {
487 QDomElement elemGeometryMember = doc.createElementNS( ns, u"geometryMember"_s );
488 elemGeometryMember.appendChild( geom->asGml3( doc, precision, ns, axisOrder ) );
489 elemMultiGeometry.appendChild( elemGeometryMember );
490 }
491 return elemMultiGeometry;
492}
493
494json QgsGeometryCollection::asJsonObject( int precision ) const
495{
496 json coordinates( json::array( ) );
497 for ( const QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
498 {
499 coordinates.push_back( geom->asJsonObject( precision ) );
500 }
501 return
502 {
503 { "type", "GeometryCollection" },
504 { "geometries", coordinates }
505 };
506}
507
508QString QgsGeometryCollection::asKml( int precision ) const
509{
510 QString kml;
511 kml.append( "<MultiGeometry>"_L1 );
512 const QVector< QgsAbstractGeometry * > &geometries = mGeometries;
513 for ( const QgsAbstractGeometry *geometry : geometries )
514 {
515 kml.append( geometry->asKml( precision ) );
516 }
517 kml.append( "</MultiGeometry>"_L1 );
518 return kml;
519}
520
522{
523 if ( mBoundingBox.isNull() )
524 {
525 mBoundingBox = calculateBoundingBox3D();
526 }
527 return mBoundingBox;
528}
529
531{
532 if ( mGeometries.empty() )
533 {
534 return QgsBox3D();
535 }
536
537 QgsBox3D bbox = mGeometries.at( 0 )->boundingBox3D();
538 for ( int i = 1; i < mGeometries.size(); ++i )
539 {
540 if ( mGeometries.at( i )->isEmpty() )
541 continue;
542
543 QgsBox3D geomBox = mGeometries.at( i )->boundingBox3D();
544 bbox.combineWith( geomBox );
545 }
546 return bbox;
547}
548
550{
551 mBoundingBox = QgsBox3D();
552 mHasCachedValidity = false;
553 mValidityFailureReason.clear();
555}
556
558{
559 QgsCoordinateSequence sequence;
560 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
561 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
562 {
563 QgsCoordinateSequence geomCoords = ( *geomIt )->coordinateSequence();
564
565 QgsCoordinateSequence::const_iterator cIt = geomCoords.constBegin();
566 for ( ; cIt != geomCoords.constEnd(); ++cIt )
567 {
568 sequence.push_back( *cIt );
569 }
570 }
571
572 return sequence;
573}
574
576{
577 int count = 0;
578
579 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
580 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
581 {
582 count += ( *geomIt )->nCoordinates();
583 }
584
585 return count;
586}
587
588double QgsGeometryCollection::closestSegment( const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf, double epsilon ) const
589{
590 return QgsGeometryUtils::closestSegmentFromComponents( mGeometries, QgsGeometryUtils::Part, pt, segmentPt, vertexAfter, leftOf, epsilon );
591}
592
594{
595 if ( id.part < 0 )
596 {
597 id.part = 0;
598 id.ring = -1;
599 id.vertex = -1;
600 }
601 if ( mGeometries.isEmpty() )
602 {
603 return false;
604 }
605
606 if ( id.part >= mGeometries.count() )
607 return false;
608
609 QgsAbstractGeometry *geom = mGeometries.at( id.part );
610 if ( geom->nextVertex( id, vertex ) )
611 {
612 return true;
613 }
614 if ( ( id.part + 1 ) >= numGeometries() )
615 {
616 return false;
617 }
618 ++id.part;
619 id.ring = -1;
620 id.vertex = -1;
621 return mGeometries.at( id.part )->nextVertex( id, vertex );
622}
623
625{
626 if ( position.part >= mGeometries.size() )
627 {
628 return false;
629 }
630
631 bool success = mGeometries.at( position.part )->insertVertex( position, vertex );
632 if ( success )
633 {
634 clearCache(); //set bounding box invalid
635 }
636 return success;
637}
638
640{
641 if ( position.part < 0 || position.part >= mGeometries.size() )
642 {
643 return false;
644 }
645
646 bool success = mGeometries.at( position.part )->moveVertex( position, newPos );
647 if ( success )
648 {
649 clearCache(); //set bounding box invalid
650 }
651 return success;
652}
653
655{
656 if ( position.part < 0 || position.part >= mGeometries.size() )
657 {
658 return false;
659 }
660
661 QgsAbstractGeometry *geom = mGeometries.at( position.part );
662 if ( !geom )
663 {
664 return false;
665 }
666
667 bool success = geom->deleteVertex( position );
668
669 //remove geometry if no vertices left
670 if ( geom->isEmpty() )
671 {
672 removeGeometry( position.part );
673 }
674
675 if ( success )
676 {
677 clearCache(); //set bounding box invalid
678 }
679 return success;
680}
681
683{
684 double length = 0.0;
685 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
686 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
687 {
688 length += ( *geomIt )->length();
689 }
690 return length;
691}
692
694{
695 double area = 0.0;
696 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
697 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
698 {
699 area += ( *geomIt )->area();
700 }
701 return area;
702}
703
705{
706 double area3D = 0.0;
707 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
708 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
709 {
710 area3D += ( *geomIt )->area3D();
711 }
712 return area3D;
713}
714
716{
717 double perimeter = 0.0;
718 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
719 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
720 {
721 perimeter += ( *geomIt )->perimeter();
722 }
723 return perimeter;
724}
725
726bool QgsGeometryCollection::fromCollectionWkt( const QString &wkt, const QVector<Qgis::WkbType> &subtypes, const QString &defaultChildWkbType )
727{
728 clear();
729
730 QPair<Qgis::WkbType, QString> parts = QgsGeometryUtils::wktReadBlock( wkt );
731
733 {
734 return false;
735 }
736 mWkbType = parts.first;
737
738 QString secondWithoutParentheses = parts.second;
739 secondWithoutParentheses = secondWithoutParentheses.remove( '(' ).remove( ')' ).simplified().remove( ' ' );
740 if ( ( parts.second.compare( "EMPTY"_L1, Qt::CaseInsensitive ) == 0 ) ||
741 secondWithoutParentheses.isEmpty() )
742 {
743 return true;
744 }
745
746 QString defChildWkbType = u"%1%2%3 "_s.arg( defaultChildWkbType, is3D() ? u"Z"_s : QString(), isMeasure() ? u"M"_s : QString() );
747
748 const QStringList blocks = QgsGeometryUtils::wktGetChildBlocks( parts.second, defChildWkbType );
749 for ( const QString &childWkt : blocks )
750 {
751 QPair<Qgis::WkbType, QString> childParts = QgsGeometryUtils::wktReadBlock( childWkt );
752
753 bool success = false;
754 for ( const Qgis::WkbType subtype : subtypes )
755 {
756 if ( QgsWkbTypes::flatType( childParts.first ) == QgsWkbTypes::flatType( subtype ) )
757 {
758 mGeometries.append(
759 QgsGeometryFactory::geomFromWkbType( subtype ).release()
760 );
761 if ( mGeometries.back()->fromWkt( childWkt ) )
762 {
763 success = true;
764 break;
765 }
766 }
767 }
768 if ( !success )
769 {
770 clear();
771 return false;
772 }
773 }
774
775 //scan through geometries and check if dimensionality of geometries is different to collection.
776 //if so, update the type dimensionality of the collection to match
777 bool hasZ = false;
778 bool hasM = false;
779 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
780 {
781 hasZ = hasZ || geom->is3D();
782 hasM = hasM || geom->isMeasure();
783 if ( hasZ && hasM )
784 break;
785 }
786 if ( hasZ )
787 addZValue( 0 );
788 if ( hasM )
789 addMValue( 0 );
790
791 return true;
792}
793
795{
796 QVector< QgsAbstractGeometry * >::const_iterator it = mGeometries.constBegin();
797 for ( ; it != mGeometries.constEnd(); ++it )
798 {
799 if ( ( *it )->hasCurvedSegments() )
800 {
801 return true;
802 }
803 }
804 return false;
805}
806
808{
809 std::unique_ptr< QgsAbstractGeometry > geom( QgsGeometryFactory::geomFromWkbType( QgsWkbTypes::linearType( mWkbType ) ) );
811 if ( !geomCollection )
812 {
813 return clone();
814 }
815
816 geomCollection->reserve( mGeometries.size() );
817 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
818 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
819 {
820 geomCollection->addGeometry( ( *geomIt )->segmentize( tolerance, toleranceType ) );
821 }
822 return geom.release();
823}
824
826{
827 if ( vertex.part < 0 || vertex.part >= mGeometries.size() )
828 {
829 return 0.0;
830 }
831
832 QgsAbstractGeometry *geom = mGeometries[vertex.part];
833 if ( !geom )
834 {
835 return 0.0;
836 }
837
838 return geom->vertexAngle( vertex );
839}
840
842{
843 if ( startVertex.part < 0 || startVertex.part >= mGeometries.size() )
844 {
845 return 0.0;
846 }
847
848 const QgsAbstractGeometry *geom = mGeometries[startVertex.part];
849 if ( !geom )
850 {
851 return 0.0;
852 }
853
854 return geom->segmentLength( startVertex );
855}
856
857int QgsGeometryCollection::vertexCount( int part, int ring ) const
858{
859 if ( part < 0 || part >= mGeometries.size() )
860 {
861 return 0;
862 }
863
864 return mGeometries[part]->vertexCount( 0, ring );
865}
866
868{
869 if ( part < 0 || part >= mGeometries.size() )
870 {
871 return 0;
872 }
873
874 return mGeometries[part]->ringCount();
875}
876
878{
879 return mGeometries.size();
880}
881
883{
884 if ( id.part < 0 || id.part >= mGeometries.size() )
885 {
886 return QgsPoint();
887 }
888
889 const QgsAbstractGeometry *geom = mGeometries[id.part];
890 if ( !geom )
891 {
892 return QgsPoint();
893 }
894
895 return geom->vertexAt( id );
896}
897
899{
900 if ( flags == 0 && mHasCachedValidity )
901 {
902 // use cached validity results
903 error = mValidityFailureReason;
904 return error.isEmpty();
905 }
906
907 QgsGeos geos( this, /* precision = */ 0, /* flags = */ Qgis::GeosCreationFlag::RejectOnInvalidSubGeometry );
908 bool res = geos.isValid( &error, flags & Qgis::GeometryValidityFlag::AllowSelfTouchingHoles, nullptr );
909 if ( flags == 0 )
910 {
911 mValidityFailureReason = !res ? error : QString();
912 mHasCachedValidity = true;
913 }
914 return res;
915}
916
918{
920 return false;
921
923
924 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
925 {
926 geom->addZValue( zValue );
927 }
928 clearCache();
929 return true;
930}
931
933{
935 return false;
936
938
939 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
940 {
941 geom->addMValue( mValue );
942 }
943 clearCache();
944 return true;
945}
946
947
949{
951 return false;
952
954 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
955 {
956 geom->dropZValue();
957 }
958 clearCache();
959 return true;
960}
961
963{
965 return false;
966
968 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
969 {
970 geom->dropMValue();
971 }
972 clearCache();
973 return true;
974}
975
976void QgsGeometryCollection::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
977{
978 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
979 {
980 if ( geom )
981 geom->filterVertices( filter );
982 }
983 clearCache();
984}
985
987{
988 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
989 {
990 if ( geom )
991 geom->transformVertices( transform );
992 }
993 clearCache();
994}
995
997{
998 // be tolerant if caller passed a multi type as type argument
999 const Qgis::WkbType filterSinglePartType = useFlatType ? QgsWkbTypes::flatType( QgsWkbTypes::singleType( type ) ) : QgsWkbTypes::singleType( type );
1000
1001 std::unique_ptr< QgsGeometryCollection > res;
1002 switch ( QgsWkbTypes::geometryType( type ) )
1003 {
1005 {
1006 if ( useFlatType )
1007 {
1008 // potential shortcut if we're already a matching subclass of QgsGeometryCollection
1010 return mp->clone();
1011 }
1012
1013 res = std::make_unique< QgsMultiPoint >();
1014 break;
1015 }
1017 {
1018 if ( useFlatType )
1019 {
1020 // potential shortcut if we're already a matching subclass of QgsGeometryCollection
1022 return ml->clone();
1023 }
1024
1025 res = std::make_unique< QgsMultiLineString >();
1026 break;
1027 }
1029 {
1030 if ( useFlatType )
1031 {
1032 // potential shortcut if we're already a matching subclass of QgsGeometryCollection
1034 return mp->clone();
1035 }
1036
1037 res = std::make_unique< QgsMultiPolygon>();
1038 break;
1039 }
1040
1043 return nullptr;
1044 }
1045
1046 // assume that the collection consists entirely of matching parts (ie optimize for a pessimistic scenario)
1047 res->reserve( mGeometries.size() );
1048
1049 for ( const QgsAbstractGeometry *part : mGeometries )
1050 {
1051 if ( !part )
1052 continue;
1053
1054 const QgsAbstractGeometry *simplifiedPartType = part->simplifiedTypeRef();
1055
1056 const Qgis::WkbType thisPartType = useFlatType ? QgsWkbTypes::flatType( simplifiedPartType->wkbType() ) : simplifiedPartType->wkbType();
1057 if ( thisPartType == filterSinglePartType )
1058 {
1059 res->addGeometry( part->clone() );
1060 }
1061 }
1062
1063 return res.release();
1064}
1065
1067{
1068 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
1069 {
1070 if ( geom )
1071 geom->swapXy();
1072 }
1073 clearCache();
1074}
1075
1077{
1078 auto newCollection = std::make_unique<QgsGeometryCollection>();
1079 newCollection->reserve( mGeometries.size() );
1080 for ( QgsAbstractGeometry *geom : mGeometries )
1081 {
1082 newCollection->addGeometry( geom->toCurveType() );
1083 }
1084 return newCollection.release();
1085}
1086
1088{
1089 if ( mGeometries.size() == 1 )
1090 return mGeometries.at( 0 )->simplifiedTypeRef();
1091 else
1092 return this;
1093}
1094
1096{
1097 auto res = std::make_unique< QgsGeometryCollection >();
1098 res->reserve( mGeometries.size() );
1099 for ( int i = 0; i < mGeometries.size(); ++i )
1100 {
1101 res->addGeometry( mGeometries.at( i )->simplifyByDistance( tolerance ) );
1102 }
1103 return res.release();
1104}
1105
1107{
1108 if ( !transformer )
1109 return false;
1110
1111 bool res = true;
1112 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
1113 {
1114 if ( geom )
1115 res = geom->transform( transformer, feedback );
1116
1117 if ( feedback && feedback->isCanceled() )
1118 res = false;
1119
1120 if ( !res )
1121 break;
1122 }
1123 clearCache();
1124 return res;
1125}
1126
1128{
1129 return false;
1130}
1131
1133{
1134 return mGeometries.count();
1135}
1136
1138{
1139 if ( index < 0 || index >= mGeometries.count() )
1140 return nullptr;
1141
1142 return mGeometries.at( index );
1143}
1144
1146{
1148 if ( !otherCollection )
1149 return -1;
1150
1151 int i = 0;
1152 int j = 0;
1153 while ( i < mGeometries.size() && j < otherCollection->mGeometries.size() )
1154 {
1155 const QgsAbstractGeometry *aGeom = mGeometries[i];
1156 const QgsAbstractGeometry *bGeom = otherCollection->mGeometries[j];
1157 const int comparison = aGeom->compareTo( bGeom );
1158 if ( comparison != 0 )
1159 {
1160 return comparison;
1161 }
1162 i++;
1163 j++;
1164 }
1165 if ( i < mGeometries.size() )
1166 {
1167 return 1;
1168 }
1169 if ( j < otherCollection->mGeometries.size() )
1170 {
1171 return -1;
1172 }
1173 return 0;
1174}
@ AllowSelfTouchingHoles
Indicates that self-touching holes are permitted. OGC validity states that self-touching holes are NO...
Definition qgis.h:2118
QFlags< GeometryValidityFlag > GeometryValidityFlags
Geometry validity flags.
Definition qgis.h:2121
@ RejectOnInvalidSubGeometry
Don't allow geometries with invalid sub-geometries to be created.
Definition qgis.h:2194
@ Point
Points.
Definition qgis.h:366
@ Line
Lines.
Definition qgis.h:367
@ Polygon
Polygons.
Definition qgis.h:368
@ Unknown
Unknown types.
Definition qgis.h:369
@ Null
No geometry.
Definition qgis.h:370
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:280
@ CompoundCurve
CompoundCurve.
Definition qgis.h:291
@ Point
Point.
Definition qgis.h:282
@ LineString
LineString.
Definition qgis.h:283
@ TIN
TIN.
Definition qgis.h:296
@ MultiPoint
MultiPoint.
Definition qgis.h:286
@ Polygon
Polygon.
Definition qgis.h:284
@ MultiPolygon
MultiPolygon.
Definition qgis.h:288
@ Triangle
Triangle.
Definition qgis.h:285
@ MultiLineString
MultiLineString.
Definition qgis.h:287
@ CircularString
CircularString.
Definition qgis.h:290
@ GeometryCollection
GeometryCollection.
Definition qgis.h:289
@ MultiCurve
MultiCurve.
Definition qgis.h:293
@ CurvePolygon
CurvePolygon.
Definition qgis.h:292
@ PolyhedralSurface
PolyhedralSurface.
Definition qgis.h:295
@ MultiSurface
MultiSurface.
Definition qgis.h:294
TransformDirection
Indicates the direction (forward or inverse) of a transform.
Definition qgis.h:2717
An abstract base class for classes which transform geometries by transforming input points to output ...
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.
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.
QgsAbstractGeometry()=default
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:42
void combineWith(const QgsBox3D &box)
Expands the bbox so that it covers both the original rectangle and the given rectangle.
Definition qgsbox3d.cpp:210
A const WKB pointer.
Definition qgswkbptr.h:139
Qgis::WkbType readHeader() const
readHeader
Definition qgswkbptr.cpp:56
Handles coordinate transforms between two coordinate systems.
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:55
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.
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 fromCollectionWkt(const QString &wkt, const QVector< Qgis::WkbType > &subtypes, const QString &defaultChildWkbType=QString())
Reads a collection from a WKT string.
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.
QgsGeometryCollection * simplifyByDistance(double tolerance) const override
Simplifies the geometry by applying the Douglas Peucker simplification by distance algorithm.
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.
QVector< QgsAbstractGeometry * > takeGeometries()
Removes all geometries from the collection, returning them and their ownership to the caller.
QgsGeometryCollection * clone() const override
Clones the geometry by performing a deep copy.
virtual bool addGeometries(const QVector< QgsAbstractGeometry * > &geometries)
Adds a list of geometries to the collection, transferring ownership to the collection.
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.
double area3D() const override
Returns the 3-dimensional surface area of 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.
QgsCoordinateSequence coordinateSequence() const override
Retrieves the sequence of geometries, rings and nodes.
int numGeometries() const
Returns the number of geometries within the collection.
QgsGeometryCollection * snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0, bool removeRedundantPoints=false) const override
Makes a new geometry with all the points or vertices snapped to the closest point of the grid.
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, and exception handling.
Definition qgsgeos.h:141
Multi line string geometry collection.
Multi point geometry collection.
Multi polygon geometry collection.
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:49
WKB pointer handler.
Definition qgswkbptr.h:45
static Qgis::WkbType dropM(Qgis::WkbType type)
Drops the m dimension (if present) for a WKB type and returns the new type.
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 Qgis::WkbType linearType(Qgis::WkbType type)
Returns the linear type for a WKB type.
static Qgis::WkbType dropZ(Qgis::WkbType type)
Drops the z dimension (if present) for a WKB type and returns the new type.
static Qgis::WkbType addM(Qgis::WkbType type)
Adds the m dimension to a WKB type and returns the new type.
static Qgis::WkbType addZ(Qgis::WkbType type)
Adds the z dimension to a WKB type and returns the new type.
static Q_INVOKABLE bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
static Qgis::WkbType singleType(Qgis::WkbType type)
Returns the single type for a WKB type.
Definition qgswkbtypes.h:53
static Q_INVOKABLE bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
Contains geos related utilities and functions.
Definition qgsgeos.h:77
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
T qgsgeometry_cast(QgsAbstractGeometry *geom)
QVector< QgsRingSequence > QgsCoordinateSequence
Utility class for identifying a unique vertex within a geometry.
Definition qgsvertexid.h:30
int part
Part number.
Definition qgsvertexid.h:88