Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsbookmarkalgorithms.cpp
3 : : ---------------------
4 : : begin : September 2019
5 : : copyright : (C) 2019 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 : : #include "qgsbookmarkalgorithms.h"
19 : : #include "qgsapplication.h"
20 : :
21 : : ///@cond PRIVATE
22 : :
23 : : //
24 : : // QgsBookmarksToLayerAlgorithm
25 : : //
26 : :
27 : 0 : void QgsBookmarksToLayerAlgorithm::initAlgorithm( const QVariantMap & )
28 : : {
29 : 0 : std::unique_ptr< QgsProcessingParameterEnum > sourceParam = std::make_unique<QgsProcessingParameterEnum >( QStringLiteral( "SOURCE" ), QObject::tr( "Bookmark source" ), QStringList() <<
30 : 0 : QObject::tr( "Project bookmarks" ) << QObject::tr( "User bookmarks" ), true, QVariantList() << 0 << 1 );
31 : 0 : QVariantMap wrapperMetadata;
32 : 0 : wrapperMetadata.insert( QStringLiteral( "useCheckBoxes" ), true );
33 : 0 : QVariantMap metadata;
34 : 0 : metadata.insert( QStringLiteral( "widget_wrapper" ), wrapperMetadata );
35 : 0 : sourceParam->setMetadata( metadata );
36 : 0 : addParameter( sourceParam.release() );
37 : 0 : addParameter( new QgsProcessingParameterCrs( QStringLiteral( "CRS" ), QObject::tr( "Output CRS" ), QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) ) );
38 : 0 : addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Output" ), QgsProcessing::TypeVectorPolygon ) );
39 : 0 : }
40 : :
41 : 0 : QString QgsBookmarksToLayerAlgorithm::name() const
42 : : {
43 : 0 : return QStringLiteral( "bookmarkstolayer" );
44 : : }
45 : :
46 : 0 : QString QgsBookmarksToLayerAlgorithm::displayName() const
47 : : {
48 : 0 : return QObject::tr( "Convert spatial bookmarks to layer" );
49 : : }
50 : :
51 : 0 : QStringList QgsBookmarksToLayerAlgorithm::tags() const
52 : : {
53 : 0 : return QObject::tr( "save,extract" ).split( ',' );
54 : 0 : }
55 : :
56 : 0 : QString QgsBookmarksToLayerAlgorithm::group() const
57 : : {
58 : 0 : return QObject::tr( "Vector general" );
59 : : }
60 : :
61 : 0 : QString QgsBookmarksToLayerAlgorithm::groupId() const
62 : : {
63 : 0 : return QStringLiteral( "vectorgeneral" );
64 : : }
65 : :
66 : 0 : QString QgsBookmarksToLayerAlgorithm::shortHelpString() const
67 : : {
68 : 0 : return QObject::tr( "This algorithm creates a new layer containing polygon features for stored spatial bookmarks.\n\n"
69 : : "The export can be filtered to only bookmarks belonging to the current project, to all user bookmarks, or a combination of both." );
70 : : }
71 : :
72 : 0 : QString QgsBookmarksToLayerAlgorithm::shortDescription() const
73 : : {
74 : 0 : return QObject::tr( "Converts stored spatial bookmarks to a polygon layer." );
75 : : }
76 : :
77 : 0 : QIcon QgsBookmarksToLayerAlgorithm::icon() const
78 : : {
79 : 0 : return QgsApplication::getThemeIcon( QStringLiteral( "mActionShowBookmarks.svg" ) );
80 : 0 : }
81 : :
82 : 0 : QString QgsBookmarksToLayerAlgorithm::svgIconPath() const
83 : : {
84 : 0 : return QgsApplication::iconPath( QStringLiteral( "mActionShowBookmarks.svg" ) );
85 : 0 : }
86 : :
87 : 0 : QgsBookmarksToLayerAlgorithm *QgsBookmarksToLayerAlgorithm::createInstance() const
88 : : {
89 : 0 : return new QgsBookmarksToLayerAlgorithm();
90 : : }
91 : :
92 : 0 : bool QgsBookmarksToLayerAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * )
93 : : {
94 : 0 : QList< int > sources = parameterAsEnums( parameters, QStringLiteral( "SOURCE" ), context );
95 : 0 : if ( sources.contains( 0 ) )
96 : : {
97 : 0 : if ( !context.project() )
98 : 0 : throw QgsProcessingException( QObject::tr( "No project is available for bookmark extraction" ) );
99 : 0 : mBookmarks.append( context.project()->bookmarkManager()->bookmarks() );
100 : 0 : }
101 : 0 : if ( sources.contains( 1 ) )
102 : 0 : mBookmarks.append( QgsApplication::bookmarkManager()->bookmarks() );
103 : :
104 : : return true;
105 : 0 : }
106 : :
107 : 0 : QVariantMap QgsBookmarksToLayerAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
108 : : {
109 : 0 : const QgsCoordinateReferenceSystem crs = parameterAsCrs( parameters, QStringLiteral( "CRS" ), context );
110 : 0 : QgsFields fields;
111 : 0 : fields.append( QgsField( QStringLiteral( "name" ), QVariant::String ) );
112 : 0 : fields.append( QgsField( QStringLiteral( "group" ), QVariant::String ) );
113 : 0 : QString dest;
114 : 0 : std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, QgsWkbTypes::Polygon, crs ) );
115 : 0 : if ( !sink )
116 : 0 : throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
117 : :
118 : 0 : int count = mBookmarks.count();
119 : 0 : int current = 0;
120 : 0 : double step = count > 0 ? 100.0 / count : 1;
121 : :
122 : 0 : for ( const QgsBookmark &b : std::as_const( mBookmarks ) )
123 : : {
124 : 0 : if ( feedback->isCanceled() )
125 : : {
126 : 0 : break;
127 : : }
128 : :
129 : 0 : QgsFeature feat;
130 : 0 : feat.setAttributes( QgsAttributes() << b.name() << b.group() );
131 : :
132 : 0 : QgsGeometry geom = QgsGeometry::fromRect( b.extent() );
133 : 0 : if ( b.extent().crs() != crs )
134 : : {
135 : 0 : QgsCoordinateTransform xform( b.extent().crs(), crs, context.transformContext() );
136 : 0 : geom = geom.densifyByCount( 20 );
137 : : try
138 : : {
139 : 0 : geom.transform( xform );
140 : 0 : }
141 : : catch ( QgsCsException & )
142 : : {
143 : 0 : feedback->reportError( QObject::tr( "Could not reproject bookmark %1 to destination CRS" ).arg( b.name() ) );
144 : 0 : feedback->setProgress( current++ * step );
145 : : continue;
146 : 0 : }
147 : 0 : }
148 : :
149 : 0 : feat.setGeometry( geom );
150 : :
151 : 0 : sink->addFeature( feat, QgsFeatureSink::FastInsert );
152 : :
153 : 0 : feedback->setProgress( current++ * step );
154 : 0 : }
155 : :
156 : 0 : QVariantMap outputs;
157 : 0 : outputs.insert( QStringLiteral( "OUTPUT" ), dest );
158 : 0 : return outputs;
159 : 0 : }
160 : :
161 : :
162 : : //
163 : : // QgsLayerToBookmarksAlgorithm
164 : : //
165 : :
166 : 0 : void QgsLayerToBookmarksAlgorithm::initAlgorithm( const QVariantMap & )
167 : : {
168 : 0 : addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ), QList< int >() << QgsProcessing::TypeVectorLine << QgsProcessing::TypeVectorPolygon ) );
169 : :
170 : 0 : std::unique_ptr< QgsProcessingParameterEnum > sourceParam = std::make_unique<QgsProcessingParameterEnum >( QStringLiteral( "DESTINATION" ), QObject::tr( "Bookmark destination" ), QStringList() <<
171 : 0 : QObject::tr( "Project bookmarks" ) << QObject::tr( "User bookmarks" ), false, 0 );
172 : 0 : addParameter( sourceParam.release() );
173 : :
174 : 0 : addParameter( new QgsProcessingParameterExpression( QStringLiteral( "NAME_EXPRESSION" ), QObject::tr( "Name field" ), QVariant(), QStringLiteral( "INPUT" ) ) );
175 : 0 : addParameter( new QgsProcessingParameterExpression( QStringLiteral( "GROUP_EXPRESSION" ), QObject::tr( "Group field" ), QVariant(), QStringLiteral( "INPUT" ), true ) );
176 : :
177 : 0 : addOutput( new QgsProcessingOutputNumber( QStringLiteral( "COUNT" ), QObject::tr( "Count of bookmarks added" ) ) );
178 : 0 : }
179 : :
180 : 0 : QString QgsLayerToBookmarksAlgorithm::name() const
181 : : {
182 : 0 : return QStringLiteral( "layertobookmarks" );
183 : : }
184 : :
185 : 0 : QString QgsLayerToBookmarksAlgorithm::displayName() const
186 : : {
187 : 0 : return QObject::tr( "Convert layer to spatial bookmarks" );
188 : : }
189 : :
190 : 0 : QStringList QgsLayerToBookmarksAlgorithm::tags() const
191 : : {
192 : 0 : return QObject::tr( "save,extract,store" ).split( ',' );
193 : 0 : }
194 : :
195 : 0 : QString QgsLayerToBookmarksAlgorithm::group() const
196 : : {
197 : 0 : return QObject::tr( "Vector general" );
198 : : }
199 : :
200 : 0 : QString QgsLayerToBookmarksAlgorithm::groupId() const
201 : : {
202 : 0 : return QStringLiteral( "vectorgeneral" );
203 : : }
204 : :
205 : 0 : QString QgsLayerToBookmarksAlgorithm::shortHelpString() const
206 : : {
207 : 0 : return QObject::tr( "This algorithm creates spatial bookmarks corresponding to the extent of features contained in a layer." );
208 : : }
209 : :
210 : 0 : QString QgsLayerToBookmarksAlgorithm::shortDescription() const
211 : : {
212 : 0 : return QObject::tr( "Converts feature extents to stored spatial bookmarks." );
213 : : }
214 : :
215 : 0 : QIcon QgsLayerToBookmarksAlgorithm::icon() const
216 : : {
217 : 0 : return QgsApplication::getThemeIcon( QStringLiteral( "mActionShowBookmarks.svg" ) );
218 : 0 : }
219 : :
220 : 0 : QString QgsLayerToBookmarksAlgorithm::svgIconPath() const
221 : : {
222 : 0 : return QgsApplication::iconPath( QStringLiteral( "mActionShowBookmarks.svg" ) );
223 : 0 : }
224 : :
225 : 0 : QgsLayerToBookmarksAlgorithm *QgsLayerToBookmarksAlgorithm::createInstance() const
226 : : {
227 : 0 : return new QgsLayerToBookmarksAlgorithm();
228 : : }
229 : :
230 : 0 : QVariantMap QgsLayerToBookmarksAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
231 : : {
232 : 0 : mDest = parameterAsEnum( parameters, QStringLiteral( "DESTINATION" ), context );
233 : 0 : std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
234 : 0 : if ( !source )
235 : 0 : throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
236 : :
237 : :
238 : 0 : QString nameExpressionString = parameterAsExpression( parameters, QStringLiteral( "NAME_EXPRESSION" ), context );
239 : 0 : QString groupExpressionString = parameterAsExpression( parameters, QStringLiteral( "GROUP_EXPRESSION" ), context );
240 : :
241 : 0 : QgsExpressionContext expressionContext = context.expressionContext();
242 : 0 : expressionContext.appendScope( source->createExpressionContextScope() );
243 : :
244 : 0 : QgsExpression nameExpression = QgsExpression( nameExpressionString );
245 : 0 : if ( !nameExpression.prepare( &expressionContext ) )
246 : 0 : throw QgsProcessingException( QObject::tr( "Invalid name expression: %1" ).arg( nameExpression.parserErrorString() ) );
247 : :
248 : 0 : QSet< QString > requiredColumns = nameExpression.referencedColumns();
249 : :
250 : 0 : std::unique_ptr< QgsExpression > groupExpression;
251 : 0 : if ( !groupExpressionString.isEmpty() )
252 : : {
253 : 0 : groupExpression = std::make_unique< QgsExpression >( groupExpressionString );
254 : 0 : if ( !groupExpression->prepare( &expressionContext ) )
255 : 0 : throw QgsProcessingException( QObject::tr( "Invalid group expression: %1" ).arg( groupExpression->parserErrorString() ) );
256 : 0 : requiredColumns.unite( groupExpression->referencedColumns() );
257 : 0 : }
258 : :
259 : 0 : QgsFeatureRequest req;
260 : 0 : req.setSubsetOfAttributes( requiredColumns, source->fields() );
261 : :
262 : 0 : double step = source->featureCount() > 0 ? 100.0 / source->featureCount() : 1;
263 : 0 : QgsFeatureIterator fi = source->getFeatures( req, QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks );
264 : 0 : QgsFeature f;
265 : 0 : int current = 0;
266 : 0 : while ( fi.nextFeature( f ) )
267 : : {
268 : 0 : if ( feedback->isCanceled() )
269 : : {
270 : 0 : break;
271 : : }
272 : :
273 : 0 : if ( f.hasGeometry() )
274 : : {
275 : 0 : const QgsReferencedRectangle extent( f.geometry().boundingBox(), source->sourceCrs() );
276 : 0 : expressionContext.setFeature( f );
277 : 0 : const QString name = nameExpression.evaluate( &expressionContext ).toString();
278 : 0 : if ( !nameExpression.evalErrorString().isEmpty() )
279 : : {
280 : 0 : feedback->reportError( QObject::tr( "Error evaluating name expression: %1" ).arg( nameExpression.evalErrorString() ) );
281 : 0 : feedback->setProgress( current * step );
282 : 0 : current++;
283 : 0 : continue;
284 : : }
285 : 0 : QString group;
286 : 0 : if ( groupExpression )
287 : : {
288 : 0 : group = groupExpression->evaluate( &expressionContext ).toString();
289 : 0 : if ( !groupExpression->evalErrorString().isEmpty() )
290 : : {
291 : 0 : feedback->reportError( QObject::tr( "Error evaluating group expression: %1" ).arg( groupExpression->evalErrorString() ) );
292 : 0 : feedback->setProgress( current * step );
293 : 0 : current++;
294 : 0 : continue;
295 : : }
296 : 0 : }
297 : :
298 : 0 : QgsBookmark b;
299 : 0 : b.setName( name );
300 : 0 : b.setGroup( group );
301 : 0 : b.setExtent( extent );
302 : 0 : mBookmarks << b;
303 : 0 : }
304 : 0 : feedback->setProgress( current * step );
305 : 0 : current++;
306 : : }
307 : :
308 : 0 : return QVariantMap();
309 : 0 : }
310 : :
311 : 0 : QVariantMap QgsLayerToBookmarksAlgorithm::postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback * )
312 : : {
313 : 0 : QgsBookmarkManager *dest = nullptr;
314 : 0 : switch ( mDest )
315 : : {
316 : : case 0:
317 : 0 : dest = context.project()->bookmarkManager();
318 : 0 : break;
319 : :
320 : : case 1:
321 : 0 : dest = QgsApplication::bookmarkManager();
322 : 0 : break;
323 : : }
324 : :
325 : 0 : for ( const QgsBookmark &b : std::as_const( mBookmarks ) )
326 : 0 : dest->addBookmark( b );
327 : :
328 : 0 : QVariantMap res;
329 : 0 : res.insert( QStringLiteral( "COUNT" ), mBookmarks.size() );
330 : 0 : return res;
331 : 0 : }
332 : :
333 : : ///@endcond
334 : :
335 : :
336 : :
|