QGIS API Documentation 3.41.0-Master (25ec5511245)
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#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
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
55// cppcheck-suppress operatorEqVarError
57{
58 if ( &c != this )
59 {
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
75
77{
78 auto result = std::make_unique< QgsGeometryCollection >();
79 result->mWkbType = mWkbType;
80 return result.release();
81}
82
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, bool removeRedundantPoints ) 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, removeRedundantPoints ) };
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
232bool QgsGeometryCollection::addGeometries( const QVector<QgsAbstractGeometry *> &geometries )
233{
234 mGeometries.append( geometries );
235 clearCache(); //set bounding box invalid
236 return true;
237}
238
240{
241 if ( !g )
242 {
243 return false;
244 }
245
246 index = std::min( static_cast<int>( mGeometries.count() ), index );
247
248 mGeometries.insert( index, g );
249 clearCache(); //set bounding box invalid
250 return true;
251}
252
254{
255 if ( nr >= mGeometries.size() || nr < 0 )
256 {
257 return false;
258 }
259 delete mGeometries.at( nr );
260 mGeometries.remove( nr );
261 clearCache(); //set bounding box invalid
262 return true;
263}
264
265QVector<QgsAbstractGeometry *> QgsGeometryCollection::takeGeometries()
266{
267 QVector< QgsAbstractGeometry * > results = mGeometries;
268 mGeometries.clear();
269 clearCache();
270 return results;
271}
272
274{
275 for ( QgsAbstractGeometry *geometry : std::as_const( mGeometries ) )
276 {
277 geometry->normalize();
278 }
279 std::sort( mGeometries.begin(), mGeometries.end(), []( const QgsAbstractGeometry * a, const QgsAbstractGeometry * b )
280 {
281 return a->compareTo( b ) > 0;
282 } );
283}
284
286{
287 int maxDim = 0;
288 QVector< QgsAbstractGeometry * >::const_iterator it = mGeometries.constBegin();
289 for ( ; it != mGeometries.constEnd(); ++it )
290 {
291 int dim = ( *it )->dimension();
292 if ( dim > maxDim )
293 {
294 maxDim = dim;
295 }
296 }
297 return maxDim;
298}
299
301{
302 return QStringLiteral( "GeometryCollection" );
303}
304
306{
307 for ( QgsAbstractGeometry *g : std::as_const( mGeometries ) )
308 {
309 g->transform( ct, d, transformZ );
310 }
311 clearCache(); //set bounding box invalid
312}
313
314void QgsGeometryCollection::transform( const QTransform &t, double zTranslate, double zScale, double mTranslate, double mScale )
315{
316 for ( QgsAbstractGeometry *g : std::as_const( mGeometries ) )
317 {
318 g->transform( t, zTranslate, zScale, mTranslate, mScale );
319 }
320 clearCache(); //set bounding box invalid
321}
322
323void QgsGeometryCollection::draw( QPainter &p ) const
324{
325 QVector< QgsAbstractGeometry * >::const_iterator it = mGeometries.constBegin();
326 for ( ; it != mGeometries.constEnd(); ++it )
327 {
328 ( *it )->draw( p );
329 }
330}
331
333{
334 QPainterPath p;
335 for ( const QgsAbstractGeometry *geom : mGeometries )
336 {
337 QPainterPath partPath = geom->asQPainterPath();
338 if ( !partPath.isEmpty() )
339 p.addPath( partPath );
340 }
341 return p;
342}
343
345{
346 if ( !wkbPtr )
347 {
348 return false;
349 }
350
353 return false;
354
356
357 int nGeometries = 0;
358 wkbPtr >> nGeometries;
359
360 QVector<QgsAbstractGeometry *> geometryListBackup = mGeometries;
361 mGeometries.clear();
362 mGeometries.reserve( nGeometries );
363 for ( int i = 0; i < nGeometries; ++i )
364 {
365 std::unique_ptr< QgsAbstractGeometry > geom( QgsGeometryFactory::geomFromWkb( wkbPtr ) ); // also updates wkbPtr
366 if ( geom )
367 {
368 if ( !addGeometry( geom.release() ) )
369 {
370 qDeleteAll( mGeometries );
371 mGeometries = geometryListBackup;
372 return false;
373 }
374 }
375 }
376 qDeleteAll( geometryListBackup );
377
378 clearCache(); //set bounding box invalid
379
380 return true;
381}
382
383bool QgsGeometryCollection::fromWkt( const QString &wkt )
384{
385 return fromCollectionWkt( wkt, QVector<QgsAbstractGeometry *>() << new QgsPoint << new QgsLineString << new QgsPolygon
387 << new QgsCurvePolygon
390 << new QgsMultiCurve << new QgsMultiSurface, QStringLiteral( "GeometryCollection" ) );
391}
392
394{
395 int binarySize = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
396 for ( const QgsAbstractGeometry *geom : mGeometries )
397 {
398 if ( geom )
399 {
400 binarySize += geom->wkbSize( flags );
401 }
402 }
403
404 return binarySize;
405}
406
407QByteArray QgsGeometryCollection::asWkb( WkbFlags flags ) const
408{
409 int countNonNull = 0;
410 for ( const QgsAbstractGeometry *geom : mGeometries )
411 {
412 if ( geom )
413 {
414 countNonNull ++;
415 }
416 }
417
418 QByteArray wkbArray;
419 wkbArray.resize( QgsGeometryCollection::wkbSize( flags ) );
420 QgsWkbPtr wkb( wkbArray );
421 wkb << static_cast<char>( QgsApplication::endian() );
422 wkb << static_cast<quint32>( wkbType() );
423 wkb << static_cast<quint32>( countNonNull );
424 for ( const QgsAbstractGeometry *geom : mGeometries )
425 {
426 if ( geom )
427 {
428 wkb << geom->asWkb( flags );
429 }
430 }
431 return wkbArray;
432}
433
435{
436 QString wkt = wktTypeStr();
437
438 if ( isEmpty() )
439 wkt += QLatin1String( " EMPTY" );
440 else
441 {
442 wkt += QLatin1String( " (" );
443 for ( const QgsAbstractGeometry *geom : mGeometries )
444 {
445 QString childWkt = geom->asWkt( precision );
446 if ( wktOmitChildType() )
447 {
448 childWkt = childWkt.mid( childWkt.indexOf( '(' ) );
449 }
450 wkt += childWkt + ',';
451 }
452 if ( wkt.endsWith( ',' ) )
453 {
454 wkt.chop( 1 ); // Remove last ','
455 }
456 wkt += ')';
457 }
458 return wkt;
459}
460
461QDomElement QgsGeometryCollection::asGml2( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
462{
463 QDomElement elemMultiGeometry = doc.createElementNS( ns, QStringLiteral( "MultiGeometry" ) );
464 for ( const QgsAbstractGeometry *geom : mGeometries )
465 {
466 QDomElement elemGeometryMember = doc.createElementNS( ns, QStringLiteral( "geometryMember" ) );
467 elemGeometryMember.appendChild( geom->asGml2( doc, precision, ns, axisOrder ) );
468 elemMultiGeometry.appendChild( elemGeometryMember );
469 }
470 return elemMultiGeometry;
471}
472
473QDomElement QgsGeometryCollection::asGml3( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
474{
475 QDomElement elemMultiGeometry = doc.createElementNS( ns, QStringLiteral( "MultiGeometry" ) );
476 for ( const QgsAbstractGeometry *geom : mGeometries )
477 {
478 QDomElement elemGeometryMember = doc.createElementNS( ns, QStringLiteral( "geometryMember" ) );
479 elemGeometryMember.appendChild( geom->asGml3( doc, precision, ns, axisOrder ) );
480 elemMultiGeometry.appendChild( elemGeometryMember );
481 }
482 return elemMultiGeometry;
483}
484
486{
487 json coordinates( json::array( ) );
488 for ( const QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
489 {
490 coordinates.push_back( geom->asJsonObject( precision ) );
491 }
492 return
493 {
494 { "type", "GeometryCollection" },
495 { "geometries", coordinates }
496 };
497}
498
500{
501 QString kml;
502 kml.append( QLatin1String( "<MultiGeometry>" ) );
503 const QVector< QgsAbstractGeometry * > &geometries = mGeometries;
504 for ( const QgsAbstractGeometry *geometry : geometries )
505 {
506 kml.append( geometry->asKml( precision ) );
507 }
508 kml.append( QLatin1String( "</MultiGeometry>" ) );
509 return kml;
510}
511
513{
514 if ( mBoundingBox.isNull() )
515 {
516 mBoundingBox = calculateBoundingBox3D();
517 }
518 return mBoundingBox;
519}
520
522{
523 if ( mGeometries.empty() )
524 {
525 return QgsBox3D();
526 }
527
528 QgsBox3D bbox = mGeometries.at( 0 )->boundingBox3D();
529 for ( int i = 1; i < mGeometries.size(); ++i )
530 {
531 if ( mGeometries.at( i )->isEmpty() )
532 continue;
533
534 QgsBox3D geomBox = mGeometries.at( i )->boundingBox3D();
535 bbox.combineWith( geomBox );
536 }
537 return bbox;
538}
539
541{
542 mBoundingBox = QgsBox3D();
543 mHasCachedValidity = false;
544 mValidityFailureReason.clear();
546}
547
549{
550 QgsCoordinateSequence sequence;
551 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
552 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
553 {
554 QgsCoordinateSequence geomCoords = ( *geomIt )->coordinateSequence();
555
556 QgsCoordinateSequence::const_iterator cIt = geomCoords.constBegin();
557 for ( ; cIt != geomCoords.constEnd(); ++cIt )
558 {
559 sequence.push_back( *cIt );
560 }
561 }
562
563 return sequence;
564}
565
567{
568 int count = 0;
569
570 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
571 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
572 {
573 count += ( *geomIt )->nCoordinates();
574 }
575
576 return count;
577}
578
579double QgsGeometryCollection::closestSegment( const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf, double epsilon ) const
580{
581 return QgsGeometryUtils::closestSegmentFromComponents( mGeometries, QgsGeometryUtils::Part, pt, segmentPt, vertexAfter, leftOf, epsilon );
582}
583
585{
586 if ( id.part < 0 )
587 {
588 id.part = 0;
589 id.ring = -1;
590 id.vertex = -1;
591 }
592 if ( mGeometries.isEmpty() )
593 {
594 return false;
595 }
596
597 if ( id.part >= mGeometries.count() )
598 return false;
599
600 QgsAbstractGeometry *geom = mGeometries.at( id.part );
601 if ( geom->nextVertex( id, vertex ) )
602 {
603 return true;
604 }
605 if ( ( id.part + 1 ) >= numGeometries() )
606 {
607 return false;
608 }
609 ++id.part;
610 id.ring = -1;
611 id.vertex = -1;
612 return mGeometries.at( id.part )->nextVertex( id, vertex );
613}
614
616{
617 if ( position.part >= mGeometries.size() )
618 {
619 return false;
620 }
621
622 bool success = mGeometries.at( position.part )->insertVertex( position, vertex );
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 bool success = mGeometries.at( position.part )->moveVertex( position, newPos );
638 if ( success )
639 {
640 clearCache(); //set bounding box invalid
641 }
642 return success;
643}
644
646{
647 if ( position.part < 0 || position.part >= mGeometries.size() )
648 {
649 return false;
650 }
651
652 QgsAbstractGeometry *geom = mGeometries.at( position.part );
653 if ( !geom )
654 {
655 return false;
656 }
657
658 bool success = geom->deleteVertex( position );
659
660 //remove geometry if no vertices left
661 if ( geom->isEmpty() )
662 {
663 removeGeometry( position.part );
664 }
665
666 if ( success )
667 {
668 clearCache(); //set bounding box invalid
669 }
670 return success;
671}
672
674{
675 double length = 0.0;
676 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
677 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
678 {
679 length += ( *geomIt )->length();
680 }
681 return length;
682}
683
685{
686 double area = 0.0;
687 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
688 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
689 {
690 area += ( *geomIt )->area();
691 }
692 return area;
693}
694
696{
697 double perimeter = 0.0;
698 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
699 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
700 {
701 perimeter += ( *geomIt )->perimeter();
702 }
703 return perimeter;
704}
705
706bool QgsGeometryCollection::fromCollectionWkt( const QString &wkt, const QVector<QgsAbstractGeometry *> &subtypes, const QString &defaultChildWkbType )
707{
708 clear();
709
710 QPair<Qgis::WkbType, QString> parts = QgsGeometryUtils::wktReadBlock( wkt );
711
713 {
714 qDeleteAll( subtypes );
715 return false;
716 }
717 mWkbType = parts.first;
718
719 QString secondWithoutParentheses = parts.second;
720 secondWithoutParentheses = secondWithoutParentheses.remove( '(' ).remove( ')' ).simplified().remove( ' ' );
721 if ( ( parts.second.compare( QLatin1String( "EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
722 secondWithoutParentheses.isEmpty() )
723 {
724 qDeleteAll( subtypes );
725 return true;
726 }
727
728 QString defChildWkbType = QStringLiteral( "%1%2%3 " ).arg( defaultChildWkbType, is3D() ? QStringLiteral( "Z" ) : QString(), isMeasure() ? QStringLiteral( "M" ) : QString() );
729
730 const QStringList blocks = QgsGeometryUtils::wktGetChildBlocks( parts.second, defChildWkbType );
731 for ( const QString &childWkt : blocks )
732 {
733 QPair<Qgis::WkbType, QString> childParts = QgsGeometryUtils::wktReadBlock( childWkt );
734
735 bool success = false;
736 for ( const QgsAbstractGeometry *geom : subtypes )
737 {
738 if ( QgsWkbTypes::flatType( childParts.first ) == QgsWkbTypes::flatType( geom->wkbType() ) )
739 {
740 mGeometries.append( geom->clone() );
741 if ( mGeometries.back()->fromWkt( childWkt ) )
742 {
743 success = true;
744 break;
745 }
746 }
747 }
748 if ( !success )
749 {
750 clear();
751 qDeleteAll( subtypes );
752 return false;
753 }
754 }
755 qDeleteAll( subtypes );
756
757 //scan through geometries and check if dimensionality of geometries is different to collection.
758 //if so, update the type dimensionality of the collection to match
759 bool hasZ = false;
760 bool hasM = false;
761 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
762 {
763 hasZ = hasZ || geom->is3D();
764 hasM = hasM || geom->isMeasure();
765 if ( hasZ && hasM )
766 break;
767 }
768 if ( hasZ )
769 addZValue( 0 );
770 if ( hasM )
771 addMValue( 0 );
772
773 return true;
774}
775
777{
778 QVector< QgsAbstractGeometry * >::const_iterator it = mGeometries.constBegin();
779 for ( ; it != mGeometries.constEnd(); ++it )
780 {
781 if ( ( *it )->hasCurvedSegments() )
782 {
783 return true;
784 }
785 }
786 return false;
787}
788
790{
791 std::unique_ptr< QgsAbstractGeometry > geom( QgsGeometryFactory::geomFromWkbType( QgsWkbTypes::linearType( mWkbType ) ) );
792 QgsGeometryCollection *geomCollection = qgsgeometry_cast<QgsGeometryCollection *>( geom.get() );
793 if ( !geomCollection )
794 {
795 return clone();
796 }
797
798 geomCollection->reserve( mGeometries.size() );
799 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
800 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
801 {
802 geomCollection->addGeometry( ( *geomIt )->segmentize( tolerance, toleranceType ) );
803 }
804 return geom.release();
805}
806
808{
809 if ( vertex.part < 0 || vertex.part >= mGeometries.size() )
810 {
811 return 0.0;
812 }
813
814 QgsAbstractGeometry *geom = mGeometries[vertex.part];
815 if ( !geom )
816 {
817 return 0.0;
818 }
819
820 return geom->vertexAngle( vertex );
821}
822
824{
825 if ( startVertex.part < 0 || startVertex.part >= mGeometries.size() )
826 {
827 return 0.0;
828 }
829
830 const QgsAbstractGeometry *geom = mGeometries[startVertex.part];
831 if ( !geom )
832 {
833 return 0.0;
834 }
835
836 return geom->segmentLength( startVertex );
837}
838
839int QgsGeometryCollection::vertexCount( int part, int ring ) const
840{
841 if ( part < 0 || part >= mGeometries.size() )
842 {
843 return 0;
844 }
845
846 return mGeometries[part]->vertexCount( 0, ring );
847}
848
850{
851 if ( part < 0 || part >= mGeometries.size() )
852 {
853 return 0;
854 }
855
856 return mGeometries[part]->ringCount();
857}
858
860{
861 return mGeometries.size();
862}
863
865{
866 if ( id.part < 0 || id.part >= mGeometries.size() )
867 {
868 return QgsPoint();
869 }
870
871 const QgsAbstractGeometry *geom = mGeometries[id.part];
872 if ( !geom )
873 {
874 return QgsPoint();
875 }
876
877 return geom->vertexAt( id );
878}
879
881{
882 if ( flags == 0 && mHasCachedValidity )
883 {
884 // use cached validity results
885 error = mValidityFailureReason;
886 return error.isEmpty();
887 }
888
889 QgsGeos geos( this, /* precision = */ 0, /* flags = */ Qgis::GeosCreationFlag::RejectOnInvalidSubGeometry );
890 bool res = geos.isValid( &error, flags & Qgis::GeometryValidityFlag::AllowSelfTouchingHoles, nullptr );
891 if ( flags == 0 )
892 {
893 mValidityFailureReason = !res ? error : QString();
894 mHasCachedValidity = true;
895 }
896 return res;
897}
898
900{
902 return false;
903
905
906 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
907 {
908 geom->addZValue( zValue );
909 }
910 clearCache();
911 return true;
912}
913
915{
917 return false;
918
920
921 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
922 {
923 geom->addMValue( mValue );
924 }
925 clearCache();
926 return true;
927}
928
929
931{
933 return false;
934
936 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
937 {
938 geom->dropZValue();
939 }
940 clearCache();
941 return true;
942}
943
945{
947 return false;
948
950 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
951 {
952 geom->dropMValue();
953 }
954 clearCache();
955 return true;
956}
957
958void QgsGeometryCollection::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
959{
960 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
961 {
962 if ( geom )
963 geom->filterVertices( filter );
964 }
965 clearCache();
966}
967
968void QgsGeometryCollection::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
969{
970 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
971 {
972 if ( geom )
973 geom->transformVertices( transform );
974 }
975 clearCache();
976}
977
979{
980 // be tolerant if caller passed a multi type as type argument
981 const Qgis::WkbType filterSinglePartType = useFlatType ? QgsWkbTypes::flatType( QgsWkbTypes::singleType( type ) ) : QgsWkbTypes::singleType( type );
982
983 std::unique_ptr< QgsGeometryCollection > res;
984 switch ( QgsWkbTypes::geometryType( type ) )
985 {
987 {
988 if ( useFlatType )
989 {
990 // potential shortcut if we're already a matching subclass of QgsGeometryCollection
991 if ( const QgsMultiPoint *mp = qgsgeometry_cast< const QgsMultiPoint *>( this ) )
992 return mp->clone();
993 }
994
995 res = std::make_unique< QgsMultiPoint >();
996 break;
997 }
999 {
1000 if ( useFlatType )
1001 {
1002 // potential shortcut if we're already a matching subclass of QgsGeometryCollection
1003 if ( const QgsMultiLineString *ml = qgsgeometry_cast< const QgsMultiLineString *>( this ) )
1004 return ml->clone();
1005 }
1006
1007 res = std::make_unique< QgsMultiLineString >();
1008 break;
1009 }
1011 {
1012 if ( useFlatType )
1013 {
1014 // potential shortcut if we're already a matching subclass of QgsGeometryCollection
1015 if ( const QgsMultiPolygon *mp = qgsgeometry_cast< const QgsMultiPolygon *>( this ) )
1016 return mp->clone();
1017 }
1018
1019 res = std::make_unique< QgsMultiPolygon>();
1020 break;
1021 }
1022
1025 return nullptr;
1026 }
1027
1028 // assume that the collection consists entirely of matching parts (ie optimize for a pessimistic scenario)
1029 res->reserve( mGeometries.size() );
1030
1031 for ( const QgsAbstractGeometry *part : mGeometries )
1032 {
1033 if ( !part )
1034 continue;
1035
1036 const QgsAbstractGeometry *simplifiedPartType = part->simplifiedTypeRef();
1037
1038 const Qgis::WkbType thisPartType = useFlatType ? QgsWkbTypes::flatType( simplifiedPartType->wkbType() ) : simplifiedPartType->wkbType();
1039 if ( thisPartType == filterSinglePartType )
1040 {
1041 res->addGeometry( part->clone() );
1042 }
1043 }
1044
1045 return res.release();
1046}
1047
1049{
1050 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
1051 {
1052 if ( geom )
1053 geom->swapXy();
1054 }
1055 clearCache();
1056}
1057
1059{
1060 std::unique_ptr< QgsGeometryCollection > newCollection( new QgsGeometryCollection() );
1061 newCollection->reserve( mGeometries.size() );
1062 for ( QgsAbstractGeometry *geom : mGeometries )
1063 {
1064 newCollection->addGeometry( geom->toCurveType() );
1065 }
1066 return newCollection.release();
1067}
1068
1070{
1071 if ( mGeometries.size() == 1 )
1072 return mGeometries.at( 0 )->simplifiedTypeRef();
1073 else
1074 return this;
1075}
1076
1078{
1079 std::unique_ptr< QgsGeometryCollection > res = std::make_unique< QgsGeometryCollection >();
1080 res->reserve( mGeometries.size() );
1081 for ( int i = 0; i < mGeometries.size(); ++i )
1082 {
1083 res->addGeometry( mGeometries.at( i )->simplifyByDistance( tolerance ) );
1084 }
1085 return res.release();
1086}
1087
1089{
1090 if ( !transformer )
1091 return false;
1092
1093 bool res = true;
1094 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
1095 {
1096 if ( geom )
1097 res = geom->transform( transformer, feedback );
1098
1099 if ( feedback && feedback->isCanceled() )
1100 res = false;
1101
1102 if ( !res )
1103 break;
1104 }
1105 clearCache();
1106 return res;
1107}
1108
1110{
1111 return false;
1112}
1113
1115{
1116 return mGeometries.count();
1117}
1118
1120{
1121 if ( index < 0 || index >= mGeometries.count() )
1122 return nullptr;
1123
1124 return mGeometries.at( index );
1125}
1126
1128{
1129 const QgsGeometryCollection *otherCollection = qgsgeometry_cast<const QgsGeometryCollection *>( other );
1130 if ( !otherCollection )
1131 return -1;
1132
1133 int i = 0;
1134 int j = 0;
1135 while ( i < mGeometries.size() && j < otherCollection->mGeometries.size() )
1136 {
1137 const QgsAbstractGeometry *aGeom = mGeometries[i];
1138 const QgsAbstractGeometry *bGeom = otherCollection->mGeometries[j];
1139 const int comparison = aGeom->compareTo( bGeom );
1140 if ( comparison != 0 )
1141 {
1142 return comparison;
1143 }
1144 i++;
1145 j++;
1146 }
1147 if ( i < mGeometries.size() )
1148 {
1149 return 1;
1150 }
1151 if ( j < otherCollection->mGeometries.size() )
1152 {
1153 return -1;
1154 }
1155 return 0;
1156}
@ 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:1922
@ RejectOnInvalidSubGeometry
Don't allow geometries with invalid sub-geometries to be created.
@ Polygon
Polygons.
@ Unknown
Unknown types.
@ Null
No geometry.
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:256
@ GeometryCollection
GeometryCollection.
TransformDirection
Indicates the direction (forward or inverse) of a transform.
Definition qgis.h:2502
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.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
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:144
void combineWith(const QgsBox3D &box)
Expands the bbox so that it covers both the original rectangle and the given rectangle.
Definition qgsbox3d.cpp:208
bool isNull() const
Test if the box is null (holding no spatial information).
Definition qgsbox3d.cpp:310
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
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 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.
virtual 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.
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.
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, exception handling*.
Definition qgsgeos.h:137
Line string geometry type, with support for z-dimension and m-values.
Multi curve geometry collection.
Multi line string geometry collection.
Multi point geometry collection.
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.
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 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.
static 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:75
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