QGIS API Documentation 3.99.0-Master (d270888f95f)
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 ) return false;
134
135 QgsDebugMsgLevel( u"replace by %1 at %2"_s.arg( typeid( *interface ).name() ).arg( idx ), 4 );
136 if ( !checkBounds( idx ) ) return false;
137
138 // make a copy of pipe to test connection, we test the connections
139 // of the whole pipe, because the types and band numbers may change
140 QVector<QgsRasterInterface *> interfaces = mInterfaces;
141
142 interfaces[idx] = interface;
143 bool success = false;
144 if ( connect( interfaces ) )
145 {
146 success = true;
147 delete mInterfaces.at( idx );
148 mInterfaces[idx] = interface;
149 setRole( interface, idx );
150 QgsDebugMsgLevel( u"replaced OK"_s, 4 );
151 }
152
153 // Connect or reconnect (after the test) interfaces
154 connect( mInterfaces );
155 return success;
156}
157
158Qgis::RasterPipeInterfaceRole QgsRasterPipe::interfaceRole( QgsRasterInterface *interface ) const
159{
161 if ( dynamic_cast<QgsRasterDataProvider *>( interface ) )
163 else if ( dynamic_cast<QgsRasterRenderer *>( interface ) )
165 else if ( dynamic_cast<QgsRasterResampleFilter *>( interface ) )
167 else if ( dynamic_cast<QgsBrightnessContrastFilter *>( interface ) )
169 else if ( dynamic_cast<QgsHueSaturationFilter *>( interface ) )
171 else if ( dynamic_cast<QgsRasterProjector *>( interface ) )
173 else if ( dynamic_cast<QgsRasterNuller *>( interface ) )
175
176 QgsDebugMsgLevel( u"%1 role = %2"_s.arg( typeid( *interface ).name(), qgsEnumValueToKey( role ) ), 4 );
177 return role;
178}
179
180void QgsRasterPipe::setRole( QgsRasterInterface *interface, int idx )
181{
182 Qgis::RasterPipeInterfaceRole role = interfaceRole( interface );
184 return;
185
186 mRoleMap.insert( role, idx );
187}
188
189void QgsRasterPipe::unsetRole( QgsRasterInterface *interface )
190{
191 Qgis::RasterPipeInterfaceRole role = interfaceRole( interface );
193 return;
194
195 const int roleIdx{ mRoleMap[role] };
196 mRoleMap.remove( role );
197
198 // Decrease all indexes greater than the removed one
199 const QMap<Qgis::RasterPipeInterfaceRole, int> currentRoles = mRoleMap;
200 for ( auto it = currentRoles.cbegin(); it != currentRoles.cend(); ++it )
201 {
202 if ( it.value() > roleIdx )
203 {
204 mRoleMap[it.key()] = it.value() - 1;
205 }
206 }
207}
208
210{
211 if ( !interface )
212 return false;
213
214 QgsDebugMsgLevel( typeid( *interface ).name(), 4 );
215 Qgis::RasterPipeInterfaceRole role = interfaceRole( interface );
216
217 // We don't know where to place unknown interface
219 return false;
220
221 //if ( mInterfacesMap.value ( role ) )
222 if ( mRoleMap.contains( role ) )
223 {
224 // An old interface of the same role exists -> replace
225 // replace may still fail and return false
226 return replace( mRoleMap.value( role ), interface );
227 }
228
229 int idx = 0;
230
231 // Not found, find the best default position for this kind of interface
232 // QgsRasterDataProvider - ProviderRole
233 // QgsRasterRenderer - RendererRole
234 // QgsRasterResampler - ResamplerRole
235 // QgsRasterProjector - ProjectorRole
236
237 int providerIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::Provider, -1 );
238 int rendererIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::Renderer, -1 );
239 int resamplerIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::Resampler, -1 );
240 int brightnessIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::Brightness, -1 );
241 int hueSaturationIdx = mRoleMap.value( Qgis::RasterPipeInterfaceRole::HueSaturation, -1 );
242
244 {
245 idx = 0;
246 }
248 {
249 idx = providerIdx + 1;
250 }
252 {
253 idx = std::max( providerIdx, rendererIdx ) + 1;
254 }
256 {
257 idx = std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ) + 1;
258 }
260 {
261 idx = std::max( std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ), hueSaturationIdx ) + 1;
262 }
264 {
265 idx = std::max( std::max( std::max( std::max( providerIdx, rendererIdx ), brightnessIdx ), hueSaturationIdx ), resamplerIdx ) + 1;
266 }
267
268 return insert( idx, interface ); // insert may still fail and return false
269}
270
271QgsRasterInterface *QgsRasterPipe::interface( Qgis::RasterPipeInterfaceRole role ) const
272{
273 QgsDebugMsgLevel( u"role = %1"_s.arg( qgsEnumValueToKey( role ) ), 4 );
274 if ( mRoleMap.contains( role ) )
275 {
276 return mInterfaces.value( mRoleMap.value( role ) );
277 }
278 return nullptr;
279}
280
285
287{
288 return dynamic_cast<QgsRasterRenderer *>( interface( Qgis::RasterPipeInterfaceRole::Renderer ) );
289}
290
295
300
305
310
312{
313 return dynamic_cast<QgsRasterNuller *>( interface( Qgis::RasterPipeInterfaceRole::Nuller ) );
314}
315
317{
318 QgsDebugMsgLevel( u"remove at %1"_s.arg( idx ), 4 );
319
320 if ( !checkBounds( idx ) )
321 return false;
322
323 // make a copy of pipe to test connection, we test the connections
324 // of the whole pipe, because the types and band numbers may change
325 QVector<QgsRasterInterface *> interfaces = mInterfaces;
326
327 interfaces.remove( idx );
328 bool success = false;
329 if ( connect( interfaces ) )
330 {
331 success = true;
332 unsetRole( mInterfaces.at( idx ) );
333 delete mInterfaces.at( idx );
334 mInterfaces.remove( idx );
335 QgsDebugMsgLevel( u"Pipe %1 removed OK"_s.arg( idx ), 4 );
336 }
337 else
338 {
339 QgsDebugMsgLevel( u"Error removing pipe %1"_s.arg( idx ), 4 );
340 }
341
342 // Connect or reconnect (after the test) interfaces
343 connect( mInterfaces );
344
345 return success;
346}
347
349{
350 if ( !interface ) return false;
351
352 return remove( mInterfaces.indexOf( interface ) );
353}
354
355bool QgsRasterPipe::canSetOn( int idx, bool on )
356{
357 QgsDebugMsgLevel( u"idx = %1 on = %2"_s.arg( idx ).arg( on ), 4 );
358 if ( !checkBounds( idx ) )
359 return false;
360
361 // Because setting interface on/off may change its output we must check if
362 // connection is OK after such switch
363 bool onOrig = mInterfaces.at( idx )->on();
364
365 if ( onOrig == on )
366 return true;
367
368 mInterfaces.at( idx )->setOn( on );
369
370 bool success = connect( mInterfaces );
371
372 mInterfaces.at( idx )->setOn( onOrig );
373 connect( mInterfaces );
374 return success;
375}
376
377bool QgsRasterPipe::setOn( int idx, bool on )
378{
379 QgsDebugMsgLevel( u"idx = %1 on = %2"_s.arg( idx ).arg( on ), 4 );
380 if ( !checkBounds( idx ) )
381 return false;
382
383 bool onOrig = mInterfaces.at( idx )->on();
384
385 if ( onOrig == on )
386 return true;
387
388 mInterfaces.at( idx )->setOn( on );
389
390 if ( connect( mInterfaces ) )
391 return true;
392
393 mInterfaces.at( idx )->setOn( onOrig );
394 connect( mInterfaces );
395
396 return false;
397}
398
399bool QgsRasterPipe::checkBounds( int idx ) const
400{
401 return !( idx < 0 || idx >= mInterfaces.size() );
402}
403
405{
406 mResamplingStage = stage;
407
408 int resamplerIndex = 0;
409 for ( QgsRasterInterface *interface : std::as_const( mInterfaces ) )
410 {
411 if ( interfaceRole( interface ) == Qgis::RasterPipeInterfaceRole::Resampler )
412 {
413 setOn( resamplerIndex, stage == Qgis::RasterResamplingStage::ResampleFilter );
414 break;
415 }
416 resamplerIndex ++;
417 }
418
419 if ( QgsRasterDataProvider *l_provider = provider() )
420 {
421 l_provider->enableProviderResampling( stage == Qgis::RasterResamplingStage::Provider );
422 }
423}
424
426{
427 if ( !mDataDefinedProperties.hasActiveProperties() )
428 return;
429
430 if ( mDataDefinedProperties.isActive( Property::RendererOpacity ) )
431 {
432 if ( QgsRasterRenderer *r = renderer() )
433 {
434 const double prevOpacity = r->opacity();
435 context.setOriginalValueVariable( prevOpacity * 100 );
436 bool ok = false;
437 const double opacity = mDataDefinedProperties.valueAsDouble( Property::RendererOpacity, context, prevOpacity, &ok ) / 100;
438 if ( ok )
439 {
440 r->setOpacity( opacity );
441 }
442 }
443 }
444}
445
446QgsPropertiesDefinition QgsRasterPipe::sPropertyDefinitions;
447
448void QgsRasterPipe::initPropertyDefinitions()
449{
450 const QString origin = u"raster"_s;
451
452 sPropertyDefinitions = QgsPropertiesDefinition
453 {
454 { static_cast< int >( QgsRasterPipe::Property::RendererOpacity ), QgsPropertyDefinition( "RendererOpacity", QObject::tr( "Renderer opacity" ), QgsPropertyDefinition::Opacity, origin ) },
455 };
456}
457
459{
460 static std::once_flag initialized;
461 std::call_once( initialized, initPropertyDefinitions );
462 return sPropertyDefinitions;
463}
RasterResamplingStage
Stage at which raster resampling occurs.
Definition qgis.h:1528
@ Provider
Resampling occurs in Provider.
Definition qgis.h:1530
@ ResampleFilter
Resampling occurs in ResamplingFilter.
Definition qgis.h:1529
RasterPipeInterfaceRole
Raster pipe interface roles.
Definition qgis.h:1511
@ Renderer
Raster renderer role.
Definition qgis.h:1514
@ Projector
Projector role.
Definition qgis.h:1517
@ Resampler
Resampler role.
Definition qgis.h:1516
@ HueSaturation
Hue/saturation filter role (also applies grayscale/color inversion).
Definition qgis.h:1519
@ Provider
Data provider role.
Definition qgis.h:1513
@ Nuller
Raster nuller role.
Definition qgis.h:1518
@ Unknown
Unknown role.
Definition qgis.h:1512
@ Brightness
Brightness filter role.
Definition qgis.h:1515
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:62
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:7091
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
#define QgsDebugError(str)
Definition qgslogger.h:59
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.