QGIS API Documentation 3.28.14-Firenze (exported)
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 "qgssettings.h"
21#include "qgsexception.h"
24#include "qgsvectorfilewriter.h"
30#include "qgsfileutils.h"
31#include "qgsvectorlayer.h"
32#include "qgsproviderregistry.h"
33#include "qgsmeshlayer.h"
34#include "qgspluginlayer.h"
36#include "qgsrasterfilewriter.h"
37#include "qgsvectortilelayer.h"
38#include "qgspointcloudlayer.h"
39#include "qgsannotationlayer.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
105template<typename T> QList<T *> QgsProcessingUtils::compatibleMapLayers( QgsProject *project, bool sort )
106{
107 if ( !project )
108 return QList<T *>();
109
110 QList<T *> layers;
111 const auto projectLayers = project->layers<T *>();
112 for ( T *l : projectLayers )
113 {
114 if ( canUseLayer( l ) )
115 layers << l;
116 }
117
118 if ( sort )
119 {
120 std::sort( layers.begin(), layers.end(), []( const T * a, const T * b ) -> bool
121 {
122 return QString::localeAwareCompare( a->name(), b->name() ) < 0;
123 } );
124 }
125 return layers;
126}
127
128QList<QgsMapLayer *> QgsProcessingUtils::compatibleLayers( QgsProject *project, bool sort )
129{
130 if ( !project )
131 return QList<QgsMapLayer *>();
132
133 QList<QgsMapLayer *> layers;
134
135 const auto rasterLayers = compatibleMapLayers< QgsRasterLayer >( project, false );
136 for ( QgsRasterLayer *rl : rasterLayers )
137 layers << rl;
138
139 const auto vectorLayers = compatibleVectorLayers( project, QList< int >(), false );
140 for ( QgsVectorLayer *vl : vectorLayers )
141 layers << vl;
142
143 const auto meshLayers = compatibleMapLayers< QgsMeshLayer >( project, false );
144 for ( QgsMeshLayer *ml : meshLayers )
145 layers << ml;
146
147 const auto pointCloudLayers = compatibleMapLayers< QgsPointCloudLayer >( project, false );
148 for ( QgsPointCloudLayer *pcl : pointCloudLayers )
149 layers << pcl;
150
151 const auto annotationLayers = compatibleMapLayers< QgsAnnotationLayer >( project, false );
152 for ( QgsAnnotationLayer *al : annotationLayers )
153 layers << al;
154 layers << project->mainAnnotationLayer();
155
156 const auto pluginLayers = compatibleMapLayers< QgsPluginLayer >( project, false );
157 for ( QgsPluginLayer *pl : pluginLayers )
158 layers << pl;
159
160 if ( sort )
161 {
162 std::sort( layers.begin(), layers.end(), []( const QgsMapLayer * a, const QgsMapLayer * b ) -> bool
163 {
164 return QString::localeAwareCompare( a->name(), b->name() ) < 0;
165 } );
166 }
167 return layers;
168}
169
170QString QgsProcessingUtils::encodeProviderKeyAndUri( const QString &providerKey, const QString &uri )
171{
172 return QStringLiteral( "%1://%2" ).arg( providerKey, uri );
173}
174
175bool QgsProcessingUtils::decodeProviderKeyAndUri( const QString &string, QString &providerKey, QString &uri )
176{
177 QRegularExpression re( QStringLiteral( "^(\\w+?):\\/\\/(.+)$" ) );
178 const QRegularExpressionMatch match = re.match( string );
179 if ( !match.hasMatch() )
180 return false;
181
182 providerKey = match.captured( 1 );
183 uri = match.captured( 2 );
184
185 // double check that provider is valid
186 return QgsProviderRegistry::instance()->providerMetadata( providerKey );
187}
188
189QgsMapLayer *QgsProcessingUtils::mapLayerFromStore( const QString &string, QgsMapLayerStore *store, QgsProcessingUtils::LayerHint typeHint )
190{
191 if ( !store || string.isEmpty() )
192 return nullptr;
193
194 QList< QgsMapLayer * > layers = store->mapLayers().values();
195
196 layers.erase( std::remove_if( layers.begin(), layers.end(), []( QgsMapLayer * layer )
197 {
198 switch ( layer->type() )
199 {
200 case QgsMapLayerType::VectorLayer:
201 return !canUseLayer( qobject_cast< QgsVectorLayer * >( layer ) );
202 case QgsMapLayerType::RasterLayer:
203 return !canUseLayer( qobject_cast< QgsRasterLayer * >( layer ) );
204 case QgsMapLayerType::PluginLayer:
205 case QgsMapLayerType::GroupLayer:
206 return true;
207 case QgsMapLayerType::MeshLayer:
208 return !canUseLayer( qobject_cast< QgsMeshLayer * >( layer ) );
209 case QgsMapLayerType::VectorTileLayer:
210 return !canUseLayer( qobject_cast< QgsVectorTileLayer * >( layer ) );
211 case QgsMapLayerType::PointCloudLayer:
212 return !canUseLayer( qobject_cast< QgsPointCloudLayer * >( layer ) );
213 case QgsMapLayerType::AnnotationLayer:
214 return !canUseLayer( qobject_cast< QgsAnnotationLayer * >( layer ) );
215 }
216 return true;
217 } ), layers.end() );
218
219 auto isCompatibleType = [typeHint]( QgsMapLayer * l ) -> bool
220 {
221 switch ( typeHint )
222 {
223 case LayerHint::UnknownType:
224 return true;
225
226 case LayerHint::Vector:
227 return l->type() == QgsMapLayerType::VectorLayer;
228
229 case LayerHint::Raster:
230 return l->type() == QgsMapLayerType::RasterLayer;
231
232 case LayerHint::Mesh:
233 return l->type() == QgsMapLayerType::MeshLayer;
234
235 case LayerHint::PointCloud:
236 return l->type() == QgsMapLayerType::PointCloudLayer;
237
238 case LayerHint::Annotation:
239 return l->type() == QgsMapLayerType::AnnotationLayer;
240 }
241 return true;
242 };
243
244 for ( QgsMapLayer *l : std::as_const( layers ) )
245 {
246 if ( isCompatibleType( l ) && l->id() == string )
247 return l;
248 }
249 for ( QgsMapLayer *l : std::as_const( layers ) )
250 {
251 if ( isCompatibleType( l ) && l->name() == string )
252 return l;
253 }
254 for ( QgsMapLayer *l : std::as_const( layers ) )
255 {
256 if ( isCompatibleType( l ) && normalizeLayerSource( l->source() ) == normalizeLayerSource( string ) )
257 return l;
258 }
259 return nullptr;
260}
261
262QgsMapLayer *QgsProcessingUtils::loadMapLayerFromString( const QString &string, const QgsCoordinateTransformContext &transformContext, LayerHint typeHint )
263{
264 QString provider;
265 QString uri;
266 const bool useProvider = decodeProviderKeyAndUri( string, provider, uri );
267 if ( !useProvider )
268 uri = string;
269
270 QString name;
271 // for disk based sources, we use the filename to determine a layer name
272 if ( !useProvider || ( provider == QLatin1String( "ogr" ) || provider == QLatin1String( "gdal" ) || provider == QLatin1String( "mdal" ) || provider == QLatin1String( "pdal" ) || provider == QLatin1String( "ept" ) ) )
273 {
274 QStringList components = uri.split( '|' );
275 if ( components.isEmpty() )
276 return nullptr;
277
278 QFileInfo fi;
279 if ( QFileInfo::exists( uri ) )
280 fi = QFileInfo( uri );
281 else if ( QFileInfo::exists( components.at( 0 ) ) )
282 fi = QFileInfo( components.at( 0 ) );
283 else
284 return nullptr;
285 name = fi.baseName();
286 }
287 else
288 {
289 name = QgsDataSourceUri( uri ).table();
290 }
291
292 // brute force attempt to load a matching layer
293 if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::Vector )
294 {
295 QgsVectorLayer::LayerOptions options { transformContext };
296 options.loadDefaultStyle = false;
297 options.skipCrsValidation = true;
298
299 std::unique_ptr< QgsVectorLayer > layer;
300 if ( useProvider )
301 {
302 layer = std::make_unique<QgsVectorLayer>( uri, name, provider, options );
303 }
304 else
305 {
306 // fallback to ogr
307 layer = std::make_unique<QgsVectorLayer>( uri, name, QStringLiteral( "ogr" ), options );
308 }
309 if ( layer->isValid() )
310 {
311 return layer.release();
312 }
313 }
314 if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::Raster )
315 {
316 QgsRasterLayer::LayerOptions rasterOptions;
317 rasterOptions.loadDefaultStyle = false;
318 rasterOptions.skipCrsValidation = true;
319
320 std::unique_ptr< QgsRasterLayer > rasterLayer;
321 if ( useProvider )
322 {
323 rasterLayer = std::make_unique< QgsRasterLayer >( uri, name, provider, rasterOptions );
324 }
325 else
326 {
327 // fallback to gdal
328 rasterLayer = std::make_unique< QgsRasterLayer >( uri, name, QStringLiteral( "gdal" ), rasterOptions );
329 }
330
331 if ( rasterLayer->isValid() )
332 {
333 return rasterLayer.release();
334 }
335 }
336 if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::Mesh )
337 {
338 QgsMeshLayer::LayerOptions meshOptions;
339 meshOptions.skipCrsValidation = true;
340
341 std::unique_ptr< QgsMeshLayer > meshLayer;
342 if ( useProvider )
343 {
344 meshLayer = std::make_unique< QgsMeshLayer >( uri, name, provider, meshOptions );
345 }
346 else
347 {
348 meshLayer = std::make_unique< QgsMeshLayer >( uri, name, QStringLiteral( "mdal" ), meshOptions );
349 }
350 if ( meshLayer->isValid() )
351 {
352 return meshLayer.release();
353 }
354 }
355 if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::PointCloud )
356 {
357 QgsPointCloudLayer::LayerOptions pointCloudOptions;
358 pointCloudOptions.skipCrsValidation = true;
359
360 std::unique_ptr< QgsPointCloudLayer > pointCloudLayer;
361 if ( useProvider )
362 {
363 pointCloudLayer = std::make_unique< QgsPointCloudLayer >( uri, name, provider, pointCloudOptions );
364 }
365 else
366 {
367 pointCloudLayer = std::make_unique< QgsPointCloudLayer >( uri, name, QStringLiteral( "pdal" ), pointCloudOptions );
368 }
369 if ( pointCloudLayer->isValid() )
370 {
371 return pointCloudLayer.release();
372 }
373 }
374 return nullptr;
375}
376
377QgsMapLayer *QgsProcessingUtils::mapLayerFromString( const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers, LayerHint typeHint )
378{
379 if ( string.isEmpty() )
380 return nullptr;
381
382 // prefer project layers
383 if ( context.project() && typeHint == LayerHint::Annotation && string.compare( QLatin1String( "main" ), Qt::CaseInsensitive ) == 0 )
384 return context.project()->mainAnnotationLayer();
385
386 QgsMapLayer *layer = nullptr;
387 if ( auto *lProject = context.project() )
388 {
389 QgsMapLayer *layer = mapLayerFromStore( string, lProject->layerStore(), typeHint );
390 if ( layer )
391 return layer;
392 }
393
394 layer = mapLayerFromStore( string, context.temporaryLayerStore(), typeHint );
395 if ( layer )
396 return layer;
397
398 if ( !allowLoadingNewLayers )
399 return nullptr;
400
401 layer = loadMapLayerFromString( string, context.transformContext(), typeHint );
402 if ( layer )
403 {
404 context.temporaryLayerStore()->addMapLayer( layer );
405 return layer;
406 }
407 else
408 {
409 return nullptr;
410 }
411}
412
413QgsProcessingFeatureSource *QgsProcessingUtils::variantToSource( const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue )
414{
415 QVariant val = value;
416 bool selectedFeaturesOnly = false;
417 long long featureLimit = -1;
418 bool overrideGeometryCheck = false;
420 if ( val.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
421 {
422 // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
423 QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
424 selectedFeaturesOnly = fromVar.selectedFeaturesOnly;
425 featureLimit = fromVar.featureLimit;
426 val = fromVar.source;
428 geometryCheck = fromVar.geometryCheck;
429 }
430 else if ( val.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
431 {
432 // input is a QgsProcessingOutputLayerDefinition (e.g. an output from earlier in a model) - get extra properties from it
433 QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
434 val = fromVar.sink;
435 }
436
437 if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( val ) ) )
438 {
439 std::unique_ptr< QgsProcessingFeatureSource> source = std::make_unique< QgsProcessingFeatureSource >( layer, context, false, featureLimit );
440 if ( overrideGeometryCheck )
441 source->setInvalidGeometryCheck( geometryCheck );
442 return source.release();
443 }
444
445 QString layerRef;
446 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
447 {
448 layerRef = val.value< QgsProperty >().valueAsString( context.expressionContext(), fallbackValue.toString() );
449 }
450 else if ( !val.isValid() || val.toString().isEmpty() )
451 {
452 // fall back to default
453 if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( fallbackValue ) ) )
454 {
455 std::unique_ptr< QgsProcessingFeatureSource> source = std::make_unique< QgsProcessingFeatureSource >( layer, context, false, featureLimit );
456 if ( overrideGeometryCheck )
457 source->setInvalidGeometryCheck( geometryCheck );
458 return source.release();
459 }
460
461 layerRef = fallbackValue.toString();
462 }
463 else
464 {
465 layerRef = val.toString();
466 }
467
468 if ( layerRef.isEmpty() )
469 return nullptr;
470
471 QgsVectorLayer *vl = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( layerRef, context, true, LayerHint::Vector ) );
472 if ( !vl )
473 return nullptr;
474
475 std::unique_ptr< QgsProcessingFeatureSource> source;
476 if ( selectedFeaturesOnly )
477 {
478 source = std::make_unique< QgsProcessingFeatureSource>( new QgsVectorLayerSelectedFeatureSource( vl ), context, true, featureLimit );
479 }
480 else
481 {
482 source = std::make_unique< QgsProcessingFeatureSource >( vl, context, false, featureLimit );
483 }
484
485 if ( overrideGeometryCheck )
486 source->setInvalidGeometryCheck( geometryCheck );
487 return source.release();
488}
489
490QgsCoordinateReferenceSystem QgsProcessingUtils::variantToCrs( const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue )
491{
492 QVariant val = value;
493
494 if ( val.userType() == QMetaType::type( "QgsCoordinateReferenceSystem" ) )
495 {
496 // input is a QgsCoordinateReferenceSystem - done!
497 return val.value< QgsCoordinateReferenceSystem >();
498 }
499 else if ( val.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
500 {
501 // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
502 QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
503 val = fromVar.source;
504 }
505 else if ( val.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
506 {
507 // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
508 QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
509 val = fromVar.sink;
510 }
511
512 if ( val.userType() == QMetaType::type( "QgsProperty" ) && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
513 {
514 val = val.value< QgsProperty >().staticValue();
515 }
516
517 // maybe a map layer
518 if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
519 return layer->crs();
520
521 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
522 val = val.value< QgsProperty >().valueAsString( context.expressionContext(), fallbackValue.toString() );
523
524 if ( !val.isValid() )
525 {
526 // fall back to default
527 val = fallbackValue;
528 }
529
530 QString crsText = val.toString();
531 if ( crsText.isEmpty() )
532 crsText = fallbackValue.toString();
533
534 if ( crsText.isEmpty() )
536
537 // maybe special string
538 if ( context.project() && crsText.compare( QLatin1String( "ProjectCrs" ), Qt::CaseInsensitive ) == 0 )
539 return context.project()->crs();
540
541 // maybe a map layer reference
542 if ( QgsMapLayer *layer = QgsProcessingUtils::mapLayerFromString( crsText, context ) )
543 return layer->crs();
544
545 // else CRS from string
547 crs.createFromString( crsText );
548 return crs;
549}
550
551bool QgsProcessingUtils::canUseLayer( const QgsMeshLayer *layer )
552{
553 return layer && layer->dataProvider();
554}
555
556bool QgsProcessingUtils::canUseLayer( const QgsPluginLayer *layer )
557{
558 return layer && layer->isValid();
559}
560
561bool QgsProcessingUtils::canUseLayer( const QgsVectorTileLayer *layer )
562{
563 return layer && layer->isValid();
564}
565
566bool QgsProcessingUtils::canUseLayer( const QgsRasterLayer *layer )
567{
568 return layer && layer->isValid();
569}
570
571bool QgsProcessingUtils::canUseLayer( const QgsPointCloudLayer *layer )
572{
573 return layer && layer->isValid();
574}
575
576bool QgsProcessingUtils::canUseLayer( const QgsAnnotationLayer *layer )
577{
578 return layer && layer->isValid();
579}
580
581bool QgsProcessingUtils::canUseLayer( const QgsVectorLayer *layer, const QList<int> &sourceTypes )
582{
583 return layer && layer->isValid() &&
584 ( sourceTypes.isEmpty()
585 || ( sourceTypes.contains( QgsProcessing::TypeVectorPoint ) && layer->geometryType() == QgsWkbTypes::PointGeometry )
586 || ( sourceTypes.contains( QgsProcessing::TypeVectorLine ) && layer->geometryType() == QgsWkbTypes::LineGeometry )
587 || ( sourceTypes.contains( QgsProcessing::TypeVectorPolygon ) && layer->geometryType() == QgsWkbTypes::PolygonGeometry )
588 || ( sourceTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) && layer->isSpatial() )
589 || sourceTypes.contains( QgsProcessing::TypeVector )
590 );
591}
592
593QString QgsProcessingUtils::normalizeLayerSource( const QString &source )
594{
595 QString normalized = source;
596 normalized.replace( '\\', '/' );
597 return normalized.trimmed();
598}
599
600QString QgsProcessingUtils::variantToPythonLiteral( const QVariant &value )
601{
602 if ( !value.isValid() )
603 return QStringLiteral( "None" );
604
605 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
606 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
607 else if ( value.userType() == QMetaType::type( "QgsCoordinateReferenceSystem" ) )
608 {
609 if ( !value.value< QgsCoordinateReferenceSystem >().isValid() )
610 return QStringLiteral( "QgsCoordinateReferenceSystem()" );
611 else
612 return QStringLiteral( "QgsCoordinateReferenceSystem('%1')" ).arg( value.value< QgsCoordinateReferenceSystem >().authid() );
613 }
614 else if ( value.userType() == QMetaType::type( "QgsRectangle" ) )
615 {
616 QgsRectangle r = value.value<QgsRectangle>();
617 return QStringLiteral( "'%1, %3, %2, %4'" ).arg( qgsDoubleToString( r.xMinimum() ),
621 }
622 else if ( value.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
623 {
625 return QStringLiteral( "'%1, %3, %2, %4 [%5]'" ).arg( qgsDoubleToString( r.xMinimum() ),
628 qgsDoubleToString( r.yMaximum() ), r.crs().authid() );
629 }
630 else if ( value.userType() == QMetaType::type( "QgsPointXY" ) )
631 {
632 QgsPointXY r = value.value<QgsPointXY>();
633 return QStringLiteral( "'%1,%2'" ).arg( qgsDoubleToString( r.x() ),
634 qgsDoubleToString( r.y() ) );
635 }
636 else if ( value.userType() == QMetaType::type( "QgsReferencedPointXY" ) )
637 {
639 return QStringLiteral( "'%1,%2 [%3]'" ).arg( qgsDoubleToString( r.x() ),
640 qgsDoubleToString( r.y() ),
641 r.crs().authid() );
642 }
643
644 switch ( value.type() )
645 {
646 case QVariant::Bool:
647 return value.toBool() ? QStringLiteral( "True" ) : QStringLiteral( "False" );
648
649 case QVariant::Double:
650 return QString::number( value.toDouble() );
651
652 case QVariant::Int:
653 case QVariant::UInt:
654 return QString::number( value.toInt() );
655
656 case QVariant::LongLong:
657 case QVariant::ULongLong:
658 return QString::number( value.toLongLong() );
659
660 case QVariant::List:
661 {
662 QStringList parts;
663 const QVariantList vl = value.toList();
664 for ( const QVariant &v : vl )
665 {
666 parts << variantToPythonLiteral( v );
667 }
668 return parts.join( ',' ).prepend( '[' ).append( ']' );
669 }
670
671 case QVariant::Map:
672 {
673 const QVariantMap map = value.toMap();
674 QStringList parts;
675 parts.reserve( map.size() );
676 for ( auto it = map.constBegin(); it != map.constEnd(); ++it )
677 {
678 parts << QStringLiteral( "%1: %2" ).arg( stringToPythonLiteral( it.key() ), variantToPythonLiteral( it.value() ) );
679 }
680 return parts.join( ',' ).prepend( '{' ).append( '}' );
681 }
682
683 case QVariant::DateTime:
684 {
685 const QDateTime dateTime = value.toDateTime();
686 return QStringLiteral( "QDateTime(QDate(%1, %2, %3), QTime(%4, %5, %6))" )
687 .arg( dateTime.date().year() )
688 .arg( dateTime.date().month() )
689 .arg( dateTime.date().day() )
690 .arg( dateTime.time().hour() )
691 .arg( dateTime.time().minute() )
692 .arg( dateTime.time().second() );
693 }
694
695 default:
696 break;
697 }
698
699 return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
700}
701
702QString QgsProcessingUtils::stringToPythonLiteral( const QString &string )
703{
704 QString s = string;
705 s.replace( '\\', QLatin1String( "\\\\" ) );
706 s.replace( '\n', QLatin1String( "\\n" ) );
707 s.replace( '\r', QLatin1String( "\\r" ) );
708 s.replace( '\t', QLatin1String( "\\t" ) );
709
710 if ( s.contains( '\'' ) && !s.contains( '\"' ) )
711 {
712 s = s.prepend( '"' ).append( '"' );
713 }
714 else
715 {
716 s.replace( '\'', QLatin1String( "\\\'" ) );
717 s = s.prepend( '\'' ).append( '\'' );
718 }
719 return s;
720}
721
722void QgsProcessingUtils::parseDestinationString( QString &destination, QString &providerKey, QString &uri, QString &layerName, QString &format, QMap<QString, QVariant> &options, bool &useWriter, QString &extension )
723{
724 extension.clear();
725 bool matched = decodeProviderKeyAndUri( destination, providerKey, uri );
726
727 if ( !matched )
728 {
729 QRegularExpression splitRx( QStringLiteral( "^(.{3,}?):(.*)$" ) );
730 QRegularExpressionMatch match = splitRx.match( destination );
731 if ( match.hasMatch() )
732 {
733 providerKey = match.captured( 1 );
734 uri = match.captured( 2 );
735 matched = true;
736 }
737 }
738
739 if ( matched )
740 {
741 if ( providerKey == QLatin1String( "postgis" ) ) // older processing used "postgis" instead of "postgres"
742 {
743 providerKey = QStringLiteral( "postgres" );
744 }
745 if ( providerKey == QLatin1String( "ogr" ) )
746 {
747 QgsDataSourceUri dsUri( uri );
748 if ( !dsUri.database().isEmpty() )
749 {
750 if ( !dsUri.table().isEmpty() )
751 {
752 layerName = dsUri.table();
753 options.insert( QStringLiteral( "layerName" ), layerName );
754 }
755 uri = dsUri.database();
756 extension = QFileInfo( uri ).completeSuffix();
757 format = QgsVectorFileWriter::driverForExtension( extension );
758 options.insert( QStringLiteral( "driverName" ), format );
759 }
760 else
761 {
762 extension = QFileInfo( uri ).completeSuffix();
763 options.insert( QStringLiteral( "driverName" ), QgsVectorFileWriter::driverForExtension( extension ) );
764 }
765 options.insert( QStringLiteral( "update" ), true );
766 }
767 useWriter = false;
768 }
769 else
770 {
771 useWriter = true;
772 providerKey = QStringLiteral( "ogr" );
773
774 QRegularExpression splitRx( QStringLiteral( "^(.*)\\.(.*?)$" ) );
775 QRegularExpressionMatch match = splitRx.match( destination );
776 if ( match.hasMatch() )
777 {
778 extension = match.captured( 2 );
779 format = QgsVectorFileWriter::driverForExtension( extension );
780 }
781
782 if ( format.isEmpty() )
783 {
784 format = QStringLiteral( "GPKG" );
785 destination = destination + QStringLiteral( ".gpkg" );
786 }
787
788 options.insert( QStringLiteral( "driverName" ), format );
789 uri = destination;
790 }
791}
792
793QgsFeatureSink *QgsProcessingUtils::createFeatureSink( QString &destination, QgsProcessingContext &context, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &createOptions, const QStringList &datasourceOptions, const QStringList &layerOptions, QgsFeatureSink::SinkFlags sinkFlags, QgsRemappingSinkDefinition *remappingDefinition )
794{
795 QVariantMap options = createOptions;
796 if ( !options.contains( QStringLiteral( "fileEncoding" ) ) )
797 {
798 // no destination encoding specified, use default
799 options.insert( QStringLiteral( "fileEncoding" ), context.defaultEncoding().isEmpty() ? QStringLiteral( "system" ) : context.defaultEncoding() );
800 }
801
802 if ( destination.isEmpty() || destination.startsWith( QLatin1String( "memory:" ) ) )
803 {
804 // strip "memory:" from start of destination
805 if ( destination.startsWith( QLatin1String( "memory:" ) ) )
806 destination = destination.mid( 7 );
807
808 if ( destination.isEmpty() )
809 destination = QStringLiteral( "output" );
810
811 // memory provider cannot be used with QgsVectorLayerImport - so create layer manually
812 std::unique_ptr< QgsVectorLayer > layer( QgsMemoryProviderUtils::createMemoryLayer( destination, fields, geometryType, crs ) );
813 if ( !layer || !layer->isValid() )
814 {
815 throw QgsProcessingException( QObject::tr( "Could not create memory layer" ) );
816 }
817
818 layer->setCustomProperty( QStringLiteral( "OnConvertFormatRegeneratePrimaryKey" ), static_cast< bool >( sinkFlags & QgsFeatureSink::RegeneratePrimaryKey ) );
819
820 // update destination to layer ID
821 destination = layer->id();
822
823 // this is a factory, so we need to return a proxy
824 std::unique_ptr< QgsProcessingFeatureSink > sink( new QgsProcessingFeatureSink( layer->dataProvider(), destination, context ) );
825 context.temporaryLayerStore()->addMapLayer( layer.release() );
826
827 return sink.release();
828 }
829 else
830 {
831 QString providerKey;
832 QString uri;
833 QString layerName;
834 QString format;
835 QString extension;
836 bool useWriter = false;
837 parseDestinationString( destination, providerKey, uri, layerName, format, options, useWriter, extension );
838
839 QgsFields newFields = fields;
840 if ( useWriter && providerKey == QLatin1String( "ogr" ) )
841 {
842 // use QgsVectorFileWriter for OGR destinations instead of QgsVectorLayerImport, as that allows
843 // us to use any OGR format which supports feature addition
844 QString finalFileName;
845 QString finalLayerName;
847 saveOptions.fileEncoding = options.value( QStringLiteral( "fileEncoding" ) ).toString();
848 saveOptions.layerName = !layerName.isEmpty() ? layerName : options.value( QStringLiteral( "layerName" ) ).toString();
849 saveOptions.driverName = format;
850 saveOptions.datasourceOptions = !datasourceOptions.isEmpty() ? datasourceOptions : QgsVectorFileWriter::defaultDatasetOptions( format );
851 saveOptions.layerOptions = !layerOptions.isEmpty() ? layerOptions : QgsVectorFileWriter::defaultLayerOptions( format );
853 if ( remappingDefinition )
854 {
856 // sniff destination file to get correct wkb type and crs
857 std::unique_ptr< QgsVectorLayer > vl = std::make_unique< QgsVectorLayer >( destination );
858 if ( vl->isValid() )
859 {
860 remappingDefinition->setDestinationWkbType( vl->wkbType() );
861 remappingDefinition->setDestinationCrs( vl->crs() );
862 newFields = vl->fields();
863 remappingDefinition->setDestinationFields( newFields );
864 }
865 context.expressionContext().setFields( fields );
866 }
867 else
868 {
870 }
871 std::unique_ptr< QgsVectorFileWriter > writer( QgsVectorFileWriter::create( destination, newFields, geometryType, crs, context.transformContext(), saveOptions, sinkFlags, &finalFileName, &finalLayerName ) );
872 if ( writer->hasError() )
873 {
874 throw QgsProcessingException( QObject::tr( "Could not create layer %1: %2" ).arg( destination, writer->errorMessage() ) );
875 }
876 destination = finalFileName;
877 if ( !saveOptions.layerName.isEmpty() && !finalLayerName.isEmpty() )
878 destination += QStringLiteral( "|layername=%1" ).arg( finalLayerName );
879
880 if ( remappingDefinition )
881 {
882 std::unique_ptr< QgsRemappingProxyFeatureSink > remapSink = std::make_unique< QgsRemappingProxyFeatureSink >( *remappingDefinition, writer.release(), true );
883 remapSink->setExpressionContext( context.expressionContext() );
884 remapSink->setTransformContext( context.transformContext() );
885 return new QgsProcessingFeatureSink( remapSink.release(), destination, context, true );
886 }
887 else
888 return new QgsProcessingFeatureSink( writer.release(), destination, context, true );
889 }
890 else
891 {
892 const QgsVectorLayer::LayerOptions layerOptions { context.transformContext() };
893 if ( remappingDefinition )
894 {
895 //write to existing layer
896
897 // use destination string as layer name (eg "postgis:..." )
898 if ( !layerName.isEmpty() )
899 {
900 QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( providerKey, uri );
901 parts.insert( QStringLiteral( "layerName" ), layerName );
902 uri = QgsProviderRegistry::instance()->encodeUri( providerKey, parts );
903 }
904
905 std::unique_ptr< QgsVectorLayer > layer = std::make_unique<QgsVectorLayer>( uri, destination, providerKey, layerOptions );
906 // update destination to layer ID
907 destination = layer->id();
908 if ( layer->isValid() )
909 {
910 remappingDefinition->setDestinationWkbType( layer->wkbType() );
911 remappingDefinition->setDestinationCrs( layer->crs() );
912 remappingDefinition->setDestinationFields( layer->fields() );
913 }
914
915 std::unique_ptr< QgsRemappingProxyFeatureSink > remapSink = std::make_unique< QgsRemappingProxyFeatureSink >( *remappingDefinition, layer->dataProvider(), false );
916 context.temporaryLayerStore()->addMapLayer( layer.release() );
917 remapSink->setExpressionContext( context.expressionContext() );
918 remapSink->setTransformContext( context.transformContext() );
919 context.expressionContext().setFields( fields );
920 return new QgsProcessingFeatureSink( remapSink.release(), destination, context, true );
921 }
922 else
923 {
924 //create empty layer
925 std::unique_ptr< QgsVectorLayerExporter > exporter = std::make_unique<QgsVectorLayerExporter>( uri, providerKey, newFields, geometryType, crs, true, options, sinkFlags );
926 if ( exporter->errorCode() != Qgis::VectorExportResult::Success )
927 {
928 throw QgsProcessingException( QObject::tr( "Could not create layer %1: %2" ).arg( destination, exporter->errorMessage() ) );
929 }
930
931 // use destination string as layer name (eg "postgis:..." )
932 if ( !layerName.isEmpty() )
933 {
934 uri += QStringLiteral( "|layername=%1" ).arg( layerName );
935 // update destination to generated URI
936 destination = uri;
937 }
938
939 return new QgsProcessingFeatureSink( exporter.release(), destination, context, true );
940 }
941 }
942 }
943}
944
945void QgsProcessingUtils::createFeatureSinkPython( QgsFeatureSink **sink, QString &destination, QgsProcessingContext &context, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &options )
946{
947 *sink = createFeatureSink( destination, context, fields, geometryType, crs, options );
948}
949
950
952{
953 QgsRectangle extent;
954 for ( const QgsMapLayer *layer : layers )
955 {
956 if ( !layer )
957 continue;
958
959 if ( crs.isValid() )
960 {
961 //transform layer extent to target CRS
962 QgsCoordinateTransform ct( layer->crs(), crs, context.transformContext() );
964 try
965 {
966 QgsRectangle reprojExtent = ct.transformBoundingBox( layer->extent() );
967 extent.combineExtentWith( reprojExtent );
968 }
969 catch ( QgsCsException & )
970 {
971 // can't reproject... what to do here? hmmm?
972 // let's ignore this layer for now, but maybe we should just use the original extent?
973 }
974 }
975 else
976 {
977 extent.combineExtentWith( layer->extent() );
978 }
979
980 }
981 return extent;
982}
983
984// Deprecated
986{
987 QgsProcessingContext context;
988 return QgsProcessingUtils::combineLayerExtents( layers, crs, context );
989}
990
991QVariant QgsProcessingUtils::generateIteratingDestination( const QVariant &input, const QVariant &id, QgsProcessingContext &context )
992{
993 if ( !input.isValid() )
994 return QStringLiteral( "memory:%1" ).arg( id.toString() );
995
996 if ( input.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
997 {
998 QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( input );
999 QVariant newSink = generateIteratingDestination( fromVar.sink, id, context );
1000 fromVar.sink = QgsProperty::fromValue( newSink );
1001 return fromVar;
1002 }
1003 else if ( input.userType() == QMetaType::type( "QgsProperty" ) )
1004 {
1005 QString res = input.value< QgsProperty>().valueAsString( context.expressionContext() );
1006 return generateIteratingDestination( res, id, context );
1007 }
1008 else
1009 {
1010 QString res = input.toString();
1012 {
1013 // temporary outputs map to temporary outputs!
1015 }
1016 else if ( res.startsWith( QLatin1String( "memory:" ) ) )
1017 {
1018 return QString( res + '_' + id.toString() );
1019 }
1020 else
1021 {
1022 // assume a filename type output for now
1023 // TODO - uris?
1024 int lastIndex = res.lastIndexOf( '.' );
1025 return lastIndex >= 0 ? QString( res.left( lastIndex ) + '_' + id.toString() + res.mid( lastIndex ) ) : QString( res + '_' + id.toString() );
1026 }
1027 }
1028}
1029
1031{
1032 // we maintain a list of temporary folders -- this allows us to append additional
1033 // folders when a setting change causes the base temp folder to change, while deferring
1034 // cleanup of ALL these temp folders until session end (we can't cleanup older folders immediately,
1035 // because we don't know whether they have data in them which is still wanted)
1036 static std::vector< std::unique_ptr< QTemporaryDir > > sTempFolders;
1037 static QString sFolder;
1038 static QMutex sMutex;
1039 QMutexLocker locker( &sMutex );
1040 const QString basePath = QgsProcessing::settingsTempPath.value();
1041 if ( basePath.isEmpty() )
1042 {
1043 // default setting -- automatically create a temp folder
1044 if ( sTempFolders.empty() )
1045 {
1046 const QString templatePath = QStringLiteral( "%1/processing_XXXXXX" ).arg( QDir::tempPath() );
1047 std::unique_ptr< QTemporaryDir > tempFolder = std::make_unique< QTemporaryDir >( templatePath );
1048 sFolder = tempFolder->path();
1049 sTempFolders.emplace_back( std::move( tempFolder ) );
1050 }
1051 }
1052 else if ( sFolder.isEmpty() || !sFolder.startsWith( basePath ) || sTempFolders.empty() )
1053 {
1054 if ( !QDir().exists( basePath ) )
1055 QDir().mkpath( basePath );
1056
1057 const QString templatePath = QStringLiteral( "%1/processing_XXXXXX" ).arg( basePath );
1058 std::unique_ptr< QTemporaryDir > tempFolder = std::make_unique< QTemporaryDir >( templatePath );
1059 sFolder = tempFolder->path();
1060 sTempFolders.emplace_back( std::move( tempFolder ) );
1061 }
1062 return sFolder;
1063}
1064
1065QString QgsProcessingUtils::generateTempFilename( const QString &basename )
1066{
1067 QString subPath = QUuid::createUuid().toString().remove( '-' ).remove( '{' ).remove( '}' );
1068 QString path = tempFolder() + '/' + subPath;
1069 if ( !QDir( path ).exists() ) //make sure the directory exists - it shouldn't, but lets be safe...
1070 {
1071 QDir tmpDir;
1072 tmpDir.mkdir( path );
1073 }
1074 return path + '/' + QgsFileUtils::stringToSafeFilename( basename );
1075}
1076
1078{
1079 auto getText = [map]( const QString & key )->QString
1080 {
1081 if ( map.contains( key ) )
1082 return map.value( key ).toString();
1083 return QString();
1084 };
1085
1086 QString s;
1087 s += QStringLiteral( "<html><body><p>" ) + getText( QStringLiteral( "ALG_DESC" ) ) + QStringLiteral( "</p>\n" );
1088
1089 QString inputs;
1090 const auto parameterDefinitions = algorithm->parameterDefinitions();
1091 for ( const QgsProcessingParameterDefinition *def : parameterDefinitions )
1092 {
1093 if ( def->flags() & QgsProcessingParameterDefinition::FlagHidden || def->isDestination() )
1094 continue;
1095
1096 if ( !getText( def->name() ).isEmpty() )
1097 {
1098 inputs += QStringLiteral( "<h3>" ) + def->description() + QStringLiteral( "</h3>\n" );
1099 inputs += QStringLiteral( "<p>" ) + getText( def->name() ) + QStringLiteral( "</p>\n" );
1100 }
1101 }
1102 if ( !inputs.isEmpty() )
1103 s += QStringLiteral( "<h2>" ) + QObject::tr( "Input parameters" ) + QStringLiteral( "</h2>\n" ) + inputs;
1104
1105 QString outputs;
1106 const auto outputDefinitions = algorithm->outputDefinitions();
1107 for ( const QgsProcessingOutputDefinition *def : outputDefinitions )
1108 {
1109 if ( !getText( def->name() ).isEmpty() )
1110 {
1111 outputs += QStringLiteral( "<h3>" ) + def->description() + QStringLiteral( "</h3>\n" );
1112 outputs += QStringLiteral( "<p>" ) + getText( def->name() ) + QStringLiteral( "</p>\n" );
1113 }
1114 }
1115 if ( !outputs.isEmpty() )
1116 s += QStringLiteral( "<h2>" ) + QObject::tr( "Outputs" ) + QStringLiteral( "</h2>\n" ) + outputs;
1117
1118 if ( !map.value( QStringLiteral( "EXAMPLES" ) ).toString().isEmpty() )
1119 s += QStringLiteral( "<h2>%1</h2>\n<p>%2</p>" ).arg( QObject::tr( "Examples" ), getText( QStringLiteral( "EXAMPLES" ) ) );
1120
1121 s += QLatin1String( "<br>" );
1122 if ( !map.value( QStringLiteral( "ALG_CREATOR" ) ).toString().isEmpty() )
1123 s += QStringLiteral( "<p align=\"right\">" ) + QObject::tr( "Algorithm author:" ) + QStringLiteral( " " ) + getText( QStringLiteral( "ALG_CREATOR" ) ) + QStringLiteral( "</p>" );
1124 if ( !map.value( QStringLiteral( "ALG_HELP_CREATOR" ) ).toString().isEmpty() )
1125 s += QStringLiteral( "<p align=\"right\">" ) + QObject::tr( "Help author:" ) + QStringLiteral( " " ) + getText( QStringLiteral( "ALG_HELP_CREATOR" ) ) + QStringLiteral( "</p>" );
1126 if ( !map.value( QStringLiteral( "ALG_VERSION" ) ).toString().isEmpty() )
1127 s += QStringLiteral( "<p align=\"right\">" ) + QObject::tr( "Algorithm version:" ) + QStringLiteral( " " ) + getText( QStringLiteral( "ALG_VERSION" ) ) + QStringLiteral( "</p>" );
1128
1129 s += QLatin1String( "</body></html>" );
1130 return s;
1131}
1132
1133QString convertToCompatibleFormatInternal( const QgsVectorLayer *vl, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback, QString *layerName,
1134 long long featureLimit )
1135{
1136 bool requiresTranslation = false;
1137
1138 // if we are only looking for selected features then we have to export back to disk,
1139 // as we need to subset only selected features, a concept which doesn't exist outside QGIS!
1140 requiresTranslation = requiresTranslation || selectedFeaturesOnly;
1141
1142 // if we are limiting the feature count, we better export
1143 requiresTranslation = requiresTranslation || featureLimit != -1;
1144
1145 // if the data provider is NOT ogr, then we HAVE to convert. Otherwise we run into
1146 // issues with data providers like spatialite, delimited text where the format can be
1147 // opened outside of QGIS, but with potentially very different behavior!
1148 requiresTranslation = requiresTranslation || vl->providerType() != QLatin1String( "ogr" );
1149
1150 // if the layer has a feature filter set, then we HAVE to convert. Feature filters are
1151 // a purely QGIS concept.
1152 requiresTranslation = requiresTranslation || !vl->subsetString().isEmpty();
1153
1154 // if the layer opened using GDAL's virtual I/O mechanism (/vsizip/, etc.), then
1155 // we HAVE to convert as other tools may not work with it
1156 requiresTranslation = requiresTranslation || vl->source().startsWith( QLatin1String( "/vsi" ) );
1157
1158 // Check if layer is a disk based format and if so if the layer's path has a compatible filename suffix
1159 QString diskPath;
1160 if ( !requiresTranslation )
1161 {
1162 const QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( vl->providerType(), vl->source() );
1163 if ( parts.contains( QStringLiteral( "path" ) ) )
1164 {
1165 diskPath = parts.value( QStringLiteral( "path" ) ).toString();
1166 QFileInfo fi( diskPath );
1167 requiresTranslation = !compatibleFormats.contains( fi.suffix(), Qt::CaseInsensitive );
1168
1169 // if the layer name doesn't match the filename, we need to convert the layer. This method can only return
1170 // a filename, and cannot handle layernames as well as file paths
1171 const QString srcLayerName = parts.value( QStringLiteral( "layerName" ) ).toString();
1172 if ( layerName )
1173 {
1174 // differing layer names are acceptable
1175 *layerName = srcLayerName;
1176 }
1177 else
1178 {
1179 // differing layer names are NOT acceptable
1180 requiresTranslation = requiresTranslation || ( !srcLayerName.isEmpty() && srcLayerName != fi.baseName() );
1181 }
1182 }
1183 else
1184 {
1185 requiresTranslation = true; // not a disk-based format
1186 }
1187 }
1188
1189 if ( requiresTranslation )
1190 {
1191 QString temp = QgsProcessingUtils::generateTempFilename( baseName + '.' + preferredFormat );
1192
1194 saveOptions.fileEncoding = context.defaultEncoding();
1195 saveOptions.driverName = QgsVectorFileWriter::driverForExtension( preferredFormat );
1196 std::unique_ptr< QgsVectorFileWriter > writer( QgsVectorFileWriter::create( temp, vl->fields(), vl->wkbType(), vl->crs(), context.transformContext(), saveOptions ) );
1197 QgsFeature f;
1199 if ( featureLimit != -1 )
1200 {
1201 if ( selectedFeaturesOnly )
1202 it = vl->getSelectedFeatures( QgsFeatureRequest().setLimit( featureLimit ) );
1203 else
1204 it = vl->getFeatures( QgsFeatureRequest().setLimit( featureLimit ) );
1205 }
1206 else
1207 {
1208 if ( selectedFeaturesOnly )
1209 it = vl->getSelectedFeatures( QgsFeatureRequest().setLimit( featureLimit ) );
1210 else
1211 it = vl->getFeatures();
1212 }
1213
1214 while ( it.nextFeature( f ) )
1215 {
1216 if ( feedback->isCanceled() )
1217 return QString();
1218 writer->addFeature( f, QgsFeatureSink::FastInsert );
1219 }
1220 return temp;
1221 }
1222 else
1223 {
1224 return diskPath;
1225 }
1226}
1227
1228QString QgsProcessingUtils::convertToCompatibleFormat( const QgsVectorLayer *vl, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback, long long featureLimit )
1229{
1230 return convertToCompatibleFormatInternal( vl, selectedFeaturesOnly, baseName, compatibleFormats, preferredFormat, context, feedback, nullptr, featureLimit );
1231}
1232
1233QString 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 )
1234{
1235 layerName.clear();
1236 return convertToCompatibleFormatInternal( layer, selectedFeaturesOnly, baseName, compatibleFormats, preferredFormat, context, feedback, &layerName, featureLimit );
1237}
1238
1239QgsFields QgsProcessingUtils::combineFields( const QgsFields &fieldsA, const QgsFields &fieldsB, const QString &fieldsBPrefix )
1240{
1241 QgsFields outFields = fieldsA;
1242 QSet< QString > usedNames;
1243 for ( const QgsField &f : fieldsA )
1244 {
1245 usedNames.insert( f.name().toLower() );
1246 }
1247
1248 for ( const QgsField &f : fieldsB )
1249 {
1250 QgsField newField = f;
1251 newField.setName( fieldsBPrefix + f.name() );
1252 if ( usedNames.contains( newField.name().toLower() ) )
1253 {
1254 int idx = 2;
1255 QString newName = newField.name() + '_' + QString::number( idx );
1256 while ( usedNames.contains( newName.toLower() ) || fieldsB.indexOf( newName ) != -1 )
1257 {
1258 idx++;
1259 newName = newField.name() + '_' + QString::number( idx );
1260 }
1261 newField.setName( newName );
1262 outFields.append( newField );
1263 }
1264 else
1265 {
1266 outFields.append( newField );
1267 }
1268 usedNames.insert( newField.name() );
1269 }
1270
1271 return outFields;
1272}
1273
1274
1275QList<int> QgsProcessingUtils::fieldNamesToIndices( const QStringList &fieldNames, const QgsFields &fields )
1276{
1277 QList<int> indices;
1278 if ( !fieldNames.isEmpty() )
1279 {
1280 indices.reserve( fieldNames.count() );
1281 for ( const QString &f : fieldNames )
1282 {
1283 int idx = fields.lookupField( f );
1284 if ( idx >= 0 )
1285 indices.append( idx );
1286 }
1287 }
1288 else
1289 {
1290 indices.reserve( fields.count() );
1291 for ( int i = 0; i < fields.count(); ++i )
1292 indices.append( i );
1293 }
1294 return indices;
1295}
1296
1297
1298QgsFields QgsProcessingUtils::indicesToFields( const QList<int> &indices, const QgsFields &fields )
1299{
1300 QgsFields fieldsSubset;
1301 for ( int i : indices )
1302 fieldsSubset.append( fields.at( i ) );
1303 return fieldsSubset;
1304}
1305
1307{
1309 if ( setting == -1 )
1310 return QStringLiteral( "gpkg" );
1311 return QgsVectorFileWriter::supportedFormatExtensions().value( setting, QStringLiteral( "gpkg" ) );
1312}
1313
1315{
1317 if ( setting == -1 )
1318 return QStringLiteral( "tif" );
1319 return QgsRasterFileWriter::supportedFormatExtensions().value( setting, QStringLiteral( "tif" ) );
1320}
1321
1323{
1324 return QStringLiteral( "las" );
1325}
1326
1327QVariantMap QgsProcessingUtils::removePointerValuesFromMap( const QVariantMap &map )
1328{
1329 auto layerPointerToString = []( QgsMapLayer * layer ) -> QString
1330 {
1331 if ( layer && layer->providerType() == QLatin1String( "memory" ) )
1332 return layer->id();
1333 else if ( layer )
1334 return layer->source();
1335 else
1336 return QString();
1337 };
1338
1339 auto cleanPointerValues = [&layerPointerToString]( const QVariant & value ) -> QVariant
1340 {
1341 if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( value.value< QObject * >() ) )
1342 {
1343 // don't store pointers in maps for long-term storage
1344 return layerPointerToString( layer );
1345 }
1346 else if ( value.userType() == QMetaType::type( "QPointer< QgsMapLayer >" ) )
1347 {
1348 // don't store pointers in maps for long-term storage
1349 return layerPointerToString( value.value< QPointer< QgsMapLayer > >().data() );
1350 }
1351 else
1352 {
1353 return value;
1354 }
1355 };
1356
1357 QVariantMap res;
1358 for ( auto it = map.constBegin(); it != map.constEnd(); ++it )
1359 {
1360 if ( it->type() == QVariant::Map )
1361 {
1362 res.insert( it.key(), removePointerValuesFromMap( it.value().toMap() ) );
1363 }
1364 else if ( it->type() == QVariant::List )
1365 {
1366 QVariantList dest;
1367 const QVariantList source = it.value().toList();
1368 dest.reserve( source.size() );
1369 for ( const QVariant &v : source )
1370 {
1371 dest.append( cleanPointerValues( v ) );
1372 }
1373 res.insert( it.key(), dest );
1374 }
1375 else
1376 {
1377 res.insert( it.key(), cleanPointerValues( it.value() ) );
1378 }
1379 }
1380 return res;
1381}
1382
1383QString QgsProcessingUtils::resolveDefaultEncoding( const QString &defaultEncoding )
1384{
1385 if ( ! QTextCodec::availableCodecs().contains( defaultEncoding.toLatin1() ) )
1386 {
1387 const QString systemCodec = QTextCodec::codecForLocale()->name();
1388 if ( ! systemCodec.isEmpty() )
1389 {
1390 return systemCodec;
1391 }
1392 return QString( "UTF-8" );
1393 }
1394
1395 return defaultEncoding;
1396}
1397
1398//
1399// QgsProcessingFeatureSource
1400//
1401
1402QgsProcessingFeatureSource::QgsProcessingFeatureSource( QgsFeatureSource *originalSource, const QgsProcessingContext &context, bool ownsOriginalSource, long long featureLimit )
1403 : mSource( originalSource )
1404 , mOwnsSource( ownsOriginalSource )
1405 , mInvalidGeometryCheck( QgsWkbTypes::geometryType( mSource->wkbType() ) == QgsWkbTypes::PointGeometry
1406 ? QgsFeatureRequest::GeometryNoCheck // never run geometry validity checks for point layers!
1407 : context.invalidGeometryCheck() )
1408 , mInvalidGeometryCallback( context.invalidGeometryCallback( originalSource ) )
1409 , mTransformErrorCallback( context.transformErrorCallback() )
1410 , mInvalidGeometryCallbackSkip( context.defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::GeometrySkipInvalid, originalSource ) )
1411 , mInvalidGeometryCallbackAbort( context.defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::GeometryAbortOnInvalid, originalSource ) )
1412 , mFeatureLimit( featureLimit )
1413{}
1414
1416{
1417 if ( mOwnsSource )
1418 delete mSource;
1419}
1420
1422{
1423 QgsFeatureRequest req( request );
1424 req.setTransformErrorCallback( mTransformErrorCallback );
1425
1426 if ( flags & FlagSkipGeometryValidityChecks )
1428 else
1429 {
1430 req.setInvalidGeometryCheck( mInvalidGeometryCheck );
1431 req.setInvalidGeometryCallback( mInvalidGeometryCallback );
1432 }
1433
1434 if ( mFeatureLimit != -1 && req.limit() != -1 )
1435 req.setLimit( std::min( static_cast< long long >( req.limit() ), mFeatureLimit ) );
1436 else if ( mFeatureLimit != -1 )
1437 req.setLimit( mFeatureLimit );
1438
1439 return mSource->getFeatures( req );
1440}
1441
1443{
1444 FeatureAvailability sourceAvailability = mSource->hasFeatures();
1445 if ( sourceAvailability == NoFeaturesAvailable )
1446 return NoFeaturesAvailable; // never going to be features if underlying source has no features
1447 else if ( mInvalidGeometryCheck == QgsFeatureRequest::GeometryNoCheck )
1448 return sourceAvailability;
1449 else
1450 // we don't know... source has features, but these may be filtered out by invalid geometry check
1452}
1453
1455{
1456 QgsFeatureRequest req( request );
1457 req.setInvalidGeometryCheck( mInvalidGeometryCheck );
1458 req.setInvalidGeometryCallback( mInvalidGeometryCallback );
1459 req.setTransformErrorCallback( mTransformErrorCallback );
1460
1461 if ( mFeatureLimit != -1 && req.limit() != -1 )
1462 req.setLimit( std::min( static_cast< long long >( req.limit() ), mFeatureLimit ) );
1463 else if ( mFeatureLimit != -1 )
1464 req.setLimit( mFeatureLimit );
1465
1466 return mSource->getFeatures( req );
1467}
1468
1473
1475{
1476 return mSource->fields();
1477}
1478
1480{
1481 return mSource->wkbType();
1482}
1483
1485{
1486 if ( mFeatureLimit == -1 )
1487 return mSource->featureCount();
1488 else
1489 return std::min( mFeatureLimit, mSource->featureCount() );
1490}
1491
1493{
1494 return mSource->sourceName();
1495
1496}
1497
1498QSet<QVariant> QgsProcessingFeatureSource::uniqueValues( int fieldIndex, int limit ) const
1499{
1500 return mSource->uniqueValues( fieldIndex, limit );
1501}
1502
1503QVariant QgsProcessingFeatureSource::minimumValue( int fieldIndex ) const
1504{
1505 return mSource->minimumValue( fieldIndex );
1506}
1507
1508QVariant QgsProcessingFeatureSource::maximumValue( int fieldIndex ) const
1509{
1510 return mSource->maximumValue( fieldIndex );
1511}
1512
1514{
1515 return mSource->sourceExtent();
1516}
1517
1522
1527
1529{
1530 QgsExpressionContextScope *expressionContextScope = nullptr;
1531 QgsExpressionContextScopeGenerator *generator = dynamic_cast<QgsExpressionContextScopeGenerator *>( mSource );
1532 if ( generator )
1533 {
1534 expressionContextScope = generator->createExpressionContextScope();
1535 }
1536 return expressionContextScope;
1537}
1538
1540{
1541 mInvalidGeometryCheck = method;
1542 switch ( mInvalidGeometryCheck )
1543 {
1545 mInvalidGeometryCallback = nullptr;
1546 break;
1547
1549 mInvalidGeometryCallback = mInvalidGeometryCallbackSkip;
1550 break;
1551
1553 mInvalidGeometryCallback = mInvalidGeometryCallbackAbort;
1554 break;
1555
1556 }
1557}
1558
1559
1560//
1561// QgsProcessingFeatureSink
1562//
1563QgsProcessingFeatureSink::QgsProcessingFeatureSink( QgsFeatureSink *originalSink, const QString &sinkName, QgsProcessingContext &context, bool ownsOriginalSink )
1564 : QgsProxyFeatureSink( originalSink )
1565 , mContext( context )
1566 , mSinkName( sinkName )
1567 , mOwnsSink( ownsOriginalSink )
1568{}
1569
1571{
1572 if ( mOwnsSink )
1573 delete destinationSink();
1574}
1575
1576bool QgsProcessingFeatureSink::addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags )
1577{
1578 bool result = QgsProxyFeatureSink::addFeature( feature, flags );
1579 if ( !result && mContext.feedback() )
1580 {
1581 const QString error = lastError();
1582 if ( !error.isEmpty() )
1583 mContext.feedback()->reportError( QObject::tr( "Feature could not be written to %1: %2" ).arg( mSinkName, error ) );
1584 else
1585 mContext.feedback()->reportError( QObject::tr( "Feature could not be written to %1" ).arg( mSinkName ) );
1586 }
1587 return result;
1588}
1589
1590bool QgsProcessingFeatureSink::addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags )
1591{
1592 bool result = QgsProxyFeatureSink::addFeatures( features, flags );
1593 if ( !result && mContext.feedback() )
1594 {
1595 const QString error = lastError();
1596 if ( !error.isEmpty() )
1597 mContext.feedback()->reportError( QObject::tr( "%n feature(s) could not be written to %1: %2", nullptr, features.count() ).arg( mSinkName, error ) );
1598 else
1599 mContext.feedback()->reportError( QObject::tr( "%n feature(s) could not be written to %1", nullptr, features.count() ).arg( mSinkName ) );
1600 }
1601 return result;
1602}
1603
1604bool QgsProcessingFeatureSink::addFeatures( QgsFeatureIterator &iterator, QgsFeatureSink::Flags flags )
1605{
1606 bool result = QgsProxyFeatureSink::addFeatures( iterator, flags );
1607 if ( !result && mContext.feedback() )
1608 {
1609 const QString error = lastError();
1610 if ( !error.isEmpty() )
1611 mContext.feedback()->reportError( QObject::tr( "Features could not be written to %1: %2" ).arg( mSinkName, error ) );
1612 else
1613 mContext.feedback()->reportError( QObject::tr( "Features could not be written to %1" ).arg( mSinkName ) );
1614 }
1615 return result;
1616}
@ Success
No errors were encountered.
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.
QString table() const
Returns the table 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)
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setLimit(long long limit)
Set the maximum number of features to request.
InvalidGeometryCheck
Handling of features with invalid geometries.
@ GeometryNoCheck
No invalid geometry checking.
@ GeometryAbortOnInvalid
Close iterator on encountering any features with invalid geometry. This requires a slow geometry vali...
@ GeometrySkipInvalid
Skip any features with invalid geometry. This requires a slow geometry validity check for every featu...
long long limit() const
Returns the maximum number of features to request, or -1 if no limit set.
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 & setInvalidGeometryCheck(InvalidGeometryCheck check)
Sets invalid geometry checking behavior.
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 QgsFields fields() const =0
Returns the fields associated with features in the source.
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 QgsCoordinateReferenceSystem sourceCrs() const =0
Returns the coordinate reference system for features in the source.
SpatialIndexPresence
Enumeration of spatial index presence states.
virtual QgsWkbTypes::Type wkbType() const =0
Returns the geometry type for features returned by this source.
virtual FeatureAvailability hasFeatures() const
Determines if there are any features available in the source.
FeatureAvailability
Possible return value for hasFeatures() to determine if a source is empty.
@ FeaturesMaybeAvailable
There may be features available in this source.
@ NoFeaturesAvailable
There are certainly no features available in this 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 QString sourceName() const =0
Returns a friendly display name for 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.
virtual SpatialIndexPresence hasSpatialIndex() const
Returns an enum value representing the presence of a valid spatial index on the source,...
virtual QgsRectangle sourceExtent() const
Returns the extent of all geometries from the source.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:56
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:54
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:51
QString name
Definition qgsfield.h:60
void setName(const QString &name)
Set the field name.
Definition qgsfield.cpp:188
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:73
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:79
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, QgsWkbTypes::Type geometryType=QgsWkbTypes::NoGeometry, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem()) 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:59
double y
Definition qgspointxy.h:63
double x
Definition qgspointxy.h:62
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.
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.
Flags flags
Flags which dictate source behavior.
bool selectedFeaturesOnly
true if only selected features in the source should be used by algorithms.
QgsFeatureRequest::InvalidGeometryCheck geometryCheck
Geometry check method to apply to this source.
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...
@ FlagOverrideDefaultGeometryCheck
If set, the default geometry check method (as dictated by QgsProcessingContext) will be overridden fo...
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.
QgsFeatureSource::FeatureAvailability hasFeatures() const override
Determines if there are any features available in the source.
QVariant maximumValue(int fieldIndex) const override
Returns the maximum value for an attribute column or an invalid variant in case of error.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request, Flags flags) const
Returns an iterator for the features in the source, respecting the supplied feature flags.
QgsCoordinateReferenceSystem sourceCrs() const override
Returns the coordinate reference system for features in the 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.
QgsWkbTypes::Type wkbType() const override
Returns the geometry type for features returned by this source.
@ FlagSkipGeometryValidityChecks
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
QString sourceName() const override
Returns a friendly display name for the source.
SpatialIndexPresence hasSpatialIndex() const override
Returns an enum value representing the presence of a valid spatial index on the source,...
QgsFeatureIds allFeatureIds() const override
Returns a list of all feature IDs for features present in the source.
QgsProcessingFeatureSource(QgsFeatureSource *originalSource, const QgsProcessingContext &context, bool ownsOriginalSource=false, long long featureLimit=-1)
Constructor for QgsProcessingFeatureSource, accepting an original feature source originalSource and p...
QgsFields fields() const override
Returns the fields associated with features in the source.
void setInvalidGeometryCheck(QgsFeatureRequest::InvalidGeometryCheck method)
Overrides the default geometry check method for 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.
@ FlagHidden
Parameter is hidden and should not be shown to users.
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)
Converts a source vector layer to a file path of a vector layer of compatible format.
static void createFeatureSinkPython(QgsFeatureSink **sink, QString &destination, QgsProcessingContext &context, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &createOptions=QVariantMap())
Creates a feature sink ready for adding features.
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 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 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 QgsFeatureSink * createFeatureSink(QString &destination, QgsProcessingContext &context, const QgsFields &fields, QgsWkbTypes::Type 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 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()
static QString tempFolder()
Returns a session specific processing temporary folder for use in processing algorithms.
LayerHint
Layer type hints.
@ Annotation
Annotation layer type, since QGIS 3.22.
@ Vector
Vector layer type.
@ 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 generateTempFilename(const QString &basename)
Returns a temporary filename for a given file, putting it into a temporary folder (creating that fold...
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 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)
Converts a source vector layer to a file path and layer name of a vector layer of compatible format.
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 QgsMapLayer * mapLayerFromString(const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers=true, QgsProcessingUtils::LayerHint typeHint=QgsProcessingUtils::LayerHint::UnknownType)
Interprets a string as a map layer within the supplied context.
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 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 defaultRasterExtension()
Returns the default raster extension to use, in the absence of all other constraints (e....
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 const QgsSettingsEntryInteger settingsDefaultOutputRasterLayerExt
Settings entry default output raster layer ext.
static const QgsSettingsEntryInteger settingsDefaultOutputVectorLayerExt
Settings entry default output vector layer ext.
static const QString TEMPORARY_OUTPUT
Constant used to indicate that a Processing algorithm output should be a temporary layer/file.
@ TypeVectorLine
Vector line layers.
@ TypeVectorPolygon
Vector polygon layers.
@ TypeVector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
@ TypeVectorPoint
Vector point layers.
@ TypeVectorAnyGeometry
Any vector layer with geometry.
static const QgsSettingsEntryString settingsTempPath
Settings entry temp path.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:104
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:109
A store for object properties.
@ StaticProperty
Static property (QgsStaticProperty)
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
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...
Type propertyType() const
Returns the property type.
static QgsProperty fromValue(const QVariant &value, bool isActive=true)
Returns a new StaticProperty created from the specified value.
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.
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(QgsWkbTypes::Type 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.
T value(const QString &dynamicKeyPart=QString()) const
Returns settings 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.
QgsVectorFileWriter::SymbologyExport symbologyExport
Symbology to export.
QgsVectorFileWriter::ActionOnExistingFile actionOnExistingFile
Action on existing file.
QStringList datasourceOptions
List of OGR data source creation options.
static QgsVectorFileWriter * create(const QString &fileName, const QgsFields &fields, QgsWkbTypes::Type 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 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 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.
Q_INVOKABLE QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
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.
QgsFeatureIterator getSelectedFeatures(QgsFeatureRequest request=QgsFeatureRequest()) const
Returns an iterator of the selected features.
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
Type
The WKB type describes the number of dimensions a geometry has.
Definition qgswkbtypes.h:70
@ PointCloudLayer
Point cloud layer. Added in QGIS 3.18.
@ MeshLayer
Mesh layer. Added in QGIS 3.2.
@ VectorLayer
Vector layer.
@ RasterLayer
Raster layer.
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
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
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:2466
QList< QgsFeature > QgsFeatureList
Definition qgsfeature.h:922
QSet< QgsFeatureId > QgsFeatureIds
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 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.
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 vector layers.