QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 
36 QList<QgsRasterLayer *> QgsProcessingUtils::compatibleRasterLayers( QgsProject *project, bool sort )
37 {
38  if ( !project )
39  return QList<QgsRasterLayer *>();
40 
41  QList<QgsRasterLayer *> layers;
42 
43  const auto rasterLayers = project->layers<QgsRasterLayer *>();
44  for ( QgsRasterLayer *l : rasterLayers )
45  {
46  if ( canUseLayer( l ) )
47  layers << l;
48  }
49 
50  if ( sort )
51  {
52  std::sort( layers.begin(), layers.end(), []( const QgsRasterLayer * a, const QgsRasterLayer * b ) -> bool
53  {
54  return QString::localeAwareCompare( a->name(), b->name() ) < 0;
55  } );
56  }
57  return layers;
58 }
59 
60 QList<QgsVectorLayer *> QgsProcessingUtils::compatibleVectorLayers( QgsProject *project, const QList<int> &geometryTypes, bool sort )
61 {
62  if ( !project )
63  return QList<QgsVectorLayer *>();
64 
65  QList<QgsVectorLayer *> layers;
66  const auto vectorLayers = project->layers<QgsVectorLayer *>();
67  for ( QgsVectorLayer *l : vectorLayers )
68  {
69  if ( canUseLayer( l, geometryTypes ) )
70  layers << l;
71  }
72 
73  if ( sort )
74  {
75  std::sort( layers.begin(), layers.end(), []( const QgsVectorLayer * a, const QgsVectorLayer * b ) -> bool
76  {
77  return QString::localeAwareCompare( a->name(), b->name() ) < 0;
78  } );
79  }
80  return layers;
81 }
82 
83 QList<QgsMeshLayer *> QgsProcessingUtils::compatibleMeshLayers( QgsProject *project, bool sort )
84 {
85  if ( !project )
86  return QList<QgsMeshLayer *>();
87 
88  QList<QgsMeshLayer *> layers;
89  const auto meshLayers = project->layers<QgsMeshLayer *>();
90  for ( QgsMeshLayer *l : meshLayers )
91  {
92  if ( canUseLayer( l ) )
93  layers << l;
94  }
95 
96  if ( sort )
97  {
98  std::sort( layers.begin(), layers.end(), []( const QgsMeshLayer * a, const QgsMeshLayer * b ) -> bool
99  {
100  return QString::localeAwareCompare( a->name(), b->name() ) < 0;
101  } );
102  }
103  return layers;
104 }
105 
106 QList<QgsMapLayer *> QgsProcessingUtils::compatibleLayers( QgsProject *project, bool sort )
107 {
108  if ( !project )
109  return QList<QgsMapLayer *>();
110 
111  QList<QgsMapLayer *> layers;
112 
113  const auto rasterLayers = compatibleRasterLayers( project, false );
114  for ( QgsRasterLayer *rl : rasterLayers )
115  layers << rl;
116 
117  const auto vectorLayers = compatibleVectorLayers( project, QList< int >(), false );
118  for ( QgsVectorLayer *vl : vectorLayers )
119  layers << vl;
120 
121  const auto meshLayers = compatibleMeshLayers( project, false );
122  for ( QgsMeshLayer *vl : meshLayers )
123  layers << vl;
124 
125  if ( sort )
126  {
127  std::sort( layers.begin(), layers.end(), []( const QgsMapLayer * a, const QgsMapLayer * b ) -> bool
128  {
129  return QString::localeAwareCompare( a->name(), b->name() ) < 0;
130  } );
131  }
132  return layers;
133 }
134 
135 QgsMapLayer *QgsProcessingUtils::mapLayerFromStore( const QString &string, QgsMapLayerStore *store, QgsProcessingUtils::LayerHint typeHint )
136 {
137  if ( !store || string.isEmpty() )
138  return nullptr;
139 
140  QList< QgsMapLayer * > layers = store->mapLayers().values();
141 
142  layers.erase( std::remove_if( layers.begin(), layers.end(), []( QgsMapLayer * layer )
143  {
144  switch ( layer->type() )
145  {
147  return !canUseLayer( qobject_cast< QgsVectorLayer * >( layer ) );
149  return !canUseLayer( qobject_cast< QgsRasterLayer * >( layer ) );
151  return true;
153  return !canUseLayer( qobject_cast< QgsMeshLayer * >( layer ) );
154  }
155  return true;
156  } ), layers.end() );
157 
158  auto isCompatibleType = [typeHint]( QgsMapLayer * l ) -> bool
159  {
160  switch ( typeHint )
161  {
163  return true;
164 
165  case LayerHint::Vector:
166  return l->type() == QgsMapLayerType::VectorLayer;
167 
168  case LayerHint::Raster:
169  return l->type() == QgsMapLayerType::RasterLayer;
170 
171  case LayerHint::Mesh:
172  return l->type() == QgsMapLayerType::MeshLayer;
173  }
174  return true;
175  };
176 
177  for ( QgsMapLayer *l : qgis::as_const( layers ) )
178  {
179  if ( isCompatibleType( l ) && l->id() == string )
180  return l;
181  }
182  for ( QgsMapLayer *l : qgis::as_const( layers ) )
183  {
184  if ( isCompatibleType( l ) && l->name() == string )
185  return l;
186  }
187  for ( QgsMapLayer *l : qgis::as_const( layers ) )
188  {
189  if ( isCompatibleType( l ) && normalizeLayerSource( l->source() ) == normalizeLayerSource( string ) )
190  return l;
191  }
192  return nullptr;
193 }
194 
196 class ProjectionSettingRestorer
197 {
198  public:
199 
200  ProjectionSettingRestorer()
201  {
202  QgsSettings settings;
203  previousSetting = settings.value( QStringLiteral( "/Projections/defaultBehavior" ) ).toString();
204  settings.setValue( QStringLiteral( "/Projections/defaultBehavior" ), QStringLiteral( "useProject" ) );
205  }
206 
207  ~ProjectionSettingRestorer()
208  {
209  QgsSettings settings;
210  settings.setValue( QStringLiteral( "/Projections/defaultBehavior" ), previousSetting );
211  }
212 
213  QString previousSetting;
214 };
216 
217 QgsMapLayer *QgsProcessingUtils::loadMapLayerFromString( const QString &string, const QgsCoordinateTransformContext &transformContext, LayerHint typeHint )
218 {
219  QStringList components = string.split( '|' );
220  if ( components.isEmpty() )
221  return nullptr;
222 
223  QFileInfo fi;
224  if ( QFileInfo::exists( string ) )
225  fi = QFileInfo( string );
226  else if ( QFileInfo::exists( components.at( 0 ) ) )
227  fi = QFileInfo( components.at( 0 ) );
228  else
229  return nullptr;
230 
231  // TODO - remove when there is a cleaner way to block the unknown projection dialog!
232  ProjectionSettingRestorer restorer;
233  ( void )restorer; // no warnings
234 
235  QString name = fi.baseName();
236 
237  // brute force attempt to load a matching layer
238  if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::Vector )
239  {
240  QgsVectorLayer::LayerOptions options { transformContext };
241  options.loadDefaultStyle = false;
242  std::unique_ptr< QgsVectorLayer > layer = qgis::make_unique<QgsVectorLayer>( string, name, QStringLiteral( "ogr" ), options );
243  if ( layer->isValid() )
244  {
245  return layer.release();
246  }
247  }
248  if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::Raster )
249  {
250  QgsRasterLayer::LayerOptions rasterOptions;
251  rasterOptions.loadDefaultStyle = false;
252  std::unique_ptr< QgsRasterLayer > rasterLayer( new QgsRasterLayer( string, name, QStringLiteral( "gdal" ), rasterOptions ) );
253  if ( rasterLayer->isValid() )
254  {
255  return rasterLayer.release();
256  }
257  }
258  if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::Mesh )
259  {
260  QgsMeshLayer::LayerOptions meshOptions;
261  std::unique_ptr< QgsMeshLayer > meshLayer( new QgsMeshLayer( string, name, QStringLiteral( "mdal" ), meshOptions ) );
262  if ( meshLayer->isValid() )
263  {
264  return meshLayer.release();
265  }
266  }
267  return nullptr;
268 }
269 
270 QgsMapLayer *QgsProcessingUtils::mapLayerFromString( const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers, LayerHint typeHint )
271 {
272  if ( string.isEmpty() )
273  return nullptr;
274 
275  // prefer project layers
276  QgsMapLayer *layer = nullptr;
277  if ( context.project() )
278  {
279  QgsMapLayer *layer = mapLayerFromStore( string, context.project()->layerStore(), typeHint );
280  if ( layer )
281  return layer;
282  }
283 
284  layer = mapLayerFromStore( string, context.temporaryLayerStore(), typeHint );
285  if ( layer )
286  return layer;
287 
288  if ( !allowLoadingNewLayers )
289  return nullptr;
290 
291  layer = loadMapLayerFromString( string, context.transformContext(), typeHint );
292  if ( layer )
293  {
294  context.temporaryLayerStore()->addMapLayer( layer );
295  return layer;
296  }
297  else
298  {
299  return nullptr;
300  }
301 }
302 
303 QgsProcessingFeatureSource *QgsProcessingUtils::variantToSource( const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue )
304 {
305  QVariant val = value;
306  bool selectedFeaturesOnly = false;
307  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
308  {
309  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
311  selectedFeaturesOnly = fromVar.selectedFeaturesOnly;
312  val = fromVar.source;
313  }
314  else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
315  {
316  // input is a QgsProcessingOutputLayerDefinition (e.g. an output from earlier in a model) - get extra properties from it
318  val = fromVar.sink;
319  }
320 
321  if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( val ) ) )
322  {
323  return new QgsProcessingFeatureSource( layer, context );
324  }
325 
326  QString layerRef;
327  if ( val.canConvert<QgsProperty>() )
328  {
329  layerRef = val.value< QgsProperty >().valueAsString( context.expressionContext(), fallbackValue.toString() );
330  }
331  else if ( !val.isValid() || val.toString().isEmpty() )
332  {
333  // fall back to default
334  if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( fallbackValue ) ) )
335  {
336  return new QgsProcessingFeatureSource( layer, context );
337  }
338 
339  layerRef = fallbackValue.toString();
340  }
341  else
342  {
343  layerRef = val.toString();
344  }
345 
346  if ( layerRef.isEmpty() )
347  return nullptr;
348 
349  QgsVectorLayer *vl = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( layerRef, context, true, LayerHint::Vector ) );
350  if ( !vl )
351  return nullptr;
352 
353  if ( selectedFeaturesOnly )
354  {
355  return new QgsProcessingFeatureSource( new QgsVectorLayerSelectedFeatureSource( vl ), context, true );
356  }
357  else
358  {
359  return new QgsProcessingFeatureSource( vl, context );
360  }
361 }
362 
363 bool QgsProcessingUtils::canUseLayer( const QgsMeshLayer *layer )
364 {
365  return layer && layer->dataProvider();
366 }
367 
368 bool QgsProcessingUtils::canUseLayer( const QgsRasterLayer *layer )
369 {
370  return layer && layer->isValid();
371 }
372 
373 bool QgsProcessingUtils::canUseLayer( const QgsVectorLayer *layer, const QList<int> &sourceTypes )
374 {
375  return layer && layer->isValid() &&
376  ( sourceTypes.isEmpty()
377  || ( sourceTypes.contains( QgsProcessing::TypeVectorPoint ) && layer->geometryType() == QgsWkbTypes::PointGeometry )
378  || ( sourceTypes.contains( QgsProcessing::TypeVectorLine ) && layer->geometryType() == QgsWkbTypes::LineGeometry )
379  || ( sourceTypes.contains( QgsProcessing::TypeVectorPolygon ) && layer->geometryType() == QgsWkbTypes::PolygonGeometry )
380  || ( sourceTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) && layer->isSpatial() )
381  || sourceTypes.contains( QgsProcessing::TypeVector )
382  );
383 }
384 
385 QString QgsProcessingUtils::normalizeLayerSource( const QString &source )
386 {
387  QString normalized = source;
388  normalized.replace( '\\', '/' );
389  return normalized.trimmed();
390 }
391 
392 QString QgsProcessingUtils::variantToPythonLiteral( const QVariant &value )
393 {
394  if ( !value.isValid() )
395  return QStringLiteral( "None" );
396 
397  if ( value.canConvert<QgsProperty>() )
398  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
399  else if ( value.canConvert<QgsCoordinateReferenceSystem>() )
400  {
401  if ( !value.value< QgsCoordinateReferenceSystem >().isValid() )
402  return QStringLiteral( "QgsCoordinateReferenceSystem()" );
403  else
404  return QStringLiteral( "QgsCoordinateReferenceSystem('%1')" ).arg( value.value< QgsCoordinateReferenceSystem >().authid() );
405  }
406  else if ( value.canConvert< QgsRectangle >() )
407  {
408  QgsRectangle r = value.value<QgsRectangle>();
409  return QStringLiteral( "'%1, %3, %2, %4'" ).arg( qgsDoubleToString( r.xMinimum() ),
412  qgsDoubleToString( r.yMaximum() ) );
413  }
414  else if ( value.canConvert< QgsReferencedRectangle >() )
415  {
417  return QStringLiteral( "'%1, %3, %2, %4 [%5]'" ).arg( qgsDoubleToString( r.xMinimum() ),
420  qgsDoubleToString( r.yMaximum() ), r.crs().authid() );
421  }
422  else if ( value.canConvert< QgsPointXY >() )
423  {
424  QgsPointXY r = value.value<QgsPointXY>();
425  return QStringLiteral( "'%1,%2'" ).arg( qgsDoubleToString( r.x() ),
426  qgsDoubleToString( r.y() ) );
427  }
428  else if ( value.canConvert< QgsReferencedPointXY >() )
429  {
430  QgsReferencedPointXY r = value.value<QgsReferencedPointXY>();
431  return QStringLiteral( "'%1,%2 [%3]'" ).arg( qgsDoubleToString( r.x() ),
432  qgsDoubleToString( r.y() ),
433  r.crs().authid() );
434  }
435 
436  switch ( value.type() )
437  {
438  case QVariant::Bool:
439  return value.toBool() ? QStringLiteral( "True" ) : QStringLiteral( "False" );
440 
441  case QVariant::Double:
442  return QString::number( value.toDouble() );
443 
444  case QVariant::Int:
445  case QVariant::UInt:
446  return QString::number( value.toInt() );
447 
448  case QVariant::LongLong:
449  case QVariant::ULongLong:
450  return QString::number( value.toLongLong() );
451 
452  case QVariant::List:
453  {
454  QStringList parts;
455  const QVariantList vl = value.toList();
456  for ( const QVariant &v : vl )
457  {
458  parts << variantToPythonLiteral( v );
459  }
460  return parts.join( ',' ).prepend( '[' ).append( ']' );
461  }
462 
463  default:
464  break;
465  }
466 
467  return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
468 }
469 
470 QString QgsProcessingUtils::stringToPythonLiteral( const QString &string )
471 {
472  QString s = string;
473  s.replace( '\\', QStringLiteral( "\\\\" ) );
474  s.replace( '\n', QStringLiteral( "\\n" ) );
475  s.replace( '\r', QStringLiteral( "\\r" ) );
476  s.replace( '\t', QStringLiteral( "\\t" ) );
477  s.replace( '"', QStringLiteral( "\\\"" ) );
478  s.replace( '\'', QStringLiteral( "\\\'" ) );
479  s = s.prepend( '\'' ).append( '\'' );
480  return s;
481 }
482 
483 void QgsProcessingUtils::parseDestinationString( QString &destination, QString &providerKey, QString &uri, QString &layerName, QString &format, QMap<QString, QVariant> &options, bool &useWriter, QString &extension )
484 {
485  extension.clear();
486  QRegularExpression splitRx( QStringLiteral( "^(.{3,}?):(.*)$" ) );
487  QRegularExpressionMatch match = splitRx.match( destination );
488  if ( match.hasMatch() )
489  {
490  providerKey = match.captured( 1 );
491  if ( providerKey == QStringLiteral( "postgis" ) ) // older processing used "postgis" instead of "postgres"
492  {
493  providerKey = QStringLiteral( "postgres" );
494  }
495  uri = match.captured( 2 );
496  if ( providerKey == QLatin1String( "ogr" ) )
497  {
498  QgsDataSourceUri dsUri( uri );
499  if ( !dsUri.database().isEmpty() )
500  {
501  if ( !dsUri.table().isEmpty() )
502  {
503  layerName = dsUri.table();
504  options.insert( QStringLiteral( "layerName" ), layerName );
505  }
506  uri = dsUri.database();
507  extension = QFileInfo( uri ).completeSuffix();
508  format = QgsVectorFileWriter::driverForExtension( extension );
509  }
510  else
511  {
512  extension = QFileInfo( uri ).completeSuffix();
513  }
514  options.insert( QStringLiteral( "update" ), true );
515  }
516  useWriter = false;
517  }
518  else
519  {
520  useWriter = true;
521  providerKey = QStringLiteral( "ogr" );
522  QRegularExpression splitRx( QStringLiteral( "^(.*)\\.(.*?)$" ) );
523  QRegularExpressionMatch match = splitRx.match( destination );
524  if ( match.hasMatch() )
525  {
526  extension = match.captured( 2 );
527  format = QgsVectorFileWriter::driverForExtension( extension );
528  }
529 
530  if ( format.isEmpty() )
531  {
532  format = QStringLiteral( "GPKG" );
533  destination = destination + QStringLiteral( ".gpkg" );
534  }
535 
536  options.insert( QStringLiteral( "driverName" ), format );
537  uri = destination;
538  }
539 }
540 
541 QgsFeatureSink *QgsProcessingUtils::createFeatureSink( QString &destination, QgsProcessingContext &context, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &createOptions, QgsFeatureSink::SinkFlags sinkFlags )
542 {
543  QVariantMap options = createOptions;
544  if ( !options.contains( QStringLiteral( "fileEncoding" ) ) )
545  {
546  // no destination encoding specified, use default
547  options.insert( QStringLiteral( "fileEncoding" ), context.defaultEncoding().isEmpty() ? QStringLiteral( "system" ) : context.defaultEncoding() );
548  }
549 
550  if ( destination.isEmpty() || destination.startsWith( QLatin1String( "memory:" ) ) )
551  {
552  // strip "memory:" from start of destination
553  if ( destination.startsWith( QLatin1String( "memory:" ) ) )
554  destination = destination.mid( 7 );
555 
556  if ( destination.isEmpty() )
557  destination = QStringLiteral( "output" );
558 
559  // memory provider cannot be used with QgsVectorLayerImport - so create layer manually
560  std::unique_ptr< QgsVectorLayer > layer( QgsMemoryProviderUtils::createMemoryLayer( destination, fields, geometryType, crs ) );
561  if ( !layer || !layer->isValid() )
562  {
563  throw QgsProcessingException( QObject::tr( "Could not create memory layer" ) );
564  }
565 
566  // update destination to layer ID
567  destination = layer->id();
568 
569  // this is a factory, so we need to return a proxy
570  std::unique_ptr< QgsProcessingFeatureSink > sink( new QgsProcessingFeatureSink( layer->dataProvider(), destination, context ) );
571  context.temporaryLayerStore()->addMapLayer( layer.release() );
572 
573  return sink.release();
574  }
575  else
576  {
577  QString providerKey;
578  QString uri;
579  QString layerName;
580  QString format;
581  QString extension;
582  bool useWriter = false;
583  parseDestinationString( destination, providerKey, uri, layerName, format, options, useWriter, extension );
584 
585  QgsFields newFields = fields;
586  if ( useWriter && providerKey == QLatin1String( "ogr" ) )
587  {
588  // use QgsVectorFileWriter for OGR destinations instead of QgsVectorLayerImport, as that allows
589  // us to use any OGR format which supports feature addition
590  QString finalFileName;
591  std::unique_ptr< QgsVectorFileWriter > writer = qgis::make_unique< QgsVectorFileWriter >( destination, options.value( QStringLiteral( "fileEncoding" ) ).toString(), newFields, geometryType, crs, format, QgsVectorFileWriter::defaultDatasetOptions( format ),
592  QgsVectorFileWriter::defaultLayerOptions( format ), &finalFileName, QgsVectorFileWriter::NoSymbology, sinkFlags );
593 
594  if ( writer->hasError() )
595  {
596  throw QgsProcessingException( QObject::tr( "Could not create layer %1: %2" ).arg( destination, writer->errorMessage() ) );
597  }
598  destination = finalFileName;
599  return new QgsProcessingFeatureSink( writer.release(), destination, context, true );
600  }
601  else
602  {
603  //create empty layer
604  const QgsVectorLayer::LayerOptions layerOptions { context.transformContext() };
605  std::unique_ptr< QgsVectorLayerExporter > exporter = qgis::make_unique<QgsVectorLayerExporter>( uri, providerKey, newFields, geometryType, crs, true, options, sinkFlags );
606  if ( exporter->errorCode() )
607  {
608  throw QgsProcessingException( QObject::tr( "Could not create layer %1: %2" ).arg( destination, exporter->errorMessage() ) );
609  }
610 
611  // use destination string as layer name (eg "postgis:..." )
612  if ( !layerName.isEmpty() )
613  uri += QStringLiteral( "|layername=%1" ).arg( layerName );
614  std::unique_ptr< QgsVectorLayer > layer = qgis::make_unique<QgsVectorLayer>( uri, destination, providerKey, layerOptions );
615  // update destination to layer ID
616  destination = layer->id();
617 
618  context.temporaryLayerStore()->addMapLayer( layer.release() );
619  return new QgsProcessingFeatureSink( exporter.release(), destination, context, true );
620  }
621  }
622 }
623 
624 void QgsProcessingUtils::createFeatureSinkPython( QgsFeatureSink **sink, QString &destination, QgsProcessingContext &context, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &options )
625 {
626  *sink = createFeatureSink( destination, context, fields, geometryType, crs, options );
627 }
628 
629 
631 {
632  QgsRectangle extent;
633  for ( const QgsMapLayer *layer : layers )
634  {
635  if ( !layer )
636  continue;
637 
638  if ( crs.isValid() )
639  {
640  //transform layer extent to target CRS
641  QgsCoordinateTransform ct( layer->crs(), crs, context.transformContext() );
642  try
643  {
644  QgsRectangle reprojExtent = ct.transformBoundingBox( layer->extent() );
645  extent.combineExtentWith( reprojExtent );
646  }
647  catch ( QgsCsException & )
648  {
649  // can't reproject... what to do here? hmmm?
650  // let's ignore this layer for now, but maybe we should just use the original extent?
651  }
652  }
653  else
654  {
655  extent.combineExtentWith( layer->extent() );
656  }
657 
658  }
659  return extent;
660 }
661 
662 // Deprecated
664 {
665  QgsProcessingContext context;
666  return QgsProcessingUtils::combineLayerExtents( layers, crs, context );
667 }
668 
669 QVariant QgsProcessingUtils::generateIteratingDestination( const QVariant &input, const QVariant &id, QgsProcessingContext &context )
670 {
671  if ( !input.isValid() )
672  return QStringLiteral( "memory:%1" ).arg( id.toString() );
673 
674  if ( input.canConvert<QgsProcessingOutputLayerDefinition>() )
675  {
677  QVariant newSink = generateIteratingDestination( fromVar.sink, id, context );
678  fromVar.sink = QgsProperty::fromValue( newSink );
679  return fromVar;
680  }
681  else if ( input.canConvert<QgsProperty>() )
682  {
683  QString res = input.value< QgsProperty>().valueAsString( context.expressionContext() );
684  return generateIteratingDestination( res, id, context );
685  }
686  else
687  {
688  QString res = input.toString();
689  if ( res == QgsProcessing::TEMPORARY_OUTPUT )
690  {
691  // temporary outputs map to temporary outputs!
693  }
694  else if ( res.startsWith( QLatin1String( "memory:" ) ) )
695  {
696  return res + '_' + id.toString();
697  }
698  else
699  {
700  // assume a filename type output for now
701  // TODO - uris?
702  int lastIndex = res.lastIndexOf( '.' );
703  return res.left( lastIndex ) + '_' + id.toString() + res.mid( lastIndex );
704  }
705  }
706 }
707 
709 {
710  static QString sFolder;
711  static QMutex sMutex;
712  sMutex.lock();
713  if ( sFolder.isEmpty() )
714  {
715  QString subPath = QUuid::createUuid().toString().remove( '-' ).remove( '{' ).remove( '}' );
716  sFolder = QDir::tempPath() + QStringLiteral( "/processing_" ) + subPath;
717  if ( !QDir( sFolder ).exists() )
718  QDir().mkpath( sFolder );
719  }
720  sMutex.unlock();
721  return sFolder;
722 }
723 
724 QString QgsProcessingUtils::generateTempFilename( const QString &basename )
725 {
726  QString subPath = QUuid::createUuid().toString().remove( '-' ).remove( '{' ).remove( '}' );
727  QString path = tempFolder() + '/' + subPath;
728  if ( !QDir( path ).exists() ) //make sure the directory exists - it shouldn't, but lets be safe...
729  {
730  QDir tmpDir;
731  tmpDir.mkdir( path );
732  }
733  return path + '/' + QgsFileUtils::stringToSafeFilename( basename );
734 }
735 
737 {
738  auto getText = [map]( const QString & key )->QString
739  {
740  if ( map.contains( key ) )
741  return map.value( key ).toString();
742  return QString();
743  };
744 
745  QString s = QObject::tr( "<html><body><h2>Algorithm description</h2>\n" );
746  s += QStringLiteral( "<p>" ) + getText( QStringLiteral( "ALG_DESC" ) ) + QStringLiteral( "</p>\n" );
747 
748  QString inputs;
749 
750  const auto parameterDefinitions = algorithm->parameterDefinitions();
751  for ( const QgsProcessingParameterDefinition *def : parameterDefinitions )
752  {
753  inputs += QStringLiteral( "<h3>" ) + def->description() + QStringLiteral( "</h3>\n" );
754  inputs += QStringLiteral( "<p>" ) + getText( def->name() ) + QStringLiteral( "</p>\n" );
755  }
756  if ( !inputs.isEmpty() )
757  s += QObject::tr( "<h2>Input parameters</h2>\n" ) + inputs;
758 
759  QString outputs;
760  const auto outputDefinitions = algorithm->outputDefinitions();
761  for ( const QgsProcessingOutputDefinition *def : outputDefinitions )
762  {
763  outputs += QStringLiteral( "<h3>" ) + def->description() + QStringLiteral( "</h3>\n" );
764  outputs += QStringLiteral( "<p>" ) + getText( def->name() ) + QStringLiteral( "</p>\n" );
765  }
766  if ( !outputs.isEmpty() )
767  s += QObject::tr( "<h2>Outputs</h2>\n" ) + outputs;
768 
769  s += QLatin1String( "<br>" );
770  if ( !map.value( QStringLiteral( "ALG_CREATOR" ) ).toString().isEmpty() )
771  s += QObject::tr( "<p align=\"right\">Algorithm author: %1</p>" ).arg( getText( QStringLiteral( "ALG_CREATOR" ) ) );
772  if ( !map.value( QStringLiteral( "ALG_HELP_CREATOR" ) ).toString().isEmpty() )
773  s += QObject::tr( "<p align=\"right\">Help author: %1</p>" ).arg( getText( QStringLiteral( "ALG_HELP_CREATOR" ) ) );
774  if ( !map.value( QStringLiteral( "ALG_VERSION" ) ).toString().isEmpty() )
775  s += QObject::tr( "<p align=\"right\">Algorithm version: %1</p>" ).arg( getText( QStringLiteral( "ALG_VERSION" ) ) );
776 
777  s += QStringLiteral( "</body></html>" );
778  return s;
779 }
780 
781 QString QgsProcessingUtils::convertToCompatibleFormat( const QgsVectorLayer *vl, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
782 {
783  bool requiresTranslation = false;
784 
785  // if we are only looking for selected features then we have to export back to disk,
786  // as we need to subset only selected features, a concept which doesn't exist outside QGIS!
787  requiresTranslation = requiresTranslation || selectedFeaturesOnly;
788 
789  // if the data provider is NOT ogr, then we HAVE to convert. Otherwise we run into
790  // issues with data providers like spatialite, delimited text where the format can be
791  // opened outside of QGIS, but with potentially very different behavior!
792  requiresTranslation = requiresTranslation || vl->dataProvider()->name() != QLatin1String( "ogr" );
793 
794  // if the layer has a feature filter set, then we HAVE to convert. Feature filters are
795  // a purely QGIS concept.
796  requiresTranslation = requiresTranslation || !vl->subsetString().isEmpty();
797 
798  // Check if layer is a disk based format and if so if the layer's path has a compatible filename suffix
799  QString diskPath;
800  if ( !requiresTranslation )
801  {
802  const QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( vl->dataProvider()->name(), vl->source() );
803  if ( parts.contains( QStringLiteral( "path" ) ) )
804  {
805  diskPath = parts.value( QStringLiteral( "path" ) ).toString();
806  QFileInfo fi( diskPath );
807  requiresTranslation = !compatibleFormats.contains( fi.suffix(), Qt::CaseInsensitive );
808 
809  // if the layer name doesn't match the filename, we need to convert the layer. This method can only return
810  // a filename, and cannot handle layernames as well as file paths
811  const QString layerName = parts.value( QStringLiteral( "layerName" ) ).toString();
812  requiresTranslation = requiresTranslation || ( !layerName.isEmpty() && layerName != fi.baseName() );
813  }
814  else
815  {
816  requiresTranslation = true; // not a disk-based format
817  }
818  }
819 
820  if ( requiresTranslation )
821  {
822  QString temp = QgsProcessingUtils::generateTempFilename( baseName + '.' + preferredFormat );
823 
824  QgsVectorFileWriter writer( temp, context.defaultEncoding(),
825  vl->fields(), vl->wkbType(), vl->crs(), QgsVectorFileWriter::driverForExtension( preferredFormat ) );
826  QgsFeature f;
828  if ( selectedFeaturesOnly )
829  it = vl->getSelectedFeatures();
830  else
831  it = vl->getFeatures();
832 
833  while ( it.nextFeature( f ) )
834  {
835  if ( feedback->isCanceled() )
836  return QString();
837  writer.addFeature( f, QgsFeatureSink::FastInsert );
838  }
839  return temp;
840  }
841  else
842  {
843  return diskPath;
844  }
845 }
846 
847 QgsFields QgsProcessingUtils::combineFields( const QgsFields &fieldsA, const QgsFields &fieldsB, const QString &fieldsBPrefix )
848 {
849  QgsFields outFields = fieldsA;
850  QSet< QString > usedNames;
851  for ( const QgsField &f : fieldsA )
852  {
853  usedNames.insert( f.name().toLower() );
854  }
855 
856  for ( const QgsField &f : fieldsB )
857  {
858  QgsField newField = f;
859  newField.setName( fieldsBPrefix + f.name() );
860  if ( usedNames.contains( newField.name().toLower() ) )
861  {
862  int idx = 2;
863  QString newName = newField.name() + '_' + QString::number( idx );
864  while ( usedNames.contains( newName.toLower() ) )
865  {
866  idx++;
867  newName = newField.name() + '_' + QString::number( idx );
868  }
869  newField.setName( newName );
870  outFields.append( newField );
871  }
872  else
873  {
874  outFields.append( newField );
875  }
876  usedNames.insert( newField.name() );
877  }
878 
879  return outFields;
880 }
881 
882 
883 QList<int> QgsProcessingUtils::fieldNamesToIndices( const QStringList &fieldNames, const QgsFields &fields )
884 {
885  QList<int> indices;
886  if ( !fieldNames.isEmpty() )
887  {
888  indices.reserve( fieldNames.count() );
889  for ( const QString &f : fieldNames )
890  {
891  int idx = fields.lookupField( f );
892  if ( idx >= 0 )
893  indices.append( idx );
894  }
895  }
896  else
897  {
898  indices.reserve( fields.count() );
899  for ( int i = 0; i < fields.count(); ++i )
900  indices.append( i );
901  }
902  return indices;
903 }
904 
905 
906 QgsFields QgsProcessingUtils::indicesToFields( const QList<int> &indices, const QgsFields &fields )
907 {
908  QgsFields fieldsSubset;
909  for ( int i : indices )
910  fieldsSubset.append( fields.at( i ) );
911  return fieldsSubset;
912 }
913 
914 //
915 // QgsProcessingFeatureSource
916 //
917 
918 QgsProcessingFeatureSource::QgsProcessingFeatureSource( QgsFeatureSource *originalSource, const QgsProcessingContext &context, bool ownsOriginalSource )
919  : mSource( originalSource )
920  , mOwnsSource( ownsOriginalSource )
921  , mInvalidGeometryCheck( QgsWkbTypes::geometryType( mSource->wkbType() ) == QgsWkbTypes::PointGeometry
922  ? QgsFeatureRequest::GeometryNoCheck // never run geometry validity checks for point layers!
923  : context.invalidGeometryCheck() )
924  , mInvalidGeometryCallback( context.invalidGeometryCallback() )
925  , mTransformErrorCallback( context.transformErrorCallback() )
926 {}
927 
929 {
930  if ( mOwnsSource )
931  delete mSource;
932 }
933 
935 {
936  QgsFeatureRequest req( request );
937  req.setTransformErrorCallback( mTransformErrorCallback );
938 
939  if ( flags & FlagSkipGeometryValidityChecks )
941  else
942  {
943  req.setInvalidGeometryCheck( mInvalidGeometryCheck );
944  req.setInvalidGeometryCallback( mInvalidGeometryCallback );
945  }
946 
947  return mSource->getFeatures( req );
948 }
949 
951 {
952  FeatureAvailability sourceAvailability = mSource->hasFeatures();
953  if ( sourceAvailability == NoFeaturesAvailable )
954  return NoFeaturesAvailable; // never going to be features if underlying source has no features
955  else if ( mInvalidGeometryCheck == QgsFeatureRequest::GeometryNoCheck )
956  return sourceAvailability;
957  else
958  // we don't know... source has features, but these may be filtered out by invalid geometry check
959  return FeaturesMaybeAvailable;
960 }
961 
963 {
964  QgsFeatureRequest req( request );
965  req.setInvalidGeometryCheck( mInvalidGeometryCheck );
966  req.setInvalidGeometryCallback( mInvalidGeometryCallback );
967  req.setTransformErrorCallback( mTransformErrorCallback );
968  return mSource->getFeatures( req );
969 }
970 
972 {
973  return mSource->sourceCrs();
974 }
975 
977 {
978  return mSource->fields();
979 }
980 
982 {
983  return mSource->wkbType();
984 }
985 
987 {
988  return mSource->featureCount();
989 }
990 
992 {
993  return mSource->sourceName();
994 
995 }
996 
997 QSet<QVariant> QgsProcessingFeatureSource::uniqueValues( int fieldIndex, int limit ) const
998 {
999  return mSource->uniqueValues( fieldIndex, limit );
1000 }
1001 
1002 QVariant QgsProcessingFeatureSource::minimumValue( int fieldIndex ) const
1003 {
1004  return mSource->minimumValue( fieldIndex );
1005 }
1006 
1007 QVariant QgsProcessingFeatureSource::maximumValue( int fieldIndex ) const
1008 {
1009  return mSource->maximumValue( fieldIndex );
1010 }
1011 
1013 {
1014  return mSource->sourceExtent();
1015 }
1016 
1018 {
1019  return mSource->allFeatureIds();
1020 }
1021 
1023 {
1024  QgsExpressionContextScope *expressionContextScope = nullptr;
1025  QgsExpressionContextScopeGenerator *generator = dynamic_cast<QgsExpressionContextScopeGenerator *>( mSource );
1026  if ( generator )
1027  {
1028  expressionContextScope = generator->createExpressionContextScope();
1029  }
1030  return expressionContextScope;
1031 }
1032 
1033 
1034 //
1035 // QgsProcessingFeatureSink
1036 //
1037 QgsProcessingFeatureSink::QgsProcessingFeatureSink( QgsFeatureSink *originalSink, const QString &sinkName, QgsProcessingContext &context, bool ownsOriginalSink )
1038  : QgsProxyFeatureSink( originalSink )
1039  , mContext( context )
1040  , mSinkName( sinkName )
1041  , mOwnsSink( ownsOriginalSink )
1042 {}
1043 
1045 {
1046  if ( mOwnsSink )
1047  delete destinationSink();
1048 }
1049 
1050 bool QgsProcessingFeatureSink::addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags )
1051 {
1052  bool result = QgsProxyFeatureSink::addFeature( feature, flags );
1053  if ( !result )
1054  mContext.feedback()->reportError( QObject::tr( "Feature could not be written to %1" ).arg( mSinkName ) );
1055  return result;
1056 }
1057 
1058 bool QgsProcessingFeatureSink::addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags )
1059 {
1060  bool result = QgsProxyFeatureSink::addFeatures( features, flags );
1061  if ( !result )
1062  mContext.feedback()->reportError( QObject::tr( "%1 feature(s) could not be written to %2" ).arg( features.count() ).arg( mSinkName ) );
1063  return result;
1064 }
1065 
1066 bool QgsProcessingFeatureSink::addFeatures( QgsFeatureIterator &iterator, QgsFeatureSink::Flags flags )
1067 {
1068  bool result = !QgsProxyFeatureSink::addFeatures( iterator, flags );
1069  if ( !result )
1070  mContext.feedback()->reportError( QObject::tr( "Features could not be written to %1" ).arg( mSinkName ) );
1071  return result;
1072 }
int lookupField(const QString &fieldName) const
Looks up field&#39;s index from the field name.
Definition: qgsfields.cpp:324
QgsProperty sink
Sink/layer definition.
Wrapper for iterator of features from vector data provider or vector layer.
virtual QgsRectangle sourceExtent() const
Returns the extent of all geometries from the source.
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsWkbTypes::Type wkbType() const override
Returns the geometry type for features returned by this source.
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
Base class for all map layer types.
Definition: qgsmaplayer.h:78
QString table() const
Returns the table name stored in the URI.
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
static QgsRectangle combineLayerExtents(const QList< QgsMapLayer *> &layers, const QgsCoordinateReferenceSystem &crs, QgsProcessingContext &context)
Combines the extent of several map layers.
QgsFeatureRequest & setInvalidGeometryCallback(const std::function< void(const QgsFeature &)> &callback)
Sets a callback function to use when encountering an invalid geometry and invalidGeometryCheck() is s...
Base class for providing feedback from a processing algorithm.
QgsProcessingParameterDefinitions parameterDefinitions() const
Returns an ordered list of parameter definitions utilized by the algorithm.
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
virtual QgsFields fields() const =0
Returns the fields associated with features in the source.
Encapsulates settings relating to a feature sink or output raster layer for a processing algorithm...
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.
A simple feature sink which proxies feature addition on to another feature sink.
QString name
Definition: qgsfield.h:58
QgsFeatureRequest & setInvalidGeometryCheck(InvalidGeometryCheck check)
Sets invalid geometry checking behavior.
QgsProcessingFeatureSource(QgsFeatureSource *originalSource, const QgsProcessingContext &context, bool ownsOriginalSource=false)
Constructor for QgsProcessingFeatureSource, accepting an original feature source originalSource and p...
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
FeatureAvailability
Possible return value for hasFeatures() to determine if a source is empty.
LayerHint
Layer type hints.
QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
Setting options for loading vector layers.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:571
Handles storage of information regarding WKB types and their properties.
Definition: qgswkbtypes.h:40
double y
Definition: qgspointxy.h:48
A class to represent a 2D point.
Definition: qgspointxy.h:43
A QgsPointXY with associated coordinate reference system.
QgsFeatureIds allFeatureIds() const override
Returns a list of all feature IDs for features present in the source.
virtual QgsWkbTypes::Type wkbType() const =0
Returns the geometry type for features returned by this source.
An interface for objects which accept features via addFeature(s) methods.
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 QString stringToPythonLiteral(const QString &string)
Converts a string to a Python string literal.
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
QgsFeatureSource subclass which proxies methods to an underlying QgsFeatureSource, modifying results according to the settings in a QgsProcessingContext.
Container of fields for a vector layer.
Definition: qgsfields.h:42
void setName(const QString &name)
Set the field name.
Definition: qgsfield.cpp:141
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=nullptr) override
Adds a list of features to the sink.
QVariantMap decodeUri(const QString &providerKey, const QString &uri)
Breaks a provider data source URI into its component paths (e.g.
static QString driverForExtension(const QString &extension)
Returns the OGR driver name for a specified file extension.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request, Flags flags) const
Returns an iterator for the features in the source, respecting the supplied feature flags...
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...
Setting options for loading mesh layers.
Definition: qgsmeshlayer.h:98
A convenience class for writing vector files to disk.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
const QgsCoordinateReferenceSystem & crs
QVariant maximumValue(int fieldIndex) const override
Returns the maximum value for an attribute column or an invalid variant in case of error...
bool isValid() const
Returns the status of the layer.
static QString convertToCompatibleFormat(const QgsVectorLayer *layer, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback)
Converts a source vector layer to a file path to a vector layer of compatible format.
QgsRectangle sourceExtent() const override
Returns the extent of all geometries from the source.
static QString normalizeLayerSource(const QString &source)
Normalizes a layer source string for safe comparison across different operating system environments...
Abstract base class for processing algorithms.
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
bool isSpatial() const FINAL
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
QgsMapLayerStore * layerStore()
Returns a pointer to the project&#39;s internal layer store.
virtual QString name() const =0
Returns a provider name.
QgsProject * project() const
Returns the project in which the algorithm is being executed.
bool selectedFeaturesOnly
true if only selected features in the source should be used by algorithms.
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
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.
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=nullptr) override
Adds a list of features to the sink.
QgsCoordinateReferenceSystem crs() const
Returns the associated coordinate reference system, or an invalid CRS if no reference system is set...
QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const override
Returns the set of unique values contained within the specified fieldIndex from this source...
static QgsFeatureSink * createFeatureSink(QString &destination, QgsProcessingContext &context, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &createOptions=QVariantMap(), QgsFeatureSink::SinkFlags sinkFlags=nullptr)
Creates a feature sink ready for adding features.
QgsProcessingFeedback * feedback()
Returns the associated feedback object.
static QList< int > fieldNamesToIndices(const QStringList &fieldNames, const QgsFields &fields)
Returns a list of field indices parsed from the given list of field names.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
virtual QVariant minimumValue(int fieldIndex) const
Returns the minimum value for an attribute column or an invalid variant in case of error...
QgsFields fields() const override
Returns the fields associated with features in the source.
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
static QgsProperty fromValue(const QVariant &value, bool isActive=true)
Returns a new StaticProperty created from the specified value.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QgsMapLayerStore * temporaryLayerStore()
Returns a reference to the layer store used for storing temporary layers during algorithm execution...
QgsProperty source
Source definition.
static QStringList defaultLayerOptions(const QString &driverName)
Returns a list of the default layer options for a specified driver.
QVariant minimumValue(int fieldIndex) const override
Returns the minimum value for an attribute column or an invalid variant in case of error...
QgsFeatureIterator getSelectedFeatures(QgsFeatureRequest request=QgsFeatureRequest()) const
Returns an iterator of the selected features.
static QString stringToSafeFilename(const QString &string)
Converts a string to a safe filename, replacing characters which are not safe for filenames with an &#39;...
bool loadDefaultStyle
Sets to true if the default layer style should be loaded.
QgsCoordinateReferenceSystem sourceCrs() const override
Returns the coordinate reference system for features in the source.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:225
There are certainly no features available in this source.
static const QString TEMPORARY_OUTPUT
Constant used to indicate that a Processing algorithm output should be a temporary layer/file...
Definition: qgsprocessing.h:99
This class wraps a request for features to a vector layer (or directly its vector data provider)...
Custom exception class for processing related exceptions.
Definition: qgsexception.h:82
QString subsetString
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
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...
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
Reads and writes project states.
Definition: qgsproject.h:89
Vector polygon layers.
Definition: qgsprocessing.h:50
No invalid geometry checking.
A QgsRectangle with associated coordinate reference system.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=nullptr) override
Adds a single feature to the sink.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:48
QgsMeshDataProvider * dataProvider() override
Returns the layer&#39;s data provider, it may be nullptr.
Single scope for storing variables and functions for use within a QgsExpressionContext.
Contains information about the context in which a coordinate transform is executed.
static QgsProcessingFeatureSource * variantToSource(const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue=QVariant())
Converts a variant value to a new feature source.
A store for object properties.
Definition: qgsproperty.h:229
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
virtual QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const
Returns the set of unique values contained within the specified fieldIndex from this source...
QgsExpressionContext & expressionContext()
Returns the expression context.
QgsRectangle extent() const FINAL
Returns the extent of the layer.
double x
Definition: qgspointxy.h:47
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...
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...
static QString tempFolder()
Returns a session specific processing temporary folder for use in processing algorithms.
virtual QgsCoordinateReferenceSystem sourceCrs() const =0
Returns the coordinate reference system for features in the source.
QgsExpressionContextScope * createExpressionContextScope() const
Returns an expression context scope suitable for this source.
Encapsulates settings relating to a feature source input to a processing algorithm.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
QgsProcessingOutputDefinitions outputDefinitions() const
Returns an ordered list of output definitions utilized by the algorithm.
static QString generateTempFilename(const QString &basename)
Returns a temporary filename for a given file, putting it into a temporary folder (creating that fold...
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle...
Definition: qgsrectangle.h:359
Base class for the definition of processing outputs.
static QString variantToPythonLiteral(const QVariant &value)
Converts a variant to a Python literal.
QgsProxyFeatureSink subclass which reports feature addition errors to a QgsProcessingContext.
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 QgsFields indicesToFields(const QList< int > &indices, const QgsFields &fields)
Returns a subset of fields based on the indices of desired fields.
QVector< T > layers() const
Returns a list of registered map layers with a specified layer type.
Definition: qgsproject.h:767
virtual QgsExpressionContextScope * createExpressionContextScope() const =0
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QMap< QString, QgsMapLayer * > mapLayers() const
Returns a map of all layers by layer ID.
QgsFeatureSource subclass for the selected features from a QgsVectorLayer.
QgsMapLayer * addMapLayer(QgsMapLayer *layer, bool takeOwnership=true)
Add a layer to the store.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
Vector point layers.
Definition: qgsprocessing.h:48
Abstract interface for generating an expression context scope.
QString defaultEncoding() const
Returns the default encoding to use for newly created files.
An interface for objects which provide features via a getFeatures method.
QString source() const
Returns the source for the layer.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
QgsFeatureSource::FeatureAvailability hasFeatures() const override
Determines if there are any features available in the source.
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...
QString sourceName() const override
Returns a friendly display name for the source.
static QStringList defaultDatasetOptions(const QString &driverName)
Returns a list of the default dataset options for a specified driver.
This class represents a coordinate reference system (CRS).
Base class for the definition of processing parameters.
Vector line layers.
Definition: qgsprocessing.h:49
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition: qgsprocessing.h:53
Class for doing transforms between two map coordinate systems.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
Represents a mesh layer supporting display of data on structured or unstructured meshes.
Definition: qgsmeshlayer.h:90
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QString name
Definition: qgsmaplayer.h:82
A storage object for map layers, in which the layers are owned by the store and have their lifetime b...
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=nullptr) override
Adds a single feature to the sink.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
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.
virtual QVariant maximumValue(int fieldIndex) const
Returns the maximum value for an attribute column or an invalid variant in case of error...
There may be features available in this source.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer&#39;s data provider, it may be nullptr.
bool nextFeature(QgsFeature &f)
QgsFeatureSink * destinationSink()
Returns the destination QgsFeatureSink which the proxy will forward features to.
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).
virtual QString sourceName() const =0
Returns a friendly display name for the source.
long featureCount() const override
Returns the number of features contained in the source, or -1 if the feature count is unknown...
Class for storing the component parts of a RDBMS data source URI (e.g.
Represents a vector layer which manages a vector based data sets.
virtual QgsFeatureIds allFeatureIds() const
Returns a list of all feature IDs for features present in the source.
Contains information about the context in which a processing algorithm is executed.
virtual FeatureAvailability hasFeatures() const
Determines if there are any features available in the source.
QString database() const
Returns the database name stored in the URI.
Any vector layer with geometry.
Definition: qgsprocessing.h:47
QString authid() const
Returns the authority identifier for the CRS.
Setting options for loading raster layers.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:85
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...
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
QgsProcessingFeatureSink(QgsFeatureSink *originalSink, const QString &sinkName, QgsProcessingContext &context, bool ownsOriginalSink=false)
Constructor for QgsProcessingFeatureSink, accepting an original feature sink originalSink and process...