QGIS API Documentation 4.1.0-Master (60fea48833c)
Loading...
Searching...
No Matches
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 "qgsrasterpipe.h"
19
20#include <mutex>
21#include <typeinfo>
22
25#include "qgslogger.h"
27#include "qgsrasternuller.h"
28#include "qgsrasterprojector.h"
29#include "qgsrasterrenderer.h"
31
32#include <QByteArray>
33#include <QString>
34
35using namespace Qt::StringLiterals;
36
38{
39 for ( int i = 0; i < pipe.size(); i++ )
40 {
41 QgsRasterInterface *interface = pipe.at( i );
42 QgsRasterInterface *clone = interface->clone();
43
44 Qgis::RasterPipeInterfaceRole role = interfaceRole( clone );
45 QgsDebugMsgLevel( u"cloned interface with role %1"_s.arg( qgsEnumValueToKey( role ) ), 4 );
46 if ( i > 0 )
47 {
48 clone->setInput( mInterfaces.at( i - 1 ) );
49 }
50 mInterfaces.append( clone );
52 {
53 mRoleMap.insert( role, i );
54 }
55 }
57 mDataDefinedProperties = pipe.mDataDefinedProperties;
58}
59
61{
62 const auto constMInterfaces = mInterfaces;
63 for ( QgsRasterInterface *interface : constMInterfaces )
64 {
65 delete interface;
66 }
67}
68
69void QgsRasterPipe::moveToThread( QThread *thread )
70{
71 // only data provider is derived from QObject currently:
72 auto it = mRoleMap.find( Qgis::RasterPipeInterfaceRole::Provider );
73 if ( it != mRoleMap.end() )
74 {
75 if ( QgsRasterDataProvider *dp = dynamic_cast<QgsRasterDataProvider *>( mInterfaces.value( it.value() ) ) )
76 {
77 dp->moveToThread( thread );
78 }
79 }
80}
81
82bool QgsRasterPipe::connect( QVector<QgsRasterInterface *> interfaces )
83{
84 QgsDebugMsgLevel( u"Entered"_s, 4 );
85 for ( int i = 1; i < interfaces.size(); i++ )
86 {
87 if ( !interfaces[i]->setInput( interfaces[i - 1] ) )
88 {
89#ifdef QGISDEBUG
90 const QgsRasterInterface &a = *interfaces[i];
91 const QgsRasterInterface &b = *interfaces[i - 1];
92 QgsDebugError( u"cannot connect %1 to %2"_s.arg( typeid( a ).name(), typeid( b ).name() ) );
93#endif
94 return false;
95 }
96 }
97 return true;
98}
99
100bool QgsRasterPipe::insert( int idx, QgsRasterInterface *interface )
101{
102 QgsDebugMsgLevel( u"insert %1 at %2"_s.arg( typeid( *interface ).name() ).arg( idx ), 4 );
103 if ( idx > mInterfaces.size() )
104 {
105 idx = mInterfaces.size();
106 }
107 // make a copy of pipe to test connection, we test the connections
108 // of the whole pipe, because the types and band numbers may change
109 QVector<QgsRasterInterface *> interfaces = mInterfaces;
110
111 interfaces.insert( idx, interface );
112 bool success = false;
113 if ( connect( interfaces ) )
114 {
115 success = true;
116 mInterfaces.insert( idx, interface );
117 setRole( interface, idx );
118 QgsDebugMsgLevel( u"Pipe %1 inserted OK"_s.arg( idx ), 4 );
119 }
120 else
121 {
122 QgsDebugMsgLevel( u"Error inserting pipe %1"_s.arg( idx ), 4 );
123 delete interface;
124 }
125
126 // Connect or reconnect (after the test) interfaces
127 connect( mInterfaces );
128 return success;
129}
130
132{
133 if ( !interface )
134 return false;
135
136 QgsDebugMsgLevel( u"replace by %1 at %2"_s.arg( typeid( *interface ).name() ).arg( idx ), 4 );
137 if ( !checkBounds( idx ) )
138 return false;
139
140 // make a copy of pipe to test connection, we test the connections
141 // of the whole pipe, because the types and band numbers may change
142 QVector<QgsRasterInterface *> interfaces = mInterfaces;
143
144 interfaces[idx] = interface;
145 bool success = false;
146 if ( connect( interfaces ) )
147 {
148 success = true;
149 delete mInterfaces.at( idx );
150 mInterfaces[idx] = interface;
151 setRole( interface, idx );
152 QgsDebugMsgLevel( u"replaced OK"_s, 4 );
153 }
154
155 // Connect or reconnect (after the test) interfaces
156 connect( mInterfaces );
157 return success;
158}
159
160Qgis::RasterPipeInterfaceRole QgsRasterPipe::interfaceRole( QgsRasterInterface *interface ) const
161{
163 if ( dynamic_cast<QgsRasterDataProvider *>( interface ) )
165 else if ( dynamic_cast<QgsRasterRenderer *>( interface ) )
167 else if ( dynamic_cast<QgsRasterResampleFilter *>( interface ) )
169 else if ( dynamic_cast<QgsBrightnessContrastFilter *>( interface ) )
171 else if ( dynamic_cast<QgsHueSaturationFilter *>( interface ) )
173 else if ( dynamic_cast<QgsRasterProjector *>( interface ) )
175 else if ( dynamic_cast<QgsRasterNuller *>( interface ) )
177
178 QgsDebugMsgLevel( u"%1 role = %2"_s.arg( typeid( *interface ).name(), qgsEnumValueToKey( role ) ), 4 );
179 return role;
180}
181
182void QgsRasterPipe::setRole( QgsRasterInterface *interface, int idx )
183{
184 Qgis::RasterPipeInterfaceRole role = interfaceRole( interface );
186 return;
187
188 mRoleMap.insert( role, idx );
189}
190
191void QgsRasterPipe::unsetRole( QgsRasterInterface *interface )
192{
193 Qgis::RasterPipeInterfaceRole role = interfaceRole( interface );
195 return;
196
197 const int roleIdx { mRoleMap[role] };
198 mRoleMap.remove( role );
199
200 // Decrease all indexes greater than the removed one
201 const QMap<Qgis::RasterPipeInterfaceRole, int> currentRoles = mRoleMap;
202 for ( auto it = currentRoles.cbegin(); it != currentRoles.cend(); ++it )
203 {
204 if ( it.value() > roleIdx )
205 {
206 mRoleMap[it.key()] = it.value() - 1;
207 }
208 }
209}
210
212{
213 if ( !interface )
214 return false;
215
216 QgsDebugMsgLevel( typeid( *interface ).name(), 4 );
217 Qgis::RasterPipeInterfaceRole role = interfaceRole( interface );
218
219 // We don't know where to place unknown interface
221 return false;
222
223 //if ( mInterfacesMap.value ( role ) )
224 if ( mRoleMap.contains( role ) )
225 {
226 // An old interface of the same role exists -> replace
227 // replace may still fail and return false
228 return replace( mRoleMap.value( role ), interface );
229 }
230
231 int idx = 0;
232
233 // Not found, find the best default position for this kind of interface
234 // QgsRasterDataProvider - ProviderRole
235 // QgsRasterRenderer - RendererRole
236 // QgsRasterResampler - ResamplerRole
237 // QgsRasterProjector - ProjectorRole
238
239 int providerIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::Provider, -1 );
240 int rendererIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::Renderer, -1 );
241 int resamplerIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::Resampler, -1 );
242 int brightnessIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::Brightness, -1 );
243 int hueSaturationIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::HueSaturation, -1 );
244
246 {
247 idx = 0;
248 }
250 {
251 idx = providerIdx + 1;
252 }
254 {
255 idx = std::max( providerIdx, rendererIdx ) + 1;
256 }
258 {
259 idx = std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ) + 1;
260 }
262 {
263 idx = std::max( std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ), hueSaturationIdx ) + 1;
264 }
266 {
267 idx = std::max( std::max( std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ), hueSaturationIdx ), resamplerIdx ) + 1;
268 }
269
270 return insert( idx, interface ); // insert may still fail and return false
271}
272
273QgsRasterInterface *QgsRasterPipe::interface( Qgis::RasterPipeInterfaceRole role ) const
274{
275 QgsDebugMsgLevel( u"role = %1"_s.arg( qgsEnumValueToKey( role ) ), 4 );
276 if ( mRoleMap.contains( role ) )
277 {
278 return mInterfaces.value( mRoleMap.value( role ) );
279 }
280 return nullptr;
281}
282
287
289{
290 return dynamic_cast<QgsRasterRenderer *>( interface( Qgis::RasterPipeInterfaceRole::Renderer ) );
291}
292
297
302
307
312
314{
315 return dynamic_cast<QgsRasterNuller *>( interface( Qgis::RasterPipeInterfaceRole::Nuller ) );
316}
317
319{
320 QgsDebugMsgLevel( u"remove at %1"_s.arg( idx ), 4 );
321
322 if ( !checkBounds( idx ) )
323 return false;
324
325 // make a copy of pipe to test connection, we test the connections
326 // of the whole pipe, because the types and band numbers may change
327 QVector<QgsRasterInterface *> interfaces = mInterfaces;
328
329 interfaces.remove( idx );
330 bool success = false;
331 if ( connect( interfaces ) )
332 {
333 success = true;
334 unsetRole( mInterfaces.at( idx ) );
335 delete mInterfaces.at( idx );
336 mInterfaces.remove( idx );
337 QgsDebugMsgLevel( u"Pipe %1 removed OK"_s.arg( idx ), 4 );
338 }
339 else
340 {
341 QgsDebugMsgLevel( u"Error removing pipe %1"_s.arg( idx ), 4 );
342 }
343
344 // Connect or reconnect (after the test) interfaces
345 connect( mInterfaces );
346
347 return success;
348}
349
351{
352 if ( !interface )
353 return false;
354
355 return remove( mInterfaces.indexOf( interface ) );
356}
357
358bool QgsRasterPipe::canSetOn( int idx, bool on )
359{
360 QgsDebugMsgLevel( u"idx = %1 on = %2"_s.arg( idx ).arg( on ), 4 );
361 if ( !checkBounds( idx ) )
362 return false;
363
364 // Because setting interface on/off may change its output we must check if
365 // connection is OK after such switch
366 bool onOrig = mInterfaces.at( idx )->on();
367
368 if ( onOrig == on )
369 return true;
370
371 mInterfaces.at( idx )->setOn( on );
372
373 bool success = connect( mInterfaces );
374
375 mInterfaces.at( idx )->setOn( onOrig );
376 connect( mInterfaces );
377 return success;
378}
379
380bool QgsRasterPipe::setOn( int idx, bool on )
381{
382 QgsDebugMsgLevel( u"idx = %1 on = %2"_s.arg( idx ).arg( on ), 4 );
383 if ( !checkBounds( idx ) )
384 return false;
385
386 bool onOrig = mInterfaces.at( idx )->on();
387
388 if ( onOrig == on )
389 return true;
390
391 mInterfaces.at( idx )->setOn( on );
392
393 if ( connect( mInterfaces ) )
394 return true;
395
396 mInterfaces.at( idx )->setOn( onOrig );
397 connect( mInterfaces );
398
399 return false;
400}
401
402bool QgsRasterPipe::checkBounds( int idx ) const
403{
404 return !( idx < 0 || idx >= mInterfaces.size() );
405}
406
408{
409 mResamplingStage = stage;
410
411 int resamplerIndex = 0;
412 for ( QgsRasterInterface *interface : std::as_const( mInterfaces ) )
413 {
414 if ( interfaceRole( interface ) == Qgis::RasterPipeInterfaceRole::Resampler )
415 {
416 setOn( resamplerIndex, stage == Qgis::RasterResamplingStage::ResampleFilter );
417 break;
418 }
419 resamplerIndex++;
420 }
421
422 if ( QgsRasterDataProvider *l_provider = provider() )
423 {
424 l_provider->enableProviderResampling( stage == Qgis::RasterResamplingStage::Provider );
425 }
426}
427
429{
430 if ( !mDataDefinedProperties.hasActiveProperties() )
431 return;
432
433 if ( mDataDefinedProperties.isActive( Property::RendererOpacity ) )
434 {
435 if ( QgsRasterRenderer *r = renderer() )
436 {
437 const double prevOpacity = r->opacity();
438 context.setOriginalValueVariable( prevOpacity * 100 );
439 bool ok = false;
440 const double opacity = mDataDefinedProperties.valueAsDouble( Property::RendererOpacity, context, prevOpacity, &ok ) / 100;
441 if ( ok )
442 {
443 r->setOpacity( opacity );
444 }
445 }
446 }
447}
448
449QgsPropertiesDefinition QgsRasterPipe::sPropertyDefinitions;
450
451void QgsRasterPipe::initPropertyDefinitions()
452{
453 const QString origin = u"raster"_s;
454
455 sPropertyDefinitions = QgsPropertiesDefinition {
456 { static_cast< int >( QgsRasterPipe::Property::RendererOpacity ), QgsPropertyDefinition( "RendererOpacity", QObject::tr( "Renderer opacity" ), QgsPropertyDefinition::Opacity, origin ) },
457 };
458}
459
461{
462 static std::once_flag initialized;
463 std::call_once( initialized, initPropertyDefinitions );
464 return sPropertyDefinitions;
465}
RasterResamplingStage
Stage at which raster resampling occurs.
Definition qgis.h:1548
@ Provider
Resampling occurs in Provider.
Definition qgis.h:1550
@ ResampleFilter
Resampling occurs in ResamplingFilter.
Definition qgis.h:1549
RasterPipeInterfaceRole
Raster pipe interface roles.
Definition qgis.h:1531
@ Renderer
Raster renderer role.
Definition qgis.h:1534
@ Projector
Projector role.
Definition qgis.h:1537
@ Resampler
Resampler role.
Definition qgis.h:1536
@ HueSaturation
Hue/saturation filter role (also applies grayscale/color inversion).
Definition qgis.h:1539
@ Provider
Data provider role.
Definition qgis.h:1533
@ Nuller
Raster nuller role.
Definition qgis.h:1538
@ Unknown
Unknown role.
Definition qgis.h:1532
@ Brightness
Brightness filter role.
Definition qgis.h:1535
Brightness/contrast and gamma correction filter pipe for rasters.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
Color and saturation filter pipe for rasters.
Definition for a property.
Definition qgsproperty.h:47
@ Opacity
Opacity (0-100).
Definition qgsproperty.h:61
Base class for raster data providers.
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.
bool set(QgsRasterInterface *interface)
Inserts a new known interface in default place or replace interface of the same role if it already ex...
int size() const
Returns the size of the pipe (the number of interfaces contained in the pipe).
QgsRasterPipe()=default
Constructor for an empty QgsRasterPipe.
void moveToThread(QThread *thread)
Moves the pipe to another thread.
QgsRasterResampleFilter * resampleFilter() const
Returns the resample filter interface, or nullptr if no resample filter is present in the pipe.
bool replace(int idx, QgsRasterInterface *interface)
Attempts to replace the interface at specified index and reconnect the pipe.
QgsRasterDataProvider * provider() const
Returns the data provider interface, or nullptr if no data provider is present in the pipe.
@ RendererOpacity
Raster renderer global opacity.
bool canSetOn(int idx, bool on)
Returns true if the interface at the specified index may be switched on or off.
bool insert(int idx, QgsRasterInterface *interface)
Attempts to insert interface at specified index and connect if connection would fail,...
void setResamplingStage(Qgis::RasterResamplingStage stage)
Sets which stage of the pipe should apply resampling.
void evaluateDataDefinedProperties(QgsExpressionContext &context)
Evaluates any data defined properties set on the pipe, applying their results to the corresponding in...
QgsRasterProjector * projector() const
Returns the projector interface, or nullptr if no projector is present in the pipe.
bool remove(int idx)
Removes and deletes the interface at given index (if possible).
static QgsPropertiesDefinition propertyDefinitions()
Returns the definitions for data defined properties available for use in raster pipes.
QgsRasterRenderer * renderer() const
Returns the raster renderer interface, or nullptr if no raster renderer is present in the pipe.
Qgis::RasterResamplingStage resamplingStage() const
Returns which stage of the pipe should apply resampling.
QgsBrightnessContrastFilter * brightnessFilter() const
Returns the brightness filter interface, or nullptr if no brightness filter is present in the pipe.
QgsHueSaturationFilter * hueSaturationFilter() const
Returns the hue/saturation interface, or nullptr if no hue/saturation filter is present in the pipe.
QgsRasterNuller * nuller() const
Returns the raster nuller interface, or nullptr if no raster nuller is present in the pipe.
bool setOn(int idx, bool on)
Set whether the interface at the specified index is enabled.
Implements approximate projection support for optimised raster transformation.
Raster renderer pipe that applies colors to a raster.
Resample filter pipe for rasters.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:7157
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
#define QgsDebugError(str)
Definition qgslogger.h:59
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.