QGIS API Documentation 3.36.0-Maidenhead (09951dc0acf)
Loading...
Searching...
No Matches
qgsprocessingutils.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsprocessingutils.cpp
3 ------------------------
4 begin : April 2017
5 copyright : (C) 2017 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 "qgsprocessingutils.h"
19#include "qgsproject.h"
20#include "qgsexception.h"
23#include "qgsvectorfilewriter.h"
29#include "qgsfileutils.h"
30#include "qgsvectorlayer.h"
31#include "qgsproviderregistry.h"
32#include "qgsmeshlayer.h"
33#include "qgspluginlayer.h"
35#include "qgsrasterfilewriter.h"
36#include "qgsvectortilelayer.h"
37#include "qgspointcloudlayer.h"
38#include "qgsannotationlayer.h"
39#include "qgstiledscenelayer.h"
40#include <QRegularExpression>
41#include <QTextCodec>
42#include <QUuid>
43
44QList<QgsRasterLayer *> QgsProcessingUtils::compatibleRasterLayers( QgsProject *project, bool sort )
45{
46 return compatibleMapLayers< QgsRasterLayer >( project, sort );
47}
48
49QList<QgsVectorLayer *> QgsProcessingUtils::compatibleVectorLayers( QgsProject *project, const QList<int> &geometryTypes, bool sort )
50{
51 if ( !project )
52 return QList<QgsVectorLayer *>();
53
54 QList<QgsVectorLayer *> layers;
55 const auto vectorLayers = project->layers<QgsVectorLayer *>();
56 for ( QgsVectorLayer *l : vectorLayers )
57 {
58 if ( canUseLayer( l, geometryTypes ) )
59 layers << l;
60 }
61
62 if ( sort )
63 {
64 std::sort( layers.begin(), layers.end(), []( const QgsVectorLayer * a, const QgsVectorLayer * b ) -> bool
65 {
66 return QString::localeAwareCompare( a->name(), b->name() ) < 0;
67 } );
68 }
69 return layers;
70}
71
72QList<QgsMeshLayer *> QgsProcessingUtils::compatibleMeshLayers( QgsProject *project, bool sort )
73{
74 return compatibleMapLayers< QgsMeshLayer >( project, sort );
75}
76
77QList<QgsPluginLayer *> QgsProcessingUtils::compatiblePluginLayers( QgsProject *project, bool sort )
78{
79 return compatibleMapLayers< QgsPluginLayer >( project, sort );
80}
81
82QList<QgsPointCloudLayer *> QgsProcessingUtils::compatiblePointCloudLayers( QgsProject *project, bool sort )
83{
84 return compatibleMapLayers< QgsPointCloudLayer >( project, sort );
85}
86
87QList<QgsAnnotationLayer *> QgsProcessingUtils::compatibleAnnotationLayers( QgsProject *project, bool sort )
88{
89 // we have to defer sorting until we've added the main annotation layer too
90 QList<QgsAnnotationLayer *> res = compatibleMapLayers< QgsAnnotationLayer >( project, false );
91 if ( project )
92 res.append( project->mainAnnotationLayer() );
93
94 if ( sort )
95 {
96 std::sort( res.begin(), res.end(), []( const QgsAnnotationLayer * a, const QgsAnnotationLayer * b ) -> bool
97 {
98 return QString::localeAwareCompare( a->name(), b->name() ) < 0;
99 } );
100 }
101
102 return res;
103}
104
105QList<QgsVectorTileLayer *> QgsProcessingUtils::compatibleVectorTileLayers( QgsProject *project, bool sort )
106{
107 return compatibleMapLayers< QgsVectorTileLayer >( project, sort );
108}
109
110QList<QgsTiledSceneLayer *> QgsProcessingUtils::compatibleTiledSceneLayers( QgsProject *project, bool sort )
111{
112 return compatibleMapLayers< QgsTiledSceneLayer >( project, sort );
113}
114
115template<typename T> QList<T *> QgsProcessingUtils::compatibleMapLayers( QgsProject *project, bool sort )
116{
117 if ( !project )
118 return QList<T *>();
119
120 QList<T *> layers;
121 const auto projectLayers = project->layers<T *>();
122 for ( T *l : projectLayers )
123 {
124 if ( canUseLayer( l ) )
125 layers << l;
126 }
127
128 if ( sort )
129 {
130 std::sort( layers.begin(), layers.end(), []( const T * a, const T * b ) -> bool
131 {
132 return QString::localeAwareCompare( a->name(), b->name() ) < 0;
133 } );
134 }
135 return layers;
136}
137
138QList<QgsMapLayer *> QgsProcessingUtils::compatibleLayers( QgsProject *project, bool sort )
139{
140 if ( !project )
141 return QList<QgsMapLayer *>();
142
143 QList<QgsMapLayer *> layers;
144
145 const auto rasterLayers = compatibleMapLayers< QgsRasterLayer >( project, false );
146 for ( QgsRasterLayer *rl : rasterLayers )
147 layers << rl;
148
149 const auto vectorLayers = compatibleVectorLayers( project, QList< int >(), false );
150 for ( QgsVectorLayer *vl : vectorLayers )
151 layers << vl;
152
153 const auto meshLayers = compatibleMapLayers< QgsMeshLayer >( project, false );
154 for ( QgsMeshLayer *ml : meshLayers )
155 layers << ml;
156
157 const auto pointCloudLayers = compatibleMapLayers< QgsPointCloudLayer >( project, false );
158 for ( QgsPointCloudLayer *pcl : pointCloudLayers )
159 layers << pcl;
160
161 const auto annotationLayers = compatibleMapLayers< QgsAnnotationLayer >( project, false );
162 for ( QgsAnnotationLayer *al : annotationLayers )
163 layers << al;
164 layers << project->mainAnnotationLayer();
165
166 const auto vectorTileLayers = compatibleMapLayers< QgsVectorTileLayer >( project, false );
167 for ( QgsVectorTileLayer *vtl : vectorTileLayers )
168 layers << vtl;
169
170 const auto tiledSceneLayers = compatibleMapLayers< QgsTiledSceneLayer >( project, false );
171 for ( QgsTiledSceneLayer *tml : tiledSceneLayers )
172 layers << tml;
173
174 const auto pluginLayers = compatibleMapLayers< QgsPluginLayer >( project, false );
175 for ( QgsPluginLayer *pl : pluginLayers )
176 layers << pl;
177
178 if ( sort )
179 {
180 std::sort( layers.begin(), layers.end(), []( const QgsMapLayer * a, const QgsMapLayer * b ) -> bool
181 {
182 return QString::localeAwareCompare( a->name(), b->name() ) < 0;
183 } );
184 }
185 return layers;
186}
187
188QString QgsProcessingUtils::encodeProviderKeyAndUri( const QString &providerKey, const QString &uri )
189{
190 return QStringLiteral( "%1://%2" ).arg( providerKey, uri );
191}
192
193bool QgsProcessingUtils::decodeProviderKeyAndUri( const QString &string, QString &providerKey, QString &uri )
194{
195 const thread_local QRegularExpression re( QStringLiteral( "^(\\w+?):\\/\\/(.+)$" ) );
196 const QRegularExpressionMatch match = re.match( string );
197 if ( !match.hasMatch() )
198 return false;
199
200 providerKey = match.captured( 1 );
201 uri = match.captured( 2 );
202
203 // double check that provider is valid
204 return QgsProviderRegistry::instance()->providerMetadata( providerKey );
205}
206
207QgsMapLayer *QgsProcessingUtils::mapLayerFromStore( const QString &string, QgsMapLayerStore *store, QgsProcessingUtils::LayerHint typeHint )
208{
209 if ( !store || string.isEmpty() )
210 return nullptr;
211
212 QList< QgsMapLayer * > layers = store->mapLayers().values();
213
214 layers.erase( std::remove_if( layers.begin(), layers.end(), []( QgsMapLayer * layer )
215 {
216 switch ( layer->type() )
217 {
218 case Qgis::LayerType::Vector:
219 return !canUseLayer( qobject_cast< QgsVectorLayer * >( layer ) );
220 case Qgis::LayerType::Raster:
221 return !canUseLayer( qobject_cast< QgsRasterLayer * >( layer ) );
222 case Qgis::LayerType::Plugin:
223 case Qgis::LayerType::Group:
224 return true;
225 case Qgis::LayerType::Mesh:
226 return !canUseLayer( qobject_cast< QgsMeshLayer * >( layer ) );
227 case Qgis::LayerType::VectorTile:
228 return !canUseLayer( qobject_cast< QgsVectorTileLayer * >( layer ) );
229 case Qgis::LayerType::TiledScene:
230 return !canUseLayer( qobject_cast< QgsTiledSceneLayer * >( layer ) );
231 case Qgis::LayerType::PointCloud:
232 return !canUseLayer( qobject_cast< QgsPointCloudLayer * >( layer ) );
233 case Qgis::LayerType::Annotation:
234 return !canUseLayer( qobject_cast< QgsAnnotationLayer * >( layer ) );
235 }
236 return true;
237 } ), layers.end() );
238
239 auto isCompatibleType = [typeHint]( QgsMapLayer * l ) -> bool
240 {
241 switch ( typeHint )
242 {
243 case LayerHint::UnknownType:
244 return true;
245
246 case LayerHint::Vector:
247 return l->type() == Qgis::LayerType::Vector;
248
249 case LayerHint::Raster:
250 return l->type() == Qgis::LayerType::Raster;
251
252 case LayerHint::Mesh:
253 return l->type() == Qgis::LayerType::Mesh;
254
255 case LayerHint::PointCloud:
256 return l->type() == Qgis::LayerType::PointCloud;
257
258 case LayerHint::Annotation:
259 return l->type() == Qgis::LayerType::Annotation;
260
261 case LayerHint::VectorTile:
262 return l->type() == Qgis::LayerType::VectorTile;
263
264 case LayerHint::TiledScene:
265 return l->type() == Qgis::LayerType::TiledScene;
266 }
267 return true;
268 };
269
270 for ( QgsMapLayer *l : std::as_const( layers ) )
271 {
272 if ( isCompatibleType( l ) && l->id() == string )
273 return l;
274 }
275 for ( QgsMapLayer *l : std::as_const( layers ) )
276 {
277 if ( isCompatibleType( l ) && l->name() == string )
278 return l;
279 }
280 for ( QgsMapLayer *l : std::as_const( layers ) )
281 {
282 if ( isCompatibleType( l ) && normalizeLayerSource( l->source() ) == normalizeLayerSource( string ) )
283 return l;
284 }
285 return nullptr;
286}
287
288QgsMapLayer *QgsProcessingUtils::loadMapLayerFromString( const QString &string, const QgsCoordinateTransformContext &transformContext, LayerHint typeHint, QgsProcessing::LayerOptionsFlags flags )
289{
290 QString provider;
291 QString uri;
292 const bool useProvider = decodeProviderKeyAndUri( string, provider, uri );
293 if ( !useProvider )
294 uri = string;
295
296 QString name;
297
298 const QgsProviderMetadata *providerMetadata = useProvider ? QgsProviderRegistry::instance()->providerMetadata( provider ) : nullptr;
299 if ( providerMetadata )
300 {
301 // use the uri parts to determine a suitable layer name
302 const QVariantMap parts = providerMetadata->decodeUri( uri );
303 const QString layerName = parts.value( QStringLiteral( "layerName" ) ).toString();
304
305 if ( !layerName.isEmpty() )
306 {
307 name = layerName;
308 }
309 else if ( const QString path = parts.value( QStringLiteral( "path" ) ).toString(); !path.isEmpty() )
310 {
311 name = QFileInfo( path ).baseName();
312 }
313 }
314 else
315 {
316 const QStringList components = uri.split( '|' );
317 if ( components.isEmpty() )
318 return nullptr;
319
320 if ( QFileInfo fi( components.at( 0 ) ); fi.isFile() )
321 name = fi.baseName();
322 else
323 name = QFileInfo( uri ).baseName();
324 }
325
326 if ( name.isEmpty() )
327 {
328 name = QgsDataSourceUri( uri ).table();
329 }
330 if ( name.isEmpty() )
331 {
332 name = uri;
333 }
334
335 QList< Qgis::LayerType > candidateTypes;
336 switch ( typeHint )
337 {
339 {
340 if ( providerMetadata )
341 {
342 // refine the type hint based on what the provider supports
343 candidateTypes = providerMetadata->supportedLayerTypes();
344 }
345 break;
346 }
348 candidateTypes.append( Qgis::LayerType::Vector );
349 break;
351 candidateTypes.append( Qgis::LayerType::Raster );
352 break;
353 case LayerHint::Mesh:
354 candidateTypes.append( Qgis::LayerType::Mesh );
355 break;
357 candidateTypes.append( Qgis::LayerType::PointCloud );
358 break;
360 candidateTypes.append( Qgis::LayerType::Annotation );
361 break;
363 candidateTypes.append( Qgis::LayerType::VectorTile );
364 break;
366 candidateTypes.append( Qgis::LayerType::TiledScene );
367 break;
368 }
369
370 // brute force attempt to load a matching layer
371 if ( candidateTypes.empty() || candidateTypes.contains( Qgis::LayerType::Vector ) )
372 {
373 QgsVectorLayer::LayerOptions options { transformContext };
374 options.loadDefaultStyle = false;
375 options.skipCrsValidation = true;
376
377 std::unique_ptr< QgsVectorLayer > layer;
378 if ( providerMetadata )
379 {
380 layer = std::make_unique<QgsVectorLayer>( uri, name, providerMetadata->key(), options );
381 }
382 else
383 {
384 // fallback to ogr
385 layer = std::make_unique<QgsVectorLayer>( uri, name, QStringLiteral( "ogr" ), options );
386 }
387 if ( layer->isValid() )
388 {
389 return layer.release();
390 }
391 }
392 if ( candidateTypes.empty() || candidateTypes.contains( Qgis::LayerType::Raster ) )
393 {
394 QgsRasterLayer::LayerOptions rasterOptions;
395 rasterOptions.loadDefaultStyle = false;
396 rasterOptions.skipCrsValidation = true;
397
398 std::unique_ptr< QgsRasterLayer > rasterLayer;
399 if ( providerMetadata )
400 {
401 rasterLayer = std::make_unique< QgsRasterLayer >( uri, name, providerMetadata->key(), rasterOptions );
402 }
403 else
404 {
405 // fallback to gdal
406 rasterLayer = std::make_unique< QgsRasterLayer >( uri, name, QStringLiteral( "gdal" ), rasterOptions );
407 }
408
409 if ( rasterLayer->isValid() )
410 {
411 return rasterLayer.release();
412 }
413 }
414 if ( candidateTypes.empty() || candidateTypes.contains( Qgis::LayerType::Mesh ) )
415 {
416 QgsMeshLayer::LayerOptions meshOptions;
417 meshOptions.skipCrsValidation = true;
418
419 std::unique_ptr< QgsMeshLayer > meshLayer;
420 if ( providerMetadata )
421 {
422 meshLayer = std::make_unique< QgsMeshLayer >( uri, name, providerMetadata->key(), meshOptions );
423 }
424 else
425 {
426 meshLayer = std::make_unique< QgsMeshLayer >( uri, name, QStringLiteral( "mdal" ), meshOptions );
427 }
428 if ( meshLayer->isValid() )
429 {
430 return meshLayer.release();
431 }
432 }
433 if ( candidateTypes.empty() || candidateTypes.contains( Qgis::LayerType::PointCloud ) )
434 {
435 QgsPointCloudLayer::LayerOptions pointCloudOptions;
436 pointCloudOptions.skipCrsValidation = true;
437
439 {
440 pointCloudOptions.skipIndexGeneration = true;
441 }
442
443 std::unique_ptr< QgsPointCloudLayer > pointCloudLayer;
444 if ( providerMetadata )
445 {
446 pointCloudLayer = std::make_unique< QgsPointCloudLayer >( uri, name, providerMetadata->key(), pointCloudOptions );
447 }
448 else
449 {
450 const QList< QgsProviderRegistry::ProviderCandidateDetails > preferredProviders = QgsProviderRegistry::instance()->preferredProvidersForUri( uri );
451 if ( !preferredProviders.empty() )
452 {
453 pointCloudLayer = std::make_unique< QgsPointCloudLayer >( uri, name, preferredProviders.at( 0 ).metadata()->key(), pointCloudOptions );
454 }
455 }
456 if ( pointCloudLayer && pointCloudLayer->isValid() )
457 {
458 return pointCloudLayer.release();
459 }
460 }
461 if ( candidateTypes.empty() || candidateTypes.contains( Qgis::LayerType::VectorTile ) )
462 {
463 QgsDataSourceUri dsUri;
464 dsUri.setParam( "type", "mbtiles" );
465 dsUri.setParam( "url", uri );
466
467 std::unique_ptr< QgsVectorTileLayer > tileLayer;
468 tileLayer = std::make_unique< QgsVectorTileLayer >( dsUri.encodedUri(), name );
469
470 if ( tileLayer->isValid() )
471 {
472 return tileLayer.release();
473 }
474 }
475 if ( candidateTypes.empty() || candidateTypes.contains( Qgis::LayerType::TiledScene ) )
476 {
477 QgsTiledSceneLayer::LayerOptions tiledSceneOptions;
478 tiledSceneOptions.skipCrsValidation = true;
479
480 std::unique_ptr< QgsTiledSceneLayer > tiledSceneLayer;
481 if ( providerMetadata )
482 {
483 tiledSceneLayer = std::make_unique< QgsTiledSceneLayer >( uri, name, providerMetadata->key(), tiledSceneOptions );
484 }
485 else
486 {
487 const QList< QgsProviderRegistry::ProviderCandidateDetails > preferredProviders = QgsProviderRegistry::instance()->preferredProvidersForUri( uri );
488 if ( !preferredProviders.empty() )
489 {
490 tiledSceneLayer = std::make_unique< QgsTiledSceneLayer >( uri, name, preferredProviders.at( 0 ).metadata()->key(), tiledSceneOptions );
491 }
492 }
493 if ( tiledSceneLayer && tiledSceneLayer->isValid() )
494 {
495 return tiledSceneLayer.release();
496 }
497 }
498 return nullptr;
499}
500
501QgsMapLayer *QgsProcessingUtils::mapLayerFromString( const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers, LayerHint typeHint, QgsProcessing::LayerOptionsFlags flags )
502{
503 if ( string.isEmpty() )
504 return nullptr;
505
506 // prefer project layers
507 if ( context.project() && typeHint == LayerHint::Annotation && string.compare( QLatin1String( "main" ), Qt::CaseInsensitive ) == 0 )
508 return context.project()->mainAnnotationLayer();
509
510 QgsMapLayer *layer = nullptr;
511 if ( auto *lProject = context.project() )
512 {
513 QgsMapLayer *layer = mapLayerFromStore( string, lProject->layerStore(), typeHint );
514 if ( layer )
515 return layer;
516 }
517
518 layer = mapLayerFromStore( string, context.temporaryLayerStore(), typeHint );
519 if ( layer )
520 return layer;
521
522 if ( !allowLoadingNewLayers )
523 return nullptr;
524
525 layer = loadMapLayerFromString( string, context.transformContext(), typeHint, flags );
526 if ( layer )
527 {
528 context.temporaryLayerStore()->addMapLayer( layer );
529 return layer;
530 }
531 else
532 {
533 return nullptr;
534 }
535}
536
537QgsProcessingFeatureSource *QgsProcessingUtils::variantToSource( const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue )
538{
539 QVariant val = value;
540 bool selectedFeaturesOnly = false;
541 long long featureLimit = -1;
542 QString filterExpression;
543 bool overrideGeometryCheck = false;
545 if ( val.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
546 {
547 // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
548 QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
549 selectedFeaturesOnly = fromVar.selectedFeaturesOnly;
550 featureLimit = fromVar.featureLimit;
551 filterExpression = fromVar.filterExpression;
552 val = fromVar.source;
554 geometryCheck = fromVar.geometryCheck;
555 }
556 else if ( val.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
557 {
558 // input is a QgsProcessingOutputLayerDefinition (e.g. an output from earlier in a model) - get extra properties from it
559 QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
560 val = fromVar.sink;
561 }
562
563 if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( val ) ) )
564 {
565 std::unique_ptr< QgsProcessingFeatureSource> source = std::make_unique< QgsProcessingFeatureSource >( layer, context, false, featureLimit, filterExpression );
566 if ( overrideGeometryCheck )
567 source->setInvalidGeometryCheck( geometryCheck );
568 return source.release();
569 }
570
571 QString layerRef;
572 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
573 {
574 layerRef = val.value< QgsProperty >().valueAsString( context.expressionContext(), fallbackValue.toString() );
575 }
576 else if ( !val.isValid() || val.toString().isEmpty() )
577 {
578 // fall back to default
579 if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( fallbackValue ) ) )
580 {
581 std::unique_ptr< QgsProcessingFeatureSource> source = std::make_unique< QgsProcessingFeatureSource >( layer, context, false, featureLimit, filterExpression );
582 if ( overrideGeometryCheck )
583 source->setInvalidGeometryCheck( geometryCheck );
584 return source.release();
585 }
586
587 layerRef = fallbackValue.toString();
588 }
589 else
590 {
591 layerRef = val.toString();
592 }
593
594 if ( layerRef.isEmpty() )
595 return nullptr;
596
597 QgsVectorLayer *vl = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( layerRef, context, true, LayerHint::Vector ) );
598 if ( !vl )
599 return nullptr;
600
601 std::unique_ptr< QgsProcessingFeatureSource> source;
602 if ( selectedFeaturesOnly )
603 {
604 source = std::make_unique< QgsProcessingFeatureSource>( new QgsVectorLayerSelectedFeatureSource( vl ), context, true, featureLimit, filterExpression );
605 }
606 else
607 {
608 source = std::make_unique< QgsProcessingFeatureSource >( vl, context, false, featureLimit, filterExpression );
609 }
610
611 if ( overrideGeometryCheck )
612 source->setInvalidGeometryCheck( geometryCheck );
613 return source.release();
614}
615
616QgsCoordinateReferenceSystem QgsProcessingUtils::variantToCrs( const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue )
617{
618 QVariant val = value;
619
620 if ( val.userType() == QMetaType::type( "QgsCoordinateReferenceSystem" ) )
621 {
622 // input is a QgsCoordinateReferenceSystem - done!
623 return val.value< QgsCoordinateReferenceSystem >();
624 }
625 else if ( val.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
626 {
627 // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
628 QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
629 val = fromVar.source;
630 }
631 else if ( val.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
632 {
633 // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
634 QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
635 val = fromVar.sink;
636 }
637
638 if ( val.userType() == QMetaType::type( "QgsProperty" ) && val.value< QgsProperty >().propertyType() == Qgis::PropertyType::Static )
639 {
640 val = val.value< QgsProperty >().staticValue();
641 }
642
643 // maybe a map layer
644 if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
645 return layer->crs();
646
647 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
648 val = val.value< QgsProperty >().valueAsString( context.expressionContext(), fallbackValue.toString() );
649
650 if ( !val.isValid() )
651 {
652 // fall back to default
653 val = fallbackValue;
654 }
655
656 QString crsText = val.toString();
657 if ( crsText.isEmpty() )
658 crsText = fallbackValue.toString();
659
660 if ( crsText.isEmpty() )
662
663 // maybe special string
664 if ( context.project() && crsText.compare( QLatin1String( "ProjectCrs" ), Qt::CaseInsensitive ) == 0 )
665 return context.project()->crs();
666
667 // maybe a map layer reference
668 if ( QgsMapLayer *layer = QgsProcessingUtils::mapLayerFromString( crsText, context ) )
669 return layer->crs();
670
671 // else CRS from string
673 crs.createFromString( crsText );
674 return crs;
675}
676
677bool QgsProcessingUtils::canUseLayer( const QgsMeshLayer *layer )
678{
679 return layer && layer->dataProvider();
680}
681
682bool QgsProcessingUtils::canUseLayer( const QgsPluginLayer *layer )
683{
684 return layer && layer->isValid();
685}
686
687bool QgsProcessingUtils::canUseLayer( const QgsVectorTileLayer *layer )
688{
689 return layer && layer->isValid();
690}
691
692bool QgsProcessingUtils::canUseLayer( const QgsRasterLayer *layer )
693{
694 return layer && layer->isValid();
695}
696
697bool QgsProcessingUtils::canUseLayer( const QgsPointCloudLayer *layer )
698{
699 return layer && layer->isValid();
700}
701
702bool QgsProcessingUtils::canUseLayer( const QgsAnnotationLayer *layer )
703{
704 return layer && layer->isValid();
705}
706
707bool QgsProcessingUtils::canUseLayer( const QgsTiledSceneLayer *layer )
708{
709 return layer && layer->isValid();
710}
711
712bool QgsProcessingUtils::canUseLayer( const QgsVectorLayer *layer, const QList<int> &sourceTypes )
713{
714 return layer && layer->isValid() &&
715 ( sourceTypes.isEmpty()
716 || ( sourceTypes.contains( static_cast< int >( Qgis::ProcessingSourceType::VectorPoint ) ) && layer->geometryType() == Qgis::GeometryType::Point )
717 || ( sourceTypes.contains( static_cast< int >( Qgis::ProcessingSourceType::VectorLine ) ) && layer->geometryType() == Qgis::GeometryType::Line )
718 || ( sourceTypes.contains( static_cast< int >( Qgis::ProcessingSourceType::VectorPolygon ) ) && layer->geometryType() == Qgis::GeometryType::Polygon )
719 || ( sourceTypes.contains( static_cast< int >( Qgis::ProcessingSourceType::VectorAnyGeometry ) ) && layer->isSpatial() )
720 || sourceTypes.contains( static_cast< int >( Qgis::ProcessingSourceType::Vector ) )
721 );
722}
723
724QString QgsProcessingUtils::normalizeLayerSource( const QString &source )
725{
726 QString normalized = source;
727 normalized.replace( '\\', '/' );
728 return normalized.trimmed();
729}
730
732{
733 if ( !layer )
734 return QString();
735
736 const QString source = QgsProcessingUtils::normalizeLayerSource( layer->source() );
737 if ( !source.isEmpty() )
738 {
739 const QString provider = layer->providerType();
740 // don't prepend provider type for these exceptional providers -- we assume them
741 // by default if the provider type is excluded. See logic in QgsProcessingUtils::loadMapLayerFromString
742 if ( provider.compare( QLatin1String( "gdal" ), Qt::CaseInsensitive ) == 0
743 || provider.compare( QLatin1String( "ogr" ), Qt::CaseInsensitive ) == 0
744 || provider.compare( QLatin1String( "mdal" ), Qt::CaseInsensitive ) == 0 )
745 return source;
746
747 return QStringLiteral( "%1://%2" ).arg( provider, source );
748 }
749 return layer->id();
750}
751
752QString QgsProcessingUtils::variantToPythonLiteral( const QVariant &value )
753{
754 if ( !value.isValid() )
755 return QStringLiteral( "None" );
756
757 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
758 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
759 else if ( value.userType() == QMetaType::type( "QgsCoordinateReferenceSystem" ) )
760 {
761 if ( !value.value< QgsCoordinateReferenceSystem >().isValid() )
762 return QStringLiteral( "QgsCoordinateReferenceSystem()" );
763 else
764 return QStringLiteral( "QgsCoordinateReferenceSystem('%1')" ).arg( value.value< QgsCoordinateReferenceSystem >().authid() );
765 }
766 else if ( value.userType() == QMetaType::type( "QgsRectangle" ) )
767 {
768 QgsRectangle r = value.value<QgsRectangle>();
769 return QStringLiteral( "'%1, %3, %2, %4'" ).arg( qgsDoubleToString( r.xMinimum() ),
773 }
774 else if ( value.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
775 {
777 return QStringLiteral( "'%1, %3, %2, %4 [%5]'" ).arg( qgsDoubleToString( r.xMinimum() ),
780 qgsDoubleToString( r.yMaximum() ), r.crs().authid() );
781 }
782 else if ( value.userType() == QMetaType::type( "QgsPointXY" ) )
783 {
784 QgsPointXY r = value.value<QgsPointXY>();
785 return QStringLiteral( "'%1,%2'" ).arg( qgsDoubleToString( r.x() ),
786 qgsDoubleToString( r.y() ) );
787 }
788 else if ( value.userType() == QMetaType::type( "QgsReferencedPointXY" ) )
789 {
791 return QStringLiteral( "'%1,%2 [%3]'" ).arg( qgsDoubleToString( r.x() ),
792 qgsDoubleToString( r.y() ),
793 r.crs().authid() );
794 }
795
796 switch ( value.type() )
797 {
798 case QVariant::Bool:
799 return value.toBool() ? QStringLiteral( "True" ) : QStringLiteral( "False" );
800
801 case QVariant::Double:
802 return QString::number( value.toDouble() );
803
804 case QVariant::Int:
805 case QVariant::UInt:
806 return QString::number( value.toInt() );
807
808 case QVariant::LongLong:
809 case QVariant::ULongLong:
810 return QString::number( value.toLongLong() );
811
812 case QVariant::List:
813 {
814 QStringList parts;
815 const QVariantList vl = value.toList();
816 for ( const QVariant &v : vl )
817 {
818 parts << variantToPythonLiteral( v );
819 }
820 return parts.join( ',' ).prepend( '[' ).append( ']' );
821 }
822
823 case QVariant::Map:
824 {
825 const QVariantMap map = value.toMap();
826 QStringList parts;
827 parts.reserve( map.size() );
828 for ( auto it = map.constBegin(); it != map.constEnd(); ++it )
829 {
830 parts << QStringLiteral( "%1: %2" ).arg( stringToPythonLiteral( it.key() ), variantToPythonLiteral( it.value() ) );
831 }
832 return parts.join( ',' ).prepend( '{' ).append( '}' );
833 }
834
835 case QVariant::DateTime:
836 {
837 const QDateTime dateTime = value.toDateTime();
838 return QStringLiteral( "QDateTime(QDate(%1, %2, %3), QTime(%4, %5, %6))" )
839 .arg( dateTime.date().year() )
840 .arg( dateTime.date().month() )
841 .arg( dateTime.date().day() )
842 .arg( dateTime.time().hour() )
843 .arg( dateTime.time().minute() )
844 .arg( dateTime.time().second() );
845 }
846
847 default:
848 break;
849 }
850
851 return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
852}
853
854QString QgsProcessingUtils::stringToPythonLiteral( const QString &string )
855{
856 QString s = string;
857 s.replace( '\\', QLatin1String( "\\\\" ) );
858 s.replace( '\n', QLatin1String( "\\n" ) );
859 s.replace( '\r', QLatin1String( "\\r" ) );
860 s.replace( '\t', QLatin1String( "\\t" ) );
861
862 if ( s.contains( '\'' ) && !s.contains( '\"' ) )
863 {
864 s = s.prepend( '"' ).append( '"' );
865 }
866 else
867 {
868 s.replace( '\'', QLatin1String( "\\\'" ) );
869 s = s.prepend( '\'' ).append( '\'' );
870 }
871 return s;
872}
873
874void QgsProcessingUtils::parseDestinationString( QString &destination, QString &providerKey, QString &uri, QString &layerName, QString &format, QMap<QString, QVariant> &options, bool &useWriter, QString &extension )
875{
876 extension.clear();
877 bool matched = decodeProviderKeyAndUri( destination, providerKey, uri );
878
879 if ( !matched )
880 {
881 const thread_local QRegularExpression splitRx( QStringLiteral( "^(.{3,}?):(.*)$" ) );
882 QRegularExpressionMatch match = splitRx.match( destination );
883 if ( match.hasMatch() )
884 {
885 providerKey = match.captured( 1 );
886 uri = match.captured( 2 );
887 matched = true;
888 }
889 }
890
891 if ( matched )
892 {
893 if ( providerKey == QLatin1String( "postgis" ) ) // older processing used "postgis" instead of "postgres"
894 {
895 providerKey = QStringLiteral( "postgres" );
896 }
897 if ( providerKey == QLatin1String( "ogr" ) )
898 {
899 QgsDataSourceUri dsUri( uri );
900 if ( !dsUri.database().isEmpty() )
901 {
902 if ( !dsUri.table().isEmpty() )
903 {
904 layerName = dsUri.table();
905 options.insert( QStringLiteral( "layerName" ), layerName );
906 }
907 uri = dsUri.database();
908 extension = QFileInfo( uri ).completeSuffix();
909 format = QgsVectorFileWriter::driverForExtension( extension );
910 options.insert( QStringLiteral( "driverName" ), format );
911 }
912 else
913 {
914 extension = QFileInfo( uri ).completeSuffix();
915 options.insert( QStringLiteral( "driverName" ), QgsVectorFileWriter::driverForExtension( extension ) );
916 }
917 options.insert( QStringLiteral( "update" ), true );
918 }
919 useWriter = false;
920 }
921 else
922 {
923 useWriter = true;
924 providerKey = QStringLiteral( "ogr" );
925
926 const thread_local QRegularExpression splitRx( QStringLiteral( "^(.*)\\.(.*?)$" ) );
927 QRegularExpressionMatch match = splitRx.match( destination );
928 if ( match.hasMatch() )
929 {
930 extension = match.captured( 2 );
931 format = QgsVectorFileWriter::driverForExtension( extension );
932 }
933
934 if ( format.isEmpty() )
935 {
936 format = QStringLiteral( "GPKG" );
937 destination = destination + QStringLiteral( ".gpkg" );
938 }
939
940 options.insert( QStringLiteral( "driverName" ), format );
941 uri = destination;
942 }
943}
944
945QgsFeatureSink *QgsProcessingUtils::createFeatureSink( QString &destination, QgsProcessingContext &context, const QgsFields &fields, Qgis::WkbType geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &createOptions, const QStringList &datasourceOptions, const QStringList &layerOptions, QgsFeatureSink::SinkFlags sinkFlags, QgsRemappingSinkDefinition *remappingDefinition )
946{
947 QVariantMap options = createOptions;
948 if ( !options.contains( QStringLiteral( "fileEncoding" ) ) )
949 {
950 // no destination encoding specified, use default
951 options.insert( QStringLiteral( "fileEncoding" ), context.defaultEncoding().isEmpty() ? QStringLiteral( "system" ) : context.defaultEncoding() );
952 }
953
954 if ( destination.isEmpty() || destination.startsWith( QLatin1String( "memory:" ) ) )
955 {
956 // strip "memory:" from start of destination
957 if ( destination.startsWith( QLatin1String( "memory:" ) ) )
958 destination = destination.mid( 7 );
959
960 if ( destination.isEmpty() )
961 destination = QStringLiteral( "output" );
962
963 // memory provider cannot be used with QgsVectorLayerImport - so create layer manually
964 std::unique_ptr< QgsVectorLayer > layer( QgsMemoryProviderUtils::createMemoryLayer( destination, fields, geometryType, crs, false ) );
965 if ( !layer || !layer->isValid() )
966 {
967 throw QgsProcessingException( QObject::tr( "Could not create memory layer" ) );
968 }
969
970 if ( QgsProcessingFeedback *feedback = context.feedback() )
971 {
972 for ( const QgsField &field : fields )
973 {
974 // TODO -- support these!
975 if ( !field.alias().isEmpty() )
976 feedback->pushWarning( QObject::tr( "%1: Aliases are not compatible with scratch layers" ).arg( field.name() ) );
977 if ( !field.alias().isEmpty() )
978 feedback->pushWarning( QObject::tr( "%1: Comments are not compatible with scratch layers" ).arg( field.name() ) );
979 }
980 }
981
982 layer->setCustomProperty( QStringLiteral( "OnConvertFormatRegeneratePrimaryKey" ), static_cast< bool >( sinkFlags & QgsFeatureSink::RegeneratePrimaryKey ) );
983
984 // update destination to layer ID
985 destination = layer->id();
986
987 // this is a factory, so we need to return a proxy
988 std::unique_ptr< QgsProcessingFeatureSink > sink( new QgsProcessingFeatureSink( layer->dataProvider(), destination, context ) );
989 context.temporaryLayerStore()->addMapLayer( layer.release() );
990
991 return sink.release();
992 }
993 else
994 {
995 QString providerKey;
996 QString uri;
997 QString layerName;
998 QString format;
999 QString extension;
1000 bool useWriter = false;
1001 parseDestinationString( destination, providerKey, uri, layerName, format, options, useWriter, extension );
1002
1003 QgsFields newFields = fields;
1004 if ( useWriter && providerKey == QLatin1String( "ogr" ) )
1005 {
1006 // use QgsVectorFileWriter for OGR destinations instead of QgsVectorLayerImport, as that allows
1007 // us to use any OGR format which supports feature addition
1008 QString finalFileName;
1009 QString finalLayerName;
1011 saveOptions.fileEncoding = options.value( QStringLiteral( "fileEncoding" ) ).toString();
1012 saveOptions.layerName = !layerName.isEmpty() ? layerName : options.value( QStringLiteral( "layerName" ) ).toString();
1013 saveOptions.driverName = format;
1014 saveOptions.datasourceOptions = !datasourceOptions.isEmpty() ? datasourceOptions : QgsVectorFileWriter::defaultDatasetOptions( format );
1015 saveOptions.layerOptions = !layerOptions.isEmpty() ? layerOptions : QgsVectorFileWriter::defaultLayerOptions( format );
1017 if ( remappingDefinition )
1018 {
1020 // sniff destination file to get correct wkb type and crs
1021 std::unique_ptr< QgsVectorLayer > vl = std::make_unique< QgsVectorLayer >( destination );
1022 if ( vl->isValid() )
1023 {
1024 remappingDefinition->setDestinationWkbType( vl->wkbType() );
1025 remappingDefinition->setDestinationCrs( vl->crs() );
1026 newFields = vl->fields();
1027 remappingDefinition->setDestinationFields( newFields );
1028 }
1029 context.expressionContext().setFields( fields );
1030 }
1031 else
1032 {
1034 }
1035 std::unique_ptr< QgsVectorFileWriter > writer( QgsVectorFileWriter::create( destination, newFields, geometryType, crs, context.transformContext(), saveOptions, sinkFlags, &finalFileName, &finalLayerName ) );
1036 if ( writer->hasError() )
1037 {
1038 throw QgsProcessingException( QObject::tr( "Could not create layer %1: %2" ).arg( destination, writer->errorMessage() ) );
1039 }
1040
1041 if ( QgsProcessingFeedback *feedback = context.feedback() )
1042 {
1043 for ( const QgsField &field : fields )
1044 {
1045 if ( !field.alias().isEmpty() && !( writer->capabilities() & Qgis::VectorFileWriterCapability::FieldAliases ) )
1046 feedback->pushWarning( QObject::tr( "%1: Aliases are not supported by %2" ).arg( field.name(), writer->driverLongName() ) );
1047 if ( !field.alias().isEmpty() && !( writer->capabilities() & Qgis::VectorFileWriterCapability::FieldComments ) )
1048 feedback->pushWarning( QObject::tr( "%1: Comments are not supported by %2" ).arg( field.name(), writer->driverLongName() ) );
1049 }
1050 }
1051
1052 destination = finalFileName;
1053 if ( !saveOptions.layerName.isEmpty() && !finalLayerName.isEmpty() )
1054 destination += QStringLiteral( "|layername=%1" ).arg( finalLayerName );
1055
1056 if ( remappingDefinition )
1057 {
1058 std::unique_ptr< QgsRemappingProxyFeatureSink > remapSink = std::make_unique< QgsRemappingProxyFeatureSink >( *remappingDefinition, writer.release(), true );
1059 remapSink->setExpressionContext( context.expressionContext() );
1060 remapSink->setTransformContext( context.transformContext() );
1061 return new QgsProcessingFeatureSink( remapSink.release(), destination, context, true );
1062 }
1063 else
1064 return new QgsProcessingFeatureSink( writer.release(), destination, context, true );
1065 }
1066 else
1067 {
1068 const QgsVectorLayer::LayerOptions layerOptions { context.transformContext() };
1069 if ( remappingDefinition )
1070 {
1071 //write to existing layer
1072
1073 // use destination string as layer name (eg "postgis:..." )
1074 if ( !layerName.isEmpty() )
1075 {
1076 QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( providerKey, uri );
1077 parts.insert( QStringLiteral( "layerName" ), layerName );
1078 uri = QgsProviderRegistry::instance()->encodeUri( providerKey, parts );
1079 }
1080
1081 std::unique_ptr< QgsVectorLayer > layer = std::make_unique<QgsVectorLayer>( uri, destination, providerKey, layerOptions );
1082 // update destination to layer ID
1083 destination = layer->id();
1084 if ( layer->isValid() )
1085 {
1086 remappingDefinition->setDestinationWkbType( layer->wkbType() );
1087 remappingDefinition->setDestinationCrs( layer->crs() );
1088 remappingDefinition->setDestinationFields( layer->fields() );
1089 }
1090
1091 if ( QgsProcessingFeedback *feedback = context.feedback() )
1092 {
1093 const Qgis::VectorDataProviderAttributeEditCapabilities capabilities = layer->dataProvider() ? layer->dataProvider()->attributeEditCapabilities() : Qgis::VectorDataProviderAttributeEditCapabilities();
1094 for ( const QgsField &field : fields )
1095 {
1096 if ( !field.alias().isEmpty() && !( capabilities & Qgis::VectorDataProviderAttributeEditCapability::EditAlias ) )
1097 feedback->pushWarning( QObject::tr( "%1: Aliases are not supported by the %2 provider" ).arg( field.name(), providerKey ) );
1098 if ( !field.alias().isEmpty() && !( capabilities & Qgis::VectorDataProviderAttributeEditCapability::EditComment ) )
1099 feedback->pushWarning( QObject::tr( "%1: Comments are not supported by the %2 provider" ).arg( field.name(), providerKey ) );
1100 }
1101 }
1102
1103 std::unique_ptr< QgsRemappingProxyFeatureSink > remapSink = std::make_unique< QgsRemappingProxyFeatureSink >( *remappingDefinition, layer->dataProvider(), false );
1104 context.temporaryLayerStore()->addMapLayer( layer.release() );
1105 remapSink->setExpressionContext( context.expressionContext() );
1106 remapSink->setTransformContext( context.transformContext() );
1107 context.expressionContext().setFields( fields );
1108 return new QgsProcessingFeatureSink( remapSink.release(), destination, context, true );
1109 }
1110 else
1111 {
1112 //create empty layer
1113 std::unique_ptr< QgsVectorLayerExporter > exporter = std::make_unique<QgsVectorLayerExporter>( uri, providerKey, newFields, geometryType, crs, true, options, sinkFlags );
1114 if ( exporter->errorCode() != Qgis::VectorExportResult::Success )
1115 {
1116 throw QgsProcessingException( QObject::tr( "Could not create layer %1: %2" ).arg( destination, exporter->errorMessage() ) );
1117 }
1118
1119 // use destination string as layer name (eg "postgis:..." )
1120 if ( !layerName.isEmpty() )
1121 {
1122 uri += QStringLiteral( "|layername=%1" ).arg( layerName );
1123 // update destination to generated URI
1124 destination = uri;
1125 }
1126
1127 if ( QgsProcessingFeedback *feedback = context.feedback() )
1128 {
1129 for ( const QgsField &field : fields )
1130 {
1131 if ( !field.alias().isEmpty() && !( exporter->attributeEditCapabilities() & Qgis::VectorDataProviderAttributeEditCapability::EditAlias ) )
1132 feedback->pushWarning( QObject::tr( "%1: Aliases are not supported by the %2 provider" ).arg( field.name(), providerKey ) );
1133 if ( !field.alias().isEmpty() && !( exporter->attributeEditCapabilities() & Qgis::VectorDataProviderAttributeEditCapability::EditComment ) )
1134 feedback->pushWarning( QObject::tr( "%1: Comments are not supported by the %2 provider" ).arg( field.name(), providerKey ) );
1135 }
1136 }
1137
1138 return new QgsProcessingFeatureSink( exporter.release(), destination, context, true );
1139 }
1140 }
1141 }
1142}
1143
1144void QgsProcessingUtils::createFeatureSinkPython( QgsFeatureSink **sink, QString &destination, QgsProcessingContext &context, const QgsFields &fields, Qgis::WkbType geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &options )
1145{
1146 *sink = createFeatureSink( destination, context, fields, geometryType, crs, options );
1147}
1148
1149
1151{
1152 QgsRectangle extent;
1153 for ( const QgsMapLayer *layer : layers )
1154 {
1155 if ( !layer )
1156 continue;
1157
1158 if ( crs.isValid() )
1159 {
1160 //transform layer extent to target CRS
1161 QgsCoordinateTransform ct( layer->crs(), crs, context.transformContext() );
1163 try
1164 {
1165 QgsRectangle reprojExtent = ct.transformBoundingBox( layer->extent() );
1166 extent.combineExtentWith( reprojExtent );
1167 }
1168 catch ( QgsCsException & )
1169 {
1170 // can't reproject... what to do here? hmmm?
1171 // let's ignore this layer for now, but maybe we should just use the original extent?
1172 }
1173 }
1174 else
1175 {
1176 extent.combineExtentWith( layer->extent() );
1177 }
1178
1179 }
1180 return extent;
1181}
1182
1183// Deprecated
1185{
1186 QgsProcessingContext context;
1187 return QgsProcessingUtils::combineLayerExtents( layers, crs, context );
1188}
1189
1190QVariant QgsProcessingUtils::generateIteratingDestination( const QVariant &input, const QVariant &id, QgsProcessingContext &context )
1191{
1192 if ( !input.isValid() )
1193 return QStringLiteral( "memory:%1" ).arg( id.toString() );
1194
1195 if ( input.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
1196 {
1197 QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( input );
1198 QVariant newSink = generateIteratingDestination( fromVar.sink, id, context );
1199 fromVar.sink = QgsProperty::fromValue( newSink );
1200 return fromVar;
1201 }
1202 else if ( input.userType() == QMetaType::type( "QgsProperty" ) )
1203 {
1204 QString res = input.value< QgsProperty>().valueAsString( context.expressionContext() );
1205 return generateIteratingDestination( res, id, context );
1206 }
1207 else
1208 {
1209 QString res = input.toString();
1211 {
1212 // temporary outputs map to temporary outputs!
1214 }
1215 else if ( res.startsWith( QLatin1String( "memory:" ) ) )
1216 {
1217 return QString( res + '_' + id.toString() );
1218 }
1219 else
1220 {
1221 // assume a filename type output for now
1222 // TODO - uris?
1223 int lastIndex = res.lastIndexOf( '.' );
1224 return lastIndex >= 0 ? QString( res.left( lastIndex ) + '_' + id.toString() + res.mid( lastIndex ) ) : QString( res + '_' + id.toString() );
1225 }
1226 }
1227}
1228
1230{
1231 // we maintain a list of temporary folders -- this allows us to append additional
1232 // folders when a setting change causes the base temp folder to change, while deferring
1233 // cleanup of ALL these temp folders until session end (we can't cleanup older folders immediately,
1234 // because we don't know whether they have data in them which is still wanted)
1235 static std::vector< std::unique_ptr< QTemporaryDir > > sTempFolders;
1236 static QString sFolder;
1237 static QMutex sMutex;
1238 QMutexLocker locker( &sMutex );
1239 QString basePath;
1240
1241 if ( context )
1242 basePath = context->temporaryFolder();
1243 if ( basePath.isEmpty() )
1245
1246 if ( basePath.isEmpty() )
1247 {
1248 // default setting -- automatically create a temp folder
1249 if ( sTempFolders.empty() )
1250 {
1251 const QString templatePath = QStringLiteral( "%1/processing_XXXXXX" ).arg( QDir::tempPath() );
1252 std::unique_ptr< QTemporaryDir > tempFolder = std::make_unique< QTemporaryDir >( templatePath );
1253 sFolder = tempFolder->path();
1254 sTempFolders.emplace_back( std::move( tempFolder ) );
1255 }
1256 }
1257 else if ( sFolder.isEmpty() || !sFolder.startsWith( basePath ) || sTempFolders.empty() )
1258 {
1259 if ( !QDir().exists( basePath ) )
1260 QDir().mkpath( basePath );
1261
1262 const QString templatePath = QStringLiteral( "%1/processing_XXXXXX" ).arg( basePath );
1263 std::unique_ptr< QTemporaryDir > tempFolder = std::make_unique< QTemporaryDir >( templatePath );
1264 sFolder = tempFolder->path();
1265 sTempFolders.emplace_back( std::move( tempFolder ) );
1266 }
1267 return sFolder;
1268}
1269
1270QString QgsProcessingUtils::generateTempFilename( const QString &basename, const QgsProcessingContext *context )
1271{
1272 QString subPath = QUuid::createUuid().toString().remove( '-' ).remove( '{' ).remove( '}' );
1273 QString path = tempFolder( context ) + '/' + subPath;
1274 if ( !QDir( path ).exists() ) //make sure the directory exists - it shouldn't, but lets be safe...
1275 {
1276 QDir tmpDir;
1277 tmpDir.mkdir( path );
1278 }
1279 return path + '/' + QgsFileUtils::stringToSafeFilename( basename );
1280}
1281
1283{
1284 auto getText = [map]( const QString & key )->QString
1285 {
1286 if ( map.contains( key ) )
1287 return map.value( key ).toString();
1288 return QString();
1289 };
1290
1291 QString s;
1292 s += QStringLiteral( "<html><body><p>" ) + getText( QStringLiteral( "ALG_DESC" ) ) + QStringLiteral( "</p>\n" );
1293
1294 QString inputs;
1295 const auto parameterDefinitions = algorithm->parameterDefinitions();
1296 for ( const QgsProcessingParameterDefinition *def : parameterDefinitions )
1297 {
1298 if ( def->flags() & Qgis::ProcessingParameterFlag::Hidden || def->isDestination() )
1299 continue;
1300
1301 if ( !getText( def->name() ).isEmpty() )
1302 {
1303 inputs += QStringLiteral( "<h3>" ) + def->description() + QStringLiteral( "</h3>\n" );
1304 inputs += QStringLiteral( "<p>" ) + getText( def->name() ) + QStringLiteral( "</p>\n" );
1305 }
1306 }
1307 if ( !inputs.isEmpty() )
1308 s += QStringLiteral( "<h2>" ) + QObject::tr( "Input parameters" ) + QStringLiteral( "</h2>\n" ) + inputs;
1309
1310 QString outputs;
1311 const auto outputDefinitions = algorithm->outputDefinitions();
1312 for ( const QgsProcessingOutputDefinition *def : outputDefinitions )
1313 {
1314 if ( !getText( def->name() ).isEmpty() )
1315 {
1316 outputs += QStringLiteral( "<h3>" ) + def->description() + QStringLiteral( "</h3>\n" );
1317 outputs += QStringLiteral( "<p>" ) + getText( def->name() ) + QStringLiteral( "</p>\n" );
1318 }
1319 }
1320 if ( !outputs.isEmpty() )
1321 s += QStringLiteral( "<h2>" ) + QObject::tr( "Outputs" ) + QStringLiteral( "</h2>\n" ) + outputs;
1322
1323 if ( !map.value( QStringLiteral( "EXAMPLES" ) ).toString().isEmpty() )
1324 s += QStringLiteral( "<h2>%1</h2>\n<p>%2</p>" ).arg( QObject::tr( "Examples" ), getText( QStringLiteral( "EXAMPLES" ) ) );
1325
1326 s += QLatin1String( "<br>" );
1327 if ( !map.value( QStringLiteral( "ALG_CREATOR" ) ).toString().isEmpty() )
1328 s += QStringLiteral( "<p align=\"right\">" ) + QObject::tr( "Algorithm author:" ) + QStringLiteral( " " ) + getText( QStringLiteral( "ALG_CREATOR" ) ) + QStringLiteral( "</p>" );
1329 if ( !map.value( QStringLiteral( "ALG_HELP_CREATOR" ) ).toString().isEmpty() )
1330 s += QStringLiteral( "<p align=\"right\">" ) + QObject::tr( "Help author:" ) + QStringLiteral( " " ) + getText( QStringLiteral( "ALG_HELP_CREATOR" ) ) + QStringLiteral( "</p>" );
1331 if ( !map.value( QStringLiteral( "ALG_VERSION" ) ).toString().isEmpty() )
1332 s += QStringLiteral( "<p align=\"right\">" ) + QObject::tr( "Algorithm version:" ) + QStringLiteral( " " ) + getText( QStringLiteral( "ALG_VERSION" ) ) + QStringLiteral( "</p>" );
1333
1334 s += QLatin1String( "</body></html>" );
1335 return s;
1336}
1337
1338QString convertToCompatibleFormatInternal( const QgsVectorLayer *vl, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback, QString *layerName,
1339 long long featureLimit, const QString &filterExpression )
1340{
1341 bool requiresTranslation = false;
1342
1343 // if we are only looking for selected features then we have to export back to disk,
1344 // as we need to subset only selected features, a concept which doesn't exist outside QGIS!
1345 requiresTranslation = requiresTranslation || selectedFeaturesOnly;
1346
1347 // if we are limiting the feature count, we better export
1348 requiresTranslation = requiresTranslation || featureLimit != -1 || !filterExpression.isEmpty();
1349
1350 // if the data provider is NOT ogr, then we HAVE to convert. Otherwise we run into
1351 // issues with data providers like spatialite, delimited text where the format can be
1352 // opened outside of QGIS, but with potentially very different behavior!
1353 requiresTranslation = requiresTranslation || vl->providerType() != QLatin1String( "ogr" );
1354
1355 // if the layer has a feature filter set, then we HAVE to convert. Feature filters are
1356 // a purely QGIS concept.
1357 requiresTranslation = requiresTranslation || !vl->subsetString().isEmpty();
1358
1359 // if the layer opened using GDAL's virtual I/O mechanism (/vsizip/, etc.), then
1360 // we HAVE to convert as other tools may not work with it
1361 requiresTranslation = requiresTranslation || vl->source().startsWith( QLatin1String( "/vsi" ) );
1362
1363 // Check if layer is a disk based format and if so if the layer's path has a compatible filename suffix
1364 QString diskPath;
1365 if ( !requiresTranslation )
1366 {
1367 const QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( vl->providerType(), vl->source() );
1368 if ( parts.contains( QStringLiteral( "path" ) ) )
1369 {
1370 diskPath = parts.value( QStringLiteral( "path" ) ).toString();
1371 QFileInfo fi( diskPath );
1372 requiresTranslation = !compatibleFormats.contains( fi.suffix(), Qt::CaseInsensitive );
1373
1374 // if the layer name doesn't match the filename, we need to convert the layer. This method can only return
1375 // a filename, and cannot handle layernames as well as file paths
1376 const QString srcLayerName = parts.value( QStringLiteral( "layerName" ) ).toString();
1377 if ( layerName )
1378 {
1379 // differing layer names are acceptable
1380 *layerName = srcLayerName;
1381 }
1382 else
1383 {
1384 // differing layer names are NOT acceptable
1385 requiresTranslation = requiresTranslation || ( !srcLayerName.isEmpty() && srcLayerName != fi.baseName() );
1386 }
1387 }
1388 else
1389 {
1390 requiresTranslation = true; // not a disk-based format
1391 }
1392 }
1393
1394 if ( requiresTranslation )
1395 {
1396 QString temp = QgsProcessingUtils::generateTempFilename( baseName + '.' + preferredFormat, &context );
1397
1399 saveOptions.fileEncoding = context.defaultEncoding();
1400 saveOptions.driverName = QgsVectorFileWriter::driverForExtension( preferredFormat );
1401 std::unique_ptr< QgsVectorFileWriter > writer( QgsVectorFileWriter::create( temp, vl->fields(), vl->wkbType(), vl->crs(), context.transformContext(), saveOptions ) );
1402 QgsFeature f;
1404 QgsFeatureRequest request;
1405 if ( featureLimit != -1 )
1406 {
1407 request.setLimit( featureLimit );
1408 }
1409 if ( !filterExpression.isEmpty() )
1410 {
1411 request.setFilterExpression( filterExpression );
1412 }
1413
1414 if ( selectedFeaturesOnly )
1415 it = vl->getSelectedFeatures( request );
1416 else
1417 it = vl->getFeatures( request );
1418
1419 while ( it.nextFeature( f ) )
1420 {
1421 if ( feedback->isCanceled() )
1422 return QString();
1423 writer->addFeature( f, QgsFeatureSink::FastInsert );
1424 }
1425 return temp;
1426 }
1427 else
1428 {
1429 return diskPath;
1430 }
1431}
1432
1433QString QgsProcessingUtils::convertToCompatibleFormat( const QgsVectorLayer *vl, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback, long long featureLimit, const QString &filterExpression )
1434{
1435 return convertToCompatibleFormatInternal( vl, selectedFeaturesOnly, baseName, compatibleFormats, preferredFormat, context, feedback, nullptr, featureLimit, filterExpression );
1436}
1437
1438QString QgsProcessingUtils::convertToCompatibleFormatAndLayerName( const QgsVectorLayer *layer, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback, QString &layerName, long long featureLimit, const QString &filterExpression )
1439{
1440 layerName.clear();
1441 return convertToCompatibleFormatInternal( layer, selectedFeaturesOnly, baseName, compatibleFormats, preferredFormat, context, feedback, &layerName, featureLimit, filterExpression );
1442}
1443
1444QgsFields QgsProcessingUtils::combineFields( const QgsFields &fieldsA, const QgsFields &fieldsB, const QString &fieldsBPrefix )
1445{
1446 QgsFields outFields = fieldsA;
1447 QSet< QString > usedNames;
1448 for ( const QgsField &f : fieldsA )
1449 {
1450 usedNames.insert( f.name().toLower() );
1451 }
1452
1453 for ( const QgsField &f : fieldsB )
1454 {
1455 QgsField newField = f;
1456 newField.setName( fieldsBPrefix + f.name() );
1457 if ( usedNames.contains( newField.name().toLower() ) )
1458 {
1459 int idx = 2;
1460 QString newName = newField.name() + '_' + QString::number( idx );
1461 while ( usedNames.contains( newName.toLower() ) || fieldsB.indexOf( newName ) != -1 )
1462 {
1463 idx++;
1464 newName = newField.name() + '_' + QString::number( idx );
1465 }
1466 newField.setName( newName );
1467 outFields.append( newField );
1468 }
1469 else
1470 {
1471 outFields.append( newField );
1472 }
1473 usedNames.insert( newField.name() );
1474 }
1475
1476 return outFields;
1477}
1478
1479
1480QList<int> QgsProcessingUtils::fieldNamesToIndices( const QStringList &fieldNames, const QgsFields &fields )
1481{
1482 QList<int> indices;
1483 if ( !fieldNames.isEmpty() )
1484 {
1485 indices.reserve( fieldNames.count() );
1486 for ( const QString &f : fieldNames )
1487 {
1488 int idx = fields.lookupField( f );
1489 if ( idx >= 0 )
1490 indices.append( idx );
1491 }
1492 }
1493 else
1494 {
1495 indices.reserve( fields.count() );
1496 for ( int i = 0; i < fields.count(); ++i )
1497 indices.append( i );
1498 }
1499 return indices;
1500}
1501
1502
1503QgsFields QgsProcessingUtils::indicesToFields( const QList<int> &indices, const QgsFields &fields )
1504{
1505 QgsFields fieldsSubset;
1506 for ( int i : indices )
1507 fieldsSubset.append( fields.at( i ) );
1508 return fieldsSubset;
1509}
1510
1512{
1514 if ( setting == -1 )
1515 return QStringLiteral( "gpkg" );
1516 return QgsVectorFileWriter::supportedFormatExtensions().value( setting, QStringLiteral( "gpkg" ) );
1517}
1518
1520{
1522 if ( setting == -1 )
1523 return QStringLiteral( "tif" );
1524 return QgsRasterFileWriter::supportedFormatExtensions().value( setting, QStringLiteral( "tif" ) );
1525}
1526
1528{
1529 return QStringLiteral( "las" );
1530}
1531
1533{
1534 return QStringLiteral( "mbtiles" );
1535}
1536
1537QVariantMap QgsProcessingUtils::removePointerValuesFromMap( const QVariantMap &map )
1538{
1539 auto layerPointerToString = []( QgsMapLayer * layer ) -> QString
1540 {
1541 if ( layer && layer->providerType() == QLatin1String( "memory" ) )
1542 return layer->id();
1543 else if ( layer )
1544 return layer->source();
1545 else
1546 return QString();
1547 };
1548
1549 auto cleanPointerValues = [&layerPointerToString]( const QVariant & value ) -> QVariant
1550 {
1551 if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( value.value< QObject * >() ) )
1552 {
1553 // don't store pointers in maps for long-term storage
1554 return layerPointerToString( layer );
1555 }
1556 else if ( value.userType() == QMetaType::type( "QPointer< QgsMapLayer >" ) )
1557 {
1558 // don't store pointers in maps for long-term storage
1559 return layerPointerToString( value.value< QPointer< QgsMapLayer > >().data() );
1560 }
1561 else
1562 {
1563 return value;
1564 }
1565 };
1566
1567 QVariantMap res;
1568 for ( auto it = map.constBegin(); it != map.constEnd(); ++it )
1569 {
1570 if ( it->type() == QVariant::Map )
1571 {
1572 res.insert( it.key(), removePointerValuesFromMap( it.value().toMap() ) );
1573 }
1574 else if ( it->type() == QVariant::List )
1575 {
1576 QVariantList dest;
1577 const QVariantList source = it.value().toList();
1578 dest.reserve( source.size() );
1579 for ( const QVariant &v : source )
1580 {
1581 dest.append( cleanPointerValues( v ) );
1582 }
1583 res.insert( it.key(), dest );
1584 }
1585 else
1586 {
1587 res.insert( it.key(), cleanPointerValues( it.value() ) );
1588 }
1589 }
1590 return res;
1591}
1592
1593QVariantMap QgsProcessingUtils::preprocessQgisProcessParameters( const QVariantMap &parameters, bool &ok, QString &error )
1594{
1595 QVariantMap output;
1596 ok = true;
1597 for ( auto it = parameters.constBegin(); it != parameters.constEnd(); ++it )
1598 {
1599 if ( it.value().type() == QVariant::Map )
1600 {
1601 const QVariantMap value = it.value().toMap();
1602 if ( value.value( QStringLiteral( "type" ) ).toString() == QLatin1String( "data_defined" ) )
1603 {
1604 const QString expression = value.value( QStringLiteral( "expression" ) ).toString();
1605 const QString field = value.value( QStringLiteral( "field" ) ).toString();
1606 if ( !expression.isEmpty() )
1607 {
1608 output.insert( it.key(), QgsProperty::fromExpression( expression ) );
1609 }
1610 else if ( !field.isEmpty() )
1611 {
1612 output.insert( it.key(), QgsProperty::fromField( field ) );
1613 }
1614 else
1615 {
1616 ok = false;
1617 error = QObject::tr( "Invalid data defined parameter for %1, requires 'expression' or 'field' values." ).arg( it.key() );
1618 }
1619 }
1620 else
1621 {
1622 output.insert( it.key(), it.value() );
1623 }
1624 }
1625 else if ( it.value().type() == QVariant::String )
1626 {
1627 const QString stringValue = it.value().toString();
1628
1629 if ( stringValue.startsWith( QLatin1String( "field:" ) ) )
1630 {
1631 output.insert( it.key(), QgsProperty::fromField( stringValue.mid( 6 ) ) );
1632 }
1633 else if ( stringValue.startsWith( QLatin1String( "expression:" ) ) )
1634 {
1635 output.insert( it.key(), QgsProperty::fromExpression( stringValue.mid( 11 ) ) );
1636 }
1637 else
1638 {
1639 output.insert( it.key(), it.value() );
1640 }
1641 }
1642 else
1643 {
1644 output.insert( it.key(), it.value() );
1645 }
1646 }
1647 return output;
1648}
1649
1650QString QgsProcessingUtils::resolveDefaultEncoding( const QString &defaultEncoding )
1651{
1652 if ( ! QTextCodec::availableCodecs().contains( defaultEncoding.toLatin1() ) )
1653 {
1654 const QString systemCodec = QTextCodec::codecForLocale()->name();
1655 if ( ! systemCodec.isEmpty() )
1656 {
1657 return systemCodec;
1658 }
1659 return QString( "UTF-8" );
1660 }
1661
1662 return defaultEncoding;
1663}
1664
1665//
1666// QgsProcessingFeatureSource
1667//
1668
1669QgsProcessingFeatureSource::QgsProcessingFeatureSource( QgsFeatureSource *originalSource, const QgsProcessingContext &context, bool ownsOriginalSource, long long featureLimit, const QString &filterExpression )
1670 : mSource( originalSource )
1671 , mOwnsSource( ownsOriginalSource )
1672 , mSourceCrs( mSource->sourceCrs() )
1673 , mSourceFields( mSource->fields() )
1674 , mSourceWkbType( mSource->wkbType() )
1675 , mSourceName( mSource->sourceName() )
1676 , mSourceExtent( mSource->sourceExtent() )
1677 , mSourceSpatialIndexPresence( mSource->hasSpatialIndex() )
1678 , mInvalidGeometryCheck( QgsWkbTypes::geometryType( mSource->wkbType() ) == Qgis::GeometryType::Point
1679 ? Qgis::InvalidGeometryCheck::NoCheck // never run geometry validity checks for point layers!
1680 : context.invalidGeometryCheck() )
1681 , mInvalidGeometryCallback( context.invalidGeometryCallback( originalSource ) )
1682 , mTransformErrorCallback( context.transformErrorCallback() )
1683 , mInvalidGeometryCallbackSkip( context.defaultInvalidGeometryCallbackForCheck( Qgis::InvalidGeometryCheck::SkipInvalid, originalSource ) )
1684 , mInvalidGeometryCallbackAbort( context.defaultInvalidGeometryCallbackForCheck( Qgis::InvalidGeometryCheck::AbortOnInvalid, originalSource ) )
1685 , mFeatureLimit( featureLimit )
1686 , mFilterExpression( filterExpression )
1687{}
1688
1690{
1691 if ( mOwnsSource )
1692 delete mSource;
1693}
1694
1695QgsFeatureIterator QgsProcessingFeatureSource::getFeatures( const QgsFeatureRequest &request, Qgis::ProcessingFeatureSourceFlags flags ) const
1696{
1697 QgsFeatureRequest req( request );
1698 req.setTransformErrorCallback( mTransformErrorCallback );
1699
1702 else
1703 {
1704 req.setInvalidGeometryCheck( mInvalidGeometryCheck );
1705 req.setInvalidGeometryCallback( mInvalidGeometryCallback );
1706 }
1707
1708 if ( mFeatureLimit != -1 && req.limit() != -1 )
1709 req.setLimit( std::min( static_cast< long long >( req.limit() ), mFeatureLimit ) );
1710 else if ( mFeatureLimit != -1 )
1711 req.setLimit( mFeatureLimit );
1712
1713 if ( !mFilterExpression.isEmpty() )
1714 req.combineFilterExpression( mFilterExpression );
1715
1716 return mSource->getFeatures( req );
1717}
1718
1720{
1721 Qgis::FeatureAvailability sourceAvailability = mSource->hasFeatures();
1722 if ( sourceAvailability == Qgis::FeatureAvailability::NoFeaturesAvailable )
1723 return Qgis::FeatureAvailability::NoFeaturesAvailable; // never going to be features if underlying source has no features
1724 else if ( mInvalidGeometryCheck == Qgis::InvalidGeometryCheck::NoCheck && mFilterExpression.isEmpty() )
1725 return sourceAvailability;
1726 else
1727 // we don't know... source has features, but these may be filtered out by invalid geometry check or filter expression
1729}
1730
1732{
1733 QgsFeatureRequest req( request );
1734 req.setInvalidGeometryCheck( mInvalidGeometryCheck );
1735 req.setInvalidGeometryCallback( mInvalidGeometryCallback );
1736 req.setTransformErrorCallback( mTransformErrorCallback );
1737
1738 if ( mFeatureLimit != -1 && req.limit() != -1 )
1739 req.setLimit( std::min( static_cast< long long >( req.limit() ), mFeatureLimit ) );
1740 else if ( mFeatureLimit != -1 )
1741 req.setLimit( mFeatureLimit );
1742
1743 if ( !mFilterExpression.isEmpty() )
1744 req.combineFilterExpression( mFilterExpression );
1745
1746 return mSource->getFeatures( req );
1747}
1748
1753
1755{
1756 return mSourceFields;
1757}
1758
1760{
1761 return mSourceWkbType;
1762}
1763
1765{
1766 if ( !mFilterExpression.isEmpty() )
1767 return static_cast< int >( Qgis::FeatureCountState::UnknownCount );
1768
1769 if ( mFeatureLimit == -1 )
1770 return mSource->featureCount();
1771 else
1772 return std::min( mFeatureLimit, mSource->featureCount() );
1773}
1774
1776{
1777 return mSourceName;
1778}
1779
1780QSet<QVariant> QgsProcessingFeatureSource::uniqueValues( int fieldIndex, int limit ) const
1781{
1782 if ( mFilterExpression.isEmpty() )
1783 return mSource->uniqueValues( fieldIndex, limit );
1784
1785 // inefficient method when filter expression in use
1786 // TODO QGIS 4.0 -- add filter expression to virtual ::uniqueValues function
1787 if ( fieldIndex < 0 || fieldIndex >= fields().count() )
1788 return QSet<QVariant>();
1789
1792 req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
1793 req.setFilterExpression( mFilterExpression );
1794
1795 QSet<QVariant> values;
1796 QgsFeatureIterator it = getFeatures( req );
1797 QgsFeature f;
1798 while ( it.nextFeature( f ) )
1799 {
1800 values.insert( f.attribute( fieldIndex ) );
1801 if ( limit > 0 && values.size() >= limit )
1802 return values;
1803 }
1804 return values;
1805}
1806
1807QVariant QgsProcessingFeatureSource::minimumValue( int fieldIndex ) const
1808{
1809 if ( mFilterExpression.isEmpty() )
1810 return mSource->minimumValue( fieldIndex );
1811
1812 // inefficient method when filter expression in use
1813 // TODO QGIS 4.0 -- add filter expression to virtual ::minimumValue function
1814 if ( fieldIndex < 0 || fieldIndex >= fields().count() )
1815 return QVariant();
1816
1819 req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
1820
1821 QVariant min;
1822 QgsFeatureIterator it = getFeatures( req );
1823 QgsFeature f;
1824 while ( it.nextFeature( f ) )
1825 {
1826 const QVariant v = f.attribute( fieldIndex );
1827 if ( !QgsVariantUtils::isNull( v ) && ( qgsVariantLessThan( v, min ) || QgsVariantUtils::isNull( min ) ) )
1828 {
1829 min = v;
1830 }
1831 }
1832 return min;
1833}
1834
1835QVariant QgsProcessingFeatureSource::maximumValue( int fieldIndex ) const
1836{
1837 if ( mFilterExpression.isEmpty() )
1838 return mSource->maximumValue( fieldIndex );
1839
1840 // inefficient method when filter expression in use
1841 // TODO QGIS 4.0 -- add filter expression to virtual ::maximumValue function
1842 if ( fieldIndex < 0 || fieldIndex >= fields().count() )
1843 return QVariant();
1844
1847 req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
1848
1849 QVariant max;
1850 QgsFeatureIterator it = getFeatures( req );
1851 QgsFeature f;
1852 while ( it.nextFeature( f ) )
1853 {
1854 const QVariant v = f.attribute( fieldIndex );
1855 if ( !QgsVariantUtils::isNull( v ) && ( qgsVariantGreaterThan( v, max ) || QgsVariantUtils::isNull( max ) ) )
1856 {
1857 max = v;
1858 }
1859 }
1860 return max;
1861}
1862
1864{
1865 return mSourceExtent;
1866}
1867
1869{
1870 if ( mFilterExpression.isEmpty() )
1871 return mSource->allFeatureIds();
1872
1875 .setNoAttributes()
1876 .setFilterExpression( mFilterExpression ) );
1877
1878 QgsFeatureIds ids;
1879
1880 QgsFeature fet;
1881 while ( fit.nextFeature( fet ) )
1882 {
1883 ids << fet.id();
1884 }
1885
1886 return ids;
1887}
1888
1890{
1891 return mSourceSpatialIndexPresence;
1892}
1893
1895{
1896 QgsExpressionContextScope *expressionContextScope = nullptr;
1897 QgsExpressionContextScopeGenerator *generator = dynamic_cast<QgsExpressionContextScopeGenerator *>( mSource );
1898 if ( generator )
1899 {
1900 expressionContextScope = generator->createExpressionContextScope();
1901 }
1902 return expressionContextScope;
1903}
1904
1906{
1907 mInvalidGeometryCheck = method;
1908 switch ( mInvalidGeometryCheck )
1909 {
1911 mInvalidGeometryCallback = nullptr;
1912 break;
1913
1915 mInvalidGeometryCallback = mInvalidGeometryCallbackSkip;
1916 break;
1917
1919 mInvalidGeometryCallback = mInvalidGeometryCallbackAbort;
1920 break;
1921
1922 }
1923}
1924
1926{
1927 return mInvalidGeometryCheck;
1928}
1929
1930
1931//
1932// QgsProcessingFeatureSink
1933//
1934QgsProcessingFeatureSink::QgsProcessingFeatureSink( QgsFeatureSink *originalSink, const QString &sinkName, QgsProcessingContext &context, bool ownsOriginalSink )
1935 : QgsProxyFeatureSink( originalSink )
1936 , mContext( context )
1937 , mSinkName( sinkName )
1938 , mOwnsSink( ownsOriginalSink )
1939{}
1940
1942{
1943 if ( mOwnsSink )
1944 delete destinationSink();
1945}
1946
1947bool QgsProcessingFeatureSink::addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags )
1948{
1949 bool result = QgsProxyFeatureSink::addFeature( feature, flags );
1950 if ( !result && mContext.feedback() )
1951 {
1952 const QString error = lastError();
1953 if ( !error.isEmpty() )
1954 mContext.feedback()->reportError( QObject::tr( "Feature could not be written to %1: %2" ).arg( mSinkName, error ) );
1955 else
1956 mContext.feedback()->reportError( QObject::tr( "Feature could not be written to %1" ).arg( mSinkName ) );
1957 }
1958 return result;
1959}
1960
1961bool QgsProcessingFeatureSink::addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags )
1962{
1963 bool result = QgsProxyFeatureSink::addFeatures( features, flags );
1964 if ( !result && mContext.feedback() )
1965 {
1966 const QString error = lastError();
1967 if ( !error.isEmpty() )
1968 mContext.feedback()->reportError( QObject::tr( "%n feature(s) could not be written to %1: %2", nullptr, features.count() ).arg( mSinkName, error ) );
1969 else
1970 mContext.feedback()->reportError( QObject::tr( "%n feature(s) could not be written to %1", nullptr, features.count() ).arg( mSinkName ) );
1971 }
1972 return result;
1973}
1974
1975bool QgsProcessingFeatureSink::addFeatures( QgsFeatureIterator &iterator, QgsFeatureSink::Flags flags )
1976{
1977 bool result = QgsProxyFeatureSink::addFeatures( iterator, flags );
1978 if ( !result && mContext.feedback() )
1979 {
1980 const QString error = lastError();
1981 if ( !error.isEmpty() )
1982 mContext.feedback()->reportError( QObject::tr( "Features could not be written to %1: %2" ).arg( mSinkName, error ) );
1983 else
1984 mContext.feedback()->reportError( QObject::tr( "Features could not be written to %1" ).arg( mSinkName ) );
1985 }
1986 return result;
1987}
The Qgis class provides global constants for use throughout the application.
Definition qgis.h:54
@ Vector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
@ VectorAnyGeometry
Any vector layer with geometry.
@ VectorPoint
Vector point layers.
@ VectorPolygon
Vector polygon layers.
@ VectorLine
Vector line layers.
@ FieldComments
Writer can support field comments.
@ FieldAliases
Writer can support field aliases.
SpatialIndexPresence
Enumeration of spatial index presence states.
Definition qgis.h:349
@ Success
No errors were encountered.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
@ Static
Static property.
@ Polygon
Polygons.
FeatureAvailability
Possible return value for QgsFeatureSource::hasFeatures() to determine if a source is empty.
Definition qgis.h:368
@ FeaturesMaybeAvailable
There may be features available in this source.
@ NoFeaturesAvailable
There are certainly no features available in this source.
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ Vector
Vector layer.
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
@ Mesh
Mesh layer. Added in QGIS 3.2.
@ Raster
Raster layer.
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
InvalidGeometryCheck
Methods for handling of features with invalid geometries.
Definition qgis.h:1759
@ NoCheck
No invalid geometry checking.
@ AbortOnInvalid
Close iterator on encountering any features with invalid geometry. This requires a slow geometry vali...
@ SkipInvalid
Skip any features with invalid geometry. This requires a slow geometry validity check for every featu...
@ OverrideDefaultGeometryCheck
If set, the default geometry check method (as dictated by QgsProcessingContext) will be overridden fo...
@ SkipGeometryValidityChecks
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:182
@ Hidden
Parameter is hidden and should not be shown to users.
@ NoSymbology
Export only data.
Represents a map layer containing a set of georeferenced annotations, e.g.
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
bool createFromString(const QString &definition)
Set up this CRS from a string definition.
Contains information about the context in which a coordinate transform is executed.
Class for doing transforms between two map coordinate systems.
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool handle180Crossover=false) const
Transforms a rectangle from the source CRS to the destination CRS.
Custom exception class for Coordinate Reference System related exceptions.
Class for storing the component parts of a RDBMS data source URI (e.g.
QByteArray encodedUri() const
Returns the complete encoded URI as a byte array.
QString table() const
Returns the table name stored in the URI.
void setParam(const QString &key, const QString &value)
Sets a generic parameter value on the URI.
QString database() const
Returns the database name stored in the URI.
Abstract interface for generating an expression context scope.
virtual QgsExpressionContextScope * createExpressionContextScope() const =0
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Single scope for storing variables and functions for use within a QgsExpressionContext.
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
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.
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setLimit(long long limit)
Set the maximum number of features to request.
long long limit() const
Returns the maximum number of features to request, or -1 if no limit set.
QgsFeatureRequest & combineFilterExpression(const QString &expression)
Modifies the existing filter expression to add an additional expression filter.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setInvalidGeometryCheck(Qgis::InvalidGeometryCheck check)
Sets invalid geometry checking behavior.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
QgsFeatureRequest & setInvalidGeometryCallback(const std::function< void(const QgsFeature &)> &callback)
Sets a callback function to use when encountering an invalid geometry and invalidGeometryCheck() is s...
QgsFeatureRequest & setTransformErrorCallback(const std::function< void(const QgsFeature &)> &callback)
Sets a callback function to use when encountering a transform error when iterating features and a des...
An interface for objects which accept features via addFeature(s) methods.
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
@ RegeneratePrimaryKey
This flag indicates, that a primary key field cannot be guaranteed to be unique and the sink should i...
An interface for objects which provide features via a getFeatures method.
virtual QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const
Returns the set of unique values contained within the specified fieldIndex from this source.
virtual Qgis::FeatureAvailability hasFeatures() const
Determines if there are any features available in the source.
virtual QVariant minimumValue(int fieldIndex) const
Returns the minimum value for an attribute column or an invalid variant in case of error.
virtual QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const =0
Returns an iterator for the features in the source.
virtual QVariant maximumValue(int fieldIndex) const
Returns the maximum value for an attribute column or an invalid variant in case of error.
virtual long long featureCount() const =0
Returns the number of features contained in the source, or -1 if the feature count is unknown.
virtual QgsFeatureIds allFeatureIds() const
Returns a list of all feature IDs for features present in the source.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:56
QgsFeatureId id
Definition qgsfeature.h:64
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:53
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:53
QString name
Definition qgsfield.h:62
void setName(const QString &name)
Set the field name.
Definition qgsfield.cpp:216
Container of fields for a vector layer.
Definition qgsfields.h:45
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
Definition qgsfields.cpp:59
int indexOf(const QString &fieldName) const
Gets the field index from the field name.
int count() const
Returns number of items.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
static QString stringToSafeFilename(const QString &string)
Converts a string to a safe filename, replacing characters which are not safe for filenames with an '...
A storage object for map layers, in which the layers are owned by the store and have their lifetime b...
QMap< QString, QgsMapLayer * > mapLayers() const
Returns a map of all layers by layer ID.
QgsMapLayer * addMapLayer(QgsMapLayer *layer, bool takeOwnership=true)
Add a layer to the store.
Base class for all map layer types.
Definition qgsmaplayer.h:75
QString source() const
Returns the source for the layer.
QString providerType() const
Returns the provider type (provider key) for this layer.
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:81
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
virtual void setTransformContext(const QgsCoordinateTransformContext &transformContext)=0
Sets the coordinate transform context to transformContext.
static QgsVectorLayer * createMemoryLayer(const QString &name, const QgsFields &fields, Qgis::WkbType geometryType=Qgis::WkbType::NoGeometry, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem(), bool loadDefaultStyle=true) SIP_FACTORY
Creates a new memory layer using the specified parameters.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
QgsMeshDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
Base class for plugin layers.
Represents a map layer supporting display of point clouds.
A class to represent a 2D point.
Definition qgspointxy.h:60
double y
Definition qgspointxy.h:64
double x
Definition qgspointxy.h:63
Abstract base class for processing algorithms.
QgsProcessingOutputDefinitions outputDefinitions() const
Returns an ordered list of output definitions utilized by the algorithm.
QgsProcessingParameterDefinitions parameterDefinitions() const
Returns an ordered list of parameter definitions utilized by the algorithm.
Contains information about the context in which a processing algorithm is executed.
QString defaultEncoding() const
Returns the default encoding to use for newly created files.
QgsProcessingFeedback * feedback()
Returns the associated feedback object.
QgsExpressionContext & expressionContext()
Returns the expression context.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
QgsProject * project() const
Returns the project in which the algorithm is being executed.
QgsMapLayerStore * temporaryLayerStore()
Returns a reference to the layer store used for storing temporary layers during algorithm execution.
QString temporaryFolder() const
Returns the (optional) temporary folder to use when running algorithms.
Custom exception class for processing related exceptions.
QgsProxyFeatureSink subclass which reports feature addition errors to a QgsProcessingContext.
QgsProcessingFeatureSink(QgsFeatureSink *originalSink, const QString &sinkName, QgsProcessingContext &context, bool ownsOriginalSink=false)
Constructor for QgsProcessingFeatureSink, accepting an original feature sink originalSink and process...
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a list of features to the sink.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a single feature to the sink.
Encapsulates settings relating to a feature source input to a processing algorithm.
bool selectedFeaturesOnly
true if only selected features in the source should be used by algorithms.
Qgis::InvalidGeometryCheck geometryCheck
Geometry check method to apply to this source.
Qgis::ProcessingFeatureSourceDefinitionFlags flags
Flags which dictate source behavior.
long long featureLimit
If set to a value > 0, places a limit on the maximum number of features which will be read from the s...
QString filterExpression
Optional expression filter to use for filtering features which will be read from the source.
QgsFeatureSource subclass which proxies methods to an underlying QgsFeatureSource,...
QgsRectangle sourceExtent() const override
Returns the extent of all geometries from the source.
QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const override
Returns the set of unique values contained within the specified fieldIndex from this source.
QgsExpressionContextScope * createExpressionContextScope() const
Returns an expression context scope suitable for this source.
QgsProcessingFeatureSource(QgsFeatureSource *originalSource, const QgsProcessingContext &context, bool ownsOriginalSource=false, long long featureLimit=-1, const QString &filterExpression=QString())
Constructor for QgsProcessingFeatureSource, accepting an original feature source originalSource and p...
void setInvalidGeometryCheck(Qgis::InvalidGeometryCheck method)
Overrides the default geometry check method for the source.
Qgis::InvalidGeometryCheck invalidGeometryCheck() const
Returns the geometry check method for the source.
QVariant maximumValue(int fieldIndex) const override
Returns the maximum value for an attribute column or an invalid variant in case of error.
QgsCoordinateReferenceSystem sourceCrs() const override
Returns the coordinate reference system for features in the source.
Qgis::WkbType wkbType() const override
Returns the geometry type for features returned by this source.
QVariant minimumValue(int fieldIndex) const override
Returns the minimum value for an attribute column or an invalid variant in case of error.
long long featureCount() const override
Returns the number of features contained in the source, or -1 if the feature count is unknown.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request, Qgis::ProcessingFeatureSourceFlags flags) const
Returns an iterator for the features in the source, respecting the supplied feature flags.
Qgis::FeatureAvailability hasFeatures() const override
Determines if there are any features available in the source.
QString sourceName() const override
Returns a friendly display name for the source.
QgsFeatureIds allFeatureIds() const override
Returns a list of all feature IDs for features present in the source.
Qgis::SpatialIndexPresence hasSpatialIndex() const override
Returns an enum value representing the presence of a valid spatial index on the source,...
QgsFields fields() const override
Returns the fields associated with features in the source.
Base class for providing feedback from a processing algorithm.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
Base class for the definition of processing outputs.
Encapsulates settings relating to a feature sink or output raster layer for a processing algorithm.
QgsProperty sink
Sink/layer definition.
Base class for the definition of processing parameters.
static QList< QgsTiledSceneLayer * > compatibleTiledSceneLayers(QgsProject *project, bool sort=true)
Returns a list of tiled scene layers from a project which are compatible with the processing framewor...
static QString stringToPythonLiteral(const QString &string)
Converts a string to a Python string literal.
static QString defaultVectorExtension()
Returns the default vector extension to use, in the absence of all other constraints (e....
static QVariant generateIteratingDestination(const QVariant &input, const QVariant &id, QgsProcessingContext &context)
Converts an input parameter value for use in source iterating mode, where one individual sink is crea...
static QgsFields indicesToFields(const QList< int > &indices, const QgsFields &fields)
Returns a subset of fields based on the indices of desired fields.
static QList< int > fieldNamesToIndices(const QStringList &fieldNames, const QgsFields &fields)
Returns a list of field indices parsed from the given list of field names.
static QVariantMap preprocessQgisProcessParameters(const QVariantMap &parameters, bool &ok, QString &error)
Pre-processes a set of parameter values for the qgis_process command.
static QList< QgsAnnotationLayer * > compatibleAnnotationLayers(QgsProject *project, bool sort=true)
Returns a list of annotation layers from a project which are compatible with the processing framework...
static QString generateTempFilename(const QString &basename, const QgsProcessingContext *context=nullptr)
Returns a temporary filename for a given file, putting it into a temporary folder (creating that fold...
static QString normalizeLayerSource(const QString &source)
Normalizes a layer source string for safe comparison across different operating system environments.
static QString formatHelpMapAsHtml(const QVariantMap &map, const QgsProcessingAlgorithm *algorithm)
Returns a HTML formatted version of the help text encoded in a variant map for a specified algorithm.
static QgsFields combineFields(const QgsFields &fieldsA, const QgsFields &fieldsB, const QString &fieldsBPrefix=QString())
Combines two field lists, avoiding duplicate field names (in a case-insensitive manner).
static QString encodeProviderKeyAndUri(const QString &providerKey, const QString &uri)
Encodes a provider key and layer uri to a single string, for use with decodeProviderKeyAndUri()
LayerHint
Layer type hints.
@ TiledScene
Tiled scene layer type, since QGIS 3.34.
@ Annotation
Annotation layer type, since QGIS 3.22.
@ Vector
Vector layer type.
@ VectorTile
Vector tile layer type, since QGIS 3.32.
@ Mesh
Mesh layer type, since QGIS 3.6.
@ Raster
Raster layer type.
@ UnknownType
Unknown layer type.
@ PointCloud
Point cloud layer type, since QGIS 3.22.
static QString layerToStringIdentifier(const QgsMapLayer *layer)
Returns a string representation of the source for a layer.
static QgsProcessingFeatureSource * variantToSource(const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue=QVariant())
Converts a variant value to a new feature source.
static QList< QgsRasterLayer * > compatibleRasterLayers(QgsProject *project, bool sort=true)
Returns a list of raster layers from a project which are compatible with the processing framework.
static QgsRectangle combineLayerExtents(const QList< QgsMapLayer * > &layers, const QgsCoordinateReferenceSystem &crs, QgsProcessingContext &context)
Combines the extent of several map layers.
static QString resolveDefaultEncoding(const QString &defaultEncoding="System")
Returns the default encoding.
static QList< QgsPluginLayer * > compatiblePluginLayers(QgsProject *project, bool sort=true)
Returns a list of plugin layers from a project which are compatible with the processing framework.
static QString variantToPythonLiteral(const QVariant &value)
Converts a variant to a Python literal.
static QgsCoordinateReferenceSystem variantToCrs(const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue=QVariant())
Converts a variant value to a coordinate reference system.
static QList< QgsVectorLayer * > compatibleVectorLayers(QgsProject *project, const QList< int > &sourceTypes=QList< int >(), bool sort=true)
Returns a list of vector layers from a project which are compatible with the processing framework.
static QVariantMap removePointerValuesFromMap(const QVariantMap &map)
Removes any raw pointer values from an input map, replacing them with appropriate string values where...
static bool decodeProviderKeyAndUri(const QString &string, QString &providerKey, QString &uri)
Decodes a provider key and layer uri from an encoded string, for use with encodeProviderKeyAndUri()
static void createFeatureSinkPython(QgsFeatureSink **sink, QString &destination, QgsProcessingContext &context, const QgsFields &fields, Qgis::WkbType geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &createOptions=QVariantMap())
Creates a feature sink ready for adding features.
static QList< QgsVectorTileLayer * > compatibleVectorTileLayers(QgsProject *project, bool sort=true)
Returns a list of vector tile layers from a project which are compatible with the processing framewor...
static QString convertToCompatibleFormatAndLayerName(const QgsVectorLayer *layer, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback, QString &layerName, long long featureLimit=-1, const QString &filterExpression=QString())
Converts a source vector layer to a file path and layer name of a vector layer of compatible format.
static QList< QgsMapLayer * > compatibleLayers(QgsProject *project, bool sort=true)
Returns a list of map layers from a project which are compatible with the processing framework.
static QString convertToCompatibleFormat(const QgsVectorLayer *layer, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback, long long featureLimit=-1, const QString &filterExpression=QString())
Converts a source vector layer to a file path of a vector layer of compatible format.
static QgsFeatureSink * createFeatureSink(QString &destination, QgsProcessingContext &context, const QgsFields &fields, Qgis::WkbType geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &createOptions=QVariantMap(), const QStringList &datasourceOptions=QStringList(), const QStringList &layerOptions=QStringList(), QgsFeatureSink::SinkFlags sinkFlags=QgsFeatureSink::SinkFlags(), QgsRemappingSinkDefinition *remappingDefinition=nullptr)
Creates a feature sink ready for adding features.
static QString defaultRasterExtension()
Returns the default raster extension to use, in the absence of all other constraints (e....
static QString defaultVectorTileExtension()
Returns the default vector tile extension to use, in the absence of all other constraints (e....
static QgsMapLayer * mapLayerFromString(const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers=true, QgsProcessingUtils::LayerHint typeHint=QgsProcessingUtils::LayerHint::UnknownType, QgsProcessing::LayerOptionsFlags flags=QgsProcessing::LayerOptionsFlags())
Interprets a string as a map layer within the supplied context.
static QString defaultPointCloudExtension()
Returns the default point cloud extension to use, in the absence of all other constraints (e....
static QList< QgsPointCloudLayer * > compatiblePointCloudLayers(QgsProject *project, bool sort=true)
Returns a list of point cloud layers from a project which are compatible with the processing framewor...
static QList< QgsMeshLayer * > compatibleMeshLayers(QgsProject *project, bool sort=true)
Returns a list of mesh layers from a project which are compatible with the processing framework.
static QString tempFolder(const QgsProcessingContext *context=nullptr)
Returns a session specific processing temporary folder for use in processing algorithms.
static const QgsSettingsEntryInteger * settingsDefaultOutputRasterLayerExt
Settings entry default output raster layer ext.
static const QgsSettingsEntryInteger * settingsDefaultOutputVectorLayerExt
Settings entry default output vector layer ext.
static const QgsSettingsEntryString * settingsTempPath
Settings entry temp path.
static const QString TEMPORARY_OUTPUT
Constant used to indicate that a Processing algorithm output should be a temporary layer/file.
@ SkipIndexGeneration
Do not generate index when creating a layer. Makes sense only for point cloud layers.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:107
QgsAnnotationLayer * mainAnnotationLayer()
Returns the main annotation layer associated with the project.
QVector< T > layers() const
Returns a list of registered map layers with a specified layer type.
QgsCoordinateReferenceSystem crs
Definition qgsproject.h:112
A store for object properties.
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
Qgis::PropertyType propertyType() const
Returns the property type.
QVariant value(const QgsExpressionContext &context, const QVariant &defaultValue=QVariant(), bool *ok=nullptr) const
Calculates the current value of the property, including any transforms which are set for the property...
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
static QgsProperty fromField(const QString &fieldName, bool isActive=true)
Returns a new FieldBasedProperty created from the specified field name.
static QgsProperty fromValue(const QVariant &value, bool isActive=true)
Returns a new StaticProperty created from the specified value.
Holds data provider key, description, and associated shared library file or function pointer informat...
QString key() const
This returns the unique key associated with the provider.
virtual QList< Qgis::LayerType > supportedLayerTypes() const
Returns a list of the map layer types supported by the provider.
virtual QVariantMap decodeUri(const QString &uri) const
Breaks a provider data source URI into its component paths (e.g.
QVariantMap decodeUri(const QString &providerKey, const QString &uri)
Breaks a provider data source URI into its component paths (e.g.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QList< QgsProviderRegistry::ProviderCandidateDetails > preferredProvidersForUri(const QString &uri) const
Returns the details for the preferred provider(s) for opening the specified uri.
QString encodeUri(const QString &providerKey, const QVariantMap &parts)
Reassembles a provider data source URI from its component paths (e.g.
QgsProviderMetadata * providerMetadata(const QString &providerKey) const
Returns metadata of the provider or nullptr if not found.
A simple feature sink which proxies feature addition on to another feature sink.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a single feature to the sink.
QString lastError() const override
Returns the most recent error encountered by the sink, e.g.
QgsFeatureSink * destinationSink()
Returns the destination QgsFeatureSink which the proxy will forward features to.
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a list of features to the sink.
static QStringList supportedFormatExtensions(RasterFormatOptions options=SortRecommended)
Returns a list of file extensions for supported formats.
Represents a raster layer.
A rectangle specified with double values.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double xMaximum() const
Returns the x maximum value (right side of rectangle).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
QgsCoordinateReferenceSystem crs() const
Returns the associated coordinate reference system, or an invalid CRS if no reference system is set.
A QgsPointXY with associated coordinate reference system.
A QgsRectangle with associated coordinate reference system.
Defines the parameters used to remap features when creating a QgsRemappingProxyFeatureSink.
void setDestinationCrs(const QgsCoordinateReferenceSystem &destination)
Sets the destination crs used for reprojecting incoming features to the sink's destination CRS.
void setDestinationWkbType(Qgis::WkbType type)
Sets the WKB geometry type for the destination.
void setDestinationFields(const QgsFields &fields)
Sets the fields for the destination sink.
T value(const QString &dynamicKeyPart=QString()) const
Returns settings value.
Represents a map layer supporting display of tiled scene objects.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
Options to pass to writeAsVectorFormat()
QString layerName
Layer name. If let empty, it will be derived from the filename.
QStringList layerOptions
List of OGR layer creation options.
Qgis::FeatureSymbologyExport symbologyExport
Symbology to export.
QgsVectorFileWriter::ActionOnExistingFile actionOnExistingFile
Action on existing file.
QStringList datasourceOptions
List of OGR data source creation options.
static QStringList defaultLayerOptions(const QString &driverName)
Returns a list of the default layer options for a specified driver.
static QString driverForExtension(const QString &extension)
Returns the OGR driver name for a specified file extension.
static QgsVectorFileWriter * create(const QString &fileName, const QgsFields &fields, Qgis::WkbType geometryType, const QgsCoordinateReferenceSystem &srs, const QgsCoordinateTransformContext &transformContext, const QgsVectorFileWriter::SaveVectorOptions &options, QgsFeatureSink::SinkFlags sinkFlags=QgsFeatureSink::SinkFlags(), QString *newFilename=nullptr, QString *newLayer=nullptr)
Create a new vector file writer.
static QStringList defaultDatasetOptions(const QString &driverName)
Returns a list of the default dataset options for a specified driver.
static QStringList supportedFormatExtensions(VectorFormatOptions options=SortRecommended)
Returns a list of file extensions for supported formats, e.g "shp", "gpkg".
@ CreateOrOverwriteFile
Create or overwrite file.
@ AppendToLayerNoNewFields
Append features to existing layer, but do not create new fields.
QgsFeatureSource subclass for the selected features from a QgsVectorLayer.
Represents a vector layer which manages a vector based data sets.
bool isSpatial() const FINAL
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Q_INVOKABLE Qgis::WkbType wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
QgsFeatureIterator getSelectedFeatures(QgsFeatureRequest request=QgsFeatureRequest()) const
Returns an iterator of the selected features.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
QgsRectangle extent() const FINAL
Returns the extent of the layer.
Implements a map layer that is dedicated to rendering of vector tiles.
Handles storage of information regarding WKB types and their properties.
Definition qgswkbtypes.h:42
@ UnknownCount
Provider returned an unknown feature count.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into allowing algorithms to be written in pure substantial changes are required in order to port existing x Processing algorithms for QGIS x The most significant changes are outlined not GeoAlgorithm For algorithms which operate on features one by consider subclassing the QgsProcessingFeatureBasedAlgorithm class This class allows much of the boilerplate code for looping over features from a vector layer to be bypassed and instead requires implementation of a processFeature method Ensure that your algorithm(or algorithm 's parent class) implements the new pure virtual createInstance(self) call
bool qgsVariantLessThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is less than the second.
Definition qgis.cpp:120
bool qgsVariantGreaterThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is greater than the second.
Definition qgis.cpp:188
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:5061
QList< QgsFeature > QgsFeatureList
Definition qgsfeature.h:917
QSet< QgsFeatureId > QgsFeatureIds
QList< int > QgsAttributeList
Definition qgsfield.h:27
QString convertToCompatibleFormatInternal(const QgsVectorLayer *vl, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback, QString *layerName, long long featureLimit, const QString &filterExpression)
const QgsCoordinateReferenceSystem & crs
Setting options for loading mesh layers.
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
Setting options for loading point cloud layers.
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
bool skipIndexGeneration
Set to true if point cloud index generation should be skipped.
Setting options for loading raster layers.
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
bool loadDefaultStyle
Sets to true if the default layer style should be loaded.
Setting options for loading tiled scene layers.
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
Setting options for loading vector layers.