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