QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsalgorithmcoveragevalidate.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmcoveragevalidate.cpp
3 ---------------------
4 begin : October 2023
5 copyright : (C) 2023 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18
22#include "qgsgeos.h"
23
24
26
27QString QgsCoverageValidateAlgorithm::name() const
28{
29 return QStringLiteral( "coveragevalidate" );
30}
31
32QString QgsCoverageValidateAlgorithm::displayName() const
33{
34 return QObject::tr( "Validate coverage" );
35}
36
37QStringList QgsCoverageValidateAlgorithm::tags() const
38{
39 return QObject::tr( "validity,overlaps,gaps,topological,boundary" ).split( ',' );
40}
41
42QString QgsCoverageValidateAlgorithm::group() const
43{
44 return QObject::tr( "Vector coverage" );
45}
46
47QString QgsCoverageValidateAlgorithm::groupId() const
48{
49 return QStringLiteral( "vectorcoverage" );
50}
51
52void QgsCoverageValidateAlgorithm::initAlgorithm( const QVariantMap & )
53{
54 addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ), QList< int >() << static_cast< int >( Qgis::ProcessingSourceType::VectorPolygon ) ) );
55 std::unique_ptr< QgsProcessingParameterDistance> gapWidthParam = std::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "GAP_WIDTH" ),
56 QObject::tr( "Gap width" ), 0.0, QStringLiteral( "INPUT" ), false, 0, 10000000.0 );
57 gapWidthParam->setHelp( QObject::tr( "The maximum width of gaps to detect" ) );
58 addParameter( gapWidthParam.release() );
59
60 addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "INVALID_EDGES" ), QObject::tr( "Invalid edges" ), Qgis::ProcessingSourceType::VectorLine, QVariant(), true, true ) );
61 addOutput( new QgsProcessingOutputBoolean( QStringLiteral( "IS_VALID" ), QObject::tr( "Coverage is valid" ) ) );
62}
63
64QString QgsCoverageValidateAlgorithm::shortDescription() const
65{
66 return QObject::tr( "Analyzes a coverage of polygon features to find places where the assumption of exactly matching edges is not met" );
67}
68
69QString QgsCoverageValidateAlgorithm::shortHelpString() const
70{
71 return QObject::tr( "This algorithm analyzes a coverage (represented as a set of polygon features "
72 "with exactly matching edge geometry) to find places where the "
73 "assumption of exactly matching edges is not met.\n\n"
74 "Invalidity includes polygons that overlap "
75 "or that have gaps smaller than the specified gap width." );
76}
77
78QgsCoverageValidateAlgorithm *QgsCoverageValidateAlgorithm::createInstance() const
79{
80 return new QgsCoverageValidateAlgorithm();
81}
82
83QVariantMap QgsCoverageValidateAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
84{
85 std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
86 if ( !source )
87 throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
88
89 const double gapWidth = parameterAsDouble( parameters, QStringLiteral( "GAP_WIDTH" ), context );
90
91 QString sinkId;
92 std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "INVALID_EDGES" ), context, sinkId, QgsFields(), Qgis::WkbType::LineString, source->sourceCrs() ) );
93 if ( !sink && parameters.value( QStringLiteral( "INVALID_EDGES" ) ).isValid() )
94 throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "INVALID_EDGES" ) ) );
95
96 QgsGeometryCollection collection;
97
98 const long count = source->featureCount();
99 if ( count > 0 )
100 {
101 collection.reserve( count );
102 }
103
104 const double step = count > 0 ? 100.0 / count : 1;
105 int current = 0;
106
107 feedback->pushInfo( QObject::tr( "Collecting features" ) );
108
109 QgsFeature inFeature;
110 QgsFeatureIterator features = source->getFeatures();
111 while ( features.nextFeature( inFeature ) )
112 {
113 if ( feedback->isCanceled() )
114 {
115 break;
116 }
117
118 if ( inFeature.hasGeometry() )
119 {
120 collection.addGeometry( inFeature.geometry().constGet()->clone() );
121 }
122
123 feedback->setProgress( current * step * 0.2 );
124 current++;
125 }
126
127 feedback->pushInfo( QObject::tr( "Validating coverage" ) );
128
129 QgsGeos geos( &collection );
130 QString error;
131 std::unique_ptr< QgsAbstractGeometry > invalidEdges;
133 try
134 {
135 result = geos.validateCoverage( gapWidth, &invalidEdges, &error ) ;
136 }
137 catch ( QgsNotSupportedException &e )
138 {
139 throw QgsProcessingException( e.what() );
140 }
141
142 switch ( result )
143 {
145 feedback->reportError( QObject::tr( "Coverage is not valid" ) );
146 if ( invalidEdges )
147 {
148 if ( sink )
149 {
150 for ( auto partsIt = invalidEdges->const_parts_begin(); partsIt != invalidEdges->const_parts_end(); ++partsIt )
151 {
152 QgsFeature outFeature;
153 outFeature.setGeometry( QgsGeometry( *partsIt ? ( *partsIt )->clone() : nullptr ) );
154 if ( !sink->addFeature( outFeature, QgsFeatureSink::FastInsert ) )
155 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
156 }
157 }
158 }
159 break;
161 feedback->pushInfo( QObject::tr( "Coverage is valid" ) );
162 break;
164 if ( !error.isEmpty() )
165 throw QgsProcessingException( QObject::tr( "An error occurred validating coverage: %1" ).arg( error ) );
166 else
167 throw QgsProcessingException( QObject::tr( "An error occurred validating coverage" ) );
168 }
169
170 feedback->setProgress( 100 );
171
172 QVariantMap outputs;
173 outputs.insert( QStringLiteral( "OUTPUT" ), sinkId );
174 outputs.insert( QStringLiteral( "IS_VALID" ), result == Qgis::CoverageValidityResult::Valid );
175 return outputs;
176}
177
@ VectorPolygon
Vector polygon layers.
@ VectorLine
Vector line layers.
CoverageValidityResult
Coverage validity results.
Definition: qgis.h:1707
@ Valid
Coverage is valid.
@ Invalid
Coverage is invalid. Invalidity includes polygons that overlap, that have gaps smaller than the gap w...
@ Error
An exception occurred while determining validity.
@ LineString
LineString.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
QString what() const
Definition: qgsexception.h:49
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QgsGeometry geometry
Definition: qgsfeature.h:67
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:230
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:167
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:53
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:61
Container of fields for a vector layer.
Definition: qgsfields.h:45
Geometry collection.
void reserve(int size)
Attempts to allocate memory for at least size geometries.
virtual bool addGeometry(QgsAbstractGeometry *g)
Adds a geometry and takes ownership. Returns true in case of success.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:162
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Does vector analysis using the geos library and handles import, export, exception handling*.
Definition: qgsgeos.h:98
Custom exception class which is raised when an operation is not supported.
Definition: qgsexception.h:118
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
Definition: qgsexception.h:83
Base class for providing feedback from a processing algorithm.
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
A boolean output for processing algorithms.
A feature sink output for processing algorithms.
An input feature source (such as vector layers) parameter for processing algorithms.
Contains geos related utilities and functions.
Definition: qgsgeos.h:36