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