1 /***************************************************************************
2                          qgsrasterrendererregistry.cpp
3                          -----------------------------
4     begin                : January 2012
5     copyright            : (C) 2012 by Marco Hugentobler
6     email                : marco at sourcepole dot ch
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 "qgsrasterrendererregistry.h"
19 #include "qgsrasterdataprovider.h"
20 #include "qgsrastershader.h"
21 #include "qgsrastertransparency.h"
22 #include "qgsmultibandcolorrenderer.h"
23 #include "qgspalettedrasterrenderer.h"
24 #include "qgsrastercontourrenderer.h"
25 #include "qgssinglebandcolordatarenderer.h"
26 #include "qgssinglebandgrayrenderer.h"
27 #include "qgssinglebandpseudocolorrenderer.h"
28 #include "qgshillshaderenderer.h"
29 #include "qgsapplication.h"
30 #include "qgssettings.h"
31 
32 #include <QIcon>
33 
QgsRasterRendererRegistryEntry(const QString & name,const QString & visibleName,QgsRasterRendererCreateFunc rendererFunction,QgsRasterRendererWidgetCreateFunc widgetFunction)34 QgsRasterRendererRegistryEntry::QgsRasterRendererRegistryEntry( const QString &name, const QString &visibleName,
35     QgsRasterRendererCreateFunc rendererFunction,
36     QgsRasterRendererWidgetCreateFunc widgetFunction )
37   : name( name )
38   , visibleName( visibleName )
39   , rendererCreateFunction( rendererFunction )
40   , widgetCreateFunction( widgetFunction )
41 {
42 }
43 
icon()44 QIcon QgsRasterRendererRegistryEntry::icon()
45 {
46   return QgsApplication::getThemeIcon( QString( "styleicons/%1.svg" ).arg( name ) );
47 }
48 
QgsRasterRendererRegistry()49 QgsRasterRendererRegistry::QgsRasterRendererRegistry()
50 {
51   // insert items in a particular order, which is returned in renderersList()
52   insert( QgsRasterRendererRegistryEntry( QStringLiteral( "multibandcolor" ), QObject::tr( "Multiband color" ),
53                                           QgsMultiBandColorRenderer::create, nullptr ) );
54   insert( QgsRasterRendererRegistryEntry( QStringLiteral( "paletted" ), QObject::tr( "Paletted/Unique values" ), QgsPalettedRasterRenderer::create, nullptr ) );
55   insert( QgsRasterRendererRegistryEntry( QStringLiteral( "singlebandgray" ), QObject::tr( "Singleband gray" ),
56                                           QgsSingleBandGrayRenderer::create, nullptr ) );
57   insert( QgsRasterRendererRegistryEntry( QStringLiteral( "singlebandpseudocolor" ), QObject::tr( "Singleband pseudocolor" ),
58                                           QgsSingleBandPseudoColorRenderer::create, nullptr ) );
59   insert( QgsRasterRendererRegistryEntry( QStringLiteral( "singlebandcolordata" ), QObject::tr( "Singleband color data" ),
60                                           QgsSingleBandColorDataRenderer::create, nullptr ) );
61   insert( QgsRasterRendererRegistryEntry( QStringLiteral( "hillshade" ), QObject::tr( "Hillshade" ),
62                                           QgsHillshadeRenderer::create, nullptr ) );
63   insert( QgsRasterRendererRegistryEntry( QStringLiteral( "contour" ), QObject::tr( "Contours" ),
64                                           QgsRasterContourRenderer::create, nullptr ) );
65 }
66 
insert(const QgsRasterRendererRegistryEntry & entry)67 void QgsRasterRendererRegistry::insert( const QgsRasterRendererRegistryEntry &entry )
68 {
69   mEntries.insert( entry.name, entry );
70   mSortedEntries.append( entry.name );
71 }
72 
insertWidgetFunction(const QString & rendererName,QgsRasterRendererWidgetCreateFunc func)73 void QgsRasterRendererRegistry::insertWidgetFunction( const QString &rendererName, QgsRasterRendererWidgetCreateFunc func )
74 {
75   if ( !mEntries.contains( rendererName ) )
76   {
77     return;
78   }
79   mEntries[rendererName].widgetCreateFunction = func;
80 }
81 
rendererData(const QString & rendererName,QgsRasterRendererRegistryEntry & data) const82 bool QgsRasterRendererRegistry::rendererData( const QString &rendererName, QgsRasterRendererRegistryEntry &data ) const
83 {
84   QHash< QString, QgsRasterRendererRegistryEntry >::const_iterator it = mEntries.find( rendererName );
85   if ( it == mEntries.constEnd() )
86   {
87     return false;
88   }
89   data = it.value();
90   return true;
91 }
92 
renderersList() const93 QStringList QgsRasterRendererRegistry::renderersList() const
94 {
95   return mSortedEntries;
96 }
97 
entries() const98 QList< QgsRasterRendererRegistryEntry > QgsRasterRendererRegistry::entries() const
99 {
100   QList< QgsRasterRendererRegistryEntry > result;
101 
102   QHash< QString, QgsRasterRendererRegistryEntry >::const_iterator it = mEntries.constBegin();
103   for ( ; it != mEntries.constEnd(); ++it )
104   {
105     result.push_back( it.value() );
106   }
107   return result;
108 }
109 
defaultRendererForDrawingStyle(QgsRaster::DrawingStyle drawingStyle,QgsRasterDataProvider * provider) const110 QgsRasterRenderer *QgsRasterRendererRegistry::defaultRendererForDrawingStyle( QgsRaster::DrawingStyle drawingStyle, QgsRasterDataProvider *provider ) const
111 {
112   if ( !provider || provider->bandCount() < 1 )
113   {
114     return nullptr;
115   }
116 
117 
118   QgsRasterRenderer *renderer = nullptr;
119   switch ( drawingStyle )
120   {
121     case QgsRaster::PalettedColor:
122     {
123       int grayBand = 1; //reasonable default
124       QgsPalettedRasterRenderer::ClassData classes = QgsPalettedRasterRenderer::colorTableToClassData( provider->colorTable( grayBand ) );
125       renderer = new QgsPalettedRasterRenderer( provider,
126           grayBand,
127           classes );
128     }
129     break;
130     case QgsRaster::MultiBandSingleBandGray:
131     case QgsRaster::SingleBandGray:
132     {
133       int grayBand = 1;
134       renderer = new QgsSingleBandGrayRenderer( provider, grayBand );
135 
136       QgsContrastEnhancement *ce = new QgsContrastEnhancement( ( Qgis::DataType )(
137             provider->dataType( grayBand ) ) );
138 
139 // Default contrast enhancement is set from QgsRasterLayer, it has already setContrastEnhancementAlgorithm(). Default enhancement must only be set if default style was not loaded (to avoid stats calculation).
140       ( ( QgsSingleBandGrayRenderer * )renderer )->setContrastEnhancement( ce );
141       break;
142     }
143     case QgsRaster::SingleBandPseudoColor:
144     {
145       int bandNo = 1;
146       double minValue = 0;
147       double maxValue = 0;
148       // TODO: avoid calculating statistics if not necessary (default style loaded)
149       minMaxValuesForBand( bandNo, provider, minValue, maxValue );
150       QgsRasterShader *shader = new QgsRasterShader( minValue, maxValue );
151       renderer = new QgsSingleBandPseudoColorRenderer( provider, bandNo, shader );
152       break;
153     }
154     case QgsRaster::MultiBandColor:
155     {
156       QgsSettings s;
157 
158       int redBand = s.value( QStringLiteral( "/Raster/defaultRedBand" ), 1 ).toInt();
159       if ( redBand < 0 || redBand > provider->bandCount() )
160       {
161         redBand = -1;
162       }
163       int greenBand = s.value( QStringLiteral( "/Raster/defaultGreenBand" ), 2 ).toInt();
164       if ( greenBand < 0 || greenBand > provider->bandCount() )
165       {
166         greenBand = -1;
167       }
168       int blueBand = s.value( QStringLiteral( "/Raster/defaultBlueBand" ), 3 ).toInt();
169       if ( blueBand < 0 || blueBand > provider->bandCount() )
170       {
171         blueBand = -1;
172       }
173 
174       renderer = new QgsMultiBandColorRenderer( provider, redBand, greenBand, blueBand );
175       break;
176     }
177     case QgsRaster::SingleBandColorDataStyle:
178     {
179       renderer = new QgsSingleBandColorDataRenderer( provider, 1 );
180       break;
181     }
182     default:
183       return nullptr;
184   }
185 
186   QgsRasterTransparency *tr = new QgsRasterTransparency(); //renderer takes ownership
187   int bandCount = renderer->usesBands().size();
188   if ( bandCount == 1 )
189   {
190     QList<QgsRasterTransparency::TransparentSingleValuePixel> transparentSingleList;
191     tr->setTransparentSingleValuePixelList( transparentSingleList );
192   }
193   else if ( bandCount == 3 )
194   {
195     QList<QgsRasterTransparency::TransparentThreeValuePixel> transparentThreeValueList;
196     tr->setTransparentThreeValuePixelList( transparentThreeValueList );
197   }
198   renderer->setRasterTransparency( tr );
199   return renderer;
200 }
201 
minMaxValuesForBand(int band,QgsRasterDataProvider * provider,double & minValue,double & maxValue) const202 bool QgsRasterRendererRegistry::minMaxValuesForBand( int band, QgsRasterDataProvider *provider, double &minValue, double &maxValue ) const
203 {
204   if ( !provider )
205   {
206     return false;
207   }
208 
209   minValue = 0;
210   maxValue = 0;
211 
212   QgsSettings s;
213   if ( s.value( QStringLiteral( "/Raster/useStandardDeviation" ), false ).toBool() )
214   {
215     QgsRasterBandStats stats = provider->bandStatistics( band, QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev );
216 
217     double stdDevFactor = s.value( QStringLiteral( "/Raster/defaultStandardDeviation" ), 2.0 ).toDouble();
218     double diff = stdDevFactor * stats.stdDev;
219     minValue = stats.mean - diff;
220     maxValue = stats.mean + diff;
221   }
222   else
223   {
224     QgsRasterBandStats stats = provider->bandStatistics( band, QgsRasterBandStats::Min | QgsRasterBandStats::Max );
225     minValue = stats.minimumValue;
226     maxValue = stats.maximumValue;
227   }
228   return true;
229 }
230