QGIS API Documentation 3.34.0-Prizren (ffbdd678812)
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 // for disk based sources, we use the filename to determine a layer name
298 if ( !useProvider || ( provider == QLatin1String( "ogr" ) || provider == QLatin1String( "gdal" ) || provider == QLatin1String( "mdal" ) || provider == QLatin1String( "pdal" ) || provider == QLatin1String( "ept" ) || provider == QLatin1String( "copc" ) ) )
299 {
300 QStringList components = uri.split( '|' );
301 if ( components.isEmpty() )
302 return nullptr;
303
304 QFileInfo fi;
305 if ( QFileInfo::exists( uri ) )
306 fi = QFileInfo( uri );
307 else if ( QFileInfo::exists( components.at( 0 ) ) )
308 fi = QFileInfo( components.at( 0 ) );
309 else
310 return nullptr;
311 name = fi.baseName();
312 }
313 else
314 {
315 name = QgsDataSourceUri( uri ).table();
316 }
317
318 // brute force attempt to load a matching layer
319 if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::Vector )
320 {
321 QgsVectorLayer::LayerOptions options { transformContext };
322 options.loadDefaultStyle = false;
323 options.skipCrsValidation = true;
324
325 std::unique_ptr< QgsVectorLayer > layer;
326 if ( useProvider )
327 {
328 layer = std::make_unique<QgsVectorLayer>( uri, name, provider, options );
329 }
330 else
331 {
332 // fallback to ogr
333 layer = std::make_unique<QgsVectorLayer>( uri, name, QStringLiteral( "ogr" ), options );
334 }
335 if ( layer->isValid() )
336 {
337 return layer.release();
338 }
339 }
340 if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::Raster )
341 {
342 QgsRasterLayer::LayerOptions rasterOptions;
343 rasterOptions.loadDefaultStyle = false;
344 rasterOptions.skipCrsValidation = true;
345
346 std::unique_ptr< QgsRasterLayer > rasterLayer;
347 if ( useProvider )
348 {
349 rasterLayer = std::make_unique< QgsRasterLayer >( uri, name, provider, rasterOptions );
350 }
351 else
352 {
353 // fallback to gdal
354 rasterLayer = std::make_unique< QgsRasterLayer >( uri, name, QStringLiteral( "gdal" ), rasterOptions );
355 }
356
357 if ( rasterLayer->isValid() )
358 {
359 return rasterLayer.release();
360 }
361 }
362 if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::Mesh )
363 {
364 QgsMeshLayer::LayerOptions meshOptions;
365 meshOptions.skipCrsValidation = true;
366
367 std::unique_ptr< QgsMeshLayer > meshLayer;
368 if ( useProvider )
369 {
370 meshLayer = std::make_unique< QgsMeshLayer >( uri, name, provider, meshOptions );
371 }
372 else
373 {
374 meshLayer = std::make_unique< QgsMeshLayer >( uri, name, QStringLiteral( "mdal" ), meshOptions );
375 }
376 if ( meshLayer->isValid() )
377 {
378 return meshLayer.release();
379 }
380 }
381 if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::PointCloud )
382 {
383 QgsPointCloudLayer::LayerOptions pointCloudOptions;
384 pointCloudOptions.skipCrsValidation = true;
385
387 {
388 pointCloudOptions.skipIndexGeneration = true;
389 }
390
391 std::unique_ptr< QgsPointCloudLayer > pointCloudLayer;
392 if ( useProvider )
393 {
394 pointCloudLayer = std::make_unique< QgsPointCloudLayer >( uri, name, provider, pointCloudOptions );
395 }
396 else
397 {
398 const QList< QgsProviderRegistry::ProviderCandidateDetails > preferredProviders = QgsProviderRegistry::instance()->preferredProvidersForUri( uri );
399 if ( !preferredProviders.empty() )
400 {
401 pointCloudLayer = std::make_unique< QgsPointCloudLayer >( uri, name, preferredProviders.at( 0 ).metadata()->key(), pointCloudOptions );
402 }
403 }
404 if ( pointCloudLayer && pointCloudLayer->isValid() )
405 {
406 return pointCloudLayer.release();
407 }
408 }
409 if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::VectorTile )
410 {
411 QgsDataSourceUri dsUri;
412 dsUri.setParam( "type", "mbtiles" );
413 dsUri.setParam( "url", uri );
414
415 std::unique_ptr< QgsVectorTileLayer > tileLayer;
416 tileLayer = std::make_unique< QgsVectorTileLayer >( dsUri.encodedUri(), name );
417
418 if ( tileLayer->isValid() )
419 {
420 return tileLayer.release();
421 }
422 }
423 if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::TiledScene )
424 {
425 QgsTiledSceneLayer::LayerOptions tiledSceneOptions;
426 tiledSceneOptions.skipCrsValidation = true;
427
428 std::unique_ptr< QgsTiledSceneLayer > tiledSceneLayer;
429 if ( useProvider )
430 {
431 tiledSceneLayer = std::make_unique< QgsTiledSceneLayer >( uri, name, provider, tiledSceneOptions );
432 }
433 else
434 {
435 const QList< QgsProviderRegistry::ProviderCandidateDetails > preferredProviders = QgsProviderRegistry::instance()->preferredProvidersForUri( uri );
436 if ( !preferredProviders.empty() )
437 {
438 tiledSceneLayer = std::make_unique< QgsTiledSceneLayer >( uri, name, preferredProviders.at( 0 ).metadata()->key(), tiledSceneOptions );
439 }
440 }
441 if ( tiledSceneLayer && tiledSceneLayer->isValid() )
442 {
443 return tiledSceneLayer.release();
444 }
445 }
446 return nullptr;
447}
448
449QgsMapLayer *QgsProcessingUtils::mapLayerFromString( const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers, LayerHint typeHint, QgsProcessing::LayerOptionsFlags flags )
450{
451 if ( string.isEmpty() )
452 return nullptr;
453
454 // prefer project layers
455 if ( context.project() && typeHint == LayerHint::Annotation && string.compare( QLatin1String( "main" ), Qt::CaseInsensitive ) == 0 )
456 return context.project()->mainAnnotationLayer();
457
458 QgsMapLayer *layer = nullptr;
459 if ( auto *lProject = context.project() )
460 {
461 QgsMapLayer *layer = mapLayerFromStore( string, lProject->layerStore(), typeHint );
462 if ( layer )
463 return layer;
464 }
465
466 layer = mapLayerFromStore( string, context.temporaryLayerStore(), typeHint );
467 if ( layer )
468 return layer;
469
470 if ( !allowLoadingNewLayers )
471 return nullptr;
472
473 layer = loadMapLayerFromString( string, context.transformContext(), typeHint, flags );
474 if ( layer )
475 {
476 context.temporaryLayerStore()->addMapLayer( layer );
477 return layer;
478 }
479 else
480 {
481 return nullptr;
482 }
483}
484
485QgsProcessingFeatureSource *QgsProcessingUtils::variantToSource( const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue )
486{
487 QVariant val = value;
488 bool selectedFeaturesOnly = false;
489 long long featureLimit = -1;
490 QString filterExpression;
491 bool overrideGeometryCheck = false;
493 if ( val.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
494 {
495 // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
496 QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
497 selectedFeaturesOnly = fromVar.selectedFeaturesOnly;
498 featureLimit = fromVar.featureLimit;
499 filterExpression = fromVar.filterExpression;
500 val = fromVar.source;
502 geometryCheck = fromVar.geometryCheck;
503 }
504 else if ( val.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
505 {
506 // input is a QgsProcessingOutputLayerDefinition (e.g. an output from earlier in a model) - get extra properties from it
507 QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
508 val = fromVar.sink;
509 }
510
511 if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( val ) ) )
512 {
513 std::unique_ptr< QgsProcessingFeatureSource> source = std::make_unique< QgsProcessingFeatureSource >( layer, context, false, featureLimit, filterExpression );
514 if ( overrideGeometryCheck )
515 source->setInvalidGeometryCheck( geometryCheck );
516 return source.release();
517 }
518
519 QString layerRef;
520 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
521 {
522 layerRef = val.value< QgsProperty >().valueAsString( context.expressionContext(), fallbackValue.toString() );
523 }
524 else if ( !val.isValid() || val.toString().isEmpty() )
525 {
526 // fall back to default
527 if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( fallbackValue ) ) )
528 {
529 std::unique_ptr< QgsProcessingFeatureSource> source = std::make_unique< QgsProcessingFeatureSource >( layer, context, false, featureLimit, filterExpression );
530 if ( overrideGeometryCheck )
531 source->setInvalidGeometryCheck( geometryCheck );
532 return source.release();
533 }
534
535 layerRef = fallbackValue.toString();
536 }
537 else
538 {
539 layerRef = val.toString();
540 }
541
542 if ( layerRef.isEmpty() )
543 return nullptr;
544
545 QgsVectorLayer *vl = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( layerRef, context, true, LayerHint::Vector ) );
546 if ( !vl )
547 return nullptr;
548
549 std::unique_ptr< QgsProcessingFeatureSource> source;
550 if ( selectedFeaturesOnly )
551 {
552 source = std::make_unique< QgsProcessingFeatureSource>( new QgsVectorLayerSelectedFeatureSource( vl ), context, true, featureLimit, filterExpression );
553 }
554 else
555 {
556 source = std::make_unique< QgsProcessingFeatureSource >( vl, context, false, featureLimit, filterExpression );
557 }
558
559 if ( overrideGeometryCheck )
560 source->setInvalidGeometryCheck( geometryCheck );
561 return source.release();
562}
563
564QgsCoordinateReferenceSystem QgsProcessingUtils::variantToCrs( const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue )
565{
566 QVariant val = value;
567
568 if ( val.userType() == QMetaType::type( "QgsCoordinateReferenceSystem" ) )
569 {
570 // input is a QgsCoordinateReferenceSystem - done!
571 return val.value< QgsCoordinateReferenceSystem >();
572 }
573 else if ( val.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
574 {
575 // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
576 QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
577 val = fromVar.source;
578 }
579 else if ( val.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
580 {
581 // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
582 QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
583 val = fromVar.sink;
584 }
585
586 if ( val.userType() == QMetaType::type( "QgsProperty" ) && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
587 {
588 val = val.value< QgsProperty >().staticValue();
589 }
590
591 // maybe a map layer
592 if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
593 return layer->crs();
594
595 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
596 val = val.value< QgsProperty >().valueAsString( context.expressionContext(), fallbackValue.toString() );
597
598 if ( !val.isValid() )
599 {
600 // fall back to default
601 val = fallbackValue;
602 }
603
604 QString crsText = val.toString();
605 if ( crsText.isEmpty() )
606 crsText = fallbackValue.toString();
607
608 if ( crsText.isEmpty() )
610
611 // maybe special string
612 if ( context.project() && crsText.compare( QLatin1String( "ProjectCrs" ), Qt::CaseInsensitive ) == 0 )
613 return context.project()->crs();
614
615 // maybe a map layer reference
616 if ( QgsMapLayer *layer = QgsProcessingUtils::mapLayerFromString( crsText, context ) )
617 return layer->crs();
618
619 // else CRS from string
621 crs.createFromString( crsText );
622 return crs;
623}
624
625bool QgsProcessingUtils::canUseLayer( const QgsMeshLayer *layer )
626{
627 return layer && layer->dataProvider();
628}
629
630bool QgsProcessingUtils::canUseLayer( const QgsPluginLayer *layer )
631{
632 return layer && layer->isValid();
633}
634
635bool QgsProcessingUtils::canUseLayer( const QgsVectorTileLayer *layer )
636{
637 return layer && layer->isValid();
638}
639
640bool QgsProcessingUtils::canUseLayer( const QgsRasterLayer *layer )
641{
642 return layer && layer->isValid();
643}
644
645bool QgsProcessingUtils::canUseLayer( const QgsPointCloudLayer *layer )
646{
647 return layer && layer->isValid();
648}
649
650bool QgsProcessingUtils::canUseLayer( const QgsAnnotationLayer *layer )
651{
652 return layer && layer->isValid();
653}
654
655bool QgsProcessingUtils::canUseLayer( const QgsTiledSceneLayer *layer )
656{
657 return layer && layer->isValid();
658}
659
660bool QgsProcessingUtils::canUseLayer( const QgsVectorLayer *layer, const QList<int> &sourceTypes )
661{
662 return layer && layer->isValid() &&
663 ( sourceTypes.isEmpty()
664 || ( sourceTypes.contains( QgsProcessing::TypeVectorPoint ) && layer->geometryType() == Qgis::GeometryType::Point )
665 || ( sourceTypes.contains( QgsProcessing::TypeVectorLine ) && layer->geometryType() == Qgis::GeometryType::Line )
666 || ( sourceTypes.contains( QgsProcessing::TypeVectorPolygon ) && layer->geometryType() == Qgis::GeometryType::Polygon )
667 || ( sourceTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) && layer->isSpatial() )
668 || sourceTypes.contains( QgsProcessing::TypeVector )
669 );
670}
671
672QString QgsProcessingUtils::normalizeLayerSource( const QString &source )
673{
674 QString normalized = source;
675 normalized.replace( '\\', '/' );
676 return normalized.trimmed();
677}
678
679QString QgsProcessingUtils::variantToPythonLiteral( const QVariant &value )
680{
681 if ( !value.isValid() )
682 return QStringLiteral( "None" );
683
684 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
685 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
686 else if ( value.userType() == QMetaType::type( "QgsCoordinateReferenceSystem" ) )
687 {
688 if ( !value.value< QgsCoordinateReferenceSystem >().isValid() )
689 return QStringLiteral( "QgsCoordinateReferenceSystem()" );
690 else
691 return QStringLiteral( "QgsCoordinateReferenceSystem('%1')" ).arg( value.value< QgsCoordinateReferenceSystem >().authid() );
692 }
693 else if ( value.userType() == QMetaType::type( "QgsRectangle" ) )
694 {
695 QgsRectangle r = value.value<QgsRectangle>();
696 return QStringLiteral( "'%1, %3, %2, %4'" ).arg( qgsDoubleToString( r.xMinimum() ),
700 }
701 else if ( value.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
702 {
704 return QStringLiteral( "'%1, %3, %2, %4 [%5]'" ).arg( qgsDoubleToString( r.xMinimum() ),
707 qgsDoubleToString( r.yMaximum() ), r.crs().authid() );
708 }
709 else if ( value.userType() == QMetaType::type( "QgsPointXY" ) )
710 {
711 QgsPointXY r = value.value<QgsPointXY>();
712 return QStringLiteral( "'%1,%2'" ).arg( qgsDoubleToString( r.x() ),
713 qgsDoubleToString( r.y() ) );
714 }
715 else if ( value.userType() == QMetaType::type( "QgsReferencedPointXY" ) )
716 {
718 return QStringLiteral( "'%1,%2 [%3]'" ).arg( qgsDoubleToString( r.x() ),
719 qgsDoubleToString( r.y() ),
720 r.crs().authid() );
721 }
722
723 switch ( value.type() )
724 {
725 case QVariant::Bool:
726 return value.toBool() ? QStringLiteral( "True" ) : QStringLiteral( "False" );
727
728 case QVariant::Double:
729 return QString::number( value.toDouble() );
730
731 case QVariant::Int:
732 case QVariant::UInt:
733 return QString::number( value.toInt() );
734
735 case QVariant::LongLong:
736 case QVariant::ULongLong:
737 return QString::number( value.toLongLong() );
738
739 case QVariant::List:
740 {
741 QStringList parts;
742 const QVariantList vl = value.toList();
743 for ( const QVariant &v : vl )
744 {
745 parts << variantToPythonLiteral( v );
746 }
747 return parts.join( ',' ).prepend( '[' ).append( ']' );
748 }
749
750 case QVariant::Map:
751 {
752 const QVariantMap map = value.toMap();
753 QStringList parts;
754 parts.reserve( map.size() );
755 for ( auto it = map.constBegin(); it != map.constEnd(); ++it )
756 {
757 parts << QStringLiteral( "%1: %2" ).arg( stringToPythonLiteral( it.key() ), variantToPythonLiteral( it.value() ) );
758 }
759 return parts.join( ',' ).prepend( '{' ).append( '}' );
760 }
761
762 case QVariant::DateTime:
763 {
764 const QDateTime dateTime = value.toDateTime();
765 return QStringLiteral( "QDateTime(QDate(%1, %2, %3), QTime(%4, %5, %6))" )
766 .arg( dateTime.date().year() )
767 .arg( dateTime.date().month() )
768 .arg( dateTime.date().day() )
769 .arg( dateTime.time().hour() )
770 .arg( dateTime.time().minute() )
771 .arg( dateTime.time().second() );
772 }
773
774 default:
775 break;
776 }
777
778 return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
779}
780
781QString QgsProcessingUtils::stringToPythonLiteral( const QString &string )
782{
783 QString s = string;
784 s.replace( '\\', QLatin1String( "\\\\" ) );
785 s.replace( '\n', QLatin1String( "\\n" ) );
786 s.replace( '\r', QLatin1String( "\\r" ) );
787 s.replace( '\t', QLatin1String( "\\t" ) );
788
789 if ( s.contains( '\'' ) && !s.contains( '\"' ) )
790 {
791 s = s.prepend( '"' ).append( '"' );
792 }
793 else
794 {
795 s.replace( '\'', QLatin1String( "\\\'" ) );
796 s = s.prepend( '\'' ).append( '\'' );
797 }
798 return s;
799}
800
801void QgsProcessingUtils::parseDestinationString( QString &destination, QString &providerKey, QString &uri, QString &layerName, QString &format, QMap<QString, QVariant> &options, bool &useWriter, QString &extension )
802{
803 extension.clear();
804 bool matched = decodeProviderKeyAndUri( destination, providerKey, uri );
805
806 if ( !matched )
807 {
808 const thread_local QRegularExpression splitRx( QStringLiteral( "^(.{3,}?):(.*)$" ) );
809 QRegularExpressionMatch match = splitRx.match( destination );
810 if ( match.hasMatch() )
811 {
812 providerKey = match.captured( 1 );
813 uri = match.captured( 2 );
814 matched = true;
815 }
816 }
817
818 if ( matched )
819 {
820 if ( providerKey == QLatin1String( "postgis" ) ) // older processing used "postgis" instead of "postgres"
821 {
822 providerKey = QStringLiteral( "postgres" );
823 }
824 if ( providerKey == QLatin1String( "ogr" ) )
825 {
826 QgsDataSourceUri dsUri( uri );
827 if ( !dsUri.database().isEmpty() )
828 {
829 if ( !dsUri.table().isEmpty() )
830 {
831 layerName = dsUri.table();
832 options.insert( QStringLiteral( "layerName" ), layerName );
833 }
834 uri = dsUri.database();
835 extension = QFileInfo( uri ).completeSuffix();
836 format = QgsVectorFileWriter::driverForExtension( extension );
837 options.insert( QStringLiteral( "driverName" ), format );
838 }
839 else
840 {
841 extension = QFileInfo( uri ).completeSuffix();
842 options.insert( QStringLiteral( "driverName" ), QgsVectorFileWriter::driverForExtension( extension ) );
843 }
844 options.insert( QStringLiteral( "update" ), true );
845 }
846 useWriter = false;
847 }
848 else
849 {
850 useWriter = true;
851 providerKey = QStringLiteral( "ogr" );
852
853 const thread_local QRegularExpression splitRx( QStringLiteral( "^(.*)\\.(.*?)$" ) );
854 QRegularExpressionMatch match = splitRx.match( destination );
855 if ( match.hasMatch() )
856 {
857 extension = match.captured( 2 );
858 format = QgsVectorFileWriter::driverForExtension( extension );
859 }
860
861 if ( format.isEmpty() )
862 {
863 format = QStringLiteral( "GPKG" );
864 destination = destination + QStringLiteral( ".gpkg" );
865 }
866
867 options.insert( QStringLiteral( "driverName" ), format );
868 uri = destination;
869 }
870}
871
872QgsFeatureSink *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 )
873{
874 QVariantMap options = createOptions;
875 if ( !options.contains( QStringLiteral( "fileEncoding" ) ) )
876 {
877 // no destination encoding specified, use default
878 options.insert( QStringLiteral( "fileEncoding" ), context.defaultEncoding().isEmpty() ? QStringLiteral( "system" ) : context.defaultEncoding() );
879 }
880
881 if ( destination.isEmpty() || destination.startsWith( QLatin1String( "memory:" ) ) )
882 {
883 // strip "memory:" from start of destination
884 if ( destination.startsWith( QLatin1String( "memory:" ) ) )
885 destination = destination.mid( 7 );
886
887 if ( destination.isEmpty() )
888 destination = QStringLiteral( "output" );
889
890 // memory provider cannot be used with QgsVectorLayerImport - so create layer manually
891 std::unique_ptr< QgsVectorLayer > layer( QgsMemoryProviderUtils::createMemoryLayer( destination, fields, geometryType, crs, false ) );
892 if ( !layer || !layer->isValid() )
893 {
894 throw QgsProcessingException( QObject::tr( "Could not create memory layer" ) );
895 }
896
897 if ( QgsProcessingFeedback *feedback = context.feedback() )
898 {
899 for ( const QgsField &field : fields )
900 {
901 // TODO -- support these!
902 if ( !field.alias().isEmpty() )
903 feedback->pushWarning( QObject::tr( "%1: Aliases are not compatible with scratch layers" ).arg( field.name() ) );
904 if ( !field.alias().isEmpty() )
905 feedback->pushWarning( QObject::tr( "%1: Comments are not compatible with scratch layers" ).arg( field.name() ) );
906 }
907 }
908
909 layer->setCustomProperty( QStringLiteral( "OnConvertFormatRegeneratePrimaryKey" ), static_cast< bool >( sinkFlags & QgsFeatureSink::RegeneratePrimaryKey ) );
910
911 // update destination to layer ID
912 destination = layer->id();
913
914 // this is a factory, so we need to return a proxy
915 std::unique_ptr< QgsProcessingFeatureSink > sink( new QgsProcessingFeatureSink( layer->dataProvider(), destination, context ) );
916 context.temporaryLayerStore()->addMapLayer( layer.release() );
917
918 return sink.release();
919 }
920 else
921 {
922 QString providerKey;
923 QString uri;
924 QString layerName;
925 QString format;
926 QString extension;
927 bool useWriter = false;
928 parseDestinationString( destination, providerKey, uri, layerName, format, options, useWriter, extension );
929
930 QgsFields newFields = fields;
931 if ( useWriter && providerKey == QLatin1String( "ogr" ) )
932 {
933 // use QgsVectorFileWriter for OGR destinations instead of QgsVectorLayerImport, as that allows
934 // us to use any OGR format which supports feature addition
935 QString finalFileName;
936 QString finalLayerName;
938 saveOptions.fileEncoding = options.value( QStringLiteral( "fileEncoding" ) ).toString();
939 saveOptions.layerName = !layerName.isEmpty() ? layerName : options.value( QStringLiteral( "layerName" ) ).toString();
940 saveOptions.driverName = format;
941 saveOptions.datasourceOptions = !datasourceOptions.isEmpty() ? datasourceOptions : QgsVectorFileWriter::defaultDatasetOptions( format );
942 saveOptions.layerOptions = !layerOptions.isEmpty() ? layerOptions : QgsVectorFileWriter::defaultLayerOptions( format );
944 if ( remappingDefinition )
945 {
947 // sniff destination file to get correct wkb type and crs
948 std::unique_ptr< QgsVectorLayer > vl = std::make_unique< QgsVectorLayer >( destination );
949 if ( vl->isValid() )
950 {
951 remappingDefinition->setDestinationWkbType( vl->wkbType() );
952 remappingDefinition->setDestinationCrs( vl->crs() );
953 newFields = vl->fields();
954 remappingDefinition->setDestinationFields( newFields );
955 }
956 context.expressionContext().setFields( fields );
957 }
958 else
959 {
961 }
962 std::unique_ptr< QgsVectorFileWriter > writer( QgsVectorFileWriter::create( destination, newFields, geometryType, crs, context.transformContext(), saveOptions, sinkFlags, &finalFileName, &finalLayerName ) );
963 if ( writer->hasError() )
964 {
965 throw QgsProcessingException( QObject::tr( "Could not create layer %1: %2" ).arg( destination, writer->errorMessage() ) );
966 }
967
968 if ( QgsProcessingFeedback *feedback = context.feedback() )
969 {
970 for ( const QgsField &field : fields )
971 {
972 if ( !field.alias().isEmpty() && !( writer->capabilities() & Qgis::VectorFileWriterCapability::FieldAliases ) )
973 feedback->pushWarning( QObject::tr( "%1: Aliases are not supported by %2" ).arg( field.name(), writer->driverLongName() ) );
974 if ( !field.alias().isEmpty() && !( writer->capabilities() & Qgis::VectorFileWriterCapability::FieldComments ) )
975 feedback->pushWarning( QObject::tr( "%1: Comments are not supported by %2" ).arg( field.name(), writer->driverLongName() ) );
976 }
977 }
978
979 destination = finalFileName;
980 if ( !saveOptions.layerName.isEmpty() && !finalLayerName.isEmpty() )
981 destination += QStringLiteral( "|layername=%1" ).arg( finalLayerName );
982
983 if ( remappingDefinition )
984 {
985 std::unique_ptr< QgsRemappingProxyFeatureSink > remapSink = std::make_unique< QgsRemappingProxyFeatureSink >( *remappingDefinition, writer.release(), true );
986 remapSink->setExpressionContext( context.expressionContext() );
987 remapSink->setTransformContext( context.transformContext() );
988 return new QgsProcessingFeatureSink( remapSink.release(), destination, context, true );
989 }
990 else
991 return new QgsProcessingFeatureSink( writer.release(), destination, context, true );
992 }
993 else
994 {
995 const QgsVectorLayer::LayerOptions layerOptions { context.transformContext() };
996 if ( remappingDefinition )
997 {
998 //write to existing layer
999
1000 // use destination string as layer name (eg "postgis:..." )
1001 if ( !layerName.isEmpty() )
1002 {
1003 QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( providerKey, uri );
1004 parts.insert( QStringLiteral( "layerName" ), layerName );
1005 uri = QgsProviderRegistry::instance()->encodeUri( providerKey, parts );
1006 }
1007
1008 std::unique_ptr< QgsVectorLayer > layer = std::make_unique<QgsVectorLayer>( uri, destination, providerKey, layerOptions );
1009 // update destination to layer ID
1010 destination = layer->id();
1011 if ( layer->isValid() )
1012 {
1013 remappingDefinition->setDestinationWkbType( layer->wkbType() );
1014 remappingDefinition->setDestinationCrs( layer->crs() );
1015 remappingDefinition->setDestinationFields( layer->fields() );
1016 }
1017
1018 if ( QgsProcessingFeedback *feedback = context.feedback() )
1019 {
1020 const Qgis::VectorDataProviderAttributeEditCapabilities capabilities = layer->dataProvider() ? layer->dataProvider()->attributeEditCapabilities() : Qgis::VectorDataProviderAttributeEditCapabilities();
1021 for ( const QgsField &field : fields )
1022 {
1023 if ( !field.alias().isEmpty() && !( capabilities & Qgis::VectorDataProviderAttributeEditCapability::EditAlias ) )
1024 feedback->pushWarning( QObject::tr( "%1: Aliases are not supported by the %2 provider" ).arg( field.name(), providerKey ) );
1025 if ( !field.alias().isEmpty() && !( capabilities & Qgis::VectorDataProviderAttributeEditCapability::EditComment ) )
1026 feedback->pushWarning( QObject::tr( "%1: Comments are not supported by the %2 provider" ).arg( field.name(), providerKey ) );
1027 }
1028 }
1029
1030 std::unique_ptr< QgsRemappingProxyFeatureSink > remapSink = std::make_unique< QgsRemappingProxyFeatureSink >( *remappingDefinition, layer->dataProvider(), false );
1031 context.temporaryLayerStore()->addMapLayer( layer.release() );
1032 remapSink->setExpressionContext( context.expressionContext() );
1033 remapSink->setTransformContext( context.transformContext() );
1034 context.expressionContext().setFields( fields );
1035 return new QgsProcessingFeatureSink( remapSink.release(), destination, context, true );
1036 }
1037 else
1038 {
1039 //create empty layer
1040 std::unique_ptr< QgsVectorLayerExporter > exporter = std::make_unique<QgsVectorLayerExporter>( uri, providerKey, newFields, geometryType, crs, true, options, sinkFlags );
1041 if ( exporter->errorCode() != Qgis::VectorExportResult::Success )
1042 {
1043 throw QgsProcessingException( QObject::tr( "Could not create layer %1: %2" ).arg( destination, exporter->errorMessage() ) );
1044 }
1045
1046 // use destination string as layer name (eg "postgis:..." )
1047 if ( !layerName.isEmpty() )
1048 {
1049 uri += QStringLiteral( "|layername=%1" ).arg( layerName );
1050 // update destination to generated URI
1051 destination = uri;
1052 }
1053
1054 if ( QgsProcessingFeedback *feedback = context.feedback() )
1055 {
1056 for ( const QgsField &field : fields )
1057 {
1058 if ( !field.alias().isEmpty() && !( exporter->attributeEditCapabilities() & Qgis::VectorDataProviderAttributeEditCapability::EditAlias ) )
1059 feedback->pushWarning( QObject::tr( "%1: Aliases are not supported by the %2 provider" ).arg( field.name(), providerKey ) );
1060 if ( !field.alias().isEmpty() && !( exporter->attributeEditCapabilities() & Qgis::VectorDataProviderAttributeEditCapability::EditComment ) )
1061 feedback->pushWarning( QObject::tr( "%1: Comments are not supported by the %2 provider" ).arg( field.name(), providerKey ) );
1062 }
1063 }
1064
1065 return new QgsProcessingFeatureSink( exporter.release(), destination, context, true );
1066 }
1067 }
1068 }
1069}
1070
1071void QgsProcessingUtils::createFeatureSinkPython( QgsFeatureSink **sink, QString &destination, QgsProcessingContext &context, const QgsFields &fields, Qgis::WkbType geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &options )
1072{
1073 *sink = createFeatureSink( destination, context, fields, geometryType, crs, options );
1074}
1075
1076
1078{
1079 QgsRectangle extent;
1080 for ( const QgsMapLayer *layer : layers )
1081 {
1082 if ( !layer )
1083 continue;
1084
1085 if ( crs.isValid() )
1086 {
1087 //transform layer extent to target CRS
1088 QgsCoordinateTransform ct( layer->crs(), crs, context.transformContext() );
1090 try
1091 {
1092 QgsRectangle reprojExtent = ct.transformBoundingBox( layer->extent() );
1093 extent.combineExtentWith( reprojExtent );
1094 }
1095 catch ( QgsCsException & )
1096 {
1097 // can't reproject... what to do here? hmmm?
1098 // let's ignore this layer for now, but maybe we should just use the original extent?
1099 }
1100 }
1101 else
1102 {
1103 extent.combineExtentWith( layer->extent() );
1104 }
1105
1106 }
1107 return extent;
1108}
1109
1110// Deprecated
1112{
1113 QgsProcessingContext context;
1114 return QgsProcessingUtils::combineLayerExtents( layers, crs, context );
1115}
1116
1117QVariant QgsProcessingUtils::generateIteratingDestination( const QVariant &input, const QVariant &id, QgsProcessingContext &context )
1118{
1119 if ( !input.isValid() )
1120 return QStringLiteral( "memory:%1" ).arg( id.toString() );
1121
1122 if ( input.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
1123 {
1124 QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( input );
1125 QVariant newSink = generateIteratingDestination( fromVar.sink, id, context );
1126 fromVar.sink = QgsProperty::fromValue( newSink );
1127 return fromVar;
1128 }
1129 else if ( input.userType() == QMetaType::type( "QgsProperty" ) )
1130 {
1131 QString res = input.value< QgsProperty>().valueAsString( context.expressionContext() );
1132 return generateIteratingDestination( res, id, context );
1133 }
1134 else
1135 {
1136 QString res = input.toString();
1138 {
1139 // temporary outputs map to temporary outputs!
1141 }
1142 else if ( res.startsWith( QLatin1String( "memory:" ) ) )
1143 {
1144 return QString( res + '_' + id.toString() );
1145 }
1146 else
1147 {
1148 // assume a filename type output for now
1149 // TODO - uris?
1150 int lastIndex = res.lastIndexOf( '.' );
1151 return lastIndex >= 0 ? QString( res.left( lastIndex ) + '_' + id.toString() + res.mid( lastIndex ) ) : QString( res + '_' + id.toString() );
1152 }
1153 }
1154}
1155
1157{
1158 // we maintain a list of temporary folders -- this allows us to append additional
1159 // folders when a setting change causes the base temp folder to change, while deferring
1160 // cleanup of ALL these temp folders until session end (we can't cleanup older folders immediately,
1161 // because we don't know whether they have data in them which is still wanted)
1162 static std::vector< std::unique_ptr< QTemporaryDir > > sTempFolders;
1163 static QString sFolder;
1164 static QMutex sMutex;
1165 QMutexLocker locker( &sMutex );
1166 QString basePath;
1167
1168 if ( context )
1169 basePath = context->temporaryFolder();
1170 if ( basePath.isEmpty() )
1172
1173 if ( basePath.isEmpty() )
1174 {
1175 // default setting -- automatically create a temp folder
1176 if ( sTempFolders.empty() )
1177 {
1178 const QString templatePath = QStringLiteral( "%1/processing_XXXXXX" ).arg( QDir::tempPath() );
1179 std::unique_ptr< QTemporaryDir > tempFolder = std::make_unique< QTemporaryDir >( templatePath );
1180 sFolder = tempFolder->path();
1181 sTempFolders.emplace_back( std::move( tempFolder ) );
1182 }
1183 }
1184 else if ( sFolder.isEmpty() || !sFolder.startsWith( basePath ) || sTempFolders.empty() )
1185 {
1186 if ( !QDir().exists( basePath ) )
1187 QDir().mkpath( basePath );
1188
1189 const QString templatePath = QStringLiteral( "%1/processing_XXXXXX" ).arg( basePath );
1190 std::unique_ptr< QTemporaryDir > tempFolder = std::make_unique< QTemporaryDir >( templatePath );
1191 sFolder = tempFolder->path();
1192 sTempFolders.emplace_back( std::move( tempFolder ) );
1193 }
1194 return sFolder;
1195}
1196
1197QString QgsProcessingUtils::generateTempFilename( const QString &basename, const QgsProcessingContext *context )
1198{
1199 QString subPath = QUuid::createUuid().toString().remove( '-' ).remove( '{' ).remove( '}' );
1200 QString path = tempFolder( context ) + '/' + subPath;
1201 if ( !QDir( path ).exists() ) //make sure the directory exists - it shouldn't, but lets be safe...
1202 {
1203 QDir tmpDir;
1204 tmpDir.mkdir( path );
1205 }
1206 return path + '/' + QgsFileUtils::stringToSafeFilename( basename );
1207}
1208
1210{
1211 auto getText = [map]( const QString & key )->QString
1212 {
1213 if ( map.contains( key ) )
1214 return map.value( key ).toString();
1215 return QString();
1216 };
1217
1218 QString s;
1219 s += QStringLiteral( "<html><body><p>" ) + getText( QStringLiteral( "ALG_DESC" ) ) + QStringLiteral( "</p>\n" );
1220
1221 QString inputs;
1222 const auto parameterDefinitions = algorithm->parameterDefinitions();
1223 for ( const QgsProcessingParameterDefinition *def : parameterDefinitions )
1224 {
1225 if ( def->flags() & QgsProcessingParameterDefinition::FlagHidden || def->isDestination() )
1226 continue;
1227
1228 if ( !getText( def->name() ).isEmpty() )
1229 {
1230 inputs += QStringLiteral( "<h3>" ) + def->description() + QStringLiteral( "</h3>\n" );
1231 inputs += QStringLiteral( "<p>" ) + getText( def->name() ) + QStringLiteral( "</p>\n" );
1232 }
1233 }
1234 if ( !inputs.isEmpty() )
1235 s += QStringLiteral( "<h2>" ) + QObject::tr( "Input parameters" ) + QStringLiteral( "</h2>\n" ) + inputs;
1236
1237 QString outputs;
1238 const auto outputDefinitions = algorithm->outputDefinitions();
1239 for ( const QgsProcessingOutputDefinition *def : outputDefinitions )
1240 {
1241 if ( !getText( def->name() ).isEmpty() )
1242 {
1243 outputs += QStringLiteral( "<h3>" ) + def->description() + QStringLiteral( "</h3>\n" );
1244 outputs += QStringLiteral( "<p>" ) + getText( def->name() ) + QStringLiteral( "</p>\n" );
1245 }
1246 }
1247 if ( !outputs.isEmpty() )
1248 s += QStringLiteral( "<h2>" ) + QObject::tr( "Outputs" ) + QStringLiteral( "</h2>\n" ) + outputs;
1249
1250 if ( !map.value( QStringLiteral( "EXAMPLES" ) ).toString().isEmpty() )
1251 s += QStringLiteral( "<h2>%1</h2>\n<p>%2</p>" ).arg( QObject::tr( "Examples" ), getText( QStringLiteral( "EXAMPLES" ) ) );
1252
1253 s += QLatin1String( "<br>" );
1254 if ( !map.value( QStringLiteral( "ALG_CREATOR" ) ).toString().isEmpty() )
1255 s += QStringLiteral( "<p align=\"right\">" ) + QObject::tr( "Algorithm author:" ) + QStringLiteral( " " ) + getText( QStringLiteral( "ALG_CREATOR" ) ) + QStringLiteral( "</p>" );
1256 if ( !map.value( QStringLiteral( "ALG_HELP_CREATOR" ) ).toString().isEmpty() )
1257 s += QStringLiteral( "<p align=\"right\">" ) + QObject::tr( "Help author:" ) + QStringLiteral( " " ) + getText( QStringLiteral( "ALG_HELP_CREATOR" ) ) + QStringLiteral( "</p>" );
1258 if ( !map.value( QStringLiteral( "ALG_VERSION" ) ).toString().isEmpty() )
1259 s += QStringLiteral( "<p align=\"right\">" ) + QObject::tr( "Algorithm version:" ) + QStringLiteral( " " ) + getText( QStringLiteral( "ALG_VERSION" ) ) + QStringLiteral( "</p>" );
1260
1261 s += QLatin1String( "</body></html>" );
1262 return s;
1263}
1264
1265QString convertToCompatibleFormatInternal( const QgsVectorLayer *vl, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback, QString *layerName,
1266 long long featureLimit, const QString &filterExpression )
1267{
1268 bool requiresTranslation = false;
1269
1270 // if we are only looking for selected features then we have to export back to disk,
1271 // as we need to subset only selected features, a concept which doesn't exist outside QGIS!
1272 requiresTranslation = requiresTranslation || selectedFeaturesOnly;
1273
1274 // if we are limiting the feature count, we better export
1275 requiresTranslation = requiresTranslation || featureLimit != -1 || !filterExpression.isEmpty();
1276
1277 // if the data provider is NOT ogr, then we HAVE to convert. Otherwise we run into
1278 // issues with data providers like spatialite, delimited text where the format can be
1279 // opened outside of QGIS, but with potentially very different behavior!
1280 requiresTranslation = requiresTranslation || vl->providerType() != QLatin1String( "ogr" );
1281
1282 // if the layer has a feature filter set, then we HAVE to convert. Feature filters are
1283 // a purely QGIS concept.
1284 requiresTranslation = requiresTranslation || !vl->subsetString().isEmpty();
1285
1286 // if the layer opened using GDAL's virtual I/O mechanism (/vsizip/, etc.), then
1287 // we HAVE to convert as other tools may not work with it
1288 requiresTranslation = requiresTranslation || vl->source().startsWith( QLatin1String( "/vsi" ) );
1289
1290 // Check if layer is a disk based format and if so if the layer's path has a compatible filename suffix
1291 QString diskPath;
1292 if ( !requiresTranslation )
1293 {
1294 const QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( vl->providerType(), vl->source() );
1295 if ( parts.contains( QStringLiteral( "path" ) ) )
1296 {
1297 diskPath = parts.value( QStringLiteral( "path" ) ).toString();
1298 QFileInfo fi( diskPath );
1299 requiresTranslation = !compatibleFormats.contains( fi.suffix(), Qt::CaseInsensitive );
1300
1301 // if the layer name doesn't match the filename, we need to convert the layer. This method can only return
1302 // a filename, and cannot handle layernames as well as file paths
1303 const QString srcLayerName = parts.value( QStringLiteral( "layerName" ) ).toString();
1304 if ( layerName )
1305 {
1306 // differing layer names are acceptable
1307 *layerName = srcLayerName;
1308 }
1309 else
1310 {
1311 // differing layer names are NOT acceptable
1312 requiresTranslation = requiresTranslation || ( !srcLayerName.isEmpty() && srcLayerName != fi.baseName() );
1313 }
1314 }
1315 else
1316 {
1317 requiresTranslation = true; // not a disk-based format
1318 }
1319 }
1320
1321 if ( requiresTranslation )
1322 {
1323 QString temp = QgsProcessingUtils::generateTempFilename( baseName + '.' + preferredFormat, &context );
1324
1326 saveOptions.fileEncoding = context.defaultEncoding();
1327 saveOptions.driverName = QgsVectorFileWriter::driverForExtension( preferredFormat );
1328 std::unique_ptr< QgsVectorFileWriter > writer( QgsVectorFileWriter::create( temp, vl->fields(), vl->wkbType(), vl->crs(), context.transformContext(), saveOptions ) );
1329 QgsFeature f;
1331 QgsFeatureRequest request;
1332 if ( featureLimit != -1 )
1333 {
1334 request.setLimit( featureLimit );
1335 }
1336 if ( !filterExpression.isEmpty() )
1337 {
1338 request.setFilterExpression( filterExpression );
1339 }
1340
1341 if ( selectedFeaturesOnly )
1342 it = vl->getSelectedFeatures( request );
1343 else
1344 it = vl->getFeatures( request );
1345
1346 while ( it.nextFeature( f ) )
1347 {
1348 if ( feedback->isCanceled() )
1349 return QString();
1350 writer->addFeature( f, QgsFeatureSink::FastInsert );
1351 }
1352 return temp;
1353 }
1354 else
1355 {
1356 return diskPath;
1357 }
1358}
1359
1360QString 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 )
1361{
1362 return convertToCompatibleFormatInternal( vl, selectedFeaturesOnly, baseName, compatibleFormats, preferredFormat, context, feedback, nullptr, featureLimit, filterExpression );
1363}
1364
1365QString 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 )
1366{
1367 layerName.clear();
1368 return convertToCompatibleFormatInternal( layer, selectedFeaturesOnly, baseName, compatibleFormats, preferredFormat, context, feedback, &layerName, featureLimit, filterExpression );
1369}
1370
1371QgsFields QgsProcessingUtils::combineFields( const QgsFields &fieldsA, const QgsFields &fieldsB, const QString &fieldsBPrefix )
1372{
1373 QgsFields outFields = fieldsA;
1374 QSet< QString > usedNames;
1375 for ( const QgsField &f : fieldsA )
1376 {
1377 usedNames.insert( f.name().toLower() );
1378 }
1379
1380 for ( const QgsField &f : fieldsB )
1381 {
1382 QgsField newField = f;
1383 newField.setName( fieldsBPrefix + f.name() );
1384 if ( usedNames.contains( newField.name().toLower() ) )
1385 {
1386 int idx = 2;
1387 QString newName = newField.name() + '_' + QString::number( idx );
1388 while ( usedNames.contains( newName.toLower() ) || fieldsB.indexOf( newName ) != -1 )
1389 {
1390 idx++;
1391 newName = newField.name() + '_' + QString::number( idx );
1392 }
1393 newField.setName( newName );
1394 outFields.append( newField );
1395 }
1396 else
1397 {
1398 outFields.append( newField );
1399 }
1400 usedNames.insert( newField.name() );
1401 }
1402
1403 return outFields;
1404}
1405
1406
1407QList<int> QgsProcessingUtils::fieldNamesToIndices( const QStringList &fieldNames, const QgsFields &fields )
1408{
1409 QList<int> indices;
1410 if ( !fieldNames.isEmpty() )
1411 {
1412 indices.reserve( fieldNames.count() );
1413 for ( const QString &f : fieldNames )
1414 {
1415 int idx = fields.lookupField( f );
1416 if ( idx >= 0 )
1417 indices.append( idx );
1418 }
1419 }
1420 else
1421 {
1422 indices.reserve( fields.count() );
1423 for ( int i = 0; i < fields.count(); ++i )
1424 indices.append( i );
1425 }
1426 return indices;
1427}
1428
1429
1430QgsFields QgsProcessingUtils::indicesToFields( const QList<int> &indices, const QgsFields &fields )
1431{
1432 QgsFields fieldsSubset;
1433 for ( int i : indices )
1434 fieldsSubset.append( fields.at( i ) );
1435 return fieldsSubset;
1436}
1437
1439{
1441 if ( setting == -1 )
1442 return QStringLiteral( "gpkg" );
1443 return QgsVectorFileWriter::supportedFormatExtensions().value( setting, QStringLiteral( "gpkg" ) );
1444}
1445
1447{
1449 if ( setting == -1 )
1450 return QStringLiteral( "tif" );
1451 return QgsRasterFileWriter::supportedFormatExtensions().value( setting, QStringLiteral( "tif" ) );
1452}
1453
1455{
1456 return QStringLiteral( "las" );
1457}
1458
1460{
1461 return QStringLiteral( "mbtiles" );
1462}
1463
1464QVariantMap QgsProcessingUtils::removePointerValuesFromMap( const QVariantMap &map )
1465{
1466 auto layerPointerToString = []( QgsMapLayer * layer ) -> QString
1467 {
1468 if ( layer && layer->providerType() == QLatin1String( "memory" ) )
1469 return layer->id();
1470 else if ( layer )
1471 return layer->source();
1472 else
1473 return QString();
1474 };
1475
1476 auto cleanPointerValues = [&layerPointerToString]( const QVariant & value ) -> QVariant
1477 {
1478 if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( value.value< QObject * >() ) )
1479 {
1480 // don't store pointers in maps for long-term storage
1481 return layerPointerToString( layer );
1482 }
1483 else if ( value.userType() == QMetaType::type( "QPointer< QgsMapLayer >" ) )
1484 {
1485 // don't store pointers in maps for long-term storage
1486 return layerPointerToString( value.value< QPointer< QgsMapLayer > >().data() );
1487 }
1488 else
1489 {
1490 return value;
1491 }
1492 };
1493
1494 QVariantMap res;
1495 for ( auto it = map.constBegin(); it != map.constEnd(); ++it )
1496 {
1497 if ( it->type() == QVariant::Map )
1498 {
1499 res.insert( it.key(), removePointerValuesFromMap( it.value().toMap() ) );
1500 }
1501 else if ( it->type() == QVariant::List )
1502 {
1503 QVariantList dest;
1504 const QVariantList source = it.value().toList();
1505 dest.reserve( source.size() );
1506 for ( const QVariant &v : source )
1507 {
1508 dest.append( cleanPointerValues( v ) );
1509 }
1510 res.insert( it.key(), dest );
1511 }
1512 else
1513 {
1514 res.insert( it.key(), cleanPointerValues( it.value() ) );
1515 }
1516 }
1517 return res;
1518}
1519
1520QVariantMap QgsProcessingUtils::preprocessQgisProcessParameters( const QVariantMap &parameters, bool &ok, QString &error )
1521{
1522 QVariantMap output;
1523 ok = true;
1524 for ( auto it = parameters.constBegin(); it != parameters.constEnd(); ++it )
1525 {
1526 if ( it.value().type() == QVariant::Map )
1527 {
1528 const QVariantMap value = it.value().toMap();
1529 if ( value.value( QStringLiteral( "type" ) ).toString() == QLatin1String( "data_defined" ) )
1530 {
1531 const QString expression = value.value( QStringLiteral( "expression" ) ).toString();
1532 const QString field = value.value( QStringLiteral( "field" ) ).toString();
1533 if ( !expression.isEmpty() )
1534 {
1535 output.insert( it.key(), QgsProperty::fromExpression( expression ) );
1536 }
1537 else if ( !field.isEmpty() )
1538 {
1539 output.insert( it.key(), QgsProperty::fromField( field ) );
1540 }
1541 else
1542 {
1543 ok = false;
1544 error = QObject::tr( "Invalid data defined parameter for %1, requires 'expression' or 'field' values." ).arg( it.key() );
1545 }
1546 }
1547 else
1548 {
1549 output.insert( it.key(), it.value() );
1550 }
1551 }
1552 else if ( it.value().type() == QVariant::String )
1553 {
1554 const QString stringValue = it.value().toString();
1555
1556 if ( stringValue.startsWith( QLatin1String( "field:" ) ) )
1557 {
1558 output.insert( it.key(), QgsProperty::fromField( stringValue.mid( 6 ) ) );
1559 }
1560 else if ( stringValue.startsWith( QLatin1String( "expression:" ) ) )
1561 {
1562 output.insert( it.key(), QgsProperty::fromExpression( stringValue.mid( 11 ) ) );
1563 }
1564 else
1565 {
1566 output.insert( it.key(), it.value() );
1567 }
1568 }
1569 else
1570 {
1571 output.insert( it.key(), it.value() );
1572 }
1573 }
1574 return output;
1575}
1576
1577QString QgsProcessingUtils::resolveDefaultEncoding( const QString &defaultEncoding )
1578{
1579 if ( ! QTextCodec::availableCodecs().contains( defaultEncoding.toLatin1() ) )
1580 {
1581 const QString systemCodec = QTextCodec::codecForLocale()->name();
1582 if ( ! systemCodec.isEmpty() )
1583 {
1584 return systemCodec;
1585 }
1586 return QString( "UTF-8" );
1587 }
1588
1589 return defaultEncoding;
1590}
1591
1592//
1593// QgsProcessingFeatureSource
1594//
1595
1596QgsProcessingFeatureSource::QgsProcessingFeatureSource( QgsFeatureSource *originalSource, const QgsProcessingContext &context, bool ownsOriginalSource, long long featureLimit, const QString &filterExpression )
1597 : mSource( originalSource )
1598 , mOwnsSource( ownsOriginalSource )
1599 , mSourceCrs( mSource->sourceCrs() )
1600 , mSourceFields( mSource->fields() )
1601 , mSourceWkbType( mSource->wkbType() )
1602 , mSourceName( mSource->sourceName() )
1603 , mSourceExtent( mSource->sourceExtent() )
1604 , mSourceSpatialIndexPresence( mSource->hasSpatialIndex() )
1605 , mInvalidGeometryCheck( QgsWkbTypes::geometryType( mSource->wkbType() ) == Qgis::GeometryType::Point
1606 ? QgsFeatureRequest::GeometryNoCheck // never run geometry validity checks for point layers!
1607 : context.invalidGeometryCheck() )
1608 , mInvalidGeometryCallback( context.invalidGeometryCallback( originalSource ) )
1609 , mTransformErrorCallback( context.transformErrorCallback() )
1610 , mInvalidGeometryCallbackSkip( context.defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::GeometrySkipInvalid, originalSource ) )
1611 , mInvalidGeometryCallbackAbort( context.defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::GeometryAbortOnInvalid, originalSource ) )
1612 , mFeatureLimit( featureLimit )
1613 , mFilterExpression( filterExpression )
1614{}
1615
1617{
1618 if ( mOwnsSource )
1619 delete mSource;
1620}
1621
1623{
1624 QgsFeatureRequest req( request );
1625 req.setTransformErrorCallback( mTransformErrorCallback );
1626
1627 if ( flags & FlagSkipGeometryValidityChecks )
1629 else
1630 {
1631 req.setInvalidGeometryCheck( mInvalidGeometryCheck );
1632 req.setInvalidGeometryCallback( mInvalidGeometryCallback );
1633 }
1634
1635 if ( mFeatureLimit != -1 && req.limit() != -1 )
1636 req.setLimit( std::min( static_cast< long long >( req.limit() ), mFeatureLimit ) );
1637 else if ( mFeatureLimit != -1 )
1638 req.setLimit( mFeatureLimit );
1639
1640 if ( !mFilterExpression.isEmpty() )
1641 req.combineFilterExpression( mFilterExpression );
1642
1643 return mSource->getFeatures( req );
1644}
1645
1647{
1648 FeatureAvailability sourceAvailability = mSource->hasFeatures();
1649 if ( sourceAvailability == NoFeaturesAvailable )
1650 return NoFeaturesAvailable; // never going to be features if underlying source has no features
1651 else if ( mInvalidGeometryCheck == QgsFeatureRequest::GeometryNoCheck && mFilterExpression.isEmpty() )
1652 return sourceAvailability;
1653 else
1654 // we don't know... source has features, but these may be filtered out by invalid geometry check or filter expression
1656}
1657
1659{
1660 QgsFeatureRequest req( request );
1661 req.setInvalidGeometryCheck( mInvalidGeometryCheck );
1662 req.setInvalidGeometryCallback( mInvalidGeometryCallback );
1663 req.setTransformErrorCallback( mTransformErrorCallback );
1664
1665 if ( mFeatureLimit != -1 && req.limit() != -1 )
1666 req.setLimit( std::min( static_cast< long long >( req.limit() ), mFeatureLimit ) );
1667 else if ( mFeatureLimit != -1 )
1668 req.setLimit( mFeatureLimit );
1669
1670 if ( !mFilterExpression.isEmpty() )
1671 req.combineFilterExpression( mFilterExpression );
1672
1673 return mSource->getFeatures( req );
1674}
1675
1680
1682{
1683 return mSourceFields;
1684}
1685
1687{
1688 return mSourceWkbType;
1689}
1690
1692{
1693 if ( !mFilterExpression.isEmpty() )
1694 return static_cast< int >( Qgis::FeatureCountState::UnknownCount );
1695
1696 if ( mFeatureLimit == -1 )
1697 return mSource->featureCount();
1698 else
1699 return std::min( mFeatureLimit, mSource->featureCount() );
1700}
1701
1703{
1704 return mSourceName;
1705}
1706
1707QSet<QVariant> QgsProcessingFeatureSource::uniqueValues( int fieldIndex, int limit ) const
1708{
1709 if ( mFilterExpression.isEmpty() )
1710 return mSource->uniqueValues( fieldIndex, limit );
1711
1712 // inefficient method when filter expression in use
1713 // TODO QGIS 4.0 -- add filter expression to virtual ::uniqueValues function
1714 if ( fieldIndex < 0 || fieldIndex >= fields().count() )
1715 return QSet<QVariant>();
1716
1719 req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
1720 req.setFilterExpression( mFilterExpression );
1721
1722 QSet<QVariant> values;
1723 QgsFeatureIterator it = getFeatures( req );
1724 QgsFeature f;
1725 while ( it.nextFeature( f ) )
1726 {
1727 values.insert( f.attribute( fieldIndex ) );
1728 if ( limit > 0 && values.size() >= limit )
1729 return values;
1730 }
1731 return values;
1732}
1733
1734QVariant QgsProcessingFeatureSource::minimumValue( int fieldIndex ) const
1735{
1736 if ( mFilterExpression.isEmpty() )
1737 return mSource->minimumValue( fieldIndex );
1738
1739 // inefficient method when filter expression in use
1740 // TODO QGIS 4.0 -- add filter expression to virtual ::minimumValue function
1741 if ( fieldIndex < 0 || fieldIndex >= fields().count() )
1742 return QVariant();
1743
1746 req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
1747
1748 QVariant min;
1749 QgsFeatureIterator it = getFeatures( req );
1750 QgsFeature f;
1751 while ( it.nextFeature( f ) )
1752 {
1753 const QVariant v = f.attribute( fieldIndex );
1754 if ( !QgsVariantUtils::isNull( v ) && ( qgsVariantLessThan( v, min ) || QgsVariantUtils::isNull( min ) ) )
1755 {
1756 min = v;
1757 }
1758 }
1759 return min;
1760}
1761
1762QVariant QgsProcessingFeatureSource::maximumValue( int fieldIndex ) const
1763{
1764 if ( mFilterExpression.isEmpty() )
1765 return mSource->maximumValue( fieldIndex );
1766
1767 // inefficient method when filter expression in use
1768 // TODO QGIS 4.0 -- add filter expression to virtual ::maximumValue function
1769 if ( fieldIndex < 0 || fieldIndex >= fields().count() )
1770 return QVariant();
1771
1774 req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
1775
1776 QVariant max;
1777 QgsFeatureIterator it = getFeatures( req );
1778 QgsFeature f;
1779 while ( it.nextFeature( f ) )
1780 {
1781 const QVariant v = f.attribute( fieldIndex );
1782 if ( !QgsVariantUtils::isNull( v ) && ( qgsVariantGreaterThan( v, max ) || QgsVariantUtils::isNull( max ) ) )
1783 {
1784 max = v;
1785 }
1786 }
1787 return max;
1788}
1789
1791{
1792 return mSourceExtent;
1793}
1794
1796{
1797 if ( mFilterExpression.isEmpty() )
1798 return mSource->allFeatureIds();
1799
1802 .setNoAttributes()
1803 .setFilterExpression( mFilterExpression ) );
1804
1805 QgsFeatureIds ids;
1806
1807 QgsFeature fet;
1808 while ( fit.nextFeature( fet ) )
1809 {
1810 ids << fet.id();
1811 }
1812
1813 return ids;
1814}
1815
1817{
1818 return mSourceSpatialIndexPresence;
1819}
1820
1822{
1823 QgsExpressionContextScope *expressionContextScope = nullptr;
1824 QgsExpressionContextScopeGenerator *generator = dynamic_cast<QgsExpressionContextScopeGenerator *>( mSource );
1825 if ( generator )
1826 {
1827 expressionContextScope = generator->createExpressionContextScope();
1828 }
1829 return expressionContextScope;
1830}
1831
1833{
1834 mInvalidGeometryCheck = method;
1835 switch ( mInvalidGeometryCheck )
1836 {
1838 mInvalidGeometryCallback = nullptr;
1839 break;
1840
1842 mInvalidGeometryCallback = mInvalidGeometryCallbackSkip;
1843 break;
1844
1846 mInvalidGeometryCallback = mInvalidGeometryCallbackAbort;
1847 break;
1848
1849 }
1850}
1851
1852
1853//
1854// QgsProcessingFeatureSink
1855//
1856QgsProcessingFeatureSink::QgsProcessingFeatureSink( QgsFeatureSink *originalSink, const QString &sinkName, QgsProcessingContext &context, bool ownsOriginalSink )
1857 : QgsProxyFeatureSink( originalSink )
1858 , mContext( context )
1859 , mSinkName( sinkName )
1860 , mOwnsSink( ownsOriginalSink )
1861{}
1862
1864{
1865 if ( mOwnsSink )
1866 delete destinationSink();
1867}
1868
1869bool QgsProcessingFeatureSink::addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags )
1870{
1871 bool result = QgsProxyFeatureSink::addFeature( feature, flags );
1872 if ( !result && mContext.feedback() )
1873 {
1874 const QString error = lastError();
1875 if ( !error.isEmpty() )
1876 mContext.feedback()->reportError( QObject::tr( "Feature could not be written to %1: %2" ).arg( mSinkName, error ) );
1877 else
1878 mContext.feedback()->reportError( QObject::tr( "Feature could not be written to %1" ).arg( mSinkName ) );
1879 }
1880 return result;
1881}
1882
1883bool QgsProcessingFeatureSink::addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags )
1884{
1885 bool result = QgsProxyFeatureSink::addFeatures( features, flags );
1886 if ( !result && mContext.feedback() )
1887 {
1888 const QString error = lastError();
1889 if ( !error.isEmpty() )
1890 mContext.feedback()->reportError( QObject::tr( "%n feature(s) could not be written to %1: %2", nullptr, features.count() ).arg( mSinkName, error ) );
1891 else
1892 mContext.feedback()->reportError( QObject::tr( "%n feature(s) could not be written to %1", nullptr, features.count() ).arg( mSinkName ) );
1893 }
1894 return result;
1895}
1896
1897bool QgsProcessingFeatureSink::addFeatures( QgsFeatureIterator &iterator, QgsFeatureSink::Flags flags )
1898{
1899 bool result = QgsProxyFeatureSink::addFeatures( iterator, flags );
1900 if ( !result && mContext.feedback() )
1901 {
1902 const QString error = lastError();
1903 if ( !error.isEmpty() )
1904 mContext.feedback()->reportError( QObject::tr( "Features could not be written to %1: %2" ).arg( mSinkName, error ) );
1905 else
1906 mContext.feedback()->reportError( QObject::tr( "Features could not be written to %1" ).arg( mSinkName ) );
1907 }
1908 return result;
1909}
The Qgis class provides global constants for use throughout the application.
Definition qgis.h:54
@ FieldComments
Writer can support field comments.
@ FieldAliases
Writer can support field aliases.
@ Success
No errors were encountered.
@ Polygon
Polygons.
@ 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.
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:182
@ 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)
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 & combineFilterExpression(const QString &expression)
Modifies the existing filter expression to add an additional expression filter.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
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 QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const
Returns the set of unique values contained within the specified fieldIndex from this source.
SpatialIndexPresence
Enumeration of spatial index presence states.
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 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:54
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:74
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:80
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: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.
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.
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...
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...
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.
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.
@ 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.
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 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 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.
@ 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.
@ 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.
@ 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...
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
Type propertyType() const
Returns the property type.
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.
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)
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:43
@ 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:4271
QList< QgsFeature > QgsFeatureList
Definition qgsfeature.h:920
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.