QGIS API Documentation  3.20.0-Odense (decaadbb31)
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 
33 {
34  for ( int i = 0; i < pipe.size(); i++ )
35  {
36  QgsRasterInterface *interface = pipe.at( i );
37  QgsRasterInterface *clone = interface->clone();
38 
39  Role role = interfaceRole( clone );
40  QgsDebugMsgLevel( QStringLiteral( "cloned interface with role %1" ).arg( role ), 4 );
41  if ( i > 0 )
42  {
43  clone->setInput( mInterfaces.at( i - 1 ) );
44  }
45  mInterfaces.append( clone );
46  if ( role != UnknownRole )
47  {
48  mRoleMap.insert( role, i );
49  }
50  }
52 }
53 
55 {
56  const auto constMInterfaces = mInterfaces;
57  for ( QgsRasterInterface *interface : constMInterfaces )
58  {
59  delete interface;
60  }
61 }
62 
63 bool QgsRasterPipe::connect( QVector<QgsRasterInterface *> interfaces )
64 {
65  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
66  for ( int i = 1; i < interfaces.size(); i++ )
67  {
68  if ( ! interfaces[i]->setInput( interfaces[i - 1] ) )
69  {
70 #ifdef QGISDEBUG
71  const QgsRasterInterface &a = *interfaces[i];
72  const QgsRasterInterface &b = *interfaces[i - 1];
73  QgsDebugMsg( QStringLiteral( "cannot connect %1 to %2" ).arg( typeid( a ).name(), typeid( b ).name() ) );
74 #endif
75  return false;
76  }
77  }
78  return true;
79 }
80 
81 bool QgsRasterPipe::insert( int idx, QgsRasterInterface *interface )
82 {
83  QgsDebugMsgLevel( QStringLiteral( "insert %1 at %2" ).arg( typeid( *interface ).name() ).arg( idx ), 4 );
84  if ( idx > mInterfaces.size() )
85  {
86  idx = mInterfaces.size();
87  }
88  // make a copy of pipe to test connection, we test the connections
89  // of the whole pipe, because the types and band numbers may change
90  QVector<QgsRasterInterface *> interfaces = mInterfaces;
91 
92  interfaces.insert( idx, interface );
93  bool success = false;
94  if ( connect( interfaces ) )
95  {
96  success = true;
97  mInterfaces.insert( idx, interface );
98  setRole( interface, idx );
99  QgsDebugMsgLevel( QStringLiteral( "inserted OK" ), 4 );
100  }
101 
102  // Connect or reconnect (after the test) interfaces
103  connect( mInterfaces );
104  return success;
105 }
106 
107 bool QgsRasterPipe::replace( int idx, QgsRasterInterface *interface )
108 {
109  if ( !interface ) return false;
110 
111  QgsDebugMsgLevel( QStringLiteral( "replace by %1 at %2" ).arg( typeid( *interface ).name() ).arg( idx ), 4 );
112  if ( !checkBounds( idx ) ) return false;
113 
114  // make a copy of pipe to test connection, we test the connections
115  // of the whole pipe, because the types and band numbers may change
116  QVector<QgsRasterInterface *> interfaces = mInterfaces;
117 
118  interfaces[idx] = interface;
119  bool success = false;
120  if ( connect( interfaces ) )
121  {
122  success = true;
123  delete mInterfaces.at( idx );
124  mInterfaces[idx] = interface;
125  setRole( interface, idx );
126  QgsDebugMsgLevel( QStringLiteral( "replaced OK" ), 4 );
127  }
128 
129  // Connect or reconnect (after the test) interfaces
130  connect( mInterfaces );
131  return success;
132 }
133 
134 QgsRasterPipe::Role QgsRasterPipe::interfaceRole( QgsRasterInterface *interface ) const
135 {
136  Role role = UnknownRole;
137  if ( dynamic_cast<QgsRasterDataProvider *>( interface ) ) role = ProviderRole;
138  else if ( dynamic_cast<QgsRasterRenderer *>( interface ) ) role = RendererRole;
139  else if ( dynamic_cast<QgsRasterResampleFilter *>( interface ) ) role = ResamplerRole;
140  else if ( dynamic_cast<QgsBrightnessContrastFilter *>( interface ) ) role = BrightnessRole;
141  else if ( dynamic_cast<QgsHueSaturationFilter *>( interface ) ) role = HueSaturationRole;
142  else if ( dynamic_cast<QgsRasterProjector *>( interface ) ) role = ProjectorRole;
143  else if ( dynamic_cast<QgsRasterNuller *>( interface ) ) role = NullerRole;
144 
145  QgsDebugMsgLevel( QStringLiteral( "%1 role = %2" ).arg( typeid( *interface ).name() ).arg( role ), 4 );
146  return role;
147 }
148 
149 void QgsRasterPipe::setRole( QgsRasterInterface *interface, int idx )
150 {
151  Role role = interfaceRole( interface );
152  if ( role == UnknownRole ) return;
153  mRoleMap.insert( role, idx );
154 }
155 
156 void QgsRasterPipe::unsetRole( QgsRasterInterface *interface )
157 {
158  Role role = interfaceRole( interface );
159  if ( role == UnknownRole ) return;
160  mRoleMap.remove( role );
161 }
162 
164 {
165  if ( !interface ) return false;
166 
167  QgsDebugMsgLevel( typeid( *interface ).name(), 4 );
168  Role role = interfaceRole( interface );
169 
170  // We don't know where to place unknown interface
171  if ( role == UnknownRole ) return false;
172 
173  //if ( mInterfacesMap.value ( role ) )
174  if ( mRoleMap.contains( role ) )
175  {
176  // An old interface of the same role exists -> replace
177  // replace may still fail and return false
178  return replace( mRoleMap.value( role ), interface );
179  }
180 
181  int idx = 0;
182 
183  // Not found, find the best default position for this kind of interface
184  // QgsRasterDataProvider - ProviderRole
185  // QgsRasterRenderer - RendererRole
186  // QgsRasterResampler - ResamplerRole
187  // QgsRasterProjector - ProjectorRole
188 
189  int providerIdx = mRoleMap.value( ProviderRole, -1 );
190  int rendererIdx = mRoleMap.value( RendererRole, -1 );
191  int resamplerIdx = mRoleMap.value( ResamplerRole, -1 );
192  int brightnessIdx = mRoleMap.value( BrightnessRole, -1 );
193  int hueSaturationIdx = mRoleMap.value( HueSaturationRole, -1 );
194 
195  if ( role == ProviderRole )
196  {
197  idx = 0;
198  }
199  else if ( role == RendererRole )
200  {
201  idx = providerIdx + 1;
202  }
203  else if ( role == BrightnessRole )
204  {
205  idx = std::max( providerIdx, rendererIdx ) + 1;
206  }
207  else if ( role == HueSaturationRole )
208  {
209  idx = std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ) + 1;
210  }
211  else if ( role == ResamplerRole )
212  {
213  idx = std::max( std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ), hueSaturationIdx ) + 1;
214  }
215  else if ( role == ProjectorRole )
216  {
217  idx = std::max( std::max( std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ), hueSaturationIdx ), resamplerIdx ) + 1;
218  }
219 
220  return insert( idx, interface ); // insert may still fail and return false
221 }
222 
223 QgsRasterInterface *QgsRasterPipe::interface( Role role ) const
224 {
225  QgsDebugMsgLevel( QStringLiteral( "role = %1" ).arg( role ), 4 );
226  if ( mRoleMap.contains( role ) )
227  {
228  return mInterfaces.value( mRoleMap.value( role ) );
229  }
230  return nullptr;
231 }
232 
234 {
235  return dynamic_cast<QgsRasterDataProvider *>( interface( ProviderRole ) );
236 }
237 
239 {
240  return dynamic_cast<QgsRasterRenderer *>( interface( RendererRole ) );
241 }
242 
244 {
245  return dynamic_cast<QgsRasterResampleFilter *>( interface( ResamplerRole ) );
246 }
247 
249 {
250  return dynamic_cast<QgsBrightnessContrastFilter *>( interface( BrightnessRole ) );
251 }
252 
254 {
255  return dynamic_cast<QgsHueSaturationFilter *>( interface( HueSaturationRole ) );
256 }
257 
259 {
260  return dynamic_cast<QgsRasterProjector *>( interface( ProjectorRole ) );
261 }
262 
264 {
265  return dynamic_cast<QgsRasterNuller *>( interface( NullerRole ) );
266 }
267 
268 bool QgsRasterPipe::remove( int idx )
269 {
270  QgsDebugMsgLevel( QStringLiteral( "remove at %1" ).arg( idx ), 4 );
271 
272  if ( !checkBounds( idx ) ) return false;
273 
274  // make a copy of pipe to test connection, we test the connections
275  // of the whole pipe, because the types and band numbers may change
276  QVector<QgsRasterInterface *> interfaces = mInterfaces;
277 
278  interfaces.remove( idx );
279  bool success = false;
280  if ( connect( interfaces ) )
281  {
282  success = true;
283  unsetRole( mInterfaces.at( idx ) );
284  delete mInterfaces.at( idx );
285  mInterfaces.remove( idx );
286  QgsDebugMsgLevel( QStringLiteral( "removed OK" ), 4 );
287  }
288 
289  // Connect or reconnect (after the test) interfaces
290  connect( mInterfaces );
291  return success;
292 }
293 
295 {
296  if ( !interface ) return false;
297 
298  return remove( mInterfaces.indexOf( interface ) );
299 }
300 
301 bool QgsRasterPipe::canSetOn( int idx, bool on )
302 {
303  QgsDebugMsgLevel( QStringLiteral( "idx = %1 on = %2" ).arg( idx ).arg( on ), 4 );
304  if ( !checkBounds( idx ) ) return false;
305 
306  // Because setting interface on/off may change its output we must check if
307  // connection is OK after such switch
308  bool onOrig = mInterfaces.at( idx )->on();
309 
310  if ( onOrig == on ) return true;
311 
312  mInterfaces.at( idx )->setOn( on );
313 
314  bool success = connect( mInterfaces );
315 
316  mInterfaces.at( idx )->setOn( onOrig );
317  connect( mInterfaces );
318  return success;
319 }
320 
321 bool QgsRasterPipe::setOn( int idx, bool on )
322 {
323  QgsDebugMsgLevel( QStringLiteral( "idx = %1 on = %2" ).arg( idx ).arg( on ), 4 );
324  if ( !checkBounds( idx ) ) return false;
325 
326  bool onOrig = mInterfaces.at( idx )->on();
327 
328  if ( onOrig == on ) return true;
329 
330  mInterfaces.at( idx )->setOn( on );
331 
332  if ( connect( mInterfaces ) ) return true;
333 
334  mInterfaces.at( idx )->setOn( onOrig );
335  connect( mInterfaces );
336 
337  return false;
338 }
339 
340 bool QgsRasterPipe::checkBounds( int idx ) const
341 {
342  return !( idx < 0 || idx >= mInterfaces.size() );
343 }
344 
346 {
347  mResamplingStage = stage;
349  QgsRasterDataProvider *l_provider = provider();
350  if ( l_provider )
351  {
352  l_provider->enableProviderResampling( stage == ResamplingStage::Provider );
353  }
354 }
Brightness/contrast and gamma correction filter pipe for rasters.
Color and saturation filter pipe for rasters.
Base class for raster data providers.
virtual bool enableProviderResampling(bool enable)
Enable or disable provider-level resampling.
Base class for processing filters like renderers, reprojector, resampler etc.
virtual QgsRasterInterface * clone() const =0
Clone itself, create deep copy.
Raster pipe that deals with null values.
Base class for processing modules.
Definition: qgsrasterpipe.h:47
bool set(QgsRasterInterface *interface)
Insert a new known interface in default place or replace interface of the same role if it already exi...
int size() const
QgsRasterPipe()=default
Constructor for QgsRasterPipe.
ResamplingStage
Stage at which resampling occurs.
@ Provider
Resampling occurs in Provider.
@ ResampleFilter
Resampling occurs in ResamplingFilter.
QgsRasterResampleFilter * resampleFilter() const
bool replace(int idx, QgsRasterInterface *interface)
Try to replace interface at specified index and connect if connection would fail, the interface is no...
QgsRasterDataProvider * provider() const
bool canSetOn(int idx, bool on)
Test if interface at index may be switched on/off.
bool insert(int idx, QgsRasterInterface *interface)
Try to insert interface at specified index and connect if connection would fail, the interface is not...
QgsRasterProjector * projector() const
bool remove(int idx)
Remove and delete interface at given index if possible.
QgsRasterRenderer * renderer() const
ResamplingStage resamplingStage() const
Returns which stage of the pipe should apply resampling.
void setResamplingStage(ResamplingStage stage)
Select which stage of the pipe should apply resampling.
QgsBrightnessContrastFilter * brightnessFilter() const
QgsHueSaturationFilter * hueSaturationFilter() const
QgsRasterNuller * nuller() const
bool setOn(int idx, bool on)
Set interface at index on/off Returns true on success.
QgsRasterProjector implements approximate projection support for it calculates grid of points in sour...
Raster renderer pipe that applies colors to a raster.
Resample filter pipe for rasters.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38