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