QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
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  return true;
205  case QgsMapLayerType::MeshLayer:
206  return !canUseLayer( qobject_cast< QgsMeshLayer * >( layer ) );
207  case QgsMapLayerType::VectorTileLayer:
208  return !canUseLayer( qobject_cast< QgsVectorTileLayer * >( layer ) );
209  case QgsMapLayerType::PointCloudLayer:
210  return !canUseLayer( qobject_cast< QgsPointCloudLayer * >( layer ) );
211  case QgsMapLayerType::AnnotationLayer:
212  return !canUseLayer( qobject_cast< QgsAnnotationLayer * >( layer ) );
213  }
214  return true;
215  } ), layers.end() );
216 
217  auto isCompatibleType = [typeHint]( QgsMapLayer * l ) -> bool
218  {
219  switch ( typeHint )
220  {
221  case LayerHint::UnknownType:
222  return true;
223 
224  case LayerHint::Vector:
225  return l->type() == QgsMapLayerType::VectorLayer;
226 
227  case LayerHint::Raster:
228  return l->type() == QgsMapLayerType::RasterLayer;
229 
230  case LayerHint::Mesh:
231  return l->type() == QgsMapLayerType::MeshLayer;
232 
233  case LayerHint::PointCloud:
234  return l->type() == QgsMapLayerType::PointCloudLayer;
235 
236  case LayerHint::Annotation:
237  return l->type() == QgsMapLayerType::AnnotationLayer;
238  }
239  return true;
240  };
241 
242  for ( QgsMapLayer *l : std::as_const( layers ) )
243  {
244  if ( isCompatibleType( l ) && l->id() == string )
245  return l;
246  }
247  for ( QgsMapLayer *l : std::as_const( layers ) )
248  {
249  if ( isCompatibleType( l ) && l->name() == string )
250  return l;
251  }
252  for ( QgsMapLayer *l : std::as_const( layers ) )
253  {
254  if ( isCompatibleType( l ) && normalizeLayerSource( l->source() ) == normalizeLayerSource( string ) )
255  return l;
256  }
257  return nullptr;
258 }
259 
260 QgsMapLayer *QgsProcessingUtils::loadMapLayerFromString( const QString &string, const QgsCoordinateTransformContext &transformContext, LayerHint typeHint )
261 {
262  QString provider;
263  QString uri;
264  const bool useProvider = decodeProviderKeyAndUri( string, provider, uri );
265  if ( !useProvider )
266  uri = string;
267 
268  QString name;
269  // for disk based sources, we use the filename to determine a layer name
270  if ( !useProvider || ( provider == QLatin1String( "ogr" ) || provider == QLatin1String( "gdal" ) || provider == QLatin1String( "mdal" ) || provider == QLatin1String( "pdal" ) || provider == QLatin1String( "ept" ) ) )
271  {
272  QStringList components = uri.split( '|' );
273  if ( components.isEmpty() )
274  return nullptr;
275 
276  QFileInfo fi;
277  if ( QFileInfo::exists( uri ) )
278  fi = QFileInfo( uri );
279  else if ( QFileInfo::exists( components.at( 0 ) ) )
280  fi = QFileInfo( components.at( 0 ) );
281  else
282  return nullptr;
283  name = fi.baseName();
284  }
285  else
286  {
287  name = QgsDataSourceUri( uri ).table();
288  }
289 
290  // brute force attempt to load a matching layer
291  if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::Vector )
292  {
293  QgsVectorLayer::LayerOptions options { transformContext };
294  options.loadDefaultStyle = false;
295  options.skipCrsValidation = true;
296 
297  std::unique_ptr< QgsVectorLayer > layer;
298  if ( useProvider )
299  {
300  layer = std::make_unique<QgsVectorLayer>( uri, name, provider, options );
301  }
302  else
303  {
304  // fallback to ogr
305  layer = std::make_unique<QgsVectorLayer>( uri, name, QStringLiteral( "ogr" ), options );
306  }
307  if ( layer->isValid() )
308  {
309  return layer.release();
310  }
311  }
312  if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::Raster )
313  {
314  QgsRasterLayer::LayerOptions rasterOptions;
315  rasterOptions.loadDefaultStyle = false;
316  rasterOptions.skipCrsValidation = true;
317 
318  std::unique_ptr< QgsRasterLayer > rasterLayer;
319  if ( useProvider )
320  {
321  rasterLayer = std::make_unique< QgsRasterLayer >( uri, name, provider, rasterOptions );
322  }
323  else
324  {
325  // fallback to gdal
326  rasterLayer = std::make_unique< QgsRasterLayer >( uri, name, QStringLiteral( "gdal" ), rasterOptions );
327  }
328 
329  if ( rasterLayer->isValid() )
330  {
331  return rasterLayer.release();
332  }
333  }
334  if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::Mesh )
335  {
336  QgsMeshLayer::LayerOptions meshOptions;
337  meshOptions.skipCrsValidation = true;
338 
339  std::unique_ptr< QgsMeshLayer > meshLayer;
340  if ( useProvider )
341  {
342  meshLayer = std::make_unique< QgsMeshLayer >( uri, name, provider, meshOptions );
343  }
344  else
345  {
346  meshLayer = std::make_unique< QgsMeshLayer >( uri, name, QStringLiteral( "mdal" ), meshOptions );
347  }
348  if ( meshLayer->isValid() )
349  {
350  return meshLayer.release();
351  }
352  }
353  if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::PointCloud )
354  {
355  QgsPointCloudLayer::LayerOptions pointCloudOptions;
356  pointCloudOptions.skipCrsValidation = true;
357 
358  std::unique_ptr< QgsPointCloudLayer > pointCloudLayer;
359  if ( useProvider )
360  {
361  pointCloudLayer = std::make_unique< QgsPointCloudLayer >( uri, name, provider, pointCloudOptions );
362  }
363  else
364  {
365  pointCloudLayer = std::make_unique< QgsPointCloudLayer >( uri, name, QStringLiteral( "pointcloud" ), pointCloudOptions );
366  }
367  if ( pointCloudLayer->isValid() )
368  {
369  return pointCloudLayer.release();
370  }
371  }
372  return nullptr;
373 }
374 
375 QgsMapLayer *QgsProcessingUtils::mapLayerFromString( const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers, LayerHint typeHint )
376 {
377  if ( string.isEmpty() )
378  return nullptr;
379 
380  // prefer project layers
381  if ( context.project() && typeHint == LayerHint::Annotation && string.compare( QLatin1String( "main" ), Qt::CaseInsensitive ) == 0 )
382  return context.project()->mainAnnotationLayer();
383 
384  QgsMapLayer *layer = nullptr;
385  if ( auto *lProject = context.project() )
386  {
387  QgsMapLayer *layer = mapLayerFromStore( string, lProject->layerStore(), typeHint );
388  if ( layer )
389  return layer;
390  }
391 
392  layer = mapLayerFromStore( string, context.temporaryLayerStore(), typeHint );
393  if ( layer )
394  return layer;
395 
396  if ( !allowLoadingNewLayers )
397  return nullptr;
398 
399  layer = loadMapLayerFromString( string, context.transformContext(), typeHint );
400  if ( layer )
401  {
402  context.temporaryLayerStore()->addMapLayer( layer );
403  return layer;
404  }
405  else
406  {
407  return nullptr;
408  }
409 }
410 
411 QgsProcessingFeatureSource *QgsProcessingUtils::variantToSource( const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue )
412 {
413  QVariant val = value;
414  bool selectedFeaturesOnly = false;
415  long long featureLimit = -1;
416  bool overrideGeometryCheck = false;
418  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
419  {
420  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
421  QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
422  selectedFeaturesOnly = fromVar.selectedFeaturesOnly;
423  featureLimit = fromVar.featureLimit;
424  val = fromVar.source;
425  overrideGeometryCheck = fromVar.flags & QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck;
426  geometryCheck = fromVar.geometryCheck;
427  }
428  else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
429  {
430  // input is a QgsProcessingOutputLayerDefinition (e.g. an output from earlier in a model) - get extra properties from it
431  QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
432  val = fromVar.sink;
433  }
434 
435  if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( val ) ) )
436  {
437  std::unique_ptr< QgsProcessingFeatureSource> source = std::make_unique< QgsProcessingFeatureSource >( layer, context, false, featureLimit );
438  if ( overrideGeometryCheck )
439  source->setInvalidGeometryCheck( geometryCheck );
440  return source.release();
441  }
442 
443  QString layerRef;
444  if ( val.canConvert<QgsProperty>() )
445  {
446  layerRef = val.value< QgsProperty >().valueAsString( context.expressionContext(), fallbackValue.toString() );
447  }
448  else if ( !val.isValid() || val.toString().isEmpty() )
449  {
450  // fall back to default
451  if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( fallbackValue ) ) )
452  {
453  std::unique_ptr< QgsProcessingFeatureSource> source = std::make_unique< QgsProcessingFeatureSource >( layer, context, false, featureLimit );
454  if ( overrideGeometryCheck )
455  source->setInvalidGeometryCheck( geometryCheck );
456  return source.release();
457  }
458 
459  layerRef = fallbackValue.toString();
460  }
461  else
462  {
463  layerRef = val.toString();
464  }
465 
466  if ( layerRef.isEmpty() )
467  return nullptr;
468 
469  QgsVectorLayer *vl = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( layerRef, context, true, LayerHint::Vector ) );
470  if ( !vl )
471  return nullptr;
472 
473  std::unique_ptr< QgsProcessingFeatureSource> source;
474  if ( selectedFeaturesOnly )
475  {
476  source = std::make_unique< QgsProcessingFeatureSource>( new QgsVectorLayerSelectedFeatureSource( vl ), context, true, featureLimit );
477  }
478  else
479  {
480  source = std::make_unique< QgsProcessingFeatureSource >( vl, context, false, featureLimit );
481  }
482 
483  if ( overrideGeometryCheck )
484  source->setInvalidGeometryCheck( geometryCheck );
485  return source.release();
486 }
487 
488 QgsCoordinateReferenceSystem QgsProcessingUtils::variantToCrs( const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue )
489 {
490  QVariant val = value;
491 
492  if ( val.canConvert<QgsCoordinateReferenceSystem>() )
493  {
494  // input is a QgsCoordinateReferenceSystem - done!
495  return val.value< QgsCoordinateReferenceSystem >();
496  }
497  else if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
498  {
499  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
500  QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
501  val = fromVar.source;
502  }
503  else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
504  {
505  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
506  QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
507  val = fromVar.sink;
508  }
509 
510  if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
511  {
512  val = val.value< QgsProperty >().staticValue();
513  }
514 
515  // maybe a map layer
516  if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
517  return layer->crs();
518 
519  if ( val.canConvert<QgsProperty>() )
520  val = val.value< QgsProperty >().valueAsString( context.expressionContext(), fallbackValue.toString() );
521 
522  if ( !val.isValid() )
523  {
524  // fall back to default
525  val = fallbackValue;
526  }
527 
528  QString crsText = val.toString();
529  if ( crsText.isEmpty() )
530  crsText = fallbackValue.toString();
531 
532  if ( crsText.isEmpty() )
534 
535  // maybe special string
536  if ( context.project() && crsText.compare( QLatin1String( "ProjectCrs" ), Qt::CaseInsensitive ) == 0 )
537  return context.project()->crs();
538 
539  // maybe a map layer reference
540  if ( QgsMapLayer *layer = QgsProcessingUtils::mapLayerFromString( crsText, context ) )
541  return layer->crs();
542 
543  // else CRS from string
545  crs.createFromString( crsText );
546  return crs;
547 }
548 
549 bool QgsProcessingUtils::canUseLayer( const QgsMeshLayer *layer )
550 {
551  return layer && layer->dataProvider();
552 }
553 
554 bool QgsProcessingUtils::canUseLayer( const QgsPluginLayer *layer )
555 {
556  return layer && layer->isValid();
557 }
558 
559 bool QgsProcessingUtils::canUseLayer( const QgsVectorTileLayer *layer )
560 {
561  return layer && layer->isValid();
562 }
563 
564 bool QgsProcessingUtils::canUseLayer( const QgsRasterLayer *layer )
565 {
566  return layer && layer->isValid();
567 }
568 
569 bool QgsProcessingUtils::canUseLayer( const QgsPointCloudLayer *layer )
570 {
571  return layer && layer->isValid();
572 }
573 
574 bool QgsProcessingUtils::canUseLayer( const QgsAnnotationLayer *layer )
575 {
576  return layer && layer->isValid();
577 }
578 
579 bool QgsProcessingUtils::canUseLayer( const QgsVectorLayer *layer, const QList<int> &sourceTypes )
580 {
581  return layer && layer->isValid() &&
582  ( sourceTypes.isEmpty()
583  || ( sourceTypes.contains( QgsProcessing::TypeVectorPoint ) && layer->geometryType() == QgsWkbTypes::PointGeometry )
584  || ( sourceTypes.contains( QgsProcessing::TypeVectorLine ) && layer->geometryType() == QgsWkbTypes::LineGeometry )
585  || ( sourceTypes.contains( QgsProcessing::TypeVectorPolygon ) && layer->geometryType() == QgsWkbTypes::PolygonGeometry )
586  || ( sourceTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) && layer->isSpatial() )
587  || sourceTypes.contains( QgsProcessing::TypeVector )
588  );
589 }
590 
591 QString QgsProcessingUtils::normalizeLayerSource( const QString &source )
592 {
593  QString normalized = source;
594  normalized.replace( '\\', '/' );
595  return normalized.trimmed();
596 }
597 
598 QString QgsProcessingUtils::variantToPythonLiteral( const QVariant &value )
599 {
600  if ( !value.isValid() )
601  return QStringLiteral( "None" );
602 
603  if ( value.canConvert<QgsProperty>() )
604  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
605  else if ( value.canConvert<QgsCoordinateReferenceSystem>() )
606  {
607  if ( !value.value< QgsCoordinateReferenceSystem >().isValid() )
608  return QStringLiteral( "QgsCoordinateReferenceSystem()" );
609  else
610  return QStringLiteral( "QgsCoordinateReferenceSystem('%1')" ).arg( value.value< QgsCoordinateReferenceSystem >().authid() );
611  }
612  else if ( value.canConvert< QgsRectangle >() )
613  {
614  QgsRectangle r = value.value<QgsRectangle>();
615  return QStringLiteral( "'%1, %3, %2, %4'" ).arg( qgsDoubleToString( r.xMinimum() ),
618  qgsDoubleToString( r.yMaximum() ) );
619  }
620  else if ( value.canConvert< QgsReferencedRectangle >() )
621  {
623  return QStringLiteral( "'%1, %3, %2, %4 [%5]'" ).arg( qgsDoubleToString( r.xMinimum() ),
626  qgsDoubleToString( r.yMaximum() ), r.crs().authid() );
627  }
628  else if ( value.canConvert< QgsPointXY >() )
629  {
630  QgsPointXY r = value.value<QgsPointXY>();
631  return QStringLiteral( "'%1,%2'" ).arg( qgsDoubleToString( r.x() ),
632  qgsDoubleToString( r.y() ) );
633  }
634  else if ( value.canConvert< QgsReferencedPointXY >() )
635  {
636  QgsReferencedPointXY r = value.value<QgsReferencedPointXY>();
637  return QStringLiteral( "'%1,%2 [%3]'" ).arg( qgsDoubleToString( r.x() ),
638  qgsDoubleToString( r.y() ),
639  r.crs().authid() );
640  }
641 
642  switch ( value.type() )
643  {
644  case QVariant::Bool:
645  return value.toBool() ? QStringLiteral( "True" ) : QStringLiteral( "False" );
646 
647  case QVariant::Double:
648  return QString::number( value.toDouble() );
649 
650  case QVariant::Int:
651  case QVariant::UInt:
652  return QString::number( value.toInt() );
653 
654  case QVariant::LongLong:
655  case QVariant::ULongLong:
656  return QString::number( value.toLongLong() );
657 
658  case QVariant::List:
659  {
660  QStringList parts;
661  const QVariantList vl = value.toList();
662  for ( const QVariant &v : vl )
663  {
664  parts << variantToPythonLiteral( v );
665  }
666  return parts.join( ',' ).prepend( '[' ).append( ']' );
667  }
668 
669  case QVariant::Map:
670  {
671  const QVariantMap map = value.toMap();
672  QStringList parts;
673  parts.reserve( map.size() );
674  for ( auto it = map.constBegin(); it != map.constEnd(); ++it )
675  {
676  parts << QStringLiteral( "%1: %2" ).arg( stringToPythonLiteral( it.key() ), variantToPythonLiteral( it.value() ) );
677  }
678  return parts.join( ',' ).prepend( '{' ).append( '}' );
679  }
680 
681  case QVariant::DateTime:
682  {
683  const QDateTime dateTime = value.toDateTime();
684  return QStringLiteral( "QDateTime(QDate(%1, %2, %3), QTime(%4, %5, %6))" )
685  .arg( dateTime.date().year() )
686  .arg( dateTime.date().month() )
687  .arg( dateTime.date().day() )
688  .arg( dateTime.time().hour() )
689  .arg( dateTime.time().minute() )
690  .arg( dateTime.time().second() );
691  }
692 
693  default:
694  break;
695  }
696 
697  return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
698 }
699 
700 QString QgsProcessingUtils::stringToPythonLiteral( const QString &string )
701 {
702  QString s = string;
703  s.replace( '\\', QLatin1String( "\\\\" ) );
704  s.replace( '\n', QLatin1String( "\\n" ) );
705  s.replace( '\r', QLatin1String( "\\r" ) );
706  s.replace( '\t', QLatin1String( "\\t" ) );
707 
708  if ( s.contains( '\'' ) && !s.contains( '\"' ) )
709  {
710  s = s.prepend( '"' ).append( '"' );
711  }
712  else
713  {
714  s.replace( '\'', QLatin1String( "\\\'" ) );
715  s = s.prepend( '\'' ).append( '\'' );
716  }
717  return s;
718 }
719 
720 void QgsProcessingUtils::parseDestinationString( QString &destination, QString &providerKey, QString &uri, QString &layerName, QString &format, QMap<QString, QVariant> &options, bool &useWriter, QString &extension )
721 {
722  extension.clear();
723  bool matched = decodeProviderKeyAndUri( destination, providerKey, uri );
724 
725  if ( !matched )
726  {
727  QRegularExpression splitRx( QStringLiteral( "^(.{3,}?):(.*)$" ) );
728  QRegularExpressionMatch match = splitRx.match( destination );
729  if ( match.hasMatch() )
730  {
731  providerKey = match.captured( 1 );
732  uri = match.captured( 2 );
733  matched = true;
734  }
735  }
736 
737  if ( matched )
738  {
739  if ( providerKey == QLatin1String( "postgis" ) ) // older processing used "postgis" instead of "postgres"
740  {
741  providerKey = QStringLiteral( "postgres" );
742  }
743  if ( providerKey == QLatin1String( "ogr" ) )
744  {
745  QgsDataSourceUri dsUri( uri );
746  if ( !dsUri.database().isEmpty() )
747  {
748  if ( !dsUri.table().isEmpty() )
749  {
750  layerName = dsUri.table();
751  options.insert( QStringLiteral( "layerName" ), layerName );
752  }
753  uri = dsUri.database();
754  extension = QFileInfo( uri ).completeSuffix();
755  format = QgsVectorFileWriter::driverForExtension( extension );
756  options.insert( QStringLiteral( "driverName" ), format );
757  }
758  else
759  {
760  extension = QFileInfo( uri ).completeSuffix();
761  options.insert( QStringLiteral( "driverName" ), QgsVectorFileWriter::driverForExtension( extension ) );
762  }
763  options.insert( QStringLiteral( "update" ), true );
764  }
765  useWriter = false;
766  }
767  else
768  {
769  useWriter = true;
770  providerKey = QStringLiteral( "ogr" );
771 
772  QRegularExpression splitRx( QStringLiteral( "^(.*)\\.(.*?)$" ) );
773  QRegularExpressionMatch match = splitRx.match( destination );
774  if ( match.hasMatch() )
775  {
776  extension = match.captured( 2 );
777  format = QgsVectorFileWriter::driverForExtension( extension );
778  }
779 
780  if ( format.isEmpty() )
781  {
782  format = QStringLiteral( "GPKG" );
783  destination = destination + QStringLiteral( ".gpkg" );
784  }
785 
786  options.insert( QStringLiteral( "driverName" ), format );
787  uri = destination;
788  }
789 }
790 
791 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 )
792 {
793  QVariantMap options = createOptions;
794  if ( !options.contains( QStringLiteral( "fileEncoding" ) ) )
795  {
796  // no destination encoding specified, use default
797  options.insert( QStringLiteral( "fileEncoding" ), context.defaultEncoding().isEmpty() ? QStringLiteral( "system" ) : context.defaultEncoding() );
798  }
799 
800  if ( destination.isEmpty() || destination.startsWith( QLatin1String( "memory:" ) ) )
801  {
802  // strip "memory:" from start of destination
803  if ( destination.startsWith( QLatin1String( "memory:" ) ) )
804  destination = destination.mid( 7 );
805 
806  if ( destination.isEmpty() )
807  destination = QStringLiteral( "output" );
808 
809  // memory provider cannot be used with QgsVectorLayerImport - so create layer manually
810  std::unique_ptr< QgsVectorLayer > layer( QgsMemoryProviderUtils::createMemoryLayer( destination, fields, geometryType, crs ) );
811  if ( !layer || !layer->isValid() )
812  {
813  throw QgsProcessingException( QObject::tr( "Could not create memory layer" ) );
814  }
815 
816  layer->setCustomProperty( QStringLiteral( "OnConvertFormatRegeneratePrimaryKey" ), static_cast< bool >( sinkFlags & QgsFeatureSink::RegeneratePrimaryKey ) );
817 
818  // update destination to layer ID
819  destination = layer->id();
820 
821  // this is a factory, so we need to return a proxy
822  std::unique_ptr< QgsProcessingFeatureSink > sink( new QgsProcessingFeatureSink( layer->dataProvider(), destination, context ) );
823  context.temporaryLayerStore()->addMapLayer( layer.release() );
824 
825  return sink.release();
826  }
827  else
828  {
829  QString providerKey;
830  QString uri;
831  QString layerName;
832  QString format;
833  QString extension;
834  bool useWriter = false;
835  parseDestinationString( destination, providerKey, uri, layerName, format, options, useWriter, extension );
836 
837  QgsFields newFields = fields;
838  if ( useWriter && providerKey == QLatin1String( "ogr" ) )
839  {
840  // use QgsVectorFileWriter for OGR destinations instead of QgsVectorLayerImport, as that allows
841  // us to use any OGR format which supports feature addition
842  QString finalFileName;
843  QString finalLayerName;
845  saveOptions.fileEncoding = options.value( QStringLiteral( "fileEncoding" ) ).toString();
846  saveOptions.layerName = !layerName.isEmpty() ? layerName : options.value( QStringLiteral( "layerName" ) ).toString();
847  saveOptions.driverName = format;
848  saveOptions.datasourceOptions = !datasourceOptions.isEmpty() ? datasourceOptions : QgsVectorFileWriter::defaultDatasetOptions( format );
849  saveOptions.layerOptions = !layerOptions.isEmpty() ? layerOptions : QgsVectorFileWriter::defaultLayerOptions( format );
851  if ( remappingDefinition )
852  {
854  // sniff destination file to get correct wkb type and crs
855  std::unique_ptr< QgsVectorLayer > vl = std::make_unique< QgsVectorLayer >( destination );
856  if ( vl->isValid() )
857  {
858  remappingDefinition->setDestinationWkbType( vl->wkbType() );
859  remappingDefinition->setDestinationCrs( vl->crs() );
860  newFields = vl->fields();
861  remappingDefinition->setDestinationFields( newFields );
862  }
863  context.expressionContext().setFields( fields );
864  }
865  else
866  {
868  }
869  std::unique_ptr< QgsVectorFileWriter > writer( QgsVectorFileWriter::create( destination, newFields, geometryType, crs, context.transformContext(), saveOptions, sinkFlags, &finalFileName, &finalLayerName ) );
870  if ( writer->hasError() )
871  {
872  throw QgsProcessingException( QObject::tr( "Could not create layer %1: %2" ).arg( destination, writer->errorMessage() ) );
873  }
874  destination = finalFileName;
875  if ( !saveOptions.layerName.isEmpty() && !finalLayerName.isEmpty() )
876  destination += QStringLiteral( "|layername=%1" ).arg( finalLayerName );
877 
878  if ( remappingDefinition )
879  {
880  std::unique_ptr< QgsRemappingProxyFeatureSink > remapSink = std::make_unique< QgsRemappingProxyFeatureSink >( *remappingDefinition, writer.release(), true );
881  remapSink->setExpressionContext( context.expressionContext() );
882  remapSink->setTransformContext( context.transformContext() );
883  return new QgsProcessingFeatureSink( remapSink.release(), destination, context, true );
884  }
885  else
886  return new QgsProcessingFeatureSink( writer.release(), destination, context, true );
887  }
888  else
889  {
890  const QgsVectorLayer::LayerOptions layerOptions { context.transformContext() };
891  if ( remappingDefinition )
892  {
893  //write to existing layer
894 
895  // use destination string as layer name (eg "postgis:..." )
896  if ( !layerName.isEmpty() )
897  {
898  QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( providerKey, uri );
899  parts.insert( QStringLiteral( "layerName" ), layerName );
900  uri = QgsProviderRegistry::instance()->encodeUri( providerKey, parts );
901  }
902 
903  std::unique_ptr< QgsVectorLayer > layer = std::make_unique<QgsVectorLayer>( uri, destination, providerKey, layerOptions );
904  // update destination to layer ID
905  destination = layer->id();
906  if ( layer->isValid() )
907  {
908  remappingDefinition->setDestinationWkbType( layer->wkbType() );
909  remappingDefinition->setDestinationCrs( layer->crs() );
910  remappingDefinition->setDestinationFields( layer->fields() );
911  }
912 
913  std::unique_ptr< QgsRemappingProxyFeatureSink > remapSink = std::make_unique< QgsRemappingProxyFeatureSink >( *remappingDefinition, layer->dataProvider(), false );
914  context.temporaryLayerStore()->addMapLayer( layer.release() );
915  remapSink->setExpressionContext( context.expressionContext() );
916  remapSink->setTransformContext( context.transformContext() );
917  context.expressionContext().setFields( fields );
918  return new QgsProcessingFeatureSink( remapSink.release(), destination, context, true );
919  }
920  else
921  {
922  //create empty layer
923  std::unique_ptr< QgsVectorLayerExporter > exporter = std::make_unique<QgsVectorLayerExporter>( uri, providerKey, newFields, geometryType, crs, true, options, sinkFlags );
924  if ( exporter->errorCode() != Qgis::VectorExportResult::Success )
925  {
926  throw QgsProcessingException( QObject::tr( "Could not create layer %1: %2" ).arg( destination, exporter->errorMessage() ) );
927  }
928 
929  // use destination string as layer name (eg "postgis:..." )
930  if ( !layerName.isEmpty() )
931  {
932  uri += QStringLiteral( "|layername=%1" ).arg( layerName );
933  // update destination to generated URI
934  destination = uri;
935  }
936 
937  return new QgsProcessingFeatureSink( exporter.release(), destination, context, true );
938  }
939  }
940  }
941 }
942 
943 void QgsProcessingUtils::createFeatureSinkPython( QgsFeatureSink **sink, QString &destination, QgsProcessingContext &context, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &options )
944 {
945  *sink = createFeatureSink( destination, context, fields, geometryType, crs, options );
946 }
947 
948 
950 {
951  QgsRectangle extent;
952  for ( const QgsMapLayer *layer : layers )
953  {
954  if ( !layer )
955  continue;
956 
957  if ( crs.isValid() )
958  {
959  //transform layer extent to target CRS
960  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 {
1304  if ( setting == -1 )
1305  return QStringLiteral( "gpkg" );
1306  return QgsVectorFileWriter::supportedFormatExtensions().value( setting, QStringLiteral( "gpkg" ) );
1307 }
1308 
1310 {
1312  if ( setting == -1 )
1313  return QStringLiteral( "tif" );
1314  return QgsRasterFileWriter::supportedFormatExtensions().value( setting, QStringLiteral( "tif" ) );
1315 }
1316 
1317 //
1318 // QgsProcessingFeatureSource
1319 //
1320 
1321 QgsProcessingFeatureSource::QgsProcessingFeatureSource( QgsFeatureSource *originalSource, const QgsProcessingContext &context, bool ownsOriginalSource, long long featureLimit )
1322  : mSource( originalSource )
1323  , mOwnsSource( ownsOriginalSource )
1324  , mInvalidGeometryCheck( QgsWkbTypes::geometryType( mSource->wkbType() ) == QgsWkbTypes::PointGeometry
1325  ? QgsFeatureRequest::GeometryNoCheck // never run geometry validity checks for point layers!
1326  : context.invalidGeometryCheck() )
1327  , mInvalidGeometryCallback( context.invalidGeometryCallback( originalSource ) )
1328  , mTransformErrorCallback( context.transformErrorCallback() )
1329  , mInvalidGeometryCallbackSkip( context.defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::GeometrySkipInvalid, originalSource ) )
1330  , mInvalidGeometryCallbackAbort( context.defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::GeometryAbortOnInvalid, originalSource ) )
1331  , mFeatureLimit( featureLimit )
1332 {}
1333 
1335 {
1336  if ( mOwnsSource )
1337  delete mSource;
1338 }
1339 
1341 {
1342  QgsFeatureRequest req( request );
1343  req.setTransformErrorCallback( mTransformErrorCallback );
1344 
1345  if ( flags & FlagSkipGeometryValidityChecks )
1347  else
1348  {
1349  req.setInvalidGeometryCheck( mInvalidGeometryCheck );
1350  req.setInvalidGeometryCallback( mInvalidGeometryCallback );
1351  }
1352 
1353  if ( mFeatureLimit != -1 && req.limit() != -1 )
1354  req.setLimit( std::min( static_cast< long long >( req.limit() ), mFeatureLimit ) );
1355  else if ( mFeatureLimit != -1 )
1356  req.setLimit( mFeatureLimit );
1357 
1358  return mSource->getFeatures( req );
1359 }
1360 
1362 {
1363  FeatureAvailability sourceAvailability = mSource->hasFeatures();
1364  if ( sourceAvailability == NoFeaturesAvailable )
1365  return NoFeaturesAvailable; // never going to be features if underlying source has no features
1366  else if ( mInvalidGeometryCheck == QgsFeatureRequest::GeometryNoCheck )
1367  return sourceAvailability;
1368  else
1369  // we don't know... source has features, but these may be filtered out by invalid geometry check
1370  return FeaturesMaybeAvailable;
1371 }
1372 
1374 {
1375  QgsFeatureRequest req( request );
1376  req.setInvalidGeometryCheck( mInvalidGeometryCheck );
1377  req.setInvalidGeometryCallback( mInvalidGeometryCallback );
1378  req.setTransformErrorCallback( mTransformErrorCallback );
1379 
1380  if ( mFeatureLimit != -1 && req.limit() != -1 )
1381  req.setLimit( std::min( static_cast< long long >( req.limit() ), mFeatureLimit ) );
1382  else if ( mFeatureLimit != -1 )
1383  req.setLimit( mFeatureLimit );
1384 
1385  return mSource->getFeatures( req );
1386 }
1387 
1389 {
1390  return mSource->sourceCrs();
1391 }
1392 
1394 {
1395  return mSource->fields();
1396 }
1397 
1399 {
1400  return mSource->wkbType();
1401 }
1402 
1404 {
1405  if ( mFeatureLimit == -1 )
1406  return mSource->featureCount();
1407  else
1408  return std::min( mFeatureLimit, mSource->featureCount() );
1409 }
1410 
1412 {
1413  return mSource->sourceName();
1414 
1415 }
1416 
1417 QSet<QVariant> QgsProcessingFeatureSource::uniqueValues( int fieldIndex, int limit ) const
1418 {
1419  return mSource->uniqueValues( fieldIndex, limit );
1420 }
1421 
1422 QVariant QgsProcessingFeatureSource::minimumValue( int fieldIndex ) const
1423 {
1424  return mSource->minimumValue( fieldIndex );
1425 }
1426 
1427 QVariant QgsProcessingFeatureSource::maximumValue( int fieldIndex ) const
1428 {
1429  return mSource->maximumValue( fieldIndex );
1430 }
1431 
1433 {
1434  return mSource->sourceExtent();
1435 }
1436 
1438 {
1439  return mSource->allFeatureIds();
1440 }
1441 
1443 {
1444  return mSource->hasSpatialIndex();
1445 }
1446 
1448 {
1449  QgsExpressionContextScope *expressionContextScope = nullptr;
1450  QgsExpressionContextScopeGenerator *generator = dynamic_cast<QgsExpressionContextScopeGenerator *>( mSource );
1451  if ( generator )
1452  {
1453  expressionContextScope = generator->createExpressionContextScope();
1454  }
1455  return expressionContextScope;
1456 }
1457 
1459 {
1460  mInvalidGeometryCheck = method;
1461  switch ( mInvalidGeometryCheck )
1462  {
1464  mInvalidGeometryCallback = nullptr;
1465  break;
1466 
1468  mInvalidGeometryCallback = mInvalidGeometryCallbackSkip;
1469  break;
1470 
1472  mInvalidGeometryCallback = mInvalidGeometryCallbackAbort;
1473  break;
1474 
1475  }
1476 }
1477 
1478 
1479 //
1480 // QgsProcessingFeatureSink
1481 //
1482 QgsProcessingFeatureSink::QgsProcessingFeatureSink( QgsFeatureSink *originalSink, const QString &sinkName, QgsProcessingContext &context, bool ownsOriginalSink )
1483  : QgsProxyFeatureSink( originalSink )
1484  , mContext( context )
1485  , mSinkName( sinkName )
1486  , mOwnsSink( ownsOriginalSink )
1487 {}
1488 
1490 {
1491  if ( mOwnsSink )
1492  delete destinationSink();
1493 }
1494 
1495 bool QgsProcessingFeatureSink::addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags )
1496 {
1497  bool result = QgsProxyFeatureSink::addFeature( feature, flags );
1498  if ( !result && mContext.feedback() )
1499  {
1500  const QString error = lastError();
1501  if ( !error.isEmpty() )
1502  mContext.feedback()->reportError( QObject::tr( "Feature could not be written to %1: %2" ).arg( mSinkName, error ) );
1503  else
1504  mContext.feedback()->reportError( QObject::tr( "Feature could not be written to %1" ).arg( mSinkName ) );
1505  }
1506  return result;
1507 }
1508 
1509 bool QgsProcessingFeatureSink::addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags )
1510 {
1511  bool result = QgsProxyFeatureSink::addFeatures( features, flags );
1512  if ( !result && mContext.feedback() )
1513  {
1514  const QString error = lastError();
1515  if ( !error.isEmpty() )
1516  mContext.feedback()->reportError( QObject::tr( "%1 feature(s) could not be written to %2: %3" ).arg( features.count() ).arg( mSinkName, error ) );
1517  else
1518  mContext.feedback()->reportError( QObject::tr( "%1 feature(s) could not be written to %2" ).arg( features.count() ).arg( mSinkName ) );
1519  }
1520  return result;
1521 }
1522 
1523 bool QgsProcessingFeatureSink::addFeatures( QgsFeatureIterator &iterator, QgsFeatureSink::Flags flags )
1524 {
1525  bool result = QgsProxyFeatureSink::addFeatures( iterator, flags );
1526  if ( !result && mContext.feedback() )
1527  {
1528  const QString error = lastError();
1529  if ( !error.isEmpty() )
1530  mContext.feedback()->reportError( QObject::tr( "Features could not be written to %1: %2" ).arg( mSinkName, error ) );
1531  else
1532  mContext.feedback()->reportError( QObject::tr( "Features could not be written to %1" ).arg( mSinkName ) );
1533  }
1534  return result;
1535 }
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.
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:174
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 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:232
@ StaticProperty
Static property (QgsStaticProperty)
Definition: qgsproperty.h:239
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.
qlonglong value(const QString &dynamicKeyPart=QString(), bool useDefaultValueOverride=false, qlonglong defaultValueOverride=0) const
Returns settings value.
QString value(const QString &dynamicKeyPart=QString(), bool useDefaultValueOverride=false, const QString &defaultValueOverride=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
Added in 3.18.
@ MeshLayer
Added in 3.2.
@ 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:1198
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: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.