QGIS API Documentation 3.32.0-Lima (311a8cb8a6)
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 <QRegularExpression>
40#include <QUuid>
41
42QList<QgsRasterLayer *> QgsProcessingUtils::compatibleRasterLayers( QgsProject *project, bool sort )
43{
44 return compatibleMapLayers< QgsRasterLayer >( project, sort );
45}
46
47QList<QgsVectorLayer *> QgsProcessingUtils::compatibleVectorLayers( QgsProject *project, const QList<int> &geometryTypes, bool sort )
48{
49 if ( !project )
50 return QList<QgsVectorLayer *>();
51
52 QList<QgsVectorLayer *> layers;
53 const auto vectorLayers = project->layers<QgsVectorLayer *>();
54 for ( QgsVectorLayer *l : vectorLayers )
55 {
56 if ( canUseLayer( l, geometryTypes ) )
57 layers << l;
58 }
59
60 if ( sort )
61 {
62 std::sort( layers.begin(), layers.end(), []( const QgsVectorLayer * a, const QgsVectorLayer * b ) -> bool
63 {
64 return QString::localeAwareCompare( a->name(), b->name() ) < 0;
65 } );
66 }
67 return layers;
68}
69
70QList<QgsMeshLayer *> QgsProcessingUtils::compatibleMeshLayers( QgsProject *project, bool sort )
71{
72 return compatibleMapLayers< QgsMeshLayer >( project, sort );
73}
74
75QList<QgsPluginLayer *> QgsProcessingUtils::compatiblePluginLayers( QgsProject *project, bool sort )
76{
77 return compatibleMapLayers< QgsPluginLayer >( project, sort );
78}
79
80QList<QgsPointCloudLayer *> QgsProcessingUtils::compatiblePointCloudLayers( QgsProject *project, bool sort )
81{
82 return compatibleMapLayers< QgsPointCloudLayer >( project, sort );
83}
84
85QList<QgsAnnotationLayer *> QgsProcessingUtils::compatibleAnnotationLayers( QgsProject *project, bool sort )
86{
87 // we have to defer sorting until we've added the main annotation layer too
88 QList<QgsAnnotationLayer *> res = compatibleMapLayers< QgsAnnotationLayer >( project, false );
89 if ( project )
90 res.append( project->mainAnnotationLayer() );
91
92 if ( sort )
93 {
94 std::sort( res.begin(), res.end(), []( const QgsAnnotationLayer * a, const QgsAnnotationLayer * b ) -> bool
95 {
96 return QString::localeAwareCompare( a->name(), b->name() ) < 0;
97 } );
98 }
99
100 return res;
101}
102
103QList<QgsVectorTileLayer *> QgsProcessingUtils::compatibleVectorTileLayers( QgsProject *project, bool sort )
104{
105 return compatibleMapLayers< QgsVectorTileLayer >( project, sort );
106}
107
108template<typename T> QList<T *> QgsProcessingUtils::compatibleMapLayers( QgsProject *project, bool sort )
109{
110 if ( !project )
111 return QList<T *>();
112
113 QList<T *> layers;
114 const auto projectLayers = project->layers<T *>();
115 for ( T *l : projectLayers )
116 {
117 if ( canUseLayer( l ) )
118 layers << l;
119 }
120
121 if ( sort )
122 {
123 std::sort( layers.begin(), layers.end(), []( const T * a, const T * b ) -> bool
124 {
125 return QString::localeAwareCompare( a->name(), b->name() ) < 0;
126 } );
127 }
128 return layers;
129}
130
131QList<QgsMapLayer *> QgsProcessingUtils::compatibleLayers( QgsProject *project, bool sort )
132{
133 if ( !project )
134 return QList<QgsMapLayer *>();
135
136 QList<QgsMapLayer *> layers;
137
138 const auto rasterLayers = compatibleMapLayers< QgsRasterLayer >( project, false );
139 for ( QgsRasterLayer *rl : rasterLayers )
140 layers << rl;
141
142 const auto vectorLayers = compatibleVectorLayers( project, QList< int >(), false );
143 for ( QgsVectorLayer *vl : vectorLayers )
144 layers << vl;
145
146 const auto meshLayers = compatibleMapLayers< QgsMeshLayer >( project, false );
147 for ( QgsMeshLayer *ml : meshLayers )
148 layers << ml;
149
150 const auto pointCloudLayers = compatibleMapLayers< QgsPointCloudLayer >( project, false );
151 for ( QgsPointCloudLayer *pcl : pointCloudLayers )
152 layers << pcl;
153
154 const auto annotationLayers = compatibleMapLayers< QgsAnnotationLayer >( project, false );
155 for ( QgsAnnotationLayer *al : annotationLayers )
156 layers << al;
157 layers << project->mainAnnotationLayer();
158
159 const auto vectorTileLayers = compatibleMapLayers< QgsVectorTileLayer >( project, false );
160 for ( QgsVectorTileLayer *vtl : vectorTileLayers )
161 layers << vtl;
162
163 const auto pluginLayers = compatibleMapLayers< QgsPluginLayer >( project, false );
164 for ( QgsPluginLayer *pl : pluginLayers )
165 layers << pl;
166
167 if ( sort )
168 {
169 std::sort( layers.begin(), layers.end(), []( const QgsMapLayer * a, const QgsMapLayer * b ) -> bool
170 {
171 return QString::localeAwareCompare( a->name(), b->name() ) < 0;
172 } );
173 }
174 return layers;
175}
176
177QString QgsProcessingUtils::encodeProviderKeyAndUri( const QString &providerKey, const QString &uri )
178{
179 return QStringLiteral( "%1://%2" ).arg( providerKey, uri );
180}
181
182bool QgsProcessingUtils::decodeProviderKeyAndUri( const QString &string, QString &providerKey, QString &uri )
183{
184 const thread_local QRegularExpression re( QStringLiteral( "^(\\w+?):\\/\\/(.+)$" ) );
185 const QRegularExpressionMatch match = re.match( string );
186 if ( !match.hasMatch() )
187 return false;
188
189 providerKey = match.captured( 1 );
190 uri = match.captured( 2 );
191
192 // double check that provider is valid
193 return QgsProviderRegistry::instance()->providerMetadata( providerKey );
194}
195
196QgsMapLayer *QgsProcessingUtils::mapLayerFromStore( const QString &string, QgsMapLayerStore *store, QgsProcessingUtils::LayerHint typeHint )
197{
198 if ( !store || string.isEmpty() )
199 return nullptr;
200
201 QList< QgsMapLayer * > layers = store->mapLayers().values();
202
203 layers.erase( std::remove_if( layers.begin(), layers.end(), []( QgsMapLayer * layer )
204 {
205 switch ( layer->type() )
206 {
207 case Qgis::LayerType::Vector:
208 return !canUseLayer( qobject_cast< QgsVectorLayer * >( layer ) );
209 case Qgis::LayerType::Raster:
210 return !canUseLayer( qobject_cast< QgsRasterLayer * >( layer ) );
211 case Qgis::LayerType::Plugin:
212 case Qgis::LayerType::Group:
213 return true;
214 case Qgis::LayerType::Mesh:
215 return !canUseLayer( qobject_cast< QgsMeshLayer * >( layer ) );
216 case Qgis::LayerType::VectorTile:
217 return !canUseLayer( qobject_cast< QgsVectorTileLayer * >( layer ) );
218 case Qgis::LayerType::PointCloud:
219 return !canUseLayer( qobject_cast< QgsPointCloudLayer * >( layer ) );
220 case Qgis::LayerType::Annotation:
221 return !canUseLayer( qobject_cast< QgsAnnotationLayer * >( layer ) );
222 }
223 return true;
224 } ), layers.end() );
225
226 auto isCompatibleType = [typeHint]( QgsMapLayer * l ) -> bool
227 {
228 switch ( typeHint )
229 {
230 case LayerHint::UnknownType:
231 return true;
232
233 case LayerHint::Vector:
234 return l->type() == Qgis::LayerType::Vector;
235
236 case LayerHint::Raster:
237 return l->type() == Qgis::LayerType::Raster;
238
239 case LayerHint::Mesh:
240 return l->type() == Qgis::LayerType::Mesh;
241
242 case LayerHint::PointCloud:
243 return l->type() == Qgis::LayerType::PointCloud;
244
245 case LayerHint::Annotation:
246 return l->type() == Qgis::LayerType::Annotation;
247
248 case LayerHint::VectorTile:
249 return l->type() == Qgis::LayerType::VectorTile;
250 }
251 return true;
252 };
253
254 for ( QgsMapLayer *l : std::as_const( layers ) )
255 {
256 if ( isCompatibleType( l ) && l->id() == string )
257 return l;
258 }
259 for ( QgsMapLayer *l : std::as_const( layers ) )
260 {
261 if ( isCompatibleType( l ) && l->name() == string )
262 return l;
263 }
264 for ( QgsMapLayer *l : std::as_const( layers ) )
265 {
266 if ( isCompatibleType( l ) && normalizeLayerSource( l->source() ) == normalizeLayerSource( string ) )
267 return l;
268 }
269 return nullptr;
270}
271
272QgsMapLayer *QgsProcessingUtils::loadMapLayerFromString( const QString &string, const QgsCoordinateTransformContext &transformContext, LayerHint typeHint, QgsProcessing::LayerOptionsFlags flags )
273{
274 QString provider;
275 QString uri;
276 const bool useProvider = decodeProviderKeyAndUri( string, provider, uri );
277 if ( !useProvider )
278 uri = string;
279
280 QString name;
281 // for disk based sources, we use the filename to determine a layer name
282 if ( !useProvider || ( provider == QLatin1String( "ogr" ) || provider == QLatin1String( "gdal" ) || provider == QLatin1String( "mdal" ) || provider == QLatin1String( "pdal" ) || provider == QLatin1String( "ept" ) || provider == QLatin1String( "copc" ) ) )
283 {
284 QStringList components = uri.split( '|' );
285 if ( components.isEmpty() )
286 return nullptr;
287
288 QFileInfo fi;
289 if ( QFileInfo::exists( uri ) )
290 fi = QFileInfo( uri );
291 else if ( QFileInfo::exists( components.at( 0 ) ) )
292 fi = QFileInfo( components.at( 0 ) );
293 else
294 return nullptr;
295 name = fi.baseName();
296 }
297 else
298 {
299 name = QgsDataSourceUri( uri ).table();
300 }
301
302 // brute force attempt to load a matching layer
303 if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::Vector )
304 {
305 QgsVectorLayer::LayerOptions options { transformContext };
306 options.loadDefaultStyle = false;
307 options.skipCrsValidation = true;
308
309 std::unique_ptr< QgsVectorLayer > layer;
310 if ( useProvider )
311 {
312 layer = std::make_unique<QgsVectorLayer>( uri, name, provider, options );
313 }
314 else
315 {
316 // fallback to ogr
317 layer = std::make_unique<QgsVectorLayer>( uri, name, QStringLiteral( "ogr" ), options );
318 }
319 if ( layer->isValid() )
320 {
321 return layer.release();
322 }
323 }
324 if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::Raster )
325 {
326 QgsRasterLayer::LayerOptions rasterOptions;
327 rasterOptions.loadDefaultStyle = false;
328 rasterOptions.skipCrsValidation = true;
329
330 std::unique_ptr< QgsRasterLayer > rasterLayer;
331 if ( useProvider )
332 {
333 rasterLayer = std::make_unique< QgsRasterLayer >( uri, name, provider, rasterOptions );
334 }
335 else
336 {
337 // fallback to gdal
338 rasterLayer = std::make_unique< QgsRasterLayer >( uri, name, QStringLiteral( "gdal" ), rasterOptions );
339 }
340
341 if ( rasterLayer->isValid() )
342 {
343 return rasterLayer.release();
344 }
345 }
346 if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::Mesh )
347 {
348 QgsMeshLayer::LayerOptions meshOptions;
349 meshOptions.skipCrsValidation = true;
350
351 std::unique_ptr< QgsMeshLayer > meshLayer;
352 if ( useProvider )
353 {
354 meshLayer = std::make_unique< QgsMeshLayer >( uri, name, provider, meshOptions );
355 }
356 else
357 {
358 meshLayer = std::make_unique< QgsMeshLayer >( uri, name, QStringLiteral( "mdal" ), meshOptions );
359 }
360 if ( meshLayer->isValid() )
361 {
362 return meshLayer.release();
363 }
364 }
365 if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::PointCloud )
366 {
367 QgsPointCloudLayer::LayerOptions pointCloudOptions;
368 pointCloudOptions.skipCrsValidation = true;
369
371 {
372 pointCloudOptions.skipIndexGeneration = true;
373 }
374
375 std::unique_ptr< QgsPointCloudLayer > pointCloudLayer;
376 if ( useProvider )
377 {
378 pointCloudLayer = std::make_unique< QgsPointCloudLayer >( uri, name, provider, pointCloudOptions );
379 }
380 else
381 {
382 const QList< QgsProviderRegistry::ProviderCandidateDetails > preferredProviders = QgsProviderRegistry::instance()->preferredProvidersForUri( uri );
383 if ( !preferredProviders.empty() )
384 {
385 pointCloudLayer = std::make_unique< QgsPointCloudLayer >( uri, name, preferredProviders.at( 0 ).metadata()->key(), pointCloudOptions );
386 }
387 }
388 if ( pointCloudLayer && pointCloudLayer->isValid() )
389 {
390 return pointCloudLayer.release();
391 }
392 }
393 if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::VectorTile )
394 {
395 QgsDataSourceUri dsUri;
396 dsUri.setParam( "type", "mbtiles" );
397 dsUri.setParam( "url", uri );
398
399 std::unique_ptr< QgsVectorTileLayer > tileLayer;
400 tileLayer = std::make_unique< QgsVectorTileLayer >( dsUri.encodedUri(), name );
401
402 if ( tileLayer->isValid() )
403 {
404 return tileLayer.release();
405 }
406 }
407 return nullptr;
408}
409
410QgsMapLayer *QgsProcessingUtils::mapLayerFromString( const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers, LayerHint typeHint, QgsProcessing::LayerOptionsFlags flags )
411{
412 if ( string.isEmpty() )
413 return nullptr;
414
415 // prefer project layers
416 if ( context.project() && typeHint == LayerHint::Annotation && string.compare( QLatin1String( "main" ), Qt::CaseInsensitive ) == 0 )
417 return context.project()->mainAnnotationLayer();
418
419 QgsMapLayer *layer = nullptr;
420 if ( auto *lProject = context.project() )
421 {
422 QgsMapLayer *layer = mapLayerFromStore( string, lProject->layerStore(), typeHint );
423 if ( layer )
424 return layer;
425 }
426
427 layer = mapLayerFromStore( string, context.temporaryLayerStore(), typeHint );
428 if ( layer )
429 return layer;
430
431 if ( !allowLoadingNewLayers )
432 return nullptr;
433
434 layer = loadMapLayerFromString( string, context.transformContext(), typeHint, flags );
435 if ( layer )
436 {
437 context.temporaryLayerStore()->addMapLayer( layer );
438 return layer;
439 }
440 else
441 {
442 return nullptr;
443 }
444}
445
446QgsProcessingFeatureSource *QgsProcessingUtils::variantToSource( const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue )
447{
448 QVariant val = value;
449 bool selectedFeaturesOnly = false;
450 long long featureLimit = -1;
451 QString filterExpression;
452 bool overrideGeometryCheck = false;
454 if ( val.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
455 {
456 // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
457 QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
458 selectedFeaturesOnly = fromVar.selectedFeaturesOnly;
459 featureLimit = fromVar.featureLimit;
460 filterExpression = fromVar.filterExpression;
461 val = fromVar.source;
462 overrideGeometryCheck = fromVar.flags & QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck;
463 geometryCheck = fromVar.geometryCheck;
464 }
465 else if ( val.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
466 {
467 // input is a QgsProcessingOutputLayerDefinition (e.g. an output from earlier in a model) - get extra properties from it
468 QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
469 val = fromVar.sink;
470 }
471
472 if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( val ) ) )
473 {
474 std::unique_ptr< QgsProcessingFeatureSource> source = std::make_unique< QgsProcessingFeatureSource >( layer, context, false, featureLimit, filterExpression );
475 if ( overrideGeometryCheck )
476 source->setInvalidGeometryCheck( geometryCheck );
477 return source.release();
478 }
479
480 QString layerRef;
481 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
482 {
483 layerRef = val.value< QgsProperty >().valueAsString( context.expressionContext(), fallbackValue.toString() );
484 }
485 else if ( !val.isValid() || val.toString().isEmpty() )
486 {
487 // fall back to default
488 if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( fallbackValue ) ) )
489 {
490 std::unique_ptr< QgsProcessingFeatureSource> source = std::make_unique< QgsProcessingFeatureSource >( layer, context, false, featureLimit, filterExpression );
491 if ( overrideGeometryCheck )
492 source->setInvalidGeometryCheck( geometryCheck );
493 return source.release();
494 }
495
496 layerRef = fallbackValue.toString();
497 }
498 else
499 {
500 layerRef = val.toString();
501 }
502
503 if ( layerRef.isEmpty() )
504 return nullptr;
505
506 QgsVectorLayer *vl = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( layerRef, context, true, LayerHint::Vector ) );
507 if ( !vl )
508 return nullptr;
509
510 std::unique_ptr< QgsProcessingFeatureSource> source;
511 if ( selectedFeaturesOnly )
512 {
513 source = std::make_unique< QgsProcessingFeatureSource>( new QgsVectorLayerSelectedFeatureSource( vl ), context, true, featureLimit, filterExpression );
514 }
515 else
516 {
517 source = std::make_unique< QgsProcessingFeatureSource >( vl, context, false, featureLimit, filterExpression );
518 }
519
520 if ( overrideGeometryCheck )
521 source->setInvalidGeometryCheck( geometryCheck );
522 return source.release();
523}
524
525QgsCoordinateReferenceSystem QgsProcessingUtils::variantToCrs( const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue )
526{
527 QVariant val = value;
528
529 if ( val.userType() == QMetaType::type( "QgsCoordinateReferenceSystem" ) )
530 {
531 // input is a QgsCoordinateReferenceSystem - done!
532 return val.value< QgsCoordinateReferenceSystem >();
533 }
534 else if ( val.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
535 {
536 // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
537 QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
538 val = fromVar.source;
539 }
540 else if ( val.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
541 {
542 // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
543 QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
544 val = fromVar.sink;
545 }
546
547 if ( val.userType() == QMetaType::type( "QgsProperty" ) && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
548 {
549 val = val.value< QgsProperty >().staticValue();
550 }
551
552 // maybe a map layer
553 if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
554 return layer->crs();
555
556 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
557 val = val.value< QgsProperty >().valueAsString( context.expressionContext(), fallbackValue.toString() );
558
559 if ( !val.isValid() )
560 {
561 // fall back to default
562 val = fallbackValue;
563 }
564
565 QString crsText = val.toString();
566 if ( crsText.isEmpty() )
567 crsText = fallbackValue.toString();
568
569 if ( crsText.isEmpty() )
571
572 // maybe special string
573 if ( context.project() && crsText.compare( QLatin1String( "ProjectCrs" ), Qt::CaseInsensitive ) == 0 )
574 return context.project()->crs();
575
576 // maybe a map layer reference
577 if ( QgsMapLayer *layer = QgsProcessingUtils::mapLayerFromString( crsText, context ) )
578 return layer->crs();
579
580 // else CRS from string
582 crs.createFromString( crsText );
583 return crs;
584}
585
586bool QgsProcessingUtils::canUseLayer( const QgsMeshLayer *layer )
587{
588 return layer && layer->dataProvider();
589}
590
591bool QgsProcessingUtils::canUseLayer( const QgsPluginLayer *layer )
592{
593 return layer && layer->isValid();
594}
595
596bool QgsProcessingUtils::canUseLayer( const QgsVectorTileLayer *layer )
597{
598 return layer && layer->isValid();
599}
600
601bool QgsProcessingUtils::canUseLayer( const QgsRasterLayer *layer )
602{
603 return layer && layer->isValid();
604}
605
606bool QgsProcessingUtils::canUseLayer( const QgsPointCloudLayer *layer )
607{
608 return layer && layer->isValid();
609}
610
611bool QgsProcessingUtils::canUseLayer( const QgsAnnotationLayer *layer )
612{
613 return layer && layer->isValid();
614}
615
616bool QgsProcessingUtils::canUseLayer( const QgsVectorLayer *layer, const QList<int> &sourceTypes )
617{
618 return layer && layer->isValid() &&
619 ( sourceTypes.isEmpty()
620 || ( sourceTypes.contains( QgsProcessing::TypeVectorPoint ) && layer->geometryType() == Qgis::GeometryType::Point )
621 || ( sourceTypes.contains( QgsProcessing::TypeVectorLine ) && layer->geometryType() == Qgis::GeometryType::Line )
622 || ( sourceTypes.contains( QgsProcessing::TypeVectorPolygon ) && layer->geometryType() == Qgis::GeometryType::Polygon )
623 || ( sourceTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) && layer->isSpatial() )
624 || sourceTypes.contains( QgsProcessing::TypeVector )
625 );
626}
627
628QString QgsProcessingUtils::normalizeLayerSource( const QString &source )
629{
630 QString normalized = source;
631 normalized.replace( '\\', '/' );
632 return normalized.trimmed();
633}
634
635QString QgsProcessingUtils::variantToPythonLiteral( const QVariant &value )
636{
637 if ( !value.isValid() )
638 return QStringLiteral( "None" );
639
640 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
641 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
642 else if ( value.userType() == QMetaType::type( "QgsCoordinateReferenceSystem" ) )
643 {
644 if ( !value.value< QgsCoordinateReferenceSystem >().isValid() )
645 return QStringLiteral( "QgsCoordinateReferenceSystem()" );
646 else
647 return QStringLiteral( "QgsCoordinateReferenceSystem('%1')" ).arg( value.value< QgsCoordinateReferenceSystem >().authid() );
648 }
649 else if ( value.userType() == QMetaType::type( "QgsRectangle" ) )
650 {
651 QgsRectangle r = value.value<QgsRectangle>();
652 return QStringLiteral( "'%1, %3, %2, %4'" ).arg( qgsDoubleToString( r.xMinimum() ),
656 }
657 else if ( value.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
658 {
660 return QStringLiteral( "'%1, %3, %2, %4 [%5]'" ).arg( qgsDoubleToString( r.xMinimum() ),
663 qgsDoubleToString( r.yMaximum() ), r.crs().authid() );
664 }
665 else if ( value.userType() == QMetaType::type( "QgsPointXY" ) )
666 {
667 QgsPointXY r = value.value<QgsPointXY>();
668 return QStringLiteral( "'%1,%2'" ).arg( qgsDoubleToString( r.x() ),
669 qgsDoubleToString( r.y() ) );
670 }
671 else if ( value.userType() == QMetaType::type( "QgsReferencedPointXY" ) )
672 {
674 return QStringLiteral( "'%1,%2 [%3]'" ).arg( qgsDoubleToString( r.x() ),
675 qgsDoubleToString( r.y() ),
676 r.crs().authid() );
677 }
678
679 switch ( value.type() )
680 {
681 case QVariant::Bool:
682 return value.toBool() ? QStringLiteral( "True" ) : QStringLiteral( "False" );
683
684 case QVariant::Double:
685 return QString::number( value.toDouble() );
686
687 case QVariant::Int:
688 case QVariant::UInt:
689 return QString::number( value.toInt() );
690
691 case QVariant::LongLong:
692 case QVariant::ULongLong:
693 return QString::number( value.toLongLong() );
694
695 case QVariant::List:
696 {
697 QStringList parts;
698 const QVariantList vl = value.toList();
699 for ( const QVariant &v : vl )
700 {
701 parts << variantToPythonLiteral( v );
702 }
703 return parts.join( ',' ).prepend( '[' ).append( ']' );
704 }
705
706 case QVariant::Map:
707 {
708 const QVariantMap map = value.toMap();
709 QStringList parts;
710 parts.reserve( map.size() );
711 for ( auto it = map.constBegin(); it != map.constEnd(); ++it )
712 {
713 parts << QStringLiteral( "%1: %2" ).arg( stringToPythonLiteral( it.key() ), variantToPythonLiteral( it.value() ) );
714 }
715 return parts.join( ',' ).prepend( '{' ).append( '}' );
716 }
717
718 case QVariant::DateTime:
719 {
720 const QDateTime dateTime = value.toDateTime();
721 return QStringLiteral( "QDateTime(QDate(%1, %2, %3), QTime(%4, %5, %6))" )
722 .arg( dateTime.date().year() )
723 .arg( dateTime.date().month() )
724 .arg( dateTime.date().day() )
725 .arg( dateTime.time().hour() )
726 .arg( dateTime.time().minute() )
727 .arg( dateTime.time().second() );
728 }
729
730 default:
731 break;
732 }
733
734 return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
735}
736
737QString QgsProcessingUtils::stringToPythonLiteral( const QString &string )
738{
739 QString s = string;
740 s.replace( '\\', QLatin1String( "\\\\" ) );
741 s.replace( '\n', QLatin1String( "\\n" ) );
742 s.replace( '\r', QLatin1String( "\\r" ) );
743 s.replace( '\t', QLatin1String( "\\t" ) );
744
745 if ( s.contains( '\'' ) && !s.contains( '\"' ) )
746 {
747 s = s.prepend( '"' ).append( '"' );
748 }
749 else
750 {
751 s.replace( '\'', QLatin1String( "\\\'" ) );
752 s = s.prepend( '\'' ).append( '\'' );
753 }
754 return s;
755}
756
757void QgsProcessingUtils::parseDestinationString( QString &destination, QString &providerKey, QString &uri, QString &layerName, QString &format, QMap<QString, QVariant> &options, bool &useWriter, QString &extension )
758{
759 extension.clear();
760 bool matched = decodeProviderKeyAndUri( destination, providerKey, uri );
761
762 if ( !matched )
763 {
764 const thread_local QRegularExpression splitRx( QStringLiteral( "^(.{3,}?):(.*)$" ) );
765 QRegularExpressionMatch match = splitRx.match( destination );
766 if ( match.hasMatch() )
767 {
768 providerKey = match.captured( 1 );
769 uri = match.captured( 2 );
770 matched = true;
771 }
772 }
773
774 if ( matched )
775 {
776 if ( providerKey == QLatin1String( "postgis" ) ) // older processing used "postgis" instead of "postgres"
777 {
778 providerKey = QStringLiteral( "postgres" );
779 }
780 if ( providerKey == QLatin1String( "ogr" ) )
781 {
782 QgsDataSourceUri dsUri( uri );
783 if ( !dsUri.database().isEmpty() )
784 {
785 if ( !dsUri.table().isEmpty() )
786 {
787 layerName = dsUri.table();
788 options.insert( QStringLiteral( "layerName" ), layerName );
789 }
790 uri = dsUri.database();
791 extension = QFileInfo( uri ).completeSuffix();
792 format = QgsVectorFileWriter::driverForExtension( extension );
793 options.insert( QStringLiteral( "driverName" ), format );
794 }
795 else
796 {
797 extension = QFileInfo( uri ).completeSuffix();
798 options.insert( QStringLiteral( "driverName" ), QgsVectorFileWriter::driverForExtension( extension ) );
799 }
800 options.insert( QStringLiteral( "update" ), true );
801 }
802 useWriter = false;
803 }
804 else
805 {
806 useWriter = true;
807 providerKey = QStringLiteral( "ogr" );
808
809 const thread_local QRegularExpression splitRx( QStringLiteral( "^(.*)\\.(.*?)$" ) );
810 QRegularExpressionMatch match = splitRx.match( destination );
811 if ( match.hasMatch() )
812 {
813 extension = match.captured( 2 );
814 format = QgsVectorFileWriter::driverForExtension( extension );
815 }
816
817 if ( format.isEmpty() )
818 {
819 format = QStringLiteral( "GPKG" );
820 destination = destination + QStringLiteral( ".gpkg" );
821 }
822
823 options.insert( QStringLiteral( "driverName" ), format );
824 uri = destination;
825 }
826}
827
828QgsFeatureSink *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 )
829{
830 QVariantMap options = createOptions;
831 if ( !options.contains( QStringLiteral( "fileEncoding" ) ) )
832 {
833 // no destination encoding specified, use default
834 options.insert( QStringLiteral( "fileEncoding" ), context.defaultEncoding().isEmpty() ? QStringLiteral( "system" ) : context.defaultEncoding() );
835 }
836
837 if ( destination.isEmpty() || destination.startsWith( QLatin1String( "memory:" ) ) )
838 {
839 // strip "memory:" from start of destination
840 if ( destination.startsWith( QLatin1String( "memory:" ) ) )
841 destination = destination.mid( 7 );
842
843 if ( destination.isEmpty() )
844 destination = QStringLiteral( "output" );
845
846 // memory provider cannot be used with QgsVectorLayerImport - so create layer manually
847 std::unique_ptr< QgsVectorLayer > layer( QgsMemoryProviderUtils::createMemoryLayer( destination, fields, geometryType, crs, false ) );
848 if ( !layer || !layer->isValid() )
849 {
850 throw QgsProcessingException( QObject::tr( "Could not create memory layer" ) );
851 }
852
853 if ( QgsProcessingFeedback *feedback = context.feedback() )
854 {
855 for ( const QgsField &field : fields )
856 {
857 // TODO -- support these!
858 if ( !field.alias().isEmpty() )
859 feedback->pushWarning( QObject::tr( "%1: Aliases are not compatible with scratch layers" ).arg( field.name() ) );
860 if ( !field.alias().isEmpty() )
861 feedback->pushWarning( QObject::tr( "%1: Comments are not compatible with scratch layers" ).arg( field.name() ) );
862 }
863 }
864
865 layer->setCustomProperty( QStringLiteral( "OnConvertFormatRegeneratePrimaryKey" ), static_cast< bool >( sinkFlags & QgsFeatureSink::RegeneratePrimaryKey ) );
866
867 // update destination to layer ID
868 destination = layer->id();
869
870 // this is a factory, so we need to return a proxy
871 std::unique_ptr< QgsProcessingFeatureSink > sink( new QgsProcessingFeatureSink( layer->dataProvider(), destination, context ) );
872 context.temporaryLayerStore()->addMapLayer( layer.release() );
873
874 return sink.release();
875 }
876 else
877 {
878 QString providerKey;
879 QString uri;
880 QString layerName;
881 QString format;
882 QString extension;
883 bool useWriter = false;
884 parseDestinationString( destination, providerKey, uri, layerName, format, options, useWriter, extension );
885
886 QgsFields newFields = fields;
887 if ( useWriter && providerKey == QLatin1String( "ogr" ) )
888 {
889 // use QgsVectorFileWriter for OGR destinations instead of QgsVectorLayerImport, as that allows
890 // us to use any OGR format which supports feature addition
891 QString finalFileName;
892 QString finalLayerName;
894 saveOptions.fileEncoding = options.value( QStringLiteral( "fileEncoding" ) ).toString();
895 saveOptions.layerName = !layerName.isEmpty() ? layerName : options.value( QStringLiteral( "layerName" ) ).toString();
896 saveOptions.driverName = format;
897 saveOptions.datasourceOptions = !datasourceOptions.isEmpty() ? datasourceOptions : QgsVectorFileWriter::defaultDatasetOptions( format );
898 saveOptions.layerOptions = !layerOptions.isEmpty() ? layerOptions : QgsVectorFileWriter::defaultLayerOptions( format );
900 if ( remappingDefinition )
901 {
903 // sniff destination file to get correct wkb type and crs
904 std::unique_ptr< QgsVectorLayer > vl = std::make_unique< QgsVectorLayer >( destination );
905 if ( vl->isValid() )
906 {
907 remappingDefinition->setDestinationWkbType( vl->wkbType() );
908 remappingDefinition->setDestinationCrs( vl->crs() );
909 newFields = vl->fields();
910 remappingDefinition->setDestinationFields( newFields );
911 }
912 context.expressionContext().setFields( fields );
913 }
914 else
915 {
917 }
918 std::unique_ptr< QgsVectorFileWriter > writer( QgsVectorFileWriter::create( destination, newFields, geometryType, crs, context.transformContext(), saveOptions, sinkFlags, &finalFileName, &finalLayerName ) );
919 if ( writer->hasError() )
920 {
921 throw QgsProcessingException( QObject::tr( "Could not create layer %1: %2" ).arg( destination, writer->errorMessage() ) );
922 }
923
924 if ( QgsProcessingFeedback *feedback = context.feedback() )
925 {
926 for ( const QgsField &field : fields )
927 {
928 if ( !field.alias().isEmpty() && !( writer->capabilities() & Qgis::VectorFileWriterCapability::FieldAliases ) )
929 feedback->pushWarning( QObject::tr( "%1: Aliases are not supported by %2" ).arg( field.name(), writer->driverLongName() ) );
930 if ( !field.alias().isEmpty() && !( writer->capabilities() & Qgis::VectorFileWriterCapability::FieldComments ) )
931 feedback->pushWarning( QObject::tr( "%1: Comments are not supported by %2" ).arg( field.name(), writer->driverLongName() ) );
932 }
933 }
934
935 destination = finalFileName;
936 if ( !saveOptions.layerName.isEmpty() && !finalLayerName.isEmpty() )
937 destination += QStringLiteral( "|layername=%1" ).arg( finalLayerName );
938
939 if ( remappingDefinition )
940 {
941 std::unique_ptr< QgsRemappingProxyFeatureSink > remapSink = std::make_unique< QgsRemappingProxyFeatureSink >( *remappingDefinition, writer.release(), true );
942 remapSink->setExpressionContext( context.expressionContext() );
943 remapSink->setTransformContext( context.transformContext() );
944 return new QgsProcessingFeatureSink( remapSink.release(), destination, context, true );
945 }
946 else
947 return new QgsProcessingFeatureSink( writer.release(), destination, context, true );
948 }
949 else
950 {
951 const QgsVectorLayer::LayerOptions layerOptions { context.transformContext() };
952 if ( remappingDefinition )
953 {
954 //write to existing layer
955
956 // use destination string as layer name (eg "postgis:..." )
957 if ( !layerName.isEmpty() )
958 {
959 QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( providerKey, uri );
960 parts.insert( QStringLiteral( "layerName" ), layerName );
961 uri = QgsProviderRegistry::instance()->encodeUri( providerKey, parts );
962 }
963
964 std::unique_ptr< QgsVectorLayer > layer = std::make_unique<QgsVectorLayer>( uri, destination, providerKey, layerOptions );
965 // update destination to layer ID
966 destination = layer->id();
967 if ( layer->isValid() )
968 {
969 remappingDefinition->setDestinationWkbType( layer->wkbType() );
970 remappingDefinition->setDestinationCrs( layer->crs() );
971 remappingDefinition->setDestinationFields( layer->fields() );
972 }
973
974 if ( QgsProcessingFeedback *feedback = context.feedback() )
975 {
976 const Qgis::VectorDataProviderAttributeEditCapabilities capabilities = layer->dataProvider() ? layer->dataProvider()->attributeEditCapabilities() : Qgis::VectorDataProviderAttributeEditCapabilities();
977 for ( const QgsField &field : fields )
978 {
979 if ( !field.alias().isEmpty() && !( capabilities & Qgis::VectorDataProviderAttributeEditCapability::EditAlias ) )
980 feedback->pushWarning( QObject::tr( "%1: Aliases are not supported by the %2 provider" ).arg( field.name(), providerKey ) );
981 if ( !field.alias().isEmpty() && !( capabilities & Qgis::VectorDataProviderAttributeEditCapability::EditComment ) )
982 feedback->pushWarning( QObject::tr( "%1: Comments are not supported by the %2 provider" ).arg( field.name(), providerKey ) );
983 }
984 }
985
986 std::unique_ptr< QgsRemappingProxyFeatureSink > remapSink = std::make_unique< QgsRemappingProxyFeatureSink >( *remappingDefinition, layer->dataProvider(), false );
987 context.temporaryLayerStore()->addMapLayer( layer.release() );
988 remapSink->setExpressionContext( context.expressionContext() );
989 remapSink->setTransformContext( context.transformContext() );
990 context.expressionContext().setFields( fields );
991 return new QgsProcessingFeatureSink( remapSink.release(), destination, context, true );
992 }
993 else
994 {
995 //create empty layer
996 std::unique_ptr< QgsVectorLayerExporter > exporter = std::make_unique<QgsVectorLayerExporter>( uri, providerKey, newFields, geometryType, crs, true, options, sinkFlags );
997 if ( exporter->errorCode() != Qgis::VectorExportResult::Success )
998 {
999 throw QgsProcessingException( QObject::tr( "Could not create layer %1: %2" ).arg( destination, exporter->errorMessage() ) );
1000 }
1001
1002 // use destination string as layer name (eg "postgis:..." )
1003 if ( !layerName.isEmpty() )
1004 {
1005 uri += QStringLiteral( "|layername=%1" ).arg( layerName );
1006 // update destination to generated URI
1007 destination = uri;
1008 }
1009
1010 if ( QgsProcessingFeedback *feedback = context.feedback() )
1011 {
1012 for ( const QgsField &field : fields )
1013 {
1014 if ( !field.alias().isEmpty() && !( exporter->attributeEditCapabilities() & Qgis::VectorDataProviderAttributeEditCapability::EditAlias ) )
1015 feedback->pushWarning( QObject::tr( "%1: Aliases are not supported by the %2 provider" ).arg( field.name(), providerKey ) );
1016 if ( !field.alias().isEmpty() && !( exporter->attributeEditCapabilities() & Qgis::VectorDataProviderAttributeEditCapability::EditComment ) )
1017 feedback->pushWarning( QObject::tr( "%1: Comments are not supported by the %2 provider" ).arg( field.name(), providerKey ) );
1018 }
1019 }
1020
1021 return new QgsProcessingFeatureSink( exporter.release(), destination, context, true );
1022 }
1023 }
1024 }
1025}
1026
1027void QgsProcessingUtils::createFeatureSinkPython( QgsFeatureSink **sink, QString &destination, QgsProcessingContext &context, const QgsFields &fields, Qgis::WkbType geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &options )
1028{
1029 *sink = createFeatureSink( destination, context, fields, geometryType, crs, options );
1030}
1031
1032
1034{
1035 QgsRectangle extent;
1036 for ( const QgsMapLayer *layer : layers )
1037 {
1038 if ( !layer )
1039 continue;
1040
1041 if ( crs.isValid() )
1042 {
1043 //transform layer extent to target CRS
1044 QgsCoordinateTransform ct( layer->crs(), crs, context.transformContext() );
1046 try
1047 {
1048 QgsRectangle reprojExtent = ct.transformBoundingBox( layer->extent() );
1049 extent.combineExtentWith( reprojExtent );
1050 }
1051 catch ( QgsCsException & )
1052 {
1053 // can't reproject... what to do here? hmmm?
1054 // let's ignore this layer for now, but maybe we should just use the original extent?
1055 }
1056 }
1057 else
1058 {
1059 extent.combineExtentWith( layer->extent() );
1060 }
1061
1062 }
1063 return extent;
1064}
1065
1066// Deprecated
1068{
1069 QgsProcessingContext context;
1070 return QgsProcessingUtils::combineLayerExtents( layers, crs, context );
1071}
1072
1073QVariant QgsProcessingUtils::generateIteratingDestination( const QVariant &input, const QVariant &id, QgsProcessingContext &context )
1074{
1075 if ( !input.isValid() )
1076 return QStringLiteral( "memory:%1" ).arg( id.toString() );
1077
1078 if ( input.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
1079 {
1080 QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( input );
1081 QVariant newSink = generateIteratingDestination( fromVar.sink, id, context );
1082 fromVar.sink = QgsProperty::fromValue( newSink );
1083 return fromVar;
1084 }
1085 else if ( input.userType() == QMetaType::type( "QgsProperty" ) )
1086 {
1087 QString res = input.value< QgsProperty>().valueAsString( context.expressionContext() );
1088 return generateIteratingDestination( res, id, context );
1089 }
1090 else
1091 {
1092 QString res = input.toString();
1094 {
1095 // temporary outputs map to temporary outputs!
1097 }
1098 else if ( res.startsWith( QLatin1String( "memory:" ) ) )
1099 {
1100 return QString( res + '_' + id.toString() );
1101 }
1102 else
1103 {
1104 // assume a filename type output for now
1105 // TODO - uris?
1106 int lastIndex = res.lastIndexOf( '.' );
1107 return lastIndex >= 0 ? QString( res.left( lastIndex ) + '_' + id.toString() + res.mid( lastIndex ) ) : QString( res + '_' + id.toString() );
1108 }
1109 }
1110}
1111
1113{
1114 // we maintain a list of temporary folders -- this allows us to append additional
1115 // folders when a setting change causes the base temp folder to change, while deferring
1116 // cleanup of ALL these temp folders until session end (we can't cleanup older folders immediately,
1117 // because we don't know whether they have data in them which is still wanted)
1118 static std::vector< std::unique_ptr< QTemporaryDir > > sTempFolders;
1119 static QString sFolder;
1120 static QMutex sMutex;
1121 QMutexLocker locker( &sMutex );
1122 QString basePath;
1123
1124 if ( context )
1125 basePath = context->temporaryFolder();
1126 if ( basePath.isEmpty() )
1128
1129 if ( basePath.isEmpty() )
1130 {
1131 // default setting -- automatically create a temp folder
1132 if ( sTempFolders.empty() )
1133 {
1134 const QString templatePath = QStringLiteral( "%1/processing_XXXXXX" ).arg( QDir::tempPath() );
1135 std::unique_ptr< QTemporaryDir > tempFolder = std::make_unique< QTemporaryDir >( templatePath );
1136 sFolder = tempFolder->path();
1137 sTempFolders.emplace_back( std::move( tempFolder ) );
1138 }
1139 }
1140 else if ( sFolder.isEmpty() || !sFolder.startsWith( basePath ) || sTempFolders.empty() )
1141 {
1142 if ( !QDir().exists( basePath ) )
1143 QDir().mkpath( basePath );
1144
1145 const QString templatePath = QStringLiteral( "%1/processing_XXXXXX" ).arg( basePath );
1146 std::unique_ptr< QTemporaryDir > tempFolder = std::make_unique< QTemporaryDir >( templatePath );
1147 sFolder = tempFolder->path();
1148 sTempFolders.emplace_back( std::move( tempFolder ) );
1149 }
1150 return sFolder;
1151}
1152
1153QString QgsProcessingUtils::generateTempFilename( const QString &basename, const QgsProcessingContext *context )
1154{
1155 QString subPath = QUuid::createUuid().toString().remove( '-' ).remove( '{' ).remove( '}' );
1156 QString path = tempFolder( context ) + '/' + subPath;
1157 if ( !QDir( path ).exists() ) //make sure the directory exists - it shouldn't, but lets be safe...
1158 {
1159 QDir tmpDir;
1160 tmpDir.mkdir( path );
1161 }
1162 return path + '/' + QgsFileUtils::stringToSafeFilename( basename );
1163}
1164
1166{
1167 auto getText = [map]( const QString & key )->QString
1168 {
1169 if ( map.contains( key ) )
1170 return map.value( key ).toString();
1171 return QString();
1172 };
1173
1174 QString s;
1175 s += QStringLiteral( "<html><body><p>" ) + getText( QStringLiteral( "ALG_DESC" ) ) + QStringLiteral( "</p>\n" );
1176
1177 QString inputs;
1178 const auto parameterDefinitions = algorithm->parameterDefinitions();
1179 for ( const QgsProcessingParameterDefinition *def : parameterDefinitions )
1180 {
1181 if ( def->flags() & QgsProcessingParameterDefinition::FlagHidden || def->isDestination() )
1182 continue;
1183
1184 if ( !getText( def->name() ).isEmpty() )
1185 {
1186 inputs += QStringLiteral( "<h3>" ) + def->description() + QStringLiteral( "</h3>\n" );
1187 inputs += QStringLiteral( "<p>" ) + getText( def->name() ) + QStringLiteral( "</p>\n" );
1188 }
1189 }
1190 if ( !inputs.isEmpty() )
1191 s += QStringLiteral( "<h2>" ) + QObject::tr( "Input parameters" ) + QStringLiteral( "</h2>\n" ) + inputs;
1192
1193 QString outputs;
1194 const auto outputDefinitions = algorithm->outputDefinitions();
1195 for ( const QgsProcessingOutputDefinition *def : outputDefinitions )
1196 {
1197 if ( !getText( def->name() ).isEmpty() )
1198 {
1199 outputs += QStringLiteral( "<h3>" ) + def->description() + QStringLiteral( "</h3>\n" );
1200 outputs += QStringLiteral( "<p>" ) + getText( def->name() ) + QStringLiteral( "</p>\n" );
1201 }
1202 }
1203 if ( !outputs.isEmpty() )
1204 s += QStringLiteral( "<h2>" ) + QObject::tr( "Outputs" ) + QStringLiteral( "</h2>\n" ) + outputs;
1205
1206 if ( !map.value( QStringLiteral( "EXAMPLES" ) ).toString().isEmpty() )
1207 s += QStringLiteral( "<h2>%1</h2>\n<p>%2</p>" ).arg( QObject::tr( "Examples" ), getText( QStringLiteral( "EXAMPLES" ) ) );
1208
1209 s += QLatin1String( "<br>" );
1210 if ( !map.value( QStringLiteral( "ALG_CREATOR" ) ).toString().isEmpty() )
1211 s += QStringLiteral( "<p align=\"right\">" ) + QObject::tr( "Algorithm author:" ) + QStringLiteral( " " ) + getText( QStringLiteral( "ALG_CREATOR" ) ) + QStringLiteral( "</p>" );
1212 if ( !map.value( QStringLiteral( "ALG_HELP_CREATOR" ) ).toString().isEmpty() )
1213 s += QStringLiteral( "<p align=\"right\">" ) + QObject::tr( "Help author:" ) + QStringLiteral( " " ) + getText( QStringLiteral( "ALG_HELP_CREATOR" ) ) + QStringLiteral( "</p>" );
1214 if ( !map.value( QStringLiteral( "ALG_VERSION" ) ).toString().isEmpty() )
1215 s += QStringLiteral( "<p align=\"right\">" ) + QObject::tr( "Algorithm version:" ) + QStringLiteral( " " ) + getText( QStringLiteral( "ALG_VERSION" ) ) + QStringLiteral( "</p>" );
1216
1217 s += QLatin1String( "</body></html>" );
1218 return s;
1219}
1220
1221QString convertToCompatibleFormatInternal( const QgsVectorLayer *vl, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback, QString *layerName,
1222 long long featureLimit, const QString &filterExpression )
1223{
1224 bool requiresTranslation = false;
1225
1226 // if we are only looking for selected features then we have to export back to disk,
1227 // as we need to subset only selected features, a concept which doesn't exist outside QGIS!
1228 requiresTranslation = requiresTranslation || selectedFeaturesOnly;
1229
1230 // if we are limiting the feature count, we better export
1231 requiresTranslation = requiresTranslation || featureLimit != -1 || !filterExpression.isEmpty();
1232
1233 // if the data provider is NOT ogr, then we HAVE to convert. Otherwise we run into
1234 // issues with data providers like spatialite, delimited text where the format can be
1235 // opened outside of QGIS, but with potentially very different behavior!
1236 requiresTranslation = requiresTranslation || vl->providerType() != QLatin1String( "ogr" );
1237
1238 // if the layer has a feature filter set, then we HAVE to convert. Feature filters are
1239 // a purely QGIS concept.
1240 requiresTranslation = requiresTranslation || !vl->subsetString().isEmpty();
1241
1242 // if the layer opened using GDAL's virtual I/O mechanism (/vsizip/, etc.), then
1243 // we HAVE to convert as other tools may not work with it
1244 requiresTranslation = requiresTranslation || vl->source().startsWith( QLatin1String( "/vsi" ) );
1245
1246 // Check if layer is a disk based format and if so if the layer's path has a compatible filename suffix
1247 QString diskPath;
1248 if ( !requiresTranslation )
1249 {
1250 const QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( vl->providerType(), vl->source() );
1251 if ( parts.contains( QStringLiteral( "path" ) ) )
1252 {
1253 diskPath = parts.value( QStringLiteral( "path" ) ).toString();
1254 QFileInfo fi( diskPath );
1255 requiresTranslation = !compatibleFormats.contains( fi.suffix(), Qt::CaseInsensitive );
1256
1257 // if the layer name doesn't match the filename, we need to convert the layer. This method can only return
1258 // a filename, and cannot handle layernames as well as file paths
1259 const QString srcLayerName = parts.value( QStringLiteral( "layerName" ) ).toString();
1260 if ( layerName )
1261 {
1262 // differing layer names are acceptable
1263 *layerName = srcLayerName;
1264 }
1265 else
1266 {
1267 // differing layer names are NOT acceptable
1268 requiresTranslation = requiresTranslation || ( !srcLayerName.isEmpty() && srcLayerName != fi.baseName() );
1269 }
1270 }
1271 else
1272 {
1273 requiresTranslation = true; // not a disk-based format
1274 }
1275 }
1276
1277 if ( requiresTranslation )
1278 {
1279 QString temp = QgsProcessingUtils::generateTempFilename( baseName + '.' + preferredFormat, &context );
1280
1282 saveOptions.fileEncoding = context.defaultEncoding();
1283 saveOptions.driverName = QgsVectorFileWriter::driverForExtension( preferredFormat );
1284 std::unique_ptr< QgsVectorFileWriter > writer( QgsVectorFileWriter::create( temp, vl->fields(), vl->wkbType(), vl->crs(), context.transformContext(), saveOptions ) );
1285 QgsFeature f;
1287 QgsFeatureRequest request;
1288 if ( featureLimit != -1 )
1289 {
1290 request.setLimit( featureLimit );
1291 }
1292 if ( !filterExpression.isEmpty() )
1293 {
1294 request.setFilterExpression( filterExpression );
1295 }
1296
1297 if ( selectedFeaturesOnly )
1298 it = vl->getSelectedFeatures( request );
1299 else
1300 it = vl->getFeatures( request );
1301
1302 while ( it.nextFeature( f ) )
1303 {
1304 if ( feedback->isCanceled() )
1305 return QString();
1306 writer->addFeature( f, QgsFeatureSink::FastInsert );
1307 }
1308 return temp;
1309 }
1310 else
1311 {
1312 return diskPath;
1313 }
1314}
1315
1316QString 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 )
1317{
1318 return convertToCompatibleFormatInternal( vl, selectedFeaturesOnly, baseName, compatibleFormats, preferredFormat, context, feedback, nullptr, featureLimit, filterExpression );
1319}
1320
1321QString 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 )
1322{
1323 layerName.clear();
1324 return convertToCompatibleFormatInternal( layer, selectedFeaturesOnly, baseName, compatibleFormats, preferredFormat, context, feedback, &layerName, featureLimit, filterExpression );
1325}
1326
1327QgsFields QgsProcessingUtils::combineFields( const QgsFields &fieldsA, const QgsFields &fieldsB, const QString &fieldsBPrefix )
1328{
1329 QgsFields outFields = fieldsA;
1330 QSet< QString > usedNames;
1331 for ( const QgsField &f : fieldsA )
1332 {
1333 usedNames.insert( f.name().toLower() );
1334 }
1335
1336 for ( const QgsField &f : fieldsB )
1337 {
1338 QgsField newField = f;
1339 newField.setName( fieldsBPrefix + f.name() );
1340 if ( usedNames.contains( newField.name().toLower() ) )
1341 {
1342 int idx = 2;
1343 QString newName = newField.name() + '_' + QString::number( idx );
1344 while ( usedNames.contains( newName.toLower() ) || fieldsB.indexOf( newName ) != -1 )
1345 {
1346 idx++;
1347 newName = newField.name() + '_' + QString::number( idx );
1348 }
1349 newField.setName( newName );
1350 outFields.append( newField );
1351 }
1352 else
1353 {
1354 outFields.append( newField );
1355 }
1356 usedNames.insert( newField.name() );
1357 }
1358
1359 return outFields;
1360}
1361
1362
1363QList<int> QgsProcessingUtils::fieldNamesToIndices( const QStringList &fieldNames, const QgsFields &fields )
1364{
1365 QList<int> indices;
1366 if ( !fieldNames.isEmpty() )
1367 {
1368 indices.reserve( fieldNames.count() );
1369 for ( const QString &f : fieldNames )
1370 {
1371 int idx = fields.lookupField( f );
1372 if ( idx >= 0 )
1373 indices.append( idx );
1374 }
1375 }
1376 else
1377 {
1378 indices.reserve( fields.count() );
1379 for ( int i = 0; i < fields.count(); ++i )
1380 indices.append( i );
1381 }
1382 return indices;
1383}
1384
1385
1386QgsFields QgsProcessingUtils::indicesToFields( const QList<int> &indices, const QgsFields &fields )
1387{
1388 QgsFields fieldsSubset;
1389 for ( int i : indices )
1390 fieldsSubset.append( fields.at( i ) );
1391 return fieldsSubset;
1392}
1393
1395{
1397 if ( setting == -1 )
1398 return QStringLiteral( "gpkg" );
1399 return QgsVectorFileWriter::supportedFormatExtensions().value( setting, QStringLiteral( "gpkg" ) );
1400}
1401
1403{
1405 if ( setting == -1 )
1406 return QStringLiteral( "tif" );
1407 return QgsRasterFileWriter::supportedFormatExtensions().value( setting, QStringLiteral( "tif" ) );
1408}
1409
1411{
1412 return QStringLiteral( "las" );
1413}
1414
1416{
1417 return QStringLiteral( "mbtiles" );
1418}
1419
1420QVariantMap QgsProcessingUtils::removePointerValuesFromMap( const QVariantMap &map )
1421{
1422 auto layerPointerToString = []( QgsMapLayer * layer ) -> QString
1423 {
1424 if ( layer && layer->providerType() == QLatin1String( "memory" ) )
1425 return layer->id();
1426 else if ( layer )
1427 return layer->source();
1428 else
1429 return QString();
1430 };
1431
1432 auto cleanPointerValues = [&layerPointerToString]( const QVariant & value ) -> QVariant
1433 {
1434 if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( value.value< QObject * >() ) )
1435 {
1436 // don't store pointers in maps for long-term storage
1437 return layerPointerToString( layer );
1438 }
1439 else if ( value.userType() == QMetaType::type( "QPointer< QgsMapLayer >" ) )
1440 {
1441 // don't store pointers in maps for long-term storage
1442 return layerPointerToString( value.value< QPointer< QgsMapLayer > >().data() );
1443 }
1444 else
1445 {
1446 return value;
1447 }
1448 };
1449
1450 QVariantMap res;
1451 for ( auto it = map.constBegin(); it != map.constEnd(); ++it )
1452 {
1453 if ( it->type() == QVariant::Map )
1454 {
1455 res.insert( it.key(), removePointerValuesFromMap( it.value().toMap() ) );
1456 }
1457 else if ( it->type() == QVariant::List )
1458 {
1459 QVariantList dest;
1460 const QVariantList source = it.value().toList();
1461 dest.reserve( source.size() );
1462 for ( const QVariant &v : source )
1463 {
1464 dest.append( cleanPointerValues( v ) );
1465 }
1466 res.insert( it.key(), dest );
1467 }
1468 else
1469 {
1470 res.insert( it.key(), cleanPointerValues( it.value() ) );
1471 }
1472 }
1473 return res;
1474}
1475
1476QVariantMap QgsProcessingUtils::preprocessQgisProcessParameters( const QVariantMap &parameters, bool &ok, QString &error )
1477{
1478 QVariantMap output;
1479 ok = true;
1480 for ( auto it = parameters.constBegin(); it != parameters.constEnd(); ++it )
1481 {
1482 if ( it.value().type() == QVariant::Map )
1483 {
1484 const QVariantMap value = it.value().toMap();
1485 if ( value.value( QStringLiteral( "type" ) ).toString() == QLatin1String( "data_defined" ) )
1486 {
1487 const QString expression = value.value( QStringLiteral( "expression" ) ).toString();
1488 const QString field = value.value( QStringLiteral( "field" ) ).toString();
1489 if ( !expression.isEmpty() )
1490 {
1491 output.insert( it.key(), QgsProperty::fromExpression( expression ) );
1492 }
1493 else if ( !field.isEmpty() )
1494 {
1495 output.insert( it.key(), QgsProperty::fromField( field ) );
1496 }
1497 else
1498 {
1499 ok = false;
1500 error = QObject::tr( "Invalid data defined parameter for %1, requires 'expression' or 'field' values." ).arg( it.key() );
1501 }
1502 }
1503 else
1504 {
1505 output.insert( it.key(), it.value() );
1506 }
1507 }
1508 else if ( it.value().type() == QVariant::String )
1509 {
1510 const QString stringValue = it.value().toString();
1511
1512 if ( stringValue.startsWith( QLatin1String( "field:" ) ) )
1513 {
1514 output.insert( it.key(), QgsProperty::fromField( stringValue.mid( 6 ) ) );
1515 }
1516 else if ( stringValue.startsWith( QLatin1String( "expression:" ) ) )
1517 {
1518 output.insert( it.key(), QgsProperty::fromExpression( stringValue.mid( 11 ) ) );
1519 }
1520 else
1521 {
1522 output.insert( it.key(), it.value() );
1523 }
1524 }
1525 else
1526 {
1527 output.insert( it.key(), it.value() );
1528 }
1529 }
1530 return output;
1531}
1532
1533//
1534// QgsProcessingFeatureSource
1535//
1536
1537QgsProcessingFeatureSource::QgsProcessingFeatureSource( QgsFeatureSource *originalSource, const QgsProcessingContext &context, bool ownsOriginalSource, long long featureLimit, const QString &filterExpression )
1538 : mSource( originalSource )
1539 , mOwnsSource( ownsOriginalSource )
1540 , mInvalidGeometryCheck( QgsWkbTypes::geometryType( mSource->wkbType() ) == Qgis::GeometryType::Point
1541 ? QgsFeatureRequest::GeometryNoCheck // never run geometry validity checks for point layers!
1542 : context.invalidGeometryCheck() )
1543 , mInvalidGeometryCallback( context.invalidGeometryCallback( originalSource ) )
1544 , mTransformErrorCallback( context.transformErrorCallback() )
1545 , mInvalidGeometryCallbackSkip( context.defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::GeometrySkipInvalid, originalSource ) )
1546 , mInvalidGeometryCallbackAbort( context.defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::GeometryAbortOnInvalid, originalSource ) )
1547 , mFeatureLimit( featureLimit )
1548 , mFilterExpression( filterExpression )
1549{}
1550
1552{
1553 if ( mOwnsSource )
1554 delete mSource;
1555}
1556
1558{
1559 QgsFeatureRequest req( request );
1560 req.setTransformErrorCallback( mTransformErrorCallback );
1561
1562 if ( flags & FlagSkipGeometryValidityChecks )
1564 else
1565 {
1566 req.setInvalidGeometryCheck( mInvalidGeometryCheck );
1567 req.setInvalidGeometryCallback( mInvalidGeometryCallback );
1568 }
1569
1570 if ( mFeatureLimit != -1 && req.limit() != -1 )
1571 req.setLimit( std::min( static_cast< long long >( req.limit() ), mFeatureLimit ) );
1572 else if ( mFeatureLimit != -1 )
1573 req.setLimit( mFeatureLimit );
1574
1575 if ( !mFilterExpression.isEmpty() )
1576 req.combineFilterExpression( mFilterExpression );
1577
1578 return mSource->getFeatures( req );
1579}
1580
1582{
1583 FeatureAvailability sourceAvailability = mSource->hasFeatures();
1584 if ( sourceAvailability == NoFeaturesAvailable )
1585 return NoFeaturesAvailable; // never going to be features if underlying source has no features
1586 else if ( mInvalidGeometryCheck == QgsFeatureRequest::GeometryNoCheck && mFilterExpression.isEmpty() )
1587 return sourceAvailability;
1588 else
1589 // we don't know... source has features, but these may be filtered out by invalid geometry check or filter expression
1591}
1592
1594{
1595 QgsFeatureRequest req( request );
1596 req.setInvalidGeometryCheck( mInvalidGeometryCheck );
1597 req.setInvalidGeometryCallback( mInvalidGeometryCallback );
1598 req.setTransformErrorCallback( mTransformErrorCallback );
1599
1600 if ( mFeatureLimit != -1 && req.limit() != -1 )
1601 req.setLimit( std::min( static_cast< long long >( req.limit() ), mFeatureLimit ) );
1602 else if ( mFeatureLimit != -1 )
1603 req.setLimit( mFeatureLimit );
1604
1605 if ( !mFilterExpression.isEmpty() )
1606 req.combineFilterExpression( mFilterExpression );
1607
1608 return mSource->getFeatures( req );
1609}
1610
1612{
1613 return mSource->sourceCrs();
1614}
1615
1617{
1618 return mSource->fields();
1619}
1620
1622{
1623 return mSource->wkbType();
1624}
1625
1627{
1628 if ( !mFilterExpression.isEmpty() )
1629 return static_cast< int >( Qgis::FeatureCountState::UnknownCount );
1630
1631 if ( mFeatureLimit == -1 )
1632 return mSource->featureCount();
1633 else
1634 return std::min( mFeatureLimit, mSource->featureCount() );
1635}
1636
1638{
1639 return mSource->sourceName();
1640}
1641
1642QSet<QVariant> QgsProcessingFeatureSource::uniqueValues( int fieldIndex, int limit ) const
1643{
1644 if ( mFilterExpression.isEmpty() )
1645 return mSource->uniqueValues( fieldIndex, limit );
1646
1647 // inefficient method when filter expression in use
1648 // TODO QGIS 4.0 -- add filter expression to virtual ::uniqueValues function
1649 if ( fieldIndex < 0 || fieldIndex >= fields().count() )
1650 return QSet<QVariant>();
1651
1654 req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
1655 req.setFilterExpression( mFilterExpression );
1656
1657 QSet<QVariant> values;
1658 QgsFeatureIterator it = getFeatures( req );
1659 QgsFeature f;
1660 while ( it.nextFeature( f ) )
1661 {
1662 values.insert( f.attribute( fieldIndex ) );
1663 if ( limit > 0 && values.size() >= limit )
1664 return values;
1665 }
1666 return values;
1667}
1668
1669QVariant QgsProcessingFeatureSource::minimumValue( int fieldIndex ) const
1670{
1671 if ( mFilterExpression.isEmpty() )
1672 return mSource->minimumValue( fieldIndex );
1673
1674 // inefficient method when filter expression in use
1675 // TODO QGIS 4.0 -- add filter expression to virtual ::minimumValue function
1676 if ( fieldIndex < 0 || fieldIndex >= fields().count() )
1677 return QVariant();
1678
1681 req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
1682
1683 QVariant min;
1684 QgsFeatureIterator it = getFeatures( req );
1685 QgsFeature f;
1686 while ( it.nextFeature( f ) )
1687 {
1688 const QVariant v = f.attribute( fieldIndex );
1689 if ( !QgsVariantUtils::isNull( v ) && ( qgsVariantLessThan( v, min ) || QgsVariantUtils::isNull( min ) ) )
1690 {
1691 min = v;
1692 }
1693 }
1694 return min;
1695}
1696
1697QVariant QgsProcessingFeatureSource::maximumValue( int fieldIndex ) const
1698{
1699 if ( mFilterExpression.isEmpty() )
1700 return mSource->maximumValue( fieldIndex );
1701
1702 // inefficient method when filter expression in use
1703 // TODO QGIS 4.0 -- add filter expression to virtual ::maximumValue function
1704 if ( fieldIndex < 0 || fieldIndex >= fields().count() )
1705 return QVariant();
1706
1709 req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
1710
1711 QVariant max;
1712 QgsFeatureIterator it = getFeatures( req );
1713 QgsFeature f;
1714 while ( it.nextFeature( f ) )
1715 {
1716 const QVariant v = f.attribute( fieldIndex );
1717 if ( !QgsVariantUtils::isNull( v ) && ( qgsVariantGreaterThan( v, max ) || QgsVariantUtils::isNull( max ) ) )
1718 {
1719 max = v;
1720 }
1721 }
1722 return max;
1723}
1724
1726{
1727 return mSource->sourceExtent();
1728}
1729
1731{
1732 if ( mFilterExpression.isEmpty() )
1733 return mSource->allFeatureIds();
1734
1737 .setNoAttributes()
1738 .setFilterExpression( mFilterExpression ) );
1739
1740 QgsFeatureIds ids;
1741
1742 QgsFeature fet;
1743 while ( fit.nextFeature( fet ) )
1744 {
1745 ids << fet.id();
1746 }
1747
1748 return ids;
1749}
1750
1752{
1753 return mSource->hasSpatialIndex();
1754}
1755
1757{
1758 QgsExpressionContextScope *expressionContextScope = nullptr;
1759 QgsExpressionContextScopeGenerator *generator = dynamic_cast<QgsExpressionContextScopeGenerator *>( mSource );
1760 if ( generator )
1761 {
1762 expressionContextScope = generator->createExpressionContextScope();
1763 }
1764 return expressionContextScope;
1765}
1766
1768{
1769 mInvalidGeometryCheck = method;
1770 switch ( mInvalidGeometryCheck )
1771 {
1773 mInvalidGeometryCallback = nullptr;
1774 break;
1775
1777 mInvalidGeometryCallback = mInvalidGeometryCallbackSkip;
1778 break;
1779
1781 mInvalidGeometryCallback = mInvalidGeometryCallbackAbort;
1782 break;
1783
1784 }
1785}
1786
1787
1788//
1789// QgsProcessingFeatureSink
1790//
1791QgsProcessingFeatureSink::QgsProcessingFeatureSink( QgsFeatureSink *originalSink, const QString &sinkName, QgsProcessingContext &context, bool ownsOriginalSink )
1792 : QgsProxyFeatureSink( originalSink )
1793 , mContext( context )
1794 , mSinkName( sinkName )
1795 , mOwnsSink( ownsOriginalSink )
1796{}
1797
1799{
1800 if ( mOwnsSink )
1801 delete destinationSink();
1802}
1803
1804bool QgsProcessingFeatureSink::addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags )
1805{
1806 bool result = QgsProxyFeatureSink::addFeature( feature, flags );
1807 if ( !result && mContext.feedback() )
1808 {
1809 const QString error = lastError();
1810 if ( !error.isEmpty() )
1811 mContext.feedback()->reportError( QObject::tr( "Feature could not be written to %1: %2" ).arg( mSinkName, error ) );
1812 else
1813 mContext.feedback()->reportError( QObject::tr( "Feature could not be written to %1" ).arg( mSinkName ) );
1814 }
1815 return result;
1816}
1817
1818bool QgsProcessingFeatureSink::addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags )
1819{
1820 bool result = QgsProxyFeatureSink::addFeatures( features, flags );
1821 if ( !result && mContext.feedback() )
1822 {
1823 const QString error = lastError();
1824 if ( !error.isEmpty() )
1825 mContext.feedback()->reportError( QObject::tr( "%n feature(s) could not be written to %1: %2", nullptr, features.count() ).arg( mSinkName, error ) );
1826 else
1827 mContext.feedback()->reportError( QObject::tr( "%n feature(s) could not be written to %1", nullptr, features.count() ).arg( mSinkName ) );
1828 }
1829 return result;
1830}
1831
1832bool QgsProcessingFeatureSink::addFeatures( QgsFeatureIterator &iterator, QgsFeatureSink::Flags flags )
1833{
1834 bool result = QgsProxyFeatureSink::addFeatures( iterator, flags );
1835 if ( !result && mContext.feedback() )
1836 {
1837 const QString error = lastError();
1838 if ( !error.isEmpty() )
1839 mContext.feedback()->reportError( QObject::tr( "Features could not be written to %1: %2" ).arg( mSinkName, error ) );
1840 else
1841 mContext.feedback()->reportError( QObject::tr( "Features could not be written to %1" ).arg( mSinkName ) );
1842 }
1843 return result;
1844}
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.
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition: qgis.h:154
@ 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 SIP_THROW(QgsCsException)
Transforms a rectangle from the source CRS to the destination CRS.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:67
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 QgsFields fields() const =0
Returns the fields associated with features in the source.
virtual QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const
Returns the set of unique values contained within the specified fieldIndex from this source.
virtual QgsCoordinateReferenceSystem sourceCrs() const =0
Returns the coordinate reference system for features in the source.
SpatialIndexPresence
Enumeration of spatial index presence states.
virtual Qgis::WkbType wkbType() const =0
Returns the geometry type for features returned by this source.
virtual FeatureAvailability hasFeatures() const
Determines if there are any features available in the source.
FeatureAvailability
Possible return value for hasFeatures() to determine if a source is empty.
@ FeaturesMaybeAvailable
There may be features available in this source.
@ NoFeaturesAvailable
There are certainly no features available in this source.
virtual QVariant minimumValue(int fieldIndex) const
Returns the minimum value for an attribute column or an invalid variant in case of error.
virtual QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const =0
Returns an iterator for the features in the source.
virtual QString sourceName() const =0
Returns a friendly display name for the source.
virtual QVariant maximumValue(int fieldIndex) const
Returns the maximum value for an attribute column or an invalid variant in case of error.
virtual long long featureCount() const =0
Returns the number of features contained in the source, or -1 if the feature count is unknown.
virtual QgsFeatureIds allFeatureIds() const
Returns a list of all feature IDs for features present in the source.
virtual SpatialIndexPresence hasSpatialIndex() const
Returns an enum value representing the presence of a valid spatial index on the source,...
virtual QgsRectangle sourceExtent() const
Returns the extent of all geometries from the source.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:335
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
bool isCanceled() const SIP_HOLDGIL
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
QString alias
Definition: qgsfield.h:63
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.
Definition: qgsfields.cpp:207
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:359
static QString stringToSafeFilename(const QString &string)
Converts a string to a safe filename, replacing characters which are not safe for filenames with an '...
A storage object for map layers, in which the layers are owned by the store and have their lifetime b...
QMap< QString, QgsMapLayer * > mapLayers() const
Returns a map of all layers by layer ID.
QgsMapLayer * addMapLayer(QgsMapLayer *layer, bool takeOwnership=true)
Add a layer to the store.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
QString source() const
Returns the source for the layer.
QString providerType() const
Returns the provider type (provider key) for this layer.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
bool isValid
Definition: qgsmaplayer.h:81
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.
Definition: qgsmeshlayer.h:100
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
Q_GADGET 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.
Definition: qgsexception.h:84
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...
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 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.
@ 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 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 void createFeatureSinkPython(QgsFeatureSink **sink, QString &destination, QgsProcessingContext &context, const QgsFields &fields, Qgis::WkbType geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &createOptions=QVariantMap()) SIP_THROW(QgsProcessingException)
Creates a feature sink ready for adding features.
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 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.
Definition: qgsprocessing.h:51
@ TypeVectorPolygon
Vector polygon layers.
Definition: qgsprocessing.h:52
@ TypeVector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition: qgsprocessing.h:55
@ TypeVectorPoint
Vector point layers.
Definition: qgsprocessing.h:50
@ TypeVectorAnyGeometry
Any vector layer with geometry.
Definition: qgsprocessing.h:49
@ 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.
Definition: qgsproject.h:1211
QgsCoordinateReferenceSystem crs
Definition: qgsproject.h:112
A store for object properties.
Definition: qgsproperty.h:230
@ StaticProperty
Static property (QgsStaticProperty)
Definition: qgsproperty.h:237
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.
Definition: qgsrectangle.h:42
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:183
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
Definition: qgsrectangle.h:391
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.
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.
QString subsetString
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:3927
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:920
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
QList< int > QgsAttributeList
Definition: qgsfield.h:27
const QgsField & field
Definition: qgsfield.h:554
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.
Definition: qgsmeshlayer.h:108
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
Definition: qgsmeshlayer.h:142
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 vector layers.