QGIS API Documentation 3.34.0-Prizren (ffbdd678812)
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
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
75
77{
78 const QgsGeometryCollection *otherCollection = qgsgeometry_cast< const QgsGeometryCollection * >( &other );
79 if ( !otherCollection )
80 return false;
81
82 if ( mWkbType != otherCollection->mWkbType )
83 return false;
84
85 if ( mGeometries.count() != otherCollection->mGeometries.count() )
86 return false;
87
88 for ( int i = 0; i < mGeometries.count(); ++i )
89 {
90 QgsAbstractGeometry *g1 = mGeometries.at( i );
91 QgsAbstractGeometry *g2 = otherCollection->mGeometries.at( i );
92
93 // Quick check if the geometries are exactly the same
94 if ( g1 != g2 )
95 {
96 if ( !g1 || !g2 )
97 return false;
98
99 // Slower check, compare the contents of the geometries
100 if ( *g1 != *g2 )
101 return false;
102 }
103 }
104
105 return true;
106}
107
109{
110 return !operator==( other );
111}
112
114{
115 auto result = std::make_unique< QgsGeometryCollection >();
116 result->mWkbType = mWkbType;
117 return result.release();
118}
119
124
126{
127 qDeleteAll( mGeometries );
128 mGeometries.clear();
129 clearCache(); //set bounding box invalid
130}
131
132QgsGeometryCollection *QgsGeometryCollection::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing ) const
133{
134 std::unique_ptr<QgsGeometryCollection> result;
135
136 for ( auto geom : mGeometries )
137 {
138 std::unique_ptr<QgsAbstractGeometry> gridified { geom->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing ) };
139 if ( gridified )
140 {
141 if ( !result )
142 result = std::unique_ptr<QgsGeometryCollection> { createEmptyWithSameType() };
143
144 result->mGeometries.append( gridified.release() );
145 }
146 }
147
148 return result.release();
149}
150
151bool QgsGeometryCollection::removeDuplicateNodes( double epsilon, bool useZValues )
152{
153 bool result = false;
154 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
155 {
156 if ( geom->removeDuplicateNodes( epsilon, useZValues ) ) result = true;
157 }
158 return result;
159}
160
162{
163 return nullptr;
164}
165
166void QgsGeometryCollection::adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex ) const
167{
168 if ( vertex.part < 0 || vertex.part >= mGeometries.count() )
169 {
170 previousVertex = QgsVertexId();
172 return;
173 }
174
175 mGeometries.at( vertex.part )->adjacentVertices( vertex, previousVertex, nextVertex );
176}
177
179{
180 if ( id.part < 0 || id.part >= mGeometries.count() )
181 return -1;
182
183 int number = 0;
184 int part = 0;
185 for ( QgsAbstractGeometry *geometry : mGeometries )
186 {
187 if ( part == id.part )
188 {
189 int partNumber = geometry->vertexNumberFromVertexId( QgsVertexId( 0, id.ring, id.vertex ) );
190 if ( partNumber == -1 )
191 return -1;
192 return number + partNumber;
193 }
194 else
195 {
196 number += geometry->nCoordinates();
197 }
198
199 part++;
200 }
201 return -1; // should not happen
202}
203
205{
206 if ( mGeometries.empty() )
207 return false;
208
209 // if we already have the bounding box calculated, then this check is trivial!
210 if ( !mBoundingBox.isNull() )
211 {
212 return mBoundingBox.intersects( box3d );
213 }
214
215 // otherwise loop through each member geometry and test the bounding box intersection.
216 // This gives us a chance to use optimisations which may be present on the individual
217 // geometry subclasses, and at worst it will cause a calculation of the bounding box
218 // of each individual member geometry which we would have to do anyway... (and these
219 // bounding boxes are cached, so would be reused without additional expense)
220 for ( const QgsAbstractGeometry *geometry : mGeometries )
221 {
222 if ( geometry->boundingBoxIntersects( box3d ) )
223 return true;
224 }
225
226 // even if we don't intersect the bounding box of any member geometries, we may still intersect the
227 // bounding box of the overall collection.
228 // so here we fall back to the non-optimised base class check which has to first calculate
229 // the overall bounding box of the collection..
231}
232
234{
235 mGeometries.reserve( size );
236}
237
239{
240 clearCache();
241 return mGeometries.value( n );
242}
243
245{
246 if ( mGeometries.isEmpty() )
247 return true;
248
249 for ( QgsAbstractGeometry *geometry : mGeometries )
250 {
251 if ( !geometry->isEmpty() )
252 return false;
253 }
254 return true;
255}
256
258{
259 if ( !g )
260 {
261 return false;
262 }
263
264 mGeometries.append( g );
265 clearCache(); //set bounding box invalid
266 return true;
267}
268
270{
271 if ( !g )
272 {
273 return false;
274 }
275
276 index = std::min( static_cast<int>( mGeometries.count() ), index );
277
278 mGeometries.insert( index, g );
279 clearCache(); //set bounding box invalid
280 return true;
281}
282
284{
285 if ( nr >= mGeometries.size() || nr < 0 )
286 {
287 return false;
288 }
289 delete mGeometries.at( nr );
290 mGeometries.remove( nr );
291 clearCache(); //set bounding box invalid
292 return true;
293}
294
296{
297 for ( QgsAbstractGeometry *geometry : std::as_const( mGeometries ) )
298 {
299 geometry->normalize();
300 }
301 std::sort( mGeometries.begin(), mGeometries.end(), []( const QgsAbstractGeometry * a, const QgsAbstractGeometry * b )
302 {
303 return a->compareTo( b ) > 0;
304 } );
305}
306
308{
309 int maxDim = 0;
310 QVector< QgsAbstractGeometry * >::const_iterator it = mGeometries.constBegin();
311 for ( ; it != mGeometries.constEnd(); ++it )
312 {
313 int dim = ( *it )->dimension();
314 if ( dim > maxDim )
315 {
316 maxDim = dim;
317 }
318 }
319 return maxDim;
320}
321
323{
324 return QStringLiteral( "GeometryCollection" );
325}
326
328{
329 for ( QgsAbstractGeometry *g : std::as_const( mGeometries ) )
330 {
331 g->transform( ct, d, transformZ );
332 }
333 clearCache(); //set bounding box invalid
334}
335
336void QgsGeometryCollection::transform( const QTransform &t, double zTranslate, double zScale, double mTranslate, double mScale )
337{
338 for ( QgsAbstractGeometry *g : std::as_const( mGeometries ) )
339 {
340 g->transform( t, zTranslate, zScale, mTranslate, mScale );
341 }
342 clearCache(); //set bounding box invalid
343}
344
345void QgsGeometryCollection::draw( QPainter &p ) const
346{
347 QVector< QgsAbstractGeometry * >::const_iterator it = mGeometries.constBegin();
348 for ( ; it != mGeometries.constEnd(); ++it )
349 {
350 ( *it )->draw( p );
351 }
352}
353
355{
356 QPainterPath p;
357 for ( const QgsAbstractGeometry *geom : mGeometries )
358 {
359 QPainterPath partPath = geom->asQPainterPath();
360 if ( !partPath.isEmpty() )
361 p.addPath( partPath );
362 }
363 return p;
364}
365
367{
368 if ( !wkbPtr )
369 {
370 return false;
371 }
372
375 return false;
376
378
379 int nGeometries = 0;
380 wkbPtr >> nGeometries;
381
382 QVector<QgsAbstractGeometry *> geometryListBackup = mGeometries;
383 mGeometries.clear();
384 mGeometries.reserve( nGeometries );
385 for ( int i = 0; i < nGeometries; ++i )
386 {
387 std::unique_ptr< QgsAbstractGeometry > geom( QgsGeometryFactory::geomFromWkb( wkbPtr ) ); // also updates wkbPtr
388 if ( geom )
389 {
390 if ( !addGeometry( geom.release() ) )
391 {
392 qDeleteAll( mGeometries );
393 mGeometries = geometryListBackup;
394 return false;
395 }
396 }
397 }
398 qDeleteAll( geometryListBackup );
399
400 clearCache(); //set bounding box invalid
401
402 return true;
403}
404
405bool QgsGeometryCollection::fromWkt( const QString &wkt )
406{
407 return fromCollectionWkt( wkt, QVector<QgsAbstractGeometry *>() << new QgsPoint << new QgsLineString << new QgsPolygon
409 << new QgsCurvePolygon
412 << new QgsMultiCurve << new QgsMultiSurface, QStringLiteral( "GeometryCollection" ) );
413}
414
415int QgsGeometryCollection::wkbSize( QgsAbstractGeometry::WkbFlags flags ) const
416{
417 int binarySize = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
418 for ( const QgsAbstractGeometry *geom : mGeometries )
419 {
420 if ( geom )
421 {
422 binarySize += geom->wkbSize( flags );
423 }
424 }
425
426 return binarySize;
427}
428
429QByteArray QgsGeometryCollection::asWkb( WkbFlags flags ) const
430{
431 int countNonNull = 0;
432 for ( const QgsAbstractGeometry *geom : mGeometries )
433 {
434 if ( geom )
435 {
436 countNonNull ++;
437 }
438 }
439
440 QByteArray wkbArray;
441 wkbArray.resize( QgsGeometryCollection::wkbSize( flags ) );
442 QgsWkbPtr wkb( wkbArray );
443 wkb << static_cast<char>( QgsApplication::endian() );
444 wkb << static_cast<quint32>( wkbType() );
445 wkb << static_cast<quint32>( countNonNull );
446 for ( const QgsAbstractGeometry *geom : mGeometries )
447 {
448 if ( geom )
449 {
450 wkb << geom->asWkb( flags );
451 }
452 }
453 return wkbArray;
454}
455
457{
458 QString wkt = wktTypeStr();
459
460 if ( isEmpty() )
461 wkt += QLatin1String( " EMPTY" );
462 else
463 {
464 wkt += QLatin1String( " (" );
465 for ( const QgsAbstractGeometry *geom : mGeometries )
466 {
467 QString childWkt = geom->asWkt( precision );
468 if ( wktOmitChildType() )
469 {
470 childWkt = childWkt.mid( childWkt.indexOf( '(' ) );
471 }
472 wkt += childWkt + ',';
473 }
474 if ( wkt.endsWith( ',' ) )
475 {
476 wkt.chop( 1 ); // Remove last ','
477 }
478 wkt += ')';
479 }
480 return wkt;
481}
482
483QDomElement QgsGeometryCollection::asGml2( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
484{
485 QDomElement elemMultiGeometry = doc.createElementNS( ns, QStringLiteral( "MultiGeometry" ) );
486 for ( const QgsAbstractGeometry *geom : mGeometries )
487 {
488 QDomElement elemGeometryMember = doc.createElementNS( ns, QStringLiteral( "geometryMember" ) );
489 elemGeometryMember.appendChild( geom->asGml2( doc, precision, ns, axisOrder ) );
490 elemMultiGeometry.appendChild( elemGeometryMember );
491 }
492 return elemMultiGeometry;
493}
494
495QDomElement QgsGeometryCollection::asGml3( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
496{
497 QDomElement elemMultiGeometry = doc.createElementNS( ns, QStringLiteral( "MultiGeometry" ) );
498 for ( const QgsAbstractGeometry *geom : mGeometries )
499 {
500 QDomElement elemGeometryMember = doc.createElementNS( ns, QStringLiteral( "geometryMember" ) );
501 elemGeometryMember.appendChild( geom->asGml3( doc, precision, ns, axisOrder ) );
502 elemMultiGeometry.appendChild( elemGeometryMember );
503 }
504 return elemMultiGeometry;
505}
506
508{
509 json coordinates( json::array( ) );
510 for ( const QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
511 {
512 coordinates.push_back( geom->asJsonObject( precision ) );
513 }
514 return
515 {
516 { "type", "GeometryCollection" },
517 { "geometries", coordinates }
518 };
519}
520
522{
523 QString kml;
524 kml.append( QLatin1String( "<MultiGeometry>" ) );
525 const QVector< QgsAbstractGeometry * > &geometries = mGeometries;
526 for ( const QgsAbstractGeometry *geometry : geometries )
527 {
528 kml.append( geometry->asKml( precision ) );
529 }
530 kml.append( QLatin1String( "</MultiGeometry>" ) );
531 return kml;
532}
533
535{
536 if ( mBoundingBox.isNull() )
537 {
538 mBoundingBox = calculateBoundingBox3D();
539 }
540 return mBoundingBox;
541}
542
544{
545 if ( mGeometries.empty() )
546 {
547 return QgsBox3D();
548 }
549
550 QgsBox3D bbox = mGeometries.at( 0 )->boundingBox3D();
551 for ( int i = 1; i < mGeometries.size(); ++i )
552 {
553 if ( mGeometries.at( i )->isEmpty() )
554 continue;
555
556 QgsBox3D geomBox = mGeometries.at( i )->boundingBox3D();
557 bbox.combineWith( geomBox );
558 }
559 return bbox;
560}
561
563{
564 mBoundingBox = QgsBox3D();
565 mHasCachedValidity = false;
566 mValidityFailureReason.clear();
568}
569
571{
572 QgsCoordinateSequence sequence;
573 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
574 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
575 {
576 QgsCoordinateSequence geomCoords = ( *geomIt )->coordinateSequence();
577
578 QgsCoordinateSequence::const_iterator cIt = geomCoords.constBegin();
579 for ( ; cIt != geomCoords.constEnd(); ++cIt )
580 {
581 sequence.push_back( *cIt );
582 }
583 }
584
585 return sequence;
586}
587
589{
590 int count = 0;
591
592 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
593 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
594 {
595 count += ( *geomIt )->nCoordinates();
596 }
597
598 return count;
599}
600
601double QgsGeometryCollection::closestSegment( const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf, double epsilon ) const
602{
603 return QgsGeometryUtils::closestSegmentFromComponents( mGeometries, QgsGeometryUtils::Part, pt, segmentPt, vertexAfter, leftOf, epsilon );
604}
605
607{
608 if ( id.part < 0 )
609 {
610 id.part = 0;
611 id.ring = -1;
612 id.vertex = -1;
613 }
614 if ( mGeometries.isEmpty() )
615 {
616 return false;
617 }
618
619 if ( id.part >= mGeometries.count() )
620 return false;
621
622 QgsAbstractGeometry *geom = mGeometries.at( id.part );
623 if ( geom->nextVertex( id, vertex ) )
624 {
625 return true;
626 }
627 if ( ( id.part + 1 ) >= numGeometries() )
628 {
629 return false;
630 }
631 ++id.part;
632 id.ring = -1;
633 id.vertex = -1;
634 return mGeometries.at( id.part )->nextVertex( id, vertex );
635}
636
638{
639 if ( position.part >= mGeometries.size() )
640 {
641 return false;
642 }
643
644 bool success = mGeometries.at( position.part )->insertVertex( position, vertex );
645 if ( success )
646 {
647 clearCache(); //set bounding box invalid
648 }
649 return success;
650}
651
653{
654 if ( position.part < 0 || position.part >= mGeometries.size() )
655 {
656 return false;
657 }
658
659 bool success = mGeometries.at( position.part )->moveVertex( position, newPos );
660 if ( success )
661 {
662 clearCache(); //set bounding box invalid
663 }
664 return success;
665}
666
668{
669 if ( position.part < 0 || position.part >= mGeometries.size() )
670 {
671 return false;
672 }
673
674 QgsAbstractGeometry *geom = mGeometries.at( position.part );
675 if ( !geom )
676 {
677 return false;
678 }
679
680 bool success = geom->deleteVertex( position );
681
682 //remove geometry if no vertices left
683 if ( geom->isEmpty() )
684 {
685 removeGeometry( position.part );
686 }
687
688 if ( success )
689 {
690 clearCache(); //set bounding box invalid
691 }
692 return success;
693}
694
696{
697 double length = 0.0;
698 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
699 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
700 {
701 length += ( *geomIt )->length();
702 }
703 return length;
704}
705
707{
708 double area = 0.0;
709 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
710 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
711 {
712 area += ( *geomIt )->area();
713 }
714 return area;
715}
716
718{
719 double perimeter = 0.0;
720 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
721 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
722 {
723 perimeter += ( *geomIt )->perimeter();
724 }
725 return perimeter;
726}
727
728bool QgsGeometryCollection::fromCollectionWkt( const QString &wkt, const QVector<QgsAbstractGeometry *> &subtypes, const QString &defaultChildWkbType )
729{
730 clear();
731
732 QPair<Qgis::WkbType, QString> parts = QgsGeometryUtils::wktReadBlock( wkt );
733
735 {
736 qDeleteAll( subtypes );
737 return false;
738 }
739 mWkbType = parts.first;
740
741 QString secondWithoutParentheses = parts.second;
742 secondWithoutParentheses = secondWithoutParentheses.remove( '(' ).remove( ')' ).simplified().remove( ' ' );
743 if ( ( parts.second.compare( QLatin1String( "EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
744 secondWithoutParentheses.isEmpty() )
745 {
746 qDeleteAll( subtypes );
747 return true;
748 }
749
750 QString defChildWkbType = QStringLiteral( "%1%2%3 " ).arg( defaultChildWkbType, is3D() ? QStringLiteral( "Z" ) : QString(), isMeasure() ? QStringLiteral( "M" ) : QString() );
751
752 const QStringList blocks = QgsGeometryUtils::wktGetChildBlocks( parts.second, defChildWkbType );
753 for ( const QString &childWkt : blocks )
754 {
755 QPair<Qgis::WkbType, QString> childParts = QgsGeometryUtils::wktReadBlock( childWkt );
756
757 bool success = false;
758 for ( const QgsAbstractGeometry *geom : subtypes )
759 {
760 if ( QgsWkbTypes::flatType( childParts.first ) == QgsWkbTypes::flatType( geom->wkbType() ) )
761 {
762 mGeometries.append( geom->clone() );
763 if ( mGeometries.back()->fromWkt( childWkt ) )
764 {
765 success = true;
766 break;
767 }
768 }
769 }
770 if ( !success )
771 {
772 clear();
773 qDeleteAll( subtypes );
774 return false;
775 }
776 }
777 qDeleteAll( subtypes );
778
779 //scan through geometries and check if dimensionality of geometries is different to collection.
780 //if so, update the type dimensionality of the collection to match
781 bool hasZ = false;
782 bool hasM = false;
783 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
784 {
785 hasZ = hasZ || geom->is3D();
786 hasM = hasM || geom->isMeasure();
787 if ( hasZ && hasM )
788 break;
789 }
790 if ( hasZ )
791 addZValue( 0 );
792 if ( hasM )
793 addMValue( 0 );
794
795 return true;
796}
797
799{
800 QVector< QgsAbstractGeometry * >::const_iterator it = mGeometries.constBegin();
801 for ( ; it != mGeometries.constEnd(); ++it )
802 {
803 if ( ( *it )->hasCurvedSegments() )
804 {
805 return true;
806 }
807 }
808 return false;
809}
810
812{
813 std::unique_ptr< QgsAbstractGeometry > geom( QgsGeometryFactory::geomFromWkbType( QgsWkbTypes::linearType( mWkbType ) ) );
814 QgsGeometryCollection *geomCollection = qgsgeometry_cast<QgsGeometryCollection *>( geom.get() );
815 if ( !geomCollection )
816 {
817 return clone();
818 }
819
820 geomCollection->reserve( mGeometries.size() );
821 QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
822 for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
823 {
824 geomCollection->addGeometry( ( *geomIt )->segmentize( tolerance, toleranceType ) );
825 }
826 return geom.release();
827}
828
830{
831 if ( vertex.part < 0 || vertex.part >= mGeometries.size() )
832 {
833 return 0.0;
834 }
835
836 QgsAbstractGeometry *geom = mGeometries[vertex.part];
837 if ( !geom )
838 {
839 return 0.0;
840 }
841
842 return geom->vertexAngle( vertex );
843}
844
846{
847 if ( startVertex.part < 0 || startVertex.part >= mGeometries.size() )
848 {
849 return 0.0;
850 }
851
852 const QgsAbstractGeometry *geom = mGeometries[startVertex.part];
853 if ( !geom )
854 {
855 return 0.0;
856 }
857
858 return geom->segmentLength( startVertex );
859}
860
861int QgsGeometryCollection::vertexCount( int part, int ring ) const
862{
863 if ( part < 0 || part >= mGeometries.size() )
864 {
865 return 0;
866 }
867
868 return mGeometries[part]->vertexCount( 0, ring );
869}
870
872{
873 if ( part < 0 || part >= mGeometries.size() )
874 {
875 return 0;
876 }
877
878 return mGeometries[part]->ringCount();
879}
880
882{
883 return mGeometries.size();
884}
885
887{
888 if ( id.part < 0 || id.part >= mGeometries.size() )
889 {
890 return QgsPoint();
891 }
892
893 const QgsAbstractGeometry *geom = mGeometries[id.part];
894 if ( !geom )
895 {
896 return QgsPoint();
897 }
898
899 return geom->vertexAt( id );
900}
901
902bool QgsGeometryCollection::isValid( QString &error, Qgis::GeometryValidityFlags flags ) const
903{
904 if ( flags == 0 && mHasCachedValidity )
905 {
906 // use cached validity results
907 error = mValidityFailureReason;
908 return error.isEmpty();
909 }
910
911 QgsGeos geos( this );
912 bool res = geos.isValid( &error, flags & Qgis::GeometryValidityFlag::AllowSelfTouchingHoles, nullptr );
913 if ( flags == 0 )
914 {
915 mValidityFailureReason = !res ? error : QString();
916 mHasCachedValidity = true;
917 }
918 return res;
919}
920
922{
924 return false;
925
927
928 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
929 {
930 geom->addZValue( zValue );
931 }
932 clearCache();
933 return true;
934}
935
937{
939 return false;
940
942
943 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
944 {
945 geom->addMValue( mValue );
946 }
947 clearCache();
948 return true;
949}
950
951
953{
955 return false;
956
958 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
959 {
960 geom->dropZValue();
961 }
962 clearCache();
963 return true;
964}
965
967{
969 return false;
970
972 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
973 {
974 geom->dropMValue();
975 }
976 clearCache();
977 return true;
978}
979
980void QgsGeometryCollection::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
981{
982 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
983 {
984 if ( geom )
985 geom->filterVertices( filter );
986 }
987 clearCache();
988}
989
990void QgsGeometryCollection::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
991{
992 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
993 {
994 if ( geom )
995 geom->transformVertices( transform );
996 }
997 clearCache();
998}
999
1001{
1002 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
1003 {
1004 if ( geom )
1005 geom->swapXy();
1006 }
1007 clearCache();
1008}
1009
1011{
1012 std::unique_ptr< QgsGeometryCollection > newCollection( new QgsGeometryCollection() );
1013 newCollection->reserve( mGeometries.size() );
1014 for ( QgsAbstractGeometry *geom : mGeometries )
1015 {
1016 newCollection->addGeometry( geom->toCurveType() );
1017 }
1018 return newCollection.release();
1019}
1020
1022{
1023 if ( mGeometries.size() == 1 )
1024 return mGeometries.at( 0 )->simplifiedTypeRef();
1025 else
1026 return this;
1027}
1028
1030{
1031 if ( !transformer )
1032 return false;
1033
1034 bool res = true;
1035 for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
1036 {
1037 if ( geom )
1038 res = geom->transform( transformer, feedback );
1039
1040 if ( feedback && feedback->isCanceled() )
1041 res = false;
1042
1043 if ( !res )
1044 break;
1045 }
1046 clearCache();
1047 return res;
1048}
1049
1051{
1052 return false;
1053}
1054
1056{
1057 return mGeometries.count();
1058}
1059
1061{
1062 if ( index < 0 || index >= mGeometries.count() )
1063 return nullptr;
1064
1065 return mGeometries.at( index );
1066}
1067
1069{
1070 const QgsGeometryCollection *otherCollection = qgsgeometry_cast<const QgsGeometryCollection *>( other );
1071 if ( !otherCollection )
1072 return -1;
1073
1074 int i = 0;
1075 int j = 0;
1076 while ( i < mGeometries.size() && j < otherCollection->mGeometries.size() )
1077 {
1078 const QgsAbstractGeometry *aGeom = mGeometries[i];
1079 const QgsAbstractGeometry *bGeom = otherCollection->mGeometries[j];
1080 const int comparison = aGeom->compareTo( bGeom );
1081 if ( comparison != 0 )
1082 {
1083 return comparison;
1084 }
1085 i++;
1086 j++;
1087 }
1088 if ( i < mGeometries.size() )
1089 {
1090 return 1;
1091 }
1092 if ( j < otherCollection->mGeometries.size() )
1093 {
1094 return -1;
1095 }
1096 return 0;
1097}
@ AllowSelfTouchingHoles
Indicates that self-touching holes are permitted. OGC validity states that self-touching holes are NO...
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:182
@ GeometryCollection
GeometryCollection.
TransformDirection
Flags for raster layer temporal capabilities.
Definition qgis.h:1937
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.
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 void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false)=0
Transforms the geometry using a coordinate transform.
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:44
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:45
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:54
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.
QgsBox3D boundingBox3D() const override
Returns the 3D bounding box for the geometry.
bool operator==(const QgsAbstractGeometry &other) const override
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
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.
bool operator!=(const QgsAbstractGeometry &other) const override
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:99
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:34
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::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 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:37
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QVector< QgsRingSequence > QgsCoordinateSequence
int precision
Utility class for identifying a unique vertex within a geometry.
Definition qgsvertexid.h:31
int part
Part number.
Definition qgsvertexid.h:89