QGIS API Documentation 3.43.0-Master (58029bba303)
qgsalgorithmcheckgeometrydegeneratepolygon.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmcheckgeometrydegeneratepolygon.cpp
3 ---------------------
4 begin : April 2025
5 copyright : (C) 2025 by Jacky Volpes
6 email : jacky dot volpes at oslandia 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
22#include "qgsvectorlayer.h"
24
26
27QString QgsGeometryCheckDegeneratePolygonAlgorithm::name() const
28{
29 return QStringLiteral( "checkgeometrydegeneratepolygon" );
30}
31
32QString QgsGeometryCheckDegeneratePolygonAlgorithm::displayName() const
33{
34 return QObject::tr( "Check Geometry (Degenerate polygon)" );
35}
36
37QStringList QgsGeometryCheckDegeneratePolygonAlgorithm::tags() const
38{
39 return QObject::tr( "check,geometry,degeneratepolygon" ).split( ',' );
40}
41
42QString QgsGeometryCheckDegeneratePolygonAlgorithm::group() const
43{
44 return QObject::tr( "Check geometry" );
45}
46
47QString QgsGeometryCheckDegeneratePolygonAlgorithm::groupId() const
48{
49 return QStringLiteral( "checkgeometry" );
50}
51
52QString QgsGeometryCheckDegeneratePolygonAlgorithm::shortHelpString() const
53{
54 return QObject::tr( "This algorithm checks the polygons with less than 3 points, which are degenerate polygons.\n"
55 "Degenerate polygons are errors." );
56}
57
58Qgis::ProcessingAlgorithmFlags QgsGeometryCheckDegeneratePolygonAlgorithm::flags() const
59{
61}
62
63QgsGeometryCheckDegeneratePolygonAlgorithm *QgsGeometryCheckDegeneratePolygonAlgorithm::createInstance() const
64{
65 return new QgsGeometryCheckDegeneratePolygonAlgorithm();
66}
67
68void QgsGeometryCheckDegeneratePolygonAlgorithm::initAlgorithm( const QVariantMap &configuration )
69{
70 Q_UNUSED( configuration )
71
73 QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ), QList<int>() << static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon )
74 ) );
75 addParameter( new QgsProcessingParameterField(
76 QStringLiteral( "UNIQUE_ID" ), QObject::tr( "Unique feature identifier" ), QString(), QStringLiteral( "INPUT" )
77 ) );
78 addParameter( new QgsProcessingParameterFeatureSink(
79 QStringLiteral( "ERRORS" ), QObject::tr( "Errors layer" ), Qgis::ProcessingSourceType::VectorPoint
80 ) );
81 addParameter( new QgsProcessingParameterFeatureSink(
82 QStringLiteral( "OUTPUT" ), QObject::tr( "Output layer" ), Qgis::ProcessingSourceType::VectorPolygon
83 ) );
84
85 std::unique_ptr<QgsProcessingParameterNumber> tolerance = std::make_unique<QgsProcessingParameterNumber>( QStringLiteral( "TOLERANCE" ), QObject::tr( "Tolerance" ), Qgis::ProcessingNumberParameterType::Integer, 8, false, 1, 13 );
86 tolerance->setFlags( tolerance->flags() | Qgis::ProcessingParameterFlag::Advanced );
87 addParameter( tolerance.release() );
88}
89
90bool QgsGeometryCheckDegeneratePolygonAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
91{
92 mTolerance = parameterAsInt( parameters, QStringLiteral( "TOLERANCE" ), context );
93 return true;
94}
95
96QgsFields QgsGeometryCheckDegeneratePolygonAlgorithm::outputFields()
97{
98 QgsFields fields;
99 fields.append( QgsField( QStringLiteral( "gc_layerid" ), QMetaType::QString ) );
100 fields.append( QgsField( QStringLiteral( "gc_layername" ), QMetaType::QString ) );
101 fields.append( QgsField( QStringLiteral( "gc_partidx" ), QMetaType::Int ) );
102 fields.append( QgsField( QStringLiteral( "gc_ringidx" ), QMetaType::Int ) );
103 fields.append( QgsField( QStringLiteral( "gc_vertidx" ), QMetaType::Int ) );
104 fields.append( QgsField( QStringLiteral( "gc_errorx" ), QMetaType::Double ) );
105 fields.append( QgsField( QStringLiteral( "gc_errory" ), QMetaType::Double ) );
106 fields.append( QgsField( QStringLiteral( "gc_error" ), QMetaType::QString ) );
107 return fields;
108}
109
110QVariantMap QgsGeometryCheckDegeneratePolygonAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
111{
112 QString dest_output;
113 QString dest_errors;
114 const std::unique_ptr<QgsProcessingFeatureSource> input( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
115 if ( !input )
116 throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
117
118 const QString uniqueIdFieldName( parameterAsString( parameters, QStringLiteral( "UNIQUE_ID" ), context ) );
119 const int uniqueIdFieldIdx = input->fields().indexFromName( uniqueIdFieldName );
120 if ( uniqueIdFieldIdx == -1 )
121 throw QgsProcessingException( QObject::tr( "Missing field %1 in input layer" ).arg( uniqueIdFieldName ) );
122
123 const QgsField uniqueIdField = input->fields().at( uniqueIdFieldIdx );
124
125 QgsFields fields = outputFields();
126 fields.append( uniqueIdField );
127
128 std::unique_ptr<QgsFeatureSink> sink_output( parameterAsSink(
129 parameters, QStringLiteral( "OUTPUT" ), context, dest_output, fields, input->wkbType(), input->sourceCrs()
130 ) );
131 if ( !sink_output )
132 throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
133
134 std::unique_ptr<QgsFeatureSink> sink_errors( parameterAsSink(
135 parameters, QStringLiteral( "ERRORS" ), context, dest_errors, fields, Qgis::WkbType::Point, input->sourceCrs()
136 ) );
137 if ( !sink_errors )
138 throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "ERRORS" ) ) );
139
140 QgsProcessingMultiStepFeedback multiStepFeedback( 3, feedback );
141
142 const QgsProject *project = QgsProject::instance();
143
144 QgsGeometryCheckContext checkContext = QgsGeometryCheckContext( mTolerance, project->crs(), project->transformContext(), project );
145
146 // Test detection
147 QList<QgsGeometryCheckError *> checkErrors;
148 QStringList messages;
149
150 const QgsGeometryDegeneratePolygonCheck check( &checkContext, QVariantMap() );
151
152 multiStepFeedback.setCurrentStep( 1 );
153 feedback->setProgressText( QObject::tr( "Preparing features…" ) );
154 QMap<QString, QgsFeaturePool *> checkerFeaturePools;
155
156 std::unique_ptr<QgsVectorLayer> inputLayer( input->materialize( QgsFeatureRequest() ) );
158 checkerFeaturePools.insert( inputLayer->id(), &featurePool );
159
160 multiStepFeedback.setCurrentStep( 2 );
161 feedback->setProgressText( QObject::tr( "Collecting errors…" ) );
162 check.collectErrors( checkerFeaturePools, checkErrors, messages, feedback );
163
164 multiStepFeedback.setCurrentStep( 3 );
165 feedback->setProgressText( QObject::tr( "Exporting errors…" ) );
166 const double step { checkErrors.size() > 0 ? 100.0 / checkErrors.size() : 1 };
167 long i = 0;
168 feedback->setProgress( 0.0 );
169
170 for ( QgsGeometryCheckError *error : checkErrors )
171 {
172 if ( feedback->isCanceled() )
173 {
174 break;
175 }
176
177 QgsFeature f;
178 QgsAttributes attrs = f.attributes();
179
180 attrs << error->layerId()
181 << inputLayer->name()
182 << error->vidx().part
183 << error->vidx().ring
184 << error->vidx().vertex
185 << error->location().x()
186 << error->location().y()
187 << error->value().toString()
188 << inputLayer->getFeature( error->featureId() ).attribute( uniqueIdField.name() );
189 f.setAttributes( attrs );
190
191 f.setGeometry( error->geometry() );
192 if ( !sink_output->addFeature( f, QgsFeatureSink::FastInsert ) )
193 throw QgsProcessingException( writeFeatureError( sink_output.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
194
195 f.setGeometry( error->geometry().centroid() );
196 if ( !sink_errors->addFeature( f, QgsFeatureSink::FastInsert ) )
197 throw QgsProcessingException( writeFeatureError( sink_errors.get(), parameters, QStringLiteral( "ERRORS" ) ) );
198
199 i++;
200 feedback->setProgress( 100.0 * step * static_cast<double>( i ) );
201 }
202
203 // Place the point layer above the other layer
204 if ( context.willLoadLayerOnCompletion( dest_output ) && context.willLoadLayerOnCompletion( dest_errors ) )
205 {
206 context.layerToLoadOnCompletionDetails( dest_errors ).layerSortKey = 0;
207 context.layerToLoadOnCompletionDetails( dest_output ).layerSortKey = 1;
208 }
209
210 QVariantMap outputs;
211 outputs.insert( QStringLiteral( "OUTPUT" ), dest_output );
212 outputs.insert( QStringLiteral( "ERRORS" ), dest_errors );
213
214 return outputs;
215}
216
@ VectorPoint
Vector point layers.
@ VectorPolygon
Vector polygon layers.
QFlags< ProcessingAlgorithmFlag > ProcessingAlgorithmFlags
Flags indicating how and when an algorithm operates and should be exposed to users.
Definition qgis.h:3476
@ NoThreading
Algorithm is not thread safe and cannot be run in a background thread, e.g. for algorithms which mani...
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
A vector of attributes.
Wraps a request for features to a vector layer (or directly its vector data provider).
@ 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
QgsAttributes attributes
Definition qgsfeature.h:67
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
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
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:53
QString name
Definition qgsfield.h:62
Container of fields for a vector layer.
Definition qgsfields.h:46
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
Definition qgsfields.cpp:70
Base configuration for geometry checks.
This represents an error reported by a geometry check.
virtual Qgis::ProcessingAlgorithmFlags flags() const
Returns the flags indicating how and when the algorithm operates and should be exposed to users.
int layerSortKey
Optional sorting key for sorting output layers when loading them into a project.
Contains information about the context in which a processing algorithm is executed.
QgsProcessingContext::LayerDetails & layerToLoadOnCompletionDetails(const QString &layer)
Returns a reference to the details for a given layer which is loaded on completion of the algorithm o...
bool willLoadLayerOnCompletion(const QString &layer) const
Returns true if the given layer (by ID or datasource) will be loaded into the current project upon co...
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
virtual void setProgressText(const QString &text)
Sets a progress report text string.
Processing feedback object for multi-step operations.
A feature sink output for processing algorithms.
An input feature source (such as vector layers) parameter for processing algorithms.
A vector layer or feature source field parameter for processing algorithms.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:107
static QgsProject * instance()
Returns the QgsProject singleton instance.
QgsCoordinateTransformContext transformContext
Definition qgsproject.h:113
QgsCoordinateReferenceSystem crs
Definition qgsproject.h:112
A feature pool based on a vector data provider.