QGIS API Documentation 3.32.0-Lima (311a8cb8a6)
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 );
48 if ( role != Qgis::RasterPipeInterfaceRole::Unknown )
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{
156 Qgis::RasterPipeInterfaceRole role = Qgis::RasterPipeInterfaceRole::Unknown;
157 if ( dynamic_cast<QgsRasterDataProvider *>( interface ) )
158 role = Qgis::RasterPipeInterfaceRole::Provider;
159 else if ( dynamic_cast<QgsRasterRenderer *>( interface ) )
160 role = Qgis::RasterPipeInterfaceRole::Renderer;
161 else if ( dynamic_cast<QgsRasterResampleFilter *>( interface ) )
162 role = Qgis::RasterPipeInterfaceRole::Resampler;
163 else if ( dynamic_cast<QgsBrightnessContrastFilter *>( interface ) )
164 role = Qgis::RasterPipeInterfaceRole::Brightness;
165 else if ( dynamic_cast<QgsHueSaturationFilter *>( interface ) )
166 role = Qgis::RasterPipeInterfaceRole::HueSaturation;
167 else if ( dynamic_cast<QgsRasterProjector *>( interface ) )
168 role = Qgis::RasterPipeInterfaceRole::Projector;
169 else if ( dynamic_cast<QgsRasterNuller *>( interface ) )
170 role = Qgis::RasterPipeInterfaceRole::Nuller;
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 );
179 if ( role == Qgis::RasterPipeInterfaceRole::Unknown )
180 return;
181
182 mRoleMap.insert( role, idx );
183}
184
185void QgsRasterPipe::unsetRole( QgsRasterInterface *interface )
186{
187 Qgis::RasterPipeInterfaceRole role = interfaceRole( interface );
188 if ( role == Qgis::RasterPipeInterfaceRole::Unknown )
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 auto roleMapValues {mRoleMap.values()};
196 if ( roleIdx < *std::max_element( roleMapValues.begin(), roleMapValues.end() ) )
197 {
198 for ( auto it = mRoleMap.cbegin(); it != mRoleMap.cend(); ++it )
199 {
200 if ( it.value() > roleIdx )
201 {
202 mRoleMap[it.key()] = it.value() - 1;
203 }
204 }
205 }
206}
207
209{
210 if ( !interface )
211 return false;
212
213 QgsDebugMsgLevel( typeid( *interface ).name(), 4 );
214 Qgis::RasterPipeInterfaceRole role = interfaceRole( interface );
215
216 // We don't know where to place unknown interface
217 if ( role == Qgis::RasterPipeInterfaceRole::Unknown )
218 return false;
219
220 //if ( mInterfacesMap.value ( role ) )
221 if ( mRoleMap.contains( role ) )
222 {
223 // An old interface of the same role exists -> replace
224 // replace may still fail and return false
225 return replace( mRoleMap.value( role ), interface );
226 }
227
228 int idx = 0;
229
230 // Not found, find the best default position for this kind of interface
231 // QgsRasterDataProvider - ProviderRole
232 // QgsRasterRenderer - RendererRole
233 // QgsRasterResampler - ResamplerRole
234 // QgsRasterProjector - ProjectorRole
235
236 int providerIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::Provider, -1 );
237 int rendererIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::Renderer, -1 );
238 int resamplerIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::Resampler, -1 );
239 int brightnessIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::Brightness, -1 );
240 int hueSaturationIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::HueSaturation, -1 );
241
242 if ( role == Qgis::RasterPipeInterfaceRole::Provider )
243 {
244 idx = 0;
245 }
246 else if ( role == Qgis::RasterPipeInterfaceRole::Renderer )
247 {
248 idx = providerIdx + 1;
249 }
250 else if ( role == Qgis::RasterPipeInterfaceRole::Brightness )
251 {
252 idx = std::max( providerIdx, rendererIdx ) + 1;
253 }
254 else if ( role == Qgis::RasterPipeInterfaceRole::HueSaturation )
255 {
256 idx = std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ) + 1;
257 }
258 else if ( role == Qgis::RasterPipeInterfaceRole::Resampler )
259 {
260 idx = std::max( std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ), hueSaturationIdx ) + 1;
261 }
262 else if ( role == Qgis::RasterPipeInterfaceRole::Projector )
263 {
264 idx = std::max( std::max( std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ), hueSaturationIdx ), resamplerIdx ) + 1;
265 }
266
267 return insert( idx, interface ); // insert may still fail and return false
268}
269
270QgsRasterInterface *QgsRasterPipe::interface( Qgis::RasterPipeInterfaceRole role ) const
271{
272 QgsDebugMsgLevel( QStringLiteral( "role = %1" ).arg( qgsEnumValueToKey( role ) ), 4 );
273 if ( mRoleMap.contains( role ) )
274 {
275 return mInterfaces.value( mRoleMap.value( role ) );
276 }
277 return nullptr;
278}
279
281{
282 return dynamic_cast<QgsRasterDataProvider *>( interface( Qgis::RasterPipeInterfaceRole::Provider ) );
283}
284
286{
287 return dynamic_cast<QgsRasterRenderer *>( interface( Qgis::RasterPipeInterfaceRole::Renderer ) );
288}
289
291{
292 return dynamic_cast<QgsRasterResampleFilter *>( interface( Qgis::RasterPipeInterfaceRole::Resampler ) );
293}
294
296{
297 return dynamic_cast<QgsBrightnessContrastFilter *>( interface( Qgis::RasterPipeInterfaceRole::Brightness ) );
298}
299
301{
302 return dynamic_cast<QgsHueSaturationFilter *>( interface( Qgis::RasterPipeInterfaceRole::HueSaturation ) );
303}
304
306{
307 return dynamic_cast<QgsRasterProjector *>( interface( Qgis::RasterPipeInterfaceRole::Projector ) );
308}
309
311{
312 return dynamic_cast<QgsRasterNuller *>( interface( Qgis::RasterPipeInterfaceRole::Nuller ) );
313}
314
316{
317 QgsDebugMsgLevel( QStringLiteral( "remove at %1" ).arg( idx ), 4 );
318
319 if ( !checkBounds( idx ) )
320 return false;
321
322 // make a copy of pipe to test connection, we test the connections
323 // of the whole pipe, because the types and band numbers may change
324 QVector<QgsRasterInterface *> interfaces = mInterfaces;
325
326 interfaces.remove( idx );
327 bool success = false;
328 if ( connect( interfaces ) )
329 {
330 success = true;
331 unsetRole( mInterfaces.at( idx ) );
332 delete mInterfaces.at( idx );
333 mInterfaces.remove( idx );
334 QgsDebugMsgLevel( QStringLiteral( "Pipe %1 removed OK" ).arg( idx ), 4 );
335 }
336 else
337 {
338 QgsDebugMsgLevel( QStringLiteral( "Error removing pipe %1" ).arg( idx ), 4 );
339 }
340
341 // Connect or reconnect (after the test) interfaces
342 connect( mInterfaces );
343
344 return success;
345}
346
348{
349 if ( !interface ) return false;
350
351 return remove( mInterfaces.indexOf( interface ) );
352}
353
354bool QgsRasterPipe::canSetOn( int idx, bool on )
355{
356 QgsDebugMsgLevel( QStringLiteral( "idx = %1 on = %2" ).arg( idx ).arg( on ), 4 );
357 if ( !checkBounds( idx ) )
358 return false;
359
360 // Because setting interface on/off may change its output we must check if
361 // connection is OK after such switch
362 bool onOrig = mInterfaces.at( idx )->on();
363
364 if ( onOrig == on )
365 return true;
366
367 mInterfaces.at( idx )->setOn( on );
368
369 bool success = connect( mInterfaces );
370
371 mInterfaces.at( idx )->setOn( onOrig );
372 connect( mInterfaces );
373 return success;
374}
375
376bool QgsRasterPipe::setOn( int idx, bool on )
377{
378 QgsDebugMsgLevel( QStringLiteral( "idx = %1 on = %2" ).arg( idx ).arg( on ), 4 );
379 if ( !checkBounds( idx ) )
380 return false;
381
382 bool onOrig = mInterfaces.at( idx )->on();
383
384 if ( onOrig == on )
385 return true;
386
387 mInterfaces.at( idx )->setOn( on );
388
389 if ( connect( mInterfaces ) )
390 return true;
391
392 mInterfaces.at( idx )->setOn( onOrig );
393 connect( mInterfaces );
394
395 return false;
396}
397
398bool QgsRasterPipe::checkBounds( int idx ) const
399{
400 return !( idx < 0 || idx >= mInterfaces.size() );
401}
402
404{
405 mResamplingStage = stage;
406
407 int resamplerIndex = 0;
408 for ( QgsRasterInterface *interface : std::as_const( mInterfaces ) )
409 {
410 if ( interfaceRole( interface ) == Qgis::RasterPipeInterfaceRole::Resampler )
411 {
412 setOn( resamplerIndex, stage == Qgis::RasterResamplingStage::ResampleFilter );
413 break;
414 }
415 resamplerIndex ++;
416 }
417
418 if ( QgsRasterDataProvider *l_provider = provider() )
419 {
420 l_provider->enableProviderResampling( stage == Qgis::RasterResamplingStage::Provider );
421 }
422}
423
425{
426 if ( !mDataDefinedProperties.hasActiveProperties() )
427 return;
428
429 if ( mDataDefinedProperties.isActive( RendererOpacity ) )
430 {
431 if ( QgsRasterRenderer *r = renderer() )
432 {
433 const double prevOpacity = r->opacity();
434 context.setOriginalValueVariable( prevOpacity * 100 );
435 bool ok = false;
436 const double opacity = mDataDefinedProperties.valueAsDouble( RendererOpacity, context, prevOpacity, &ok ) / 100;
437 if ( ok )
438 {
439 r->setOpacity( opacity );
440 }
441 }
442 }
443}
444
445QgsPropertiesDefinition QgsRasterPipe::sPropertyDefinitions;
446
447void QgsRasterPipe::initPropertyDefinitions()
448{
449 const QString origin = QStringLiteral( "raster" );
450
451 sPropertyDefinitions = QgsPropertiesDefinition
452 {
453 { QgsRasterPipe::RendererOpacity, QgsPropertyDefinition( "RendererOpacity", QObject::tr( "Renderer opacity" ), QgsPropertyDefinition::Opacity, origin ) },
454 };
455}
456
458{
459 static std::once_flag initialized;
460 std::call_once( initialized, [ = ]( )
461 {
462 initPropertyDefinitions();
463 } );
464 return sPropertyDefinitions;
465}
RasterResamplingStage
Stage at which raster resampling occurs.
Definition: qgis.h:1005
@ Provider
Resampling occurs in Provider.
@ ResampleFilter
Resampling occurs in ResamplingFilter.
RasterPipeInterfaceRole
Sublayer flags.
Definition: qgis.h:988
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 override
Returns true if the collection contains an active property with the specified key.
bool hasActiveProperties() const override
Returns true if the collection has any active properties, or false if all properties within the colle...
Definition for a property.
Definition: qgsproperty.h:46
@ 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.
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.
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.
@ RendererOpacity
Raster renderer global opacity.
Definition: qgsrasterpipe.h:59
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:4192
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugError(str)
Definition: qgslogger.h:38
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.