QGIS API Documentation  3.23.0-Master (eb871beae0)
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() );
962  try
963  {
964  QgsRectangle reprojExtent = ct.transformBoundingBox( layer->extent() );
965  extent.combineExtentWith( reprojExtent );
966  }
967  catch ( QgsCsException & )
968  {
969  // can't reproject... what to do here? hmmm?
970  // let's ignore this layer for now, but maybe we should just use the original extent?
971  }
972  }
973  else
974  {
975  extent.combineExtentWith( layer->extent() );
976  }
977 
978  }
979  return extent;
980 }
981 
982 // Deprecated
984 {
985  QgsProcessingContext context;
986  return QgsProcessingUtils::combineLayerExtents( layers, crs, context );
987 }
988 
989 QVariant QgsProcessingUtils::generateIteratingDestination( const QVariant &input, const QVariant &id, QgsProcessingContext &context )
990 {
991  if ( !input.isValid() )
992  return QStringLiteral( "memory:%1" ).arg( id.toString() );
993 
994  if ( input.canConvert<QgsProcessingOutputLayerDefinition>() )
995  {
996  QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( input );
997  QVariant newSink = generateIteratingDestination( fromVar.sink, id, context );
998  fromVar.sink = QgsProperty::fromValue( newSink );
999  return fromVar;
1000  }
1001  else if ( input.canConvert<QgsProperty>() )
1002  {
1003  QString res = input.value< QgsProperty>().valueAsString( context.expressionContext() );
1004  return generateIteratingDestination( res, id, context );
1005  }
1006  else
1007  {
1008  QString res = input.toString();
1009  if ( res == QgsProcessing::TEMPORARY_OUTPUT )
1010  {
1011  // temporary outputs map to temporary outputs!
1013  }
1014  else if ( res.startsWith( QLatin1String( "memory:" ) ) )
1015  {
1016  return QString( res + '_' + id.toString() );
1017  }
1018  else
1019  {
1020  // assume a filename type output for now
1021  // TODO - uris?
1022  int lastIndex = res.lastIndexOf( '.' );
1023  return QString( res.left( lastIndex ) + '_' + id.toString() + res.mid( lastIndex ) );
1024  }
1025  }
1026 }
1027 
1029 {
1030  // we maintain a list of temporary folders -- this allows us to append additional
1031  // folders when a setting change causes the base temp folder to change, while deferring
1032  // cleanup of ALL these temp folders until session end (we can't cleanup older folders immediately,
1033  // because we don't know whether they have data in them which is still wanted)
1034  static std::vector< std::unique_ptr< QTemporaryDir > > sTempFolders;
1035  static QString sFolder;
1036  static QMutex sMutex;
1037  QMutexLocker locker( &sMutex );
1038  const QString basePath = QgsProcessing::settingsTempPath.value();
1039  if ( basePath.isEmpty() )
1040  {
1041  // default setting -- automatically create a temp folder
1042  if ( sTempFolders.empty() )
1043  {
1044  const QString templatePath = QStringLiteral( "%1/processing_XXXXXX" ).arg( QDir::tempPath() );
1045  std::unique_ptr< QTemporaryDir > tempFolder = std::make_unique< QTemporaryDir >( templatePath );
1046  sFolder = tempFolder->path();
1047  sTempFolders.emplace_back( std::move( tempFolder ) );
1048  }
1049  }
1050  else if ( sFolder.isEmpty() || !sFolder.startsWith( basePath ) || sTempFolders.empty() )
1051  {
1052  if ( !QDir().exists( basePath ) )
1053  QDir().mkpath( basePath );
1054 
1055  const QString templatePath = QStringLiteral( "%1/processing_XXXXXX" ).arg( basePath );
1056  std::unique_ptr< QTemporaryDir > tempFolder = std::make_unique< QTemporaryDir >( templatePath );
1057  sFolder = tempFolder->path();
1058  sTempFolders.emplace_back( std::move( tempFolder ) );
1059  }
1060  return sFolder;
1061 }
1062 
1063 QString QgsProcessingUtils::generateTempFilename( const QString &basename )
1064 {
1065  QString subPath = QUuid::createUuid().toString().remove( '-' ).remove( '{' ).remove( '}' );
1066  QString path = tempFolder() + '/' + subPath;
1067  if ( !QDir( path ).exists() ) //make sure the directory exists - it shouldn't, but lets be safe...
1068  {
1069  QDir tmpDir;
1070  tmpDir.mkdir( path );
1071  }
1072  return path + '/' + QgsFileUtils::stringToSafeFilename( basename );
1073 }
1074 
1076 {
1077  auto getText = [map]( const QString & key )->QString
1078  {
1079  if ( map.contains( key ) )
1080  return map.value( key ).toString();
1081  return QString();
1082  };
1083 
1084  QString s;
1085  s += QStringLiteral( "<html><body><p>" ) + getText( QStringLiteral( "ALG_DESC" ) ) + QStringLiteral( "</p>\n" );
1086 
1087  QString inputs;
1088  const auto parameterDefinitions = algorithm->parameterDefinitions();
1089  for ( const QgsProcessingParameterDefinition *def : parameterDefinitions )
1090  {
1091  if ( def->flags() & QgsProcessingParameterDefinition::FlagHidden || def->isDestination() )
1092  continue;
1093 
1094  if ( !getText( def->name() ).isEmpty() )
1095  {
1096  inputs += QStringLiteral( "<h3>" ) + def->description() + QStringLiteral( "</h3>\n" );
1097  inputs += QStringLiteral( "<p>" ) + getText( def->name() ) + QStringLiteral( "</p>\n" );
1098  }
1099  }
1100  if ( !inputs.isEmpty() )
1101  s += QStringLiteral( "<h2>" ) + QObject::tr( "Input parameters" ) + QStringLiteral( "</h2>\n" ) + inputs;
1102 
1103  QString outputs;
1104  const auto outputDefinitions = algorithm->outputDefinitions();
1105  for ( const QgsProcessingOutputDefinition *def : outputDefinitions )
1106  {
1107  if ( !getText( def->name() ).isEmpty() )
1108  {
1109  outputs += QStringLiteral( "<h3>" ) + def->description() + QStringLiteral( "</h3>\n" );
1110  outputs += QStringLiteral( "<p>" ) + getText( def->name() ) + QStringLiteral( "</p>\n" );
1111  }
1112  }
1113  if ( !outputs.isEmpty() )
1114  s += QStringLiteral( "<h2>" ) + QObject::tr( "Outputs" ) + QStringLiteral( "</h2>\n" ) + outputs;
1115 
1116  s += QLatin1String( "<br>" );
1117  if ( !map.value( QStringLiteral( "ALG_CREATOR" ) ).toString().isEmpty() )
1118  s += QStringLiteral( "<p align=\"right\">" ) + QObject::tr( "Algorithm author:" ) + QStringLiteral( " " ) + getText( QStringLiteral( "ALG_CREATOR" ) ) + QStringLiteral( "</p>" );
1119  if ( !map.value( QStringLiteral( "ALG_HELP_CREATOR" ) ).toString().isEmpty() )
1120  s += QStringLiteral( "<p align=\"right\">" ) + QObject::tr( "Help author:" ) + QStringLiteral( " " ) + getText( QStringLiteral( "ALG_HELP_CREATOR" ) ) + QStringLiteral( "</p>" );
1121  if ( !map.value( QStringLiteral( "ALG_VERSION" ) ).toString().isEmpty() )
1122  s += QStringLiteral( "<p align=\"right\">" ) + QObject::tr( "Algorithm version:" ) + QStringLiteral( " " ) + getText( QStringLiteral( "ALG_VERSION" ) ) + QStringLiteral( "</p>" );
1123 
1124  s += QLatin1String( "</body></html>" );
1125  return s;
1126 }
1127 
1128 QString convertToCompatibleFormatInternal( const QgsVectorLayer *vl, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback, QString *layerName,
1129  long long featureLimit )
1130 {
1131  bool requiresTranslation = false;
1132 
1133  // if we are only looking for selected features then we have to export back to disk,
1134  // as we need to subset only selected features, a concept which doesn't exist outside QGIS!
1135  requiresTranslation = requiresTranslation || selectedFeaturesOnly;
1136 
1137  // if we are limiting the feature count, we better export
1138  requiresTranslation = requiresTranslation || featureLimit != -1;
1139 
1140  // if the data provider is NOT ogr, then we HAVE to convert. Otherwise we run into
1141  // issues with data providers like spatialite, delimited text where the format can be
1142  // opened outside of QGIS, but with potentially very different behavior!
1143  requiresTranslation = requiresTranslation || vl->providerType() != QLatin1String( "ogr" );
1144 
1145  // if the layer has a feature filter set, then we HAVE to convert. Feature filters are
1146  // a purely QGIS concept.
1147  requiresTranslation = requiresTranslation || !vl->subsetString().isEmpty();
1148 
1149  // if the layer opened using GDAL's virtual I/O mechanism (/vsizip/, etc.), then
1150  // we HAVE to convert as other tools may not work with it
1151  requiresTranslation = requiresTranslation || vl->source().startsWith( QLatin1String( "/vsi" ) );
1152 
1153  // Check if layer is a disk based format and if so if the layer's path has a compatible filename suffix
1154  QString diskPath;
1155  if ( !requiresTranslation )
1156  {
1157  const QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( vl->providerType(), vl->source() );
1158  if ( parts.contains( QStringLiteral( "path" ) ) )
1159  {
1160  diskPath = parts.value( QStringLiteral( "path" ) ).toString();
1161  QFileInfo fi( diskPath );
1162  requiresTranslation = !compatibleFormats.contains( fi.suffix(), Qt::CaseInsensitive );
1163 
1164  // if the layer name doesn't match the filename, we need to convert the layer. This method can only return
1165  // a filename, and cannot handle layernames as well as file paths
1166  const QString srcLayerName = parts.value( QStringLiteral( "layerName" ) ).toString();
1167  if ( layerName )
1168  {
1169  // differing layer names are acceptable
1170  *layerName = srcLayerName;
1171  }
1172  else
1173  {
1174  // differing layer names are NOT acceptable
1175  requiresTranslation = requiresTranslation || ( !srcLayerName.isEmpty() && srcLayerName != fi.baseName() );
1176  }
1177  }
1178  else
1179  {
1180  requiresTranslation = true; // not a disk-based format
1181  }
1182  }
1183 
1184  if ( requiresTranslation )
1185  {
1186  QString temp = QgsProcessingUtils::generateTempFilename( baseName + '.' + preferredFormat );
1187 
1189  saveOptions.fileEncoding = context.defaultEncoding();
1190  saveOptions.driverName = QgsVectorFileWriter::driverForExtension( preferredFormat );
1191  std::unique_ptr< QgsVectorFileWriter > writer( QgsVectorFileWriter::create( temp, vl->fields(), vl->wkbType(), vl->crs(), context.transformContext(), saveOptions ) );
1192  QgsFeature f;
1193  QgsFeatureIterator it;
1194  if ( featureLimit != -1 )
1195  {
1196  if ( selectedFeaturesOnly )
1197  it = vl->getSelectedFeatures( QgsFeatureRequest().setLimit( featureLimit ) );
1198  else
1199  it = vl->getFeatures( QgsFeatureRequest().setLimit( featureLimit ) );
1200  }
1201  else
1202  {
1203  if ( selectedFeaturesOnly )
1204  it = vl->getSelectedFeatures( QgsFeatureRequest().setLimit( featureLimit ) );
1205  else
1206  it = vl->getFeatures();
1207  }
1208 
1209  while ( it.nextFeature( f ) )
1210  {
1211  if ( feedback->isCanceled() )
1212  return QString();
1213  writer->addFeature( f, QgsFeatureSink::FastInsert );
1214  }
1215  return temp;
1216  }
1217  else
1218  {
1219  return diskPath;
1220  }
1221 }
1222 
1223 QString QgsProcessingUtils::convertToCompatibleFormat( const QgsVectorLayer *vl, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback, long long featureLimit )
1224 {
1225  return convertToCompatibleFormatInternal( vl, selectedFeaturesOnly, baseName, compatibleFormats, preferredFormat, context, feedback, nullptr, featureLimit );
1226 }
1227 
1228 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 )
1229 {
1230  layerName.clear();
1231  return convertToCompatibleFormatInternal( layer, selectedFeaturesOnly, baseName, compatibleFormats, preferredFormat, context, feedback, &layerName, featureLimit );
1232 }
1233 
1234 QgsFields QgsProcessingUtils::combineFields( const QgsFields &fieldsA, const QgsFields &fieldsB, const QString &fieldsBPrefix )
1235 {
1236  QgsFields outFields = fieldsA;
1237  QSet< QString > usedNames;
1238  for ( const QgsField &f : fieldsA )
1239  {
1240  usedNames.insert( f.name().toLower() );
1241  }
1242 
1243  for ( const QgsField &f : fieldsB )
1244  {
1245  QgsField newField = f;
1246  newField.setName( fieldsBPrefix + f.name() );
1247  if ( usedNames.contains( newField.name().toLower() ) )
1248  {
1249  int idx = 2;
1250  QString newName = newField.name() + '_' + QString::number( idx );
1251  while ( usedNames.contains( newName.toLower() ) )
1252  {
1253  idx++;
1254  newName = newField.name() + '_' + QString::number( idx );
1255  }
1256  newField.setName( newName );
1257  outFields.append( newField );
1258  }
1259  else
1260  {
1261  outFields.append( newField );
1262  }
1263  usedNames.insert( newField.name() );
1264  }
1265 
1266  return outFields;
1267 }
1268 
1269 
1270 QList<int> QgsProcessingUtils::fieldNamesToIndices( const QStringList &fieldNames, const QgsFields &fields )
1271 {
1272  QList<int> indices;
1273  if ( !fieldNames.isEmpty() )
1274  {
1275  indices.reserve( fieldNames.count() );
1276  for ( const QString &f : fieldNames )
1277  {
1278  int idx = fields.lookupField( f );
1279  if ( idx >= 0 )
1280  indices.append( idx );
1281  }
1282  }
1283  else
1284  {
1285  indices.reserve( fields.count() );
1286  for ( int i = 0; i < fields.count(); ++i )
1287  indices.append( i );
1288  }
1289  return indices;
1290 }
1291 
1292 
1293 QgsFields QgsProcessingUtils::indicesToFields( const QList<int> &indices, const QgsFields &fields )
1294 {
1295  QgsFields fieldsSubset;
1296  for ( int i : indices )
1297  fieldsSubset.append( fields.at( i ) );
1298  return fieldsSubset;
1299 }
1300 
1302 {
1303  const int setting = QgsProcessing::settingsDefaultOutputVectorLayerExt.value();
1304  if ( setting == -1 )
1305  return QStringLiteral( "gpkg" );
1306  return QgsVectorFileWriter::supportedFormatExtensions().value( setting, QStringLiteral( "gpkg" ) );
1307 }
1308 
1310 {
1311  const int setting = QgsProcessing::settingsDefaultOutputRasterLayerExt.value();
1312  if ( setting == -1 )
1313  return QStringLiteral( "tif" );
1314  return QgsRasterFileWriter::supportedFormatExtensions().value( setting, QStringLiteral( "tif" ) );
1315 }
1316 
1318 {
1319  return QStringLiteral( "las" );
1320 }
1321 
1322 //
1323 // QgsProcessingFeatureSource
1324 //
1325 
1326 QgsProcessingFeatureSource::QgsProcessingFeatureSource( QgsFeatureSource *originalSource, const QgsProcessingContext &context, bool ownsOriginalSource, long long featureLimit )
1327  : mSource( originalSource )
1328  , mOwnsSource( ownsOriginalSource )
1329  , mInvalidGeometryCheck( QgsWkbTypes::geometryType( mSource->wkbType() ) == QgsWkbTypes::PointGeometry
1330  ? QgsFeatureRequest::GeometryNoCheck // never run geometry validity checks for point layers!
1331  : context.invalidGeometryCheck() )
1332  , mInvalidGeometryCallback( context.invalidGeometryCallback( originalSource ) )
1333  , mTransformErrorCallback( context.transformErrorCallback() )
1334  , mInvalidGeometryCallbackSkip( context.defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::GeometrySkipInvalid, originalSource ) )
1335  , mInvalidGeometryCallbackAbort( context.defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::GeometryAbortOnInvalid, originalSource ) )
1336  , mFeatureLimit( featureLimit )
1337 {}
1338 
1340 {
1341  if ( mOwnsSource )
1342  delete mSource;
1343 }
1344 
1346 {
1347  QgsFeatureRequest req( request );
1348  req.setTransformErrorCallback( mTransformErrorCallback );
1349 
1350  if ( flags & FlagSkipGeometryValidityChecks )
1352  else
1353  {
1354  req.setInvalidGeometryCheck( mInvalidGeometryCheck );
1355  req.setInvalidGeometryCallback( mInvalidGeometryCallback );
1356  }
1357 
1358  if ( mFeatureLimit != -1 && req.limit() != -1 )
1359  req.setLimit( std::min( static_cast< long long >( req.limit() ), mFeatureLimit ) );
1360  else if ( mFeatureLimit != -1 )
1361  req.setLimit( mFeatureLimit );
1362 
1363  return mSource->getFeatures( req );
1364 }
1365 
1367 {
1368  FeatureAvailability sourceAvailability = mSource->hasFeatures();
1369  if ( sourceAvailability == NoFeaturesAvailable )
1370  return NoFeaturesAvailable; // never going to be features if underlying source has no features
1371  else if ( mInvalidGeometryCheck == QgsFeatureRequest::GeometryNoCheck )
1372  return sourceAvailability;
1373  else
1374  // we don't know... source has features, but these may be filtered out by invalid geometry check
1375  return FeaturesMaybeAvailable;
1376 }
1377 
1379 {
1380  QgsFeatureRequest req( request );
1381  req.setInvalidGeometryCheck( mInvalidGeometryCheck );
1382  req.setInvalidGeometryCallback( mInvalidGeometryCallback );
1383  req.setTransformErrorCallback( mTransformErrorCallback );
1384 
1385  if ( mFeatureLimit != -1 && req.limit() != -1 )
1386  req.setLimit( std::min( static_cast< long long >( req.limit() ), mFeatureLimit ) );
1387  else if ( mFeatureLimit != -1 )
1388  req.setLimit( mFeatureLimit );
1389 
1390  return mSource->getFeatures( req );
1391 }
1392 
1394 {
1395  return mSource->sourceCrs();
1396 }
1397 
1399 {
1400  return mSource->fields();
1401 }
1402 
1404 {
1405  return mSource->wkbType();
1406 }
1407 
1409 {
1410  if ( mFeatureLimit == -1 )
1411  return mSource->featureCount();
1412  else
1413  return std::min( mFeatureLimit, mSource->featureCount() );
1414 }
1415 
1417 {
1418  return mSource->sourceName();
1419 
1420 }
1421 
1422 QSet<QVariant> QgsProcessingFeatureSource::uniqueValues( int fieldIndex, int limit ) const
1423 {
1424  return mSource->uniqueValues( fieldIndex, limit );
1425 }
1426 
1427 QVariant QgsProcessingFeatureSource::minimumValue( int fieldIndex ) const
1428 {
1429  return mSource->minimumValue( fieldIndex );
1430 }
1431 
1432 QVariant QgsProcessingFeatureSource::maximumValue( int fieldIndex ) const
1433 {
1434  return mSource->maximumValue( fieldIndex );
1435 }
1436 
1438 {
1439  return mSource->sourceExtent();
1440 }
1441 
1443 {
1444  return mSource->allFeatureIds();
1445 }
1446 
1448 {
1449  return mSource->hasSpatialIndex();
1450 }
1451 
1453 {
1454  QgsExpressionContextScope *expressionContextScope = nullptr;
1455  QgsExpressionContextScopeGenerator *generator = dynamic_cast<QgsExpressionContextScopeGenerator *>( mSource );
1456  if ( generator )
1457  {
1458  expressionContextScope = generator->createExpressionContextScope();
1459  }
1460  return expressionContextScope;
1461 }
1462 
1464 {
1465  mInvalidGeometryCheck = method;
1466  switch ( mInvalidGeometryCheck )
1467  {
1469  mInvalidGeometryCallback = nullptr;
1470  break;
1471 
1473  mInvalidGeometryCallback = mInvalidGeometryCallbackSkip;
1474  break;
1475 
1477  mInvalidGeometryCallback = mInvalidGeometryCallbackAbort;
1478  break;
1479 
1480  }
1481 }
1482 
1483 
1484 //
1485 // QgsProcessingFeatureSink
1486 //
1487 QgsProcessingFeatureSink::QgsProcessingFeatureSink( QgsFeatureSink *originalSink, const QString &sinkName, QgsProcessingContext &context, bool ownsOriginalSink )
1488  : QgsProxyFeatureSink( originalSink )
1489  , mContext( context )
1490  , mSinkName( sinkName )
1491  , mOwnsSink( ownsOriginalSink )
1492 {}
1493 
1495 {
1496  if ( mOwnsSink )
1497  delete destinationSink();
1498 }
1499 
1500 bool QgsProcessingFeatureSink::addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags )
1501 {
1502  bool result = QgsProxyFeatureSink::addFeature( feature, flags );
1503  if ( !result && mContext.feedback() )
1504  {
1505  const QString error = lastError();
1506  if ( !error.isEmpty() )
1507  mContext.feedback()->reportError( QObject::tr( "Feature could not be written to %1: %2" ).arg( mSinkName, error ) );
1508  else
1509  mContext.feedback()->reportError( QObject::tr( "Feature could not be written to %1" ).arg( mSinkName ) );
1510  }
1511  return result;
1512 }
1513 
1514 bool QgsProcessingFeatureSink::addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags )
1515 {
1516  bool result = QgsProxyFeatureSink::addFeatures( features, flags );
1517  if ( !result && mContext.feedback() )
1518  {
1519  const QString error = lastError();
1520  if ( !error.isEmpty() )
1521  mContext.feedback()->reportError( QObject::tr( "%1 feature(s) could not be written to %2: %3" ).arg( features.count() ).arg( mSinkName, error ) );
1522  else
1523  mContext.feedback()->reportError( QObject::tr( "%1 feature(s) could not be written to %2" ).arg( features.count() ).arg( mSinkName ) );
1524  }
1525  return result;
1526 }
1527 
1528 bool QgsProcessingFeatureSink::addFeatures( QgsFeatureIterator &iterator, QgsFeatureSink::Flags flags )
1529 {
1530  bool result = QgsProxyFeatureSink::addFeatures( iterator, flags );
1531  if ( !result && mContext.feedback() )
1532  {
1533  const QString error = lastError();
1534  if ( !error.isEmpty() )
1535  mContext.feedback()->reportError( QObject::tr( "Features could not be written to %1: %2" ).arg( mSinkName, error ) );
1536  else
1537  mContext.feedback()->reportError( QObject::tr( "Features could not be written to %1" ).arg( mSinkName ) );
1538  }
1539  return result;
1540 }
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.
QString authid() const
Returns the authority identifier for the CRS.
Contains information about the context in which a coordinate transform is executed.
Class for doing transforms between two map coordinate systems.
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 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:344
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
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:97
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 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:101
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:1093
QgsCoordinateReferenceSystem crs
Definition: qgsproject.h:106
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.
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:1456
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:834
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:105
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
Definition: qgsmeshlayer.h:139
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.