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