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"
26 #include "qgsrasterresamplefilter.h"
27 #include "qgsbrightnesscontrastfilter.h"
28 #include "qgshuesaturationfilter.h"
29 #include "qgsrasterprojector.h"
30 #include "qgsrasternuller.h"
31 
QgsRasterPipe(const QgsRasterPipe & pipe)32 QgsRasterPipe::QgsRasterPipe( const QgsRasterPipe &pipe )
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   }
51   setResamplingStage( pipe.resamplingStage() );
52 }
53 
~QgsRasterPipe()54 QgsRasterPipe::~QgsRasterPipe()
55 {
56   const auto constMInterfaces = mInterfaces;
57   for ( QgsRasterInterface *interface : constMInterfaces )
58   {
59     delete interface;
60   }
61 }
62 
connect(QVector<QgsRasterInterface * > interfaces)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 
insert(int idx,QgsRasterInterface * interface)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( "Pipe %1 inserted OK" ).arg( idx ), 4 );
100   }
101   else
102   {
103     QgsDebugMsgLevel( QStringLiteral( "Error inserting pipe %1" ).arg( idx ), 4 );
104   }
105 
106   // Connect or reconnect (after the test) interfaces
107   connect( mInterfaces );
108   return success;
109 }
110 
replace(int idx,QgsRasterInterface * interface)111 bool QgsRasterPipe::replace( int idx, QgsRasterInterface *interface )
112 {
113   if ( !interface ) return false;
114 
115   QgsDebugMsgLevel( QStringLiteral( "replace by %1 at %2" ).arg( typeid( *interface ).name() ).arg( idx ), 4 );
116   if ( !checkBounds( idx ) ) return false;
117 
118   // make a copy of pipe to test connection, we test the connections
119   // of the whole pipe, because the types and band numbers may change
120   QVector<QgsRasterInterface *> interfaces = mInterfaces;
121 
122   interfaces[idx] = interface;
123   bool success = false;
124   if ( connect( interfaces ) )
125   {
126     success = true;
127     delete mInterfaces.at( idx );
128     mInterfaces[idx] = interface;
129     setRole( interface, idx );
130     QgsDebugMsgLevel( QStringLiteral( "replaced OK" ), 4 );
131   }
132 
133   // Connect or reconnect (after the test) interfaces
134   connect( mInterfaces );
135   return success;
136 }
137 
interfaceRole(QgsRasterInterface * interface) const138 QgsRasterPipe::Role QgsRasterPipe::interfaceRole( QgsRasterInterface *interface ) const
139 {
140   Role role = UnknownRole;
141   if ( dynamic_cast<QgsRasterDataProvider *>( interface ) ) role = ProviderRole;
142   else if ( dynamic_cast<QgsRasterRenderer *>( interface ) ) role = RendererRole;
143   else if ( dynamic_cast<QgsRasterResampleFilter *>( interface ) ) role = ResamplerRole;
144   else if ( dynamic_cast<QgsBrightnessContrastFilter *>( interface ) ) role = BrightnessRole;
145   else if ( dynamic_cast<QgsHueSaturationFilter *>( interface ) ) role = HueSaturationRole;
146   else if ( dynamic_cast<QgsRasterProjector *>( interface ) ) role = ProjectorRole;
147   else if ( dynamic_cast<QgsRasterNuller *>( interface ) ) role = NullerRole;
148 
149   QgsDebugMsgLevel( QStringLiteral( "%1 role = %2" ).arg( typeid( *interface ).name() ).arg( role ), 4 );
150   return role;
151 }
152 
setRole(QgsRasterInterface * interface,int idx)153 void QgsRasterPipe::setRole( QgsRasterInterface *interface, int idx )
154 {
155   Role role = interfaceRole( interface );
156   if ( role == UnknownRole ) return;
157   mRoleMap.insert( role, idx );
158 }
159 
unsetRole(QgsRasterInterface * interface)160 void QgsRasterPipe::unsetRole( QgsRasterInterface *interface )
161 {
162   Role role = interfaceRole( interface );
163   if ( role == UnknownRole ) return;
164   const int roleIdx{ mRoleMap[role] };
165   mRoleMap.remove( role );
166 
167   // Decrease all indexes greater than the removed one
168   const auto roleMapValues {mRoleMap.values()};
169   if ( roleIdx < *std::max_element( roleMapValues.begin(), roleMapValues.end() ) )
170   {
171     for ( auto it = mRoleMap.cbegin(); it != mRoleMap.cend(); ++it )
172     {
173       if ( it.value() > roleIdx )
174       {
175         mRoleMap[it.key()] = it.value() - 1;
176       }
177     }
178   }
179 }
180 
set(QgsRasterInterface * interface)181 bool QgsRasterPipe::set( QgsRasterInterface *interface )
182 {
183   if ( !interface ) return false;
184 
185   QgsDebugMsgLevel( typeid( *interface ).name(), 4 );
186   Role role = interfaceRole( interface );
187 
188   // We don't know where to place unknown interface
189   if ( role == UnknownRole ) return false;
190 
191   //if ( mInterfacesMap.value ( role ) )
192   if ( mRoleMap.contains( role ) )
193   {
194     // An old interface of the same role exists -> replace
195     // replace may still fail and return false
196     return replace( mRoleMap.value( role ), interface );
197   }
198 
199   int idx = 0;
200 
201   // Not found, find the best default position for this kind of interface
202   //   QgsRasterDataProvider  - ProviderRole
203   //   QgsRasterRenderer      - RendererRole
204   //   QgsRasterResampler     - ResamplerRole
205   //   QgsRasterProjector     - ProjectorRole
206 
207   int providerIdx = mRoleMap.value( ProviderRole, -1 );
208   int rendererIdx = mRoleMap.value( RendererRole, -1 );
209   int resamplerIdx = mRoleMap.value( ResamplerRole, -1 );
210   int brightnessIdx = mRoleMap.value( BrightnessRole, -1 );
211   int hueSaturationIdx = mRoleMap.value( HueSaturationRole, -1 );
212 
213   if ( role == ProviderRole )
214   {
215     idx = 0;
216   }
217   else if ( role == RendererRole )
218   {
219     idx = providerIdx + 1;
220   }
221   else if ( role == BrightnessRole )
222   {
223     idx = std::max( providerIdx, rendererIdx ) + 1;
224   }
225   else if ( role == HueSaturationRole )
226   {
227     idx = std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ) + 1;
228   }
229   else if ( role == ResamplerRole )
230   {
231     idx = std::max( std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ), hueSaturationIdx ) + 1;
232   }
233   else if ( role == ProjectorRole )
234   {
235     idx = std::max( std::max( std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ), hueSaturationIdx ), resamplerIdx )  + 1;
236   }
237 
238   return insert( idx, interface );  // insert may still fail and return false
239 }
240 
interface(Role role) const241 QgsRasterInterface *QgsRasterPipe::interface( Role role ) const
242 {
243   QgsDebugMsgLevel( QStringLiteral( "role = %1" ).arg( role ), 4 );
244   if ( mRoleMap.contains( role ) )
245   {
246     return mInterfaces.value( mRoleMap.value( role ) );
247   }
248   return nullptr;
249 }
250 
provider() const251 QgsRasterDataProvider *QgsRasterPipe::provider() const
252 {
253   return dynamic_cast<QgsRasterDataProvider *>( interface( ProviderRole ) );
254 }
255 
renderer() const256 QgsRasterRenderer *QgsRasterPipe::renderer() const
257 {
258   return dynamic_cast<QgsRasterRenderer *>( interface( RendererRole ) );
259 }
260 
resampleFilter() const261 QgsRasterResampleFilter *QgsRasterPipe::resampleFilter() const
262 {
263   return dynamic_cast<QgsRasterResampleFilter *>( interface( ResamplerRole ) );
264 }
265 
brightnessFilter() const266 QgsBrightnessContrastFilter *QgsRasterPipe::brightnessFilter() const
267 {
268   return dynamic_cast<QgsBrightnessContrastFilter *>( interface( BrightnessRole ) );
269 }
270 
hueSaturationFilter() const271 QgsHueSaturationFilter *QgsRasterPipe::hueSaturationFilter() const
272 {
273   return dynamic_cast<QgsHueSaturationFilter *>( interface( HueSaturationRole ) );
274 }
275 
projector() const276 QgsRasterProjector *QgsRasterPipe::projector() const
277 {
278   return dynamic_cast<QgsRasterProjector *>( interface( ProjectorRole ) );
279 }
280 
nuller() const281 QgsRasterNuller *QgsRasterPipe::nuller() const
282 {
283   return dynamic_cast<QgsRasterNuller *>( interface( NullerRole ) );
284 }
285 
remove(int idx)286 bool QgsRasterPipe::remove( int idx )
287 {
288   QgsDebugMsgLevel( QStringLiteral( "remove at %1" ).arg( idx ), 4 );
289 
290   if ( !checkBounds( idx ) ) return false;
291 
292   // make a copy of pipe to test connection, we test the connections
293   // of the whole pipe, because the types and band numbers may change
294   QVector<QgsRasterInterface *> interfaces = mInterfaces;
295 
296   interfaces.remove( idx );
297   bool success = false;
298   if ( connect( interfaces ) )
299   {
300     success = true;
301     unsetRole( mInterfaces.at( idx ) );
302     delete mInterfaces.at( idx );
303     mInterfaces.remove( idx );
304     QgsDebugMsgLevel( QStringLiteral( "Pipe %1 removed OK" ).arg( idx ), 4 );
305   }
306   else
307   {
308     QgsDebugMsgLevel( QStringLiteral( "Error removing pipe %1" ).arg( idx ), 4 );
309   }
310 
311   // Connect or reconnect (after the test) interfaces
312   connect( mInterfaces );
313 
314   return success;
315 }
316 
remove(QgsRasterInterface * interface)317 bool QgsRasterPipe::remove( QgsRasterInterface *interface )
318 {
319   if ( !interface ) return false;
320 
321   return remove( mInterfaces.indexOf( interface ) );
322 }
323 
canSetOn(int idx,bool on)324 bool QgsRasterPipe::canSetOn( int idx, bool on )
325 {
326   QgsDebugMsgLevel( QStringLiteral( "idx = %1 on = %2" ).arg( idx ).arg( on ), 4 );
327   if ( !checkBounds( idx ) ) return false;
328 
329   // Because setting interface on/off may change its output we must check if
330   // connection is OK after such switch
331   bool onOrig = mInterfaces.at( idx )->on();
332 
333   if ( onOrig == on ) return true;
334 
335   mInterfaces.at( idx )->setOn( on );
336 
337   bool success = connect( mInterfaces );
338 
339   mInterfaces.at( idx )->setOn( onOrig );
340   connect( mInterfaces );
341   return success;
342 }
343 
setOn(int idx,bool on)344 bool QgsRasterPipe::setOn( int idx, bool on )
345 {
346   QgsDebugMsgLevel( QStringLiteral( "idx = %1 on = %2" ).arg( idx ).arg( on ), 4 );
347   if ( !checkBounds( idx ) ) return false;
348 
349   bool onOrig = mInterfaces.at( idx )->on();
350 
351   if ( onOrig == on ) return true;
352 
353   mInterfaces.at( idx )->setOn( on );
354 
355   if ( connect( mInterfaces ) ) return true;
356 
357   mInterfaces.at( idx )->setOn( onOrig );
358   connect( mInterfaces );
359 
360   return false;
361 }
362 
checkBounds(int idx) const363 bool QgsRasterPipe::checkBounds( int idx ) const
364 {
365   return !( idx < 0 || idx >= mInterfaces.size() );
366 }
367 
setResamplingStage(ResamplingStage stage)368 void QgsRasterPipe::setResamplingStage( ResamplingStage stage )
369 {
370   mResamplingStage = stage;
371   setOn( ResamplerRole, stage == ResamplingStage::ResampleFilter );
372   QgsRasterDataProvider *l_provider = provider();
373   if ( l_provider )
374   {
375     l_provider->enableProviderResampling( stage == ResamplingStage::Provider );
376   }
377 }
378