QGIS API Documentation 4.3.0-Master (9b7fa678901)
Loading...
Searching...
No Matches
qgsalgorithmcoveragesimplify.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmcoveragesimplify.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
20
22#include "qgsgeos.h"
23#include "qgsvectorlayer.h"
24
25#include <QString>
26
27using namespace Qt::StringLiterals;
28
30
31QString QgsCoverageSimplifyAlgorithm::name() const
32{
33 return u"coveragesimplify"_s;
34}
35
36QString QgsCoverageSimplifyAlgorithm::displayName() const
37{
38 return QObject::tr( "Simplify coverage" );
39}
40
41QStringList QgsCoverageSimplifyAlgorithm::tags() const
42{
43 return QObject::tr( "topological,boundary" ).split( ',' );
44}
45
46QString QgsCoverageSimplifyAlgorithm::group() const
47{
48 return QObject::tr( "Vector coverage" );
49}
50
51QString QgsCoverageSimplifyAlgorithm::groupId() const
52{
53 return u"vectorcoverage"_s;
54}
55
56void QgsCoverageSimplifyAlgorithm::initAlgorithm( const QVariantMap & )
57{
58 addParameter( new QgsProcessingParameterFeatureSource( u"INPUT"_s, QObject::tr( "Input layer" ), QList<int>() << static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon ) ) );
59 addParameter( new QgsProcessingParameterDistance( u"TOLERANCE"_s, QObject::tr( "Tolerance" ), 1.0, u"INPUT"_s, false, 0, 10000000.0 ) );
60 auto boundaryParameter = std::make_unique<QgsProcessingParameterBoolean>( u"PRESERVE_BOUNDARY"_s, QObject::tr( "Preserve boundary" ), false );
61 boundaryParameter->setHelp( QObject::tr( "When enabled the outside edges of the coverage will be preserved without simplification." ) );
62 addParameter( boundaryParameter.release() );
63
64 addParameter( new QgsProcessingParameterFeatureSink( u"OUTPUT"_s, QObject::tr( "Simplified" ), Qgis::ProcessingSourceType::VectorPolygon ) );
65}
66
67QString QgsCoverageSimplifyAlgorithm::shortDescription() const
68{
69 return QObject::tr( "Simplifies a coverage of polygon features while retaining valid coverage." );
70}
71
72QString QgsCoverageSimplifyAlgorithm::shortHelpString() const
73{
74 return QObject::tr(
75 "This algorithm operates on a coverage (represented as a set of polygon features "
76 "with exactly matching edge geometry) to apply a Visvalingam–Whyatt "
77 "simplification to the edges, reducing complexity in proportion with "
78 "the provided tolerance, while retaining a valid coverage (i.e. no edges "
79 "will cross or touch after the simplification).\n\n"
80 "Geometries will never be removed, but they may be simplified down to just "
81 "a triangle. Also, some geometries (such as polygons which have too "
82 "few non-repeated points) will be returned unchanged.\n\n"
83 "If the input dataset is not a valid coverage due to overlaps, "
84 "it will still be simplified, but invalid topology such as crossing "
85 "edges will still be invalid."
86 );
87}
88
89QgsCoverageSimplifyAlgorithm *QgsCoverageSimplifyAlgorithm::createInstance() const
90{
91 return new QgsCoverageSimplifyAlgorithm();
92}
93
94QVariantMap QgsCoverageSimplifyAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
95{
96 QGS_MARK_ALGORITHM_SOURCE
97
98 std::unique_ptr<QgsProcessingFeatureSource> source( parameterAsSource( parameters, u"INPUT"_s, context ) );
99 if ( !source )
100 throw QgsProcessingException( invalidSourceError( parameters, u"INPUT"_s ) );
101
102 const bool preserveBoundary = parameterAsBoolean( parameters, u"PRESERVE_BOUNDARY"_s, context );
103 const double tolerance = parameterAsDouble( parameters, u"TOLERANCE"_s, context );
104
105 QString sinkId;
106 std::unique_ptr<QgsFeatureSink> sink( parameterAsSink( parameters, u"OUTPUT"_s, context, sinkId, source->fields(), source->wkbType(), source->sourceCrs() ) );
107 if ( !sink )
108 throw QgsProcessingException( invalidSinkError( parameters, u"OUTPUT"_s ) );
109
110 // we have no choice but to build up a list of features in advance
111 QVector<QgsFeature> featuresWithGeom;
112 QVector<QgsFeature> featuresWithoutGeom;
113 QgsGeometryCollection collection;
114
115 const long count = source->featureCount();
116 if ( count > 0 )
117 {
118 featuresWithGeom.reserve( count );
119 collection.reserve( count );
120 }
121
122 const double step = count > 0 ? 100.0 / count : 1;
123 int current = 0;
124
125 feedback->pushInfo( QObject::tr( "Collecting features" ) );
126
127 QgsFeature inFeature;
128 QgsFeatureIterator features = source->getFeatures();
129 while ( features.nextFeature( inFeature ) )
130 {
131 if ( feedback->isCanceled() )
132 {
133 break;
134 }
135
136 if ( inFeature.hasGeometry() )
137 {
138 featuresWithGeom.append( inFeature );
139 collection.addGeometry( inFeature.geometry().constGet()->clone() );
140 }
141 else
142 {
143 featuresWithoutGeom.append( inFeature );
144 }
145
146
147 feedback->setProgress( current * step * 0.2 );
148 current++;
149 }
150
151 QString error;
152 QgsGeos geos( &collection );
153 switch ( source->invalidGeometryCheck() )
154 {
156 break;
157
160 {
161 if ( geos.validateCoverage( 0, nullptr, &error ) != Qgis::CoverageValidityResult::Valid )
162 {
163 throw QgsProcessingException( QObject::tr( "Coverage is not valid" ) );
164 }
165 break;
166 }
167 }
168
169 feedback->pushInfo( QObject::tr( "Simplifying coverage" ) );
170
171 std::unique_ptr<QgsAbstractGeometry> simplified;
172 try
173 {
174 simplified = geos.simplifyCoverageVW( tolerance, preserveBoundary, &error );
175 }
176 catch ( QgsNotSupportedException &e )
177 {
178 throw QgsProcessingException( e.what() );
179 }
180
181 if ( !simplified )
182 {
183 if ( !error.isEmpty() )
184 throw QgsProcessingException( error );
185 else
186 throw QgsProcessingException( QObject::tr( "No geometry was returned for simplified coverage" ) );
187 }
188
189 feedback->setProgress( 80 );
190
191 feedback->pushInfo( QObject::tr( "Storing features" ) );
192 long long featureIndex = 0;
193 for ( auto partsIt = simplified->const_parts_begin(); partsIt != simplified->const_parts_end(); ++partsIt )
194 {
195 QgsFeature outFeature = featuresWithGeom.value( featureIndex );
196 outFeature.setGeometry( QgsGeometry( *partsIt ? ( *partsIt )->clone() : nullptr ) );
197 if ( !sink->addFeature( outFeature, QgsFeatureSink::FastInsert ) )
198 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, u"OUTPUT"_s ) );
199 else
200 feedback->featureAddedToSink( u"OUTPUT"_s );
201
202 feedback->setProgress( featureIndex * step * 0.2 + 80 );
203 featureIndex++;
204 }
205 for ( const QgsFeature &feature : featuresWithoutGeom )
206 {
207 QgsFeature outFeature = feature;
208 if ( !sink->addFeature( outFeature, QgsFeatureSink::FastInsert ) )
209 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, u"OUTPUT"_s ) );
210 else
211 feedback->featureAddedToSink( u"OUTPUT"_s );
212 }
213
214 sink->finalize();
215 feedback->featureSinkFinalized( u"OUTPUT"_s );
216
217 QVariantMap outputs;
218 outputs.insert( u"OUTPUT"_s, sinkId );
219 return outputs;
220}
221
222bool QgsCoverageSimplifyAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const
223{
224 const QgsVectorLayer *vlayer = qobject_cast<const QgsVectorLayer *>( layer );
225
226 if ( !vlayer )
227 return false;
228
229 return vlayer->geometryType() == Qgis::GeometryType::Polygon;
230}
231
232Qgis::ProcessingAlgorithmFlags QgsCoverageSimplifyAlgorithm::flags() const
233{
236 return f;
237}
238
239
@ VectorPolygon
Vector polygon layers.
Definition qgis.h:3774
@ Polygon
Polygons.
Definition qgis.h:402
QFlags< ProcessingAlgorithmFlag > ProcessingAlgorithmFlags
Flags indicating how and when an algorithm operates and should be exposed to users.
Definition qgis.h:3848
@ Valid
Coverage is valid.
Definition qgis.h:2353
@ NoCheck
No invalid geometry checking.
Definition qgis.h:2424
@ AbortOnInvalid
Close iterator on encountering any features with invalid geometry. This requires a slow geometry vali...
Definition qgis.h:2426
@ SkipInvalid
Skip any features with invalid geometry. This requires a slow geometry validity check for every featu...
Definition qgis.h:2425
@ SupportsInPlaceEdits
Algorithm supports in-place editing.
Definition qgis.h:3829
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:60
QgsGeometry geometry
Definition qgsfeature.h:66
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:56
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:65
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:175
Base class for all map layer types.
Definition qgsmaplayer.h:83
Custom exception class which is raised when an operation is not supported.
virtual Qgis::ProcessingAlgorithmFlags flags() const
Returns the flags indicating how and when the algorithm operates and should be exposed to users.
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.
void featureAddedToSink(const QString &output)
Reports that a feature was added to the the sink associated with the specified algorithm output.
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
void featureSinkFinalized(const QString &output)
Reports that a feature sink has been finalized.
A double numeric parameter for distance values.
A feature sink output for processing algorithms.
An input feature source (such as vector layers) parameter for processing algorithms.
Represents a vector layer which manages a vector based dataset.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
Contains geos related utilities and functions.
Definition qgsgeos.h:112