QGIS API Documentation 3.41.0-Master (af5edcb665c)
Loading...
Searching...
No Matches
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" ), QObject::tr( "Gap width" ), 0.0, QStringLiteral( "INPUT" ), false, 0, 10000000.0 );
56 gapWidthParam->setHelp( QObject::tr( "The maximum width of gaps to detect" ) );
57 addParameter( gapWidthParam.release() );
58
59 addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "INVALID_EDGES" ), QObject::tr( "Invalid edges" ), Qgis::ProcessingSourceType::VectorLine, QVariant(), true, true ) );
60 addOutput( new QgsProcessingOutputBoolean( QStringLiteral( "IS_VALID" ), QObject::tr( "Coverage is valid" ) ) );
61}
62
63QString QgsCoverageValidateAlgorithm::shortDescription() const
64{
65 return QObject::tr( "Analyzes a coverage of polygon features to find places where the assumption of exactly matching edges is not met" );
66}
67
68QString QgsCoverageValidateAlgorithm::shortHelpString() const
69{
70 return QObject::tr( "This algorithm analyzes a coverage (represented as a set of polygon features "
71 "with exactly matching edge geometry) to find places where the "
72 "assumption of exactly matching edges is not met.\n\n"
73 "Invalidity includes polygons that overlap "
74 "or that have gaps smaller than the specified gap width." );
75}
76
77QgsCoverageValidateAlgorithm *QgsCoverageValidateAlgorithm::createInstance() const
78{
79 return new QgsCoverageValidateAlgorithm();
80}
81
82QVariantMap QgsCoverageValidateAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
83{
84 std::unique_ptr<QgsProcessingFeatureSource> source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
85 if ( !source )
86 throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
87
88 const double gapWidth = parameterAsDouble( parameters, QStringLiteral( "GAP_WIDTH" ), context );
89
90 QString sinkId;
91 std::unique_ptr<QgsFeatureSink> sink( parameterAsSink( parameters, QStringLiteral( "INVALID_EDGES" ), context, sinkId, QgsFields(), Qgis::WkbType::LineString, source->sourceCrs() ) );
92 if ( !sink && parameters.value( QStringLiteral( "INVALID_EDGES" ) ).isValid() )
93 throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "INVALID_EDGES" ) ) );
94
95 QgsGeometryCollection collection;
96
97 const long count = source->featureCount();
98 if ( count > 0 )
99 {
100 collection.reserve( count );
101 }
102
103 const double step = count > 0 ? 100.0 / count : 1;
104 int current = 0;
105
106 feedback->pushInfo( QObject::tr( "Collecting features" ) );
107
108 QgsFeature inFeature;
109 QgsFeatureIterator features = source->getFeatures();
110 while ( features.nextFeature( inFeature ) )
111 {
112 if ( feedback->isCanceled() )
113 {
114 break;
115 }
116
117 if ( inFeature.hasGeometry() )
118 {
119 collection.addGeometry( inFeature.geometry().constGet()->clone() );
120 }
121
122 feedback->setProgress( current * step * 0.2 );
123 current++;
124 }
125
126 feedback->pushInfo( QObject::tr( "Validating coverage" ) );
127
128 QgsGeos geos( &collection );
129 QString error;
130 std::unique_ptr<QgsAbstractGeometry> invalidEdges;
132 try
133 {
134 result = geos.validateCoverage( gapWidth, &invalidEdges, &error );
135 }
136 catch ( QgsNotSupportedException &e )
137 {
138 throw QgsProcessingException( e.what() );
139 }
140
141 switch ( result )
142 {
144 feedback->reportError( QObject::tr( "Coverage is not valid" ) );
145 if ( invalidEdges )
146 {
147 if ( sink )
148 {
149 for ( auto partsIt = invalidEdges->const_parts_begin(); partsIt != invalidEdges->const_parts_end(); ++partsIt )
150 {
151 QgsFeature outFeature;
152 outFeature.setGeometry( QgsGeometry( *partsIt ? ( *partsIt )->clone() : nullptr ) );
153 if ( !sink->addFeature( outFeature, QgsFeatureSink::FastInsert ) )
154 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
155 }
156 }
157 }
158 break;
160 feedback->pushInfo( QObject::tr( "Coverage is valid" ) );
161 break;
163 if ( !error.isEmpty() )
164 throw QgsProcessingException( QObject::tr( "An error occurred validating coverage: %1" ).arg( error ) );
165 else
166 throw QgsProcessingException( QObject::tr( "An error occurred validating coverage" ) );
167 }
168
169 feedback->setProgress( 100 );
170 if ( sink )
171 sink->finalize();
172
173 QVariantMap outputs;
174 outputs.insert( QStringLiteral( "OUTPUT" ), sinkId );
175 outputs.insert( QStringLiteral( "IS_VALID" ), result == Qgis::CoverageValidityResult::Valid );
176 return outputs;
177}
178
@ VectorPolygon
Vector polygon layers.
@ VectorLine
Vector line layers.
CoverageValidityResult
Coverage validity results.
Definition qgis.h:2064
@ 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
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:58
QgsGeometry geometry
Definition qgsfeature.h:69
bool hasGeometry() const
Returns true if the feature has an associated geometry.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
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:46
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.
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, and exception handling.
Definition qgsgeos.h:139
Custom exception class which is raised when an operation is not supported.
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
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:75