QGIS API Documentation  3.15.0-Master (dbe1ef8aa2)
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( QStringLiteral( "%1" ).arg( 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 }
Base class for processing modules.
Definition: qgsrasterpipe.h:46
QgsRasterRenderer * renderer() const
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsRasterResampleFilter * resampleFilter() const
QgsRasterProjector * projector() const
Raster pipe that deals with null values.
void setResamplingStage(ResamplingStage stage)
Select which stage of the pipe should apply resampling.
ResamplingStage resamplingStage() const
Returns which stage of the pipe should apply resampling.
bool insert(int idx, QgsRasterInterface *interface)
Try to insert interface at specified index and connect if connection would fail, the interface is not...
Resample filter pipe for rasters.
Resampling occurs in Provider.
bool replace(int idx, QgsRasterInterface *interface)
Try to replace interface at specified index and connect if connection would fail, the interface is no...
virtual bool enableProviderResampling(bool enable)
Enable or disable provider-level resampling.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
Resampling occurs in ResamplingFilter.
Base class for processing filters like renderers, reprojector, resampler etc.
ResamplingStage
Stage at which resampling occurs.
int size() const
QgsRasterProjector implements approximate projection support for it calculates grid of points in sour...
bool canSetOn(int idx, bool on)
Test if interface at index may be switched on/off.
bool set(QgsRasterInterface *interface)
Insert a new known interface in default place or replace interface of the same role if it already exi...
bool remove(int idx)
Remove and delete interface at given index if possible.
bool setOn(int idx, bool on)
Set interface at index on/off Returns true on success.
virtual QgsRasterInterface * clone() const =0
Clone itself, create deep copy.
Brightness/contrast and gamma correction filter pipe for rasters.
Color and saturation filter pipe for rasters.
QgsRasterDataProvider * provider() const
QgsRasterNuller * nuller() const
QgsBrightnessContrastFilter * brightnessFilter() const
QgsHueSaturationFilter * hueSaturationFilter() const
Raster renderer pipe that applies colors to a raster.
Base class for raster data providers.
QgsRasterPipe()=default
Constructor for QgsRasterPipe.