QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsrasterpipe.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrasterpipe.cpp - Internal raster processing modules interface
3  --------------------------------------
4  Date : Jun 21, 2012
5  Copyright : (C) 2012 by Radim Blazek
6  email : radim dot blazek 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 <typeinfo>
19 
20 #include <QByteArray>
21 
22 #include "qgslogger.h"
23 #include "qgsrasterpipe.h"
24 #include "qgsrasterdataprovider.h"
25 #include "qgsrasterrenderer.h"
28 #include "qgshuesaturationfilter.h"
29 #include "qgsrasterprojector.h"
30 #include "qgsrasternuller.h"
31 
32 #include <mutex>
33 
35 {
36  for ( int i = 0; i < pipe.size(); i++ )
37  {
38  QgsRasterInterface *interface = pipe.at( i );
39  QgsRasterInterface *clone = interface->clone();
40 
41  Qgis::RasterPipeInterfaceRole role = interfaceRole( clone );
42  QgsDebugMsgLevel( QStringLiteral( "cloned interface with role %1" ).arg( qgsEnumValueToKey( role ) ), 4 );
43  if ( i > 0 )
44  {
45  clone->setInput( mInterfaces.at( i - 1 ) );
46  }
47  mInterfaces.append( clone );
48  if ( role != Qgis::RasterPipeInterfaceRole::Unknown )
49  {
50  mRoleMap.insert( role, i );
51  }
52  }
54  mDataDefinedProperties = pipe.mDataDefinedProperties;
55 }
56 
58 {
59  const auto constMInterfaces = mInterfaces;
60  for ( QgsRasterInterface *interface : constMInterfaces )
61  {
62  delete interface;
63  }
64 }
65 
66 bool QgsRasterPipe::connect( QVector<QgsRasterInterface *> interfaces )
67 {
68  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
69  for ( int i = 1; i < interfaces.size(); i++ )
70  {
71  if ( ! interfaces[i]->setInput( interfaces[i - 1] ) )
72  {
73 #ifdef QGISDEBUG
74  const QgsRasterInterface &a = *interfaces[i];
75  const QgsRasterInterface &b = *interfaces[i - 1];
76  QgsDebugMsg( QStringLiteral( "cannot connect %1 to %2" ).arg( typeid( a ).name(), typeid( b ).name() ) );
77 #endif
78  return false;
79  }
80  }
81  return true;
82 }
83 
84 bool QgsRasterPipe::insert( int idx, QgsRasterInterface *interface )
85 {
86  QgsDebugMsgLevel( QStringLiteral( "insert %1 at %2" ).arg( typeid( *interface ).name() ).arg( idx ), 4 );
87  if ( idx > mInterfaces.size() )
88  {
89  idx = mInterfaces.size();
90  }
91  // make a copy of pipe to test connection, we test the connections
92  // of the whole pipe, because the types and band numbers may change
93  QVector<QgsRasterInterface *> interfaces = mInterfaces;
94 
95  interfaces.insert( idx, interface );
96  bool success = false;
97  if ( connect( interfaces ) )
98  {
99  success = true;
100  mInterfaces.insert( idx, interface );
101  setRole( interface, idx );
102  QgsDebugMsgLevel( QStringLiteral( "Pipe %1 inserted OK" ).arg( idx ), 4 );
103  }
104  else
105  {
106  QgsDebugMsgLevel( QStringLiteral( "Error inserting pipe %1" ).arg( idx ), 4 );
107  }
108 
109  // Connect or reconnect (after the test) interfaces
110  connect( mInterfaces );
111  return success;
112 }
113 
114 bool QgsRasterPipe::replace( int idx, QgsRasterInterface *interface )
115 {
116  if ( !interface ) return false;
117 
118  QgsDebugMsgLevel( QStringLiteral( "replace by %1 at %2" ).arg( typeid( *interface ).name() ).arg( idx ), 4 );
119  if ( !checkBounds( idx ) ) return false;
120 
121  // make a copy of pipe to test connection, we test the connections
122  // of the whole pipe, because the types and band numbers may change
123  QVector<QgsRasterInterface *> interfaces = mInterfaces;
124 
125  interfaces[idx] = interface;
126  bool success = false;
127  if ( connect( interfaces ) )
128  {
129  success = true;
130  delete mInterfaces.at( idx );
131  mInterfaces[idx] = interface;
132  setRole( interface, idx );
133  QgsDebugMsgLevel( QStringLiteral( "replaced OK" ), 4 );
134  }
135 
136  // Connect or reconnect (after the test) interfaces
137  connect( mInterfaces );
138  return success;
139 }
140 
141 Qgis::RasterPipeInterfaceRole QgsRasterPipe::interfaceRole( QgsRasterInterface *interface ) const
142 {
143  Qgis::RasterPipeInterfaceRole role = Qgis::RasterPipeInterfaceRole::Unknown;
144  if ( dynamic_cast<QgsRasterDataProvider *>( interface ) )
145  role = Qgis::RasterPipeInterfaceRole::Provider;
146  else if ( dynamic_cast<QgsRasterRenderer *>( interface ) )
147  role = Qgis::RasterPipeInterfaceRole::Renderer;
148  else if ( dynamic_cast<QgsRasterResampleFilter *>( interface ) )
149  role = Qgis::RasterPipeInterfaceRole::Resampler;
150  else if ( dynamic_cast<QgsBrightnessContrastFilter *>( interface ) )
151  role = Qgis::RasterPipeInterfaceRole::Brightness;
152  else if ( dynamic_cast<QgsHueSaturationFilter *>( interface ) )
153  role = Qgis::RasterPipeInterfaceRole::HueSaturation;
154  else if ( dynamic_cast<QgsRasterProjector *>( interface ) )
155  role = Qgis::RasterPipeInterfaceRole::Projector;
156  else if ( dynamic_cast<QgsRasterNuller *>( interface ) )
157  role = Qgis::RasterPipeInterfaceRole::Nuller;
158 
159  QgsDebugMsgLevel( QStringLiteral( "%1 role = %2" ).arg( typeid( *interface ).name(), qgsEnumValueToKey( role ) ), 4 );
160  return role;
161 }
162 
163 void QgsRasterPipe::setRole( QgsRasterInterface *interface, int idx )
164 {
165  Qgis::RasterPipeInterfaceRole role = interfaceRole( interface );
166  if ( role == Qgis::RasterPipeInterfaceRole::Unknown )
167  return;
168 
169  mRoleMap.insert( role, idx );
170 }
171 
172 void QgsRasterPipe::unsetRole( QgsRasterInterface *interface )
173 {
174  Qgis::RasterPipeInterfaceRole role = interfaceRole( interface );
175  if ( role == Qgis::RasterPipeInterfaceRole::Unknown )
176  return;
177 
178  const int roleIdx{ mRoleMap[role] };
179  mRoleMap.remove( role );
180 
181  // Decrease all indexes greater than the removed one
182  const auto roleMapValues {mRoleMap.values()};
183  if ( roleIdx < *std::max_element( roleMapValues.begin(), roleMapValues.end() ) )
184  {
185  for ( auto it = mRoleMap.cbegin(); it != mRoleMap.cend(); ++it )
186  {
187  if ( it.value() > roleIdx )
188  {
189  mRoleMap[it.key()] = it.value() - 1;
190  }
191  }
192  }
193 }
194 
196 {
197  if ( !interface )
198  return false;
199 
200  QgsDebugMsgLevel( typeid( *interface ).name(), 4 );
201  Qgis::RasterPipeInterfaceRole role = interfaceRole( interface );
202 
203  // We don't know where to place unknown interface
204  if ( role == Qgis::RasterPipeInterfaceRole::Unknown )
205  return false;
206 
207  //if ( mInterfacesMap.value ( role ) )
208  if ( mRoleMap.contains( role ) )
209  {
210  // An old interface of the same role exists -> replace
211  // replace may still fail and return false
212  return replace( mRoleMap.value( role ), interface );
213  }
214 
215  int idx = 0;
216 
217  // Not found, find the best default position for this kind of interface
218  // QgsRasterDataProvider - ProviderRole
219  // QgsRasterRenderer - RendererRole
220  // QgsRasterResampler - ResamplerRole
221  // QgsRasterProjector - ProjectorRole
222 
223  int providerIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::Provider, -1 );
224  int rendererIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::Renderer, -1 );
225  int resamplerIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::Resampler, -1 );
226  int brightnessIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::Brightness, -1 );
227  int hueSaturationIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::HueSaturation, -1 );
228 
229  if ( role == Qgis::RasterPipeInterfaceRole::Provider )
230  {
231  idx = 0;
232  }
233  else if ( role == Qgis::RasterPipeInterfaceRole::Renderer )
234  {
235  idx = providerIdx + 1;
236  }
237  else if ( role == Qgis::RasterPipeInterfaceRole::Brightness )
238  {
239  idx = std::max( providerIdx, rendererIdx ) + 1;
240  }
241  else if ( role == Qgis::RasterPipeInterfaceRole::HueSaturation )
242  {
243  idx = std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ) + 1;
244  }
245  else if ( role == Qgis::RasterPipeInterfaceRole::Resampler )
246  {
247  idx = std::max( std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ), hueSaturationIdx ) + 1;
248  }
249  else if ( role == Qgis::RasterPipeInterfaceRole::Projector )
250  {
251  idx = std::max( std::max( std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ), hueSaturationIdx ), resamplerIdx ) + 1;
252  }
253 
254  return insert( idx, interface ); // insert may still fail and return false
255 }
256 
257 QgsRasterInterface *QgsRasterPipe::interface( Qgis::RasterPipeInterfaceRole role ) const
258 {
259  QgsDebugMsgLevel( QStringLiteral( "role = %1" ).arg( qgsEnumValueToKey( role ) ), 4 );
260  if ( mRoleMap.contains( role ) )
261  {
262  return mInterfaces.value( mRoleMap.value( role ) );
263  }
264  return nullptr;
265 }
266 
268 {
269  return dynamic_cast<QgsRasterDataProvider *>( interface( Qgis::RasterPipeInterfaceRole::Provider ) );
270 }
271 
273 {
274  return dynamic_cast<QgsRasterRenderer *>( interface( Qgis::RasterPipeInterfaceRole::Renderer ) );
275 }
276 
278 {
279  return dynamic_cast<QgsRasterResampleFilter *>( interface( Qgis::RasterPipeInterfaceRole::Resampler ) );
280 }
281 
283 {
284  return dynamic_cast<QgsBrightnessContrastFilter *>( interface( Qgis::RasterPipeInterfaceRole::Brightness ) );
285 }
286 
288 {
289  return dynamic_cast<QgsHueSaturationFilter *>( interface( Qgis::RasterPipeInterfaceRole::HueSaturation ) );
290 }
291 
293 {
294  return dynamic_cast<QgsRasterProjector *>( interface( Qgis::RasterPipeInterfaceRole::Projector ) );
295 }
296 
298 {
299  return dynamic_cast<QgsRasterNuller *>( interface( Qgis::RasterPipeInterfaceRole::Nuller ) );
300 }
301 
302 bool QgsRasterPipe::remove( int idx )
303 {
304  QgsDebugMsgLevel( QStringLiteral( "remove at %1" ).arg( idx ), 4 );
305 
306  if ( !checkBounds( idx ) )
307  return false;
308 
309  // make a copy of pipe to test connection, we test the connections
310  // of the whole pipe, because the types and band numbers may change
311  QVector<QgsRasterInterface *> interfaces = mInterfaces;
312 
313  interfaces.remove( idx );
314  bool success = false;
315  if ( connect( interfaces ) )
316  {
317  success = true;
318  unsetRole( mInterfaces.at( idx ) );
319  delete mInterfaces.at( idx );
320  mInterfaces.remove( idx );
321  QgsDebugMsgLevel( QStringLiteral( "Pipe %1 removed OK" ).arg( idx ), 4 );
322  }
323  else
324  {
325  QgsDebugMsgLevel( QStringLiteral( "Error removing pipe %1" ).arg( idx ), 4 );
326  }
327 
328  // Connect or reconnect (after the test) interfaces
329  connect( mInterfaces );
330 
331  return success;
332 }
333 
335 {
336  if ( !interface ) return false;
337 
338  return remove( mInterfaces.indexOf( interface ) );
339 }
340 
341 bool QgsRasterPipe::canSetOn( int idx, bool on )
342 {
343  QgsDebugMsgLevel( QStringLiteral( "idx = %1 on = %2" ).arg( idx ).arg( on ), 4 );
344  if ( !checkBounds( idx ) )
345  return false;
346 
347  // Because setting interface on/off may change its output we must check if
348  // connection is OK after such switch
349  bool onOrig = mInterfaces.at( idx )->on();
350 
351  if ( onOrig == on )
352  return true;
353 
354  mInterfaces.at( idx )->setOn( on );
355 
356  bool success = connect( mInterfaces );
357 
358  mInterfaces.at( idx )->setOn( onOrig );
359  connect( mInterfaces );
360  return success;
361 }
362 
363 bool QgsRasterPipe::setOn( int idx, bool on )
364 {
365  QgsDebugMsgLevel( QStringLiteral( "idx = %1 on = %2" ).arg( idx ).arg( on ), 4 );
366  if ( !checkBounds( idx ) )
367  return false;
368 
369  bool onOrig = mInterfaces.at( idx )->on();
370 
371  if ( onOrig == on )
372  return true;
373 
374  mInterfaces.at( idx )->setOn( on );
375 
376  if ( connect( mInterfaces ) )
377  return true;
378 
379  mInterfaces.at( idx )->setOn( onOrig );
380  connect( mInterfaces );
381 
382  return false;
383 }
384 
385 bool QgsRasterPipe::checkBounds( int idx ) const
386 {
387  return !( idx < 0 || idx >= mInterfaces.size() );
388 }
389 
391 {
392  mResamplingStage = stage;
393 
394  int resamplerIndex = 0;
395  for ( QgsRasterInterface *interface : std::as_const( mInterfaces ) )
396  {
397  if ( interfaceRole( interface ) == Qgis::RasterPipeInterfaceRole::Resampler )
398  {
399  setOn( resamplerIndex, stage == Qgis::RasterResamplingStage::ResampleFilter );
400  break;
401  }
402  resamplerIndex ++;
403  }
404 
405  if ( QgsRasterDataProvider *l_provider = provider() )
406  {
407  l_provider->enableProviderResampling( stage == Qgis::RasterResamplingStage::Provider );
408  }
409 }
410 
412 {
413  if ( !mDataDefinedProperties.hasActiveProperties() )
414  return;
415 
416  if ( mDataDefinedProperties.isActive( RendererOpacity ) )
417  {
418  if ( QgsRasterRenderer *r = renderer() )
419  {
420  const double prevOpacity = r->opacity();
421  context.setOriginalValueVariable( prevOpacity * 100 );
422  bool ok = false;
423  const double opacity = mDataDefinedProperties.valueAsDouble( RendererOpacity, context, prevOpacity, &ok ) / 100;
424  if ( ok )
425  {
426  r->setOpacity( opacity );
427  }
428  }
429  }
430 }
431 
432 QgsPropertiesDefinition QgsRasterPipe::sPropertyDefinitions;
433 
434 void QgsRasterPipe::initPropertyDefinitions()
435 {
436  const QString origin = QStringLiteral( "raster" );
437 
438  sPropertyDefinitions = QgsPropertiesDefinition
439  {
440  { QgsRasterPipe::RendererOpacity, QgsPropertyDefinition( "RendererOpacity", QObject::tr( "Renderer opacity" ), QgsPropertyDefinition::Opacity, origin ) },
441  };
442 }
443 
445 {
446  static std::once_flag initialized;
447  std::call_once( initialized, [ = ]( )
448  {
449  initPropertyDefinitions();
450  } );
451  return sPropertyDefinitions;
452 }
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:406
qgsrasterprojector.h
QgsRasterPipe::setOn
bool setOn(int idx, bool on)
Set whether the interface at the specified index is enabled.
Definition: qgsrasterpipe.cpp:363
QgsAbstractPropertyCollection::valueAsDouble
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
Definition: qgspropertycollection.cpp:66
qgsEnumValueToKey
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition: qgis.h:2440
qgsrasterpipe.h
QgsRasterPipe::insert
bool insert(int idx, QgsRasterInterface *interface)
Attempts to insert interface at specified index and connect if connection would fail,...
Definition: qgsrasterpipe.cpp:84
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsRasterPipe::~QgsRasterPipe
~QgsRasterPipe()
Definition: qgsrasterpipe.cpp:57
QgsRasterPipe::canSetOn
bool canSetOn(int idx, bool on)
Returns true if the interface at the specified index may be switched on or off.
Definition: qgsrasterpipe.cpp:341
QgsRasterPipe::set
bool set(QgsRasterInterface *interface)
Inserts a new known interface in default place or replace interface of the same role if it already ex...
Definition: qgsrasterpipe.cpp:195
QgsExpressionContext::setOriginalValueVariable
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
Definition: qgsexpressioncontext.cpp:600
QgsRasterPipe
Contains a pipeline of raster interfaces for sequential raster processing.
Definition: qgsrasterpipe.h:49
Qgis::RasterResamplingStage
RasterResamplingStage
Stage at which raster resampling occurs.
Definition: qgis.h:720
qgsrasterrenderer.h
QgsRasterNuller
Raster pipe that deals with null values.
Definition: qgsrasternuller.h:32
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsRasterPipe::provider
QgsRasterDataProvider * provider() const
Returns the data provider interface, or nullptr if no data provider is present in the pipe.
Definition: qgsrasterpipe.cpp:267
QgsRasterProjector
QgsRasterProjector implements approximate projection support for it calculates grid of points in sour...
Definition: qgsrasterprojector.h:47
QgsPropertiesDefinition
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
Definition: qgspropertycollection.h:29
QgsRasterPipe::evaluateDataDefinedProperties
void evaluateDataDefinedProperties(QgsExpressionContext &context)
Evaluates any data defined properties set on the pipe, applying their results to the corresponding in...
Definition: qgsrasterpipe.cpp:411
QgsRasterPipe::remove
bool remove(int idx)
Removes and deletes the interface at given index (if possible).
Definition: qgsrasterpipe.cpp:302
QgsRasterPipe::brightnessFilter
QgsBrightnessContrastFilter * brightnessFilter() const
Returns the brightness filter interface, or nullptr if no brightness filter is present in the pipe.
Definition: qgsrasterpipe.cpp:282
QgsRasterPipe::resamplingStage
Qgis::RasterResamplingStage resamplingStage() const
Returns which stage of the pipe should apply resampling.
Definition: qgsrasterpipe.h:225
QgsRasterPipe::renderer
QgsRasterRenderer * renderer() const
Returns the raster renderer interface, or nullptr if no raster renderer is present in the pipe.
Definition: qgsrasterpipe.cpp:272
QgsPropertyCollection::hasActiveProperties
bool hasActiveProperties() const override
Returns true if the collection has any active properties, or false if all properties within the colle...
Definition: qgspropertycollection.cpp:304
QgsRasterRenderer
Raster renderer pipe that applies colors to a raster.
Definition: qgsrasterrenderer.h:40
QgsRasterPipe::RendererOpacity
@ RendererOpacity
Raster renderer global opacity.
Definition: qgsrasterpipe.h:59
QgsRasterInterface::clone
virtual QgsRasterInterface * clone() const =0
Clone itself, create deep copy.
QgsPropertyDefinition
Definition for a property.
Definition: qgsproperty.h:46
QgsHueSaturationFilter
Color and saturation filter pipe for rasters.
Definition: qgshuesaturationfilter.h:31
QgsRasterPipe::hueSaturationFilter
QgsHueSaturationFilter * hueSaturationFilter() const
Returns the hue/saturation interface, or nullptr if no hue/saturation filter is present in the pipe.
Definition: qgsrasterpipe.cpp:287
qgsrasterresamplefilter.h
QgsRasterPipe::propertyDefinitions
static QgsPropertiesDefinition propertyDefinitions()
Returns the definitions for data defined properties available for use in raster pipes.
Definition: qgsrasterpipe.cpp:444
Qgis::RasterPipeInterfaceRole
RasterPipeInterfaceRole
Sublayer flags.
Definition: qgis.h:703
qgsbrightnesscontrastfilter.h
QgsRasterPipe::setResamplingStage
void setResamplingStage(Qgis::RasterResamplingStage stage)
Sets which stage of the pipe should apply resampling.
Definition: qgsrasterpipe.cpp:390
qgshuesaturationfilter.h
QgsRasterPipe::replace
bool replace(int idx, QgsRasterInterface *interface)
Attempts to replace the interface at specified index and reconnect the pipe.
Definition: qgsrasterpipe.cpp:114
QgsRasterInterface
Base class for processing filters like renderers, reprojector, resampler etc.
Definition: qgsrasterinterface.h:135
QgsBrightnessContrastFilter
Brightness/contrast and gamma correction filter pipe for rasters.
Definition: qgsbrightnesscontrastfilter.h:31
QgsRasterResampleFilter
Resample filter pipe for rasters.
Definition: qgsrasterresamplefilter.h:32
Qgis::RasterResamplingStage::Provider
@ Provider
Resampling occurs in Provider.
QgsPropertyDefinition::Opacity
@ Opacity
Opacity (0-100)
Definition: qgsproperty.h:62
QgsRasterPipe::resampleFilter
QgsRasterResampleFilter * resampleFilter() const
Returns the resample filter interface, or nullptr if no resample filter is present in the pipe.
Definition: qgsrasterpipe.cpp:277
QgsRasterPipe::projector
QgsRasterProjector * projector() const
Returns the projector interface, or nullptr if no projector is present in the pipe.
Definition: qgsrasterpipe.cpp:292
QgsRasterPipe::QgsRasterPipe
QgsRasterPipe()=default
Constructor for an empty QgsRasterPipe.
qgslogger.h
QgsPropertyCollection::isActive
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
Definition: qgspropertycollection.cpp:268
qgsrasternuller.h
Qgis::RasterResamplingStage::ResampleFilter
@ ResampleFilter
Resampling occurs in ResamplingFilter.
QgsRasterDataProvider
Base class for raster data providers.
Definition: qgsrasterdataprovider.h:88
QgsRasterPipe::size
int size() const
Returns the size of the pipe (the number of interfaces contained in the pipe).
Definition: qgsrasterpipe.h:147
QgsRasterPipe::nuller
QgsRasterNuller * nuller() const
Returns the raster nuller interface, or nullptr if no raster nuller is present in the pipe.
Definition: qgsrasterpipe.cpp:297
qgsrasterdataprovider.h