QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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"
25#include "qgsrasterrenderer.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 );
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
66void QgsRasterPipe::moveToThread( QThread *thread )
67{
68 // only data provider is derived from QObject currently:
69 auto it = mRoleMap.find( Qgis::RasterPipeInterfaceRole::Provider );
70 if ( it != mRoleMap.end() )
71 {
72 if ( QgsRasterDataProvider *dp = dynamic_cast<QgsRasterDataProvider *>( mInterfaces.value( it.value() ) ) )
73 {
74 dp->moveToThread( thread );
75 }
76 }
77}
78
79bool QgsRasterPipe::connect( QVector<QgsRasterInterface *> interfaces )
80{
81 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
82 for ( int i = 1; i < interfaces.size(); i++ )
83 {
84 if ( ! interfaces[i]->setInput( interfaces[i - 1] ) )
85 {
86#ifdef QGISDEBUG
87 const QgsRasterInterface &a = *interfaces[i];
88 const QgsRasterInterface &b = *interfaces[i - 1];
89 QgsDebugError( QStringLiteral( "cannot connect %1 to %2" ).arg( typeid( a ).name(), typeid( b ).name() ) );
90#endif
91 return false;
92 }
93 }
94 return true;
95}
96
97bool QgsRasterPipe::insert( int idx, QgsRasterInterface *interface )
98{
99 QgsDebugMsgLevel( QStringLiteral( "insert %1 at %2" ).arg( typeid( *interface ).name() ).arg( idx ), 4 );
100 if ( idx > mInterfaces.size() )
101 {
102 idx = mInterfaces.size();
103 }
104 // make a copy of pipe to test connection, we test the connections
105 // of the whole pipe, because the types and band numbers may change
106 QVector<QgsRasterInterface *> interfaces = mInterfaces;
107
108 interfaces.insert( idx, interface );
109 bool success = false;
110 if ( connect( interfaces ) )
111 {
112 success = true;
113 mInterfaces.insert( idx, interface );
114 setRole( interface, idx );
115 QgsDebugMsgLevel( QStringLiteral( "Pipe %1 inserted OK" ).arg( idx ), 4 );
116 }
117 else
118 {
119 QgsDebugMsgLevel( QStringLiteral( "Error inserting pipe %1" ).arg( idx ), 4 );
120 }
121
122 // Connect or reconnect (after the test) interfaces
123 connect( mInterfaces );
124 return success;
125}
126
128{
129 if ( !interface ) return false;
130
131 QgsDebugMsgLevel( QStringLiteral( "replace by %1 at %2" ).arg( typeid( *interface ).name() ).arg( idx ), 4 );
132 if ( !checkBounds( idx ) ) return false;
133
134 // make a copy of pipe to test connection, we test the connections
135 // of the whole pipe, because the types and band numbers may change
136 QVector<QgsRasterInterface *> interfaces = mInterfaces;
137
138 interfaces[idx] = interface;
139 bool success = false;
140 if ( connect( interfaces ) )
141 {
142 success = true;
143 delete mInterfaces.at( idx );
144 mInterfaces[idx] = interface;
145 setRole( interface, idx );
146 QgsDebugMsgLevel( QStringLiteral( "replaced OK" ), 4 );
147 }
148
149 // Connect or reconnect (after the test) interfaces
150 connect( mInterfaces );
151 return success;
152}
153
154Qgis::RasterPipeInterfaceRole QgsRasterPipe::interfaceRole( QgsRasterInterface *interface ) const
155{
157 if ( dynamic_cast<QgsRasterDataProvider *>( interface ) )
159 else if ( dynamic_cast<QgsRasterRenderer *>( interface ) )
161 else if ( dynamic_cast<QgsRasterResampleFilter *>( interface ) )
163 else if ( dynamic_cast<QgsBrightnessContrastFilter *>( interface ) )
165 else if ( dynamic_cast<QgsHueSaturationFilter *>( interface ) )
167 else if ( dynamic_cast<QgsRasterProjector *>( interface ) )
169 else if ( dynamic_cast<QgsRasterNuller *>( interface ) )
171
172 QgsDebugMsgLevel( QStringLiteral( "%1 role = %2" ).arg( typeid( *interface ).name(), qgsEnumValueToKey( role ) ), 4 );
173 return role;
174}
175
176void QgsRasterPipe::setRole( QgsRasterInterface *interface, int idx )
177{
178 Qgis::RasterPipeInterfaceRole role = interfaceRole( interface );
180 return;
181
182 mRoleMap.insert( role, idx );
183}
184
185void QgsRasterPipe::unsetRole( QgsRasterInterface *interface )
186{
187 Qgis::RasterPipeInterfaceRole role = interfaceRole( interface );
189 return;
190
191 const int roleIdx{ mRoleMap[role] };
192 mRoleMap.remove( role );
193
194 // Decrease all indexes greater than the removed one
195 const QMap<Qgis::RasterPipeInterfaceRole, int> currentRoles = mRoleMap;
196 for ( auto it = currentRoles.cbegin(); it != currentRoles.cend(); ++it )
197 {
198 if ( it.value() > roleIdx )
199 {
200 mRoleMap[it.key()] = it.value() - 1;
201 }
202 }
203}
204
206{
207 if ( !interface )
208 return false;
209
210 QgsDebugMsgLevel( typeid( *interface ).name(), 4 );
211 Qgis::RasterPipeInterfaceRole role = interfaceRole( interface );
212
213 // We don't know where to place unknown interface
215 return false;
216
217 //if ( mInterfacesMap.value ( role ) )
218 if ( mRoleMap.contains( role ) )
219 {
220 // An old interface of the same role exists -> replace
221 // replace may still fail and return false
222 return replace( mRoleMap.value( role ), interface );
223 }
224
225 int idx = 0;
226
227 // Not found, find the best default position for this kind of interface
228 // QgsRasterDataProvider - ProviderRole
229 // QgsRasterRenderer - RendererRole
230 // QgsRasterResampler - ResamplerRole
231 // QgsRasterProjector - ProjectorRole
232
233 int providerIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::Provider, -1 );
234 int rendererIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::Renderer, -1 );
235 int resamplerIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::Resampler, -1 );
236 int brightnessIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::Brightness, -1 );
237 int hueSaturationIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::HueSaturation, -1 );
238
240 {
241 idx = 0;
242 }
244 {
245 idx = providerIdx + 1;
246 }
248 {
249 idx = std::max( providerIdx, rendererIdx ) + 1;
250 }
252 {
253 idx = std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ) + 1;
254 }
256 {
257 idx = std::max( std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ), hueSaturationIdx ) + 1;
258 }
260 {
261 idx = std::max( std::max( std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ), hueSaturationIdx ), resamplerIdx ) + 1;
262 }
263
264 return insert( idx, interface ); // insert may still fail and return false
265}
266
267QgsRasterInterface *QgsRasterPipe::interface( Qgis::RasterPipeInterfaceRole role ) const
268{
269 QgsDebugMsgLevel( QStringLiteral( "role = %1" ).arg( qgsEnumValueToKey( role ) ), 4 );
270 if ( mRoleMap.contains( role ) )
271 {
272 return mInterfaces.value( mRoleMap.value( role ) );
273 }
274 return nullptr;
275}
276
278{
279 return dynamic_cast<QgsRasterDataProvider *>( interface( Qgis::RasterPipeInterfaceRole::Provider ) );
280}
281
283{
284 return dynamic_cast<QgsRasterRenderer *>( interface( Qgis::RasterPipeInterfaceRole::Renderer ) );
285}
286
288{
289 return dynamic_cast<QgsRasterResampleFilter *>( interface( Qgis::RasterPipeInterfaceRole::Resampler ) );
290}
291
293{
294 return dynamic_cast<QgsBrightnessContrastFilter *>( interface( Qgis::RasterPipeInterfaceRole::Brightness ) );
295}
296
298{
299 return dynamic_cast<QgsHueSaturationFilter *>( interface( Qgis::RasterPipeInterfaceRole::HueSaturation ) );
300}
301
303{
304 return dynamic_cast<QgsRasterProjector *>( interface( Qgis::RasterPipeInterfaceRole::Projector ) );
305}
306
308{
309 return dynamic_cast<QgsRasterNuller *>( interface( Qgis::RasterPipeInterfaceRole::Nuller ) );
310}
311
313{
314 QgsDebugMsgLevel( QStringLiteral( "remove at %1" ).arg( idx ), 4 );
315
316 if ( !checkBounds( idx ) )
317 return false;
318
319 // make a copy of pipe to test connection, we test the connections
320 // of the whole pipe, because the types and band numbers may change
321 QVector<QgsRasterInterface *> interfaces = mInterfaces;
322
323 interfaces.remove( idx );
324 bool success = false;
325 if ( connect( interfaces ) )
326 {
327 success = true;
328 unsetRole( mInterfaces.at( idx ) );
329 delete mInterfaces.at( idx );
330 mInterfaces.remove( idx );
331 QgsDebugMsgLevel( QStringLiteral( "Pipe %1 removed OK" ).arg( idx ), 4 );
332 }
333 else
334 {
335 QgsDebugMsgLevel( QStringLiteral( "Error removing pipe %1" ).arg( idx ), 4 );
336 }
337
338 // Connect or reconnect (after the test) interfaces
339 connect( mInterfaces );
340
341 return success;
342}
343
345{
346 if ( !interface ) return false;
347
348 return remove( mInterfaces.indexOf( interface ) );
349}
350
351bool QgsRasterPipe::canSetOn( int idx, bool on )
352{
353 QgsDebugMsgLevel( QStringLiteral( "idx = %1 on = %2" ).arg( idx ).arg( on ), 4 );
354 if ( !checkBounds( idx ) )
355 return false;
356
357 // Because setting interface on/off may change its output we must check if
358 // connection is OK after such switch
359 bool onOrig = mInterfaces.at( idx )->on();
360
361 if ( onOrig == on )
362 return true;
363
364 mInterfaces.at( idx )->setOn( on );
365
366 bool success = connect( mInterfaces );
367
368 mInterfaces.at( idx )->setOn( onOrig );
369 connect( mInterfaces );
370 return success;
371}
372
373bool QgsRasterPipe::setOn( int idx, bool on )
374{
375 QgsDebugMsgLevel( QStringLiteral( "idx = %1 on = %2" ).arg( idx ).arg( on ), 4 );
376 if ( !checkBounds( idx ) )
377 return false;
378
379 bool onOrig = mInterfaces.at( idx )->on();
380
381 if ( onOrig == on )
382 return true;
383
384 mInterfaces.at( idx )->setOn( on );
385
386 if ( connect( mInterfaces ) )
387 return true;
388
389 mInterfaces.at( idx )->setOn( onOrig );
390 connect( mInterfaces );
391
392 return false;
393}
394
395bool QgsRasterPipe::checkBounds( int idx ) const
396{
397 return !( idx < 0 || idx >= mInterfaces.size() );
398}
399
401{
402 mResamplingStage = stage;
403
404 int resamplerIndex = 0;
405 for ( QgsRasterInterface *interface : std::as_const( mInterfaces ) )
406 {
407 if ( interfaceRole( interface ) == Qgis::RasterPipeInterfaceRole::Resampler )
408 {
409 setOn( resamplerIndex, stage == Qgis::RasterResamplingStage::ResampleFilter );
410 break;
411 }
412 resamplerIndex ++;
413 }
414
415 if ( QgsRasterDataProvider *l_provider = provider() )
416 {
417 l_provider->enableProviderResampling( stage == Qgis::RasterResamplingStage::Provider );
418 }
419}
420
422{
423 if ( !mDataDefinedProperties.hasActiveProperties() )
424 return;
425
426 if ( mDataDefinedProperties.isActive( Property::RendererOpacity ) )
427 {
428 if ( QgsRasterRenderer *r = renderer() )
429 {
430 const double prevOpacity = r->opacity();
431 context.setOriginalValueVariable( prevOpacity * 100 );
432 bool ok = false;
433 const double opacity = mDataDefinedProperties.valueAsDouble( Property::RendererOpacity, context, prevOpacity, &ok ) / 100;
434 if ( ok )
435 {
436 r->setOpacity( opacity );
437 }
438 }
439 }
440}
441
442QgsPropertiesDefinition QgsRasterPipe::sPropertyDefinitions;
443
444void QgsRasterPipe::initPropertyDefinitions()
445{
446 const QString origin = QStringLiteral( "raster" );
447
448 sPropertyDefinitions = QgsPropertiesDefinition
449 {
450 { static_cast< int >( QgsRasterPipe::Property::RendererOpacity ), QgsPropertyDefinition( "RendererOpacity", QObject::tr( "Renderer opacity" ), QgsPropertyDefinition::Opacity, origin ) },
451 };
452}
453
455{
456 static std::once_flag initialized;
457 std::call_once( initialized, [ = ]( )
458 {
459 initPropertyDefinitions();
460 } );
461 return sPropertyDefinitions;
462}
RasterResamplingStage
Stage at which raster resampling occurs.
Definition: qgis.h:1138
@ Provider
Resampling occurs in Provider.
@ ResampleFilter
Resampling occurs in ResamplingFilter.
RasterPipeInterfaceRole
Raster pipe interface roles.
Definition: qgis.h:1121
@ Renderer
Raster renderer role.
@ HueSaturation
Hue/saturation filter role (also applies grayscale/color inversion)
@ Provider
Data provider role.
@ Nuller
Raster nuller role.
@ Brightness
Brightness filter role.
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.
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.
bool isActive(int key) const final
Returns true if the collection contains an active property with the specified key.
bool hasActiveProperties() const final
Returns true if the collection has any active properties, or false if all properties within the colle...
Definition for a property.
Definition: qgsproperty.h:45
@ Opacity
Opacity (0-100)
Definition: qgsproperty.h:60
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.
Contains a pipeline of raster interfaces for sequential raster processing.
Definition: qgsrasterpipe.h:50
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.
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.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition: qgis.h:5398
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugError(str)
Definition: qgslogger.h:38
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.