1
/* **************************************************************************
2
qgscolorrampshader.cpp - description
4
begin : Fri Dec 28 2007
5
copyright : (C) 2007 by Peter J. Ersts
8
This class is based off of code that was originally written by Marco Hugentobler and
9
originally part of the larger QgsRasterLayer class
10
****************************************************************************/
12
/* **************************************************************************
14
* This program is free software; you can redistribute it and/or modify *
15
* it under the terms of the GNU General Public License as published by *
16
* the Free Software Foundation; either version 2 of the License, or *
17
* (at your option) any later version. *
19
***************************************************************************/
20
#define DOUBLE_DIFF_THRESHOLD 0.0000001
22
#include "qgslogger.h"
24
#include "qgscolorrampshader.h"
28
QgsColorRampShader::QgsColorRampShader( double theMinimumValue, double theMaximumValue ) : QgsRasterShaderFunction( theMinimumValue, theMaximumValue )
30
QgsDebugMsg( "called." );
31
mMaximumColorCacheSize = 1024; //good starting value
32
mCurrentColorRampItemIndex = 0;
35
QString QgsColorRampShader::colorRampTypeAsQString()
37
switch ( mColorRampType )
40
return QString( "INTERPOLATED" );
43
return QString( "DISCRETE" );
46
return QString( "EXACT" );
49
return QString( "Unknown" );
52
bool QgsColorRampShader::discreteColor( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue )
54
int myColorRampItemCount = mColorRampItemList.count();
55
if ( myColorRampItemCount <= 0 )
60
double myTinyDiff = 0.0;
61
QgsColorRampShader::ColorRampItem myColorRampItem;
62
while ( mCurrentColorRampItemIndex >= 0 && mCurrentColorRampItemIndex < myColorRampItemCount )
64
//Start searching from the last index - assumtion is that neighboring pixels tend to be similar values
65
myColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex );
66
myTinyDiff = fabs( theValue - myColorRampItem.value );
67
//If the previous entry is less, then search closer to the top of the list (assumes mColorRampItemList is sorted)
68
if ( mCurrentColorRampItemIndex != 0 && theValue <= mColorRampItemList.at( mCurrentColorRampItemIndex - 1 ).value )
70
mCurrentColorRampItemIndex--;
72
else if ( theValue <= myColorRampItem.value || myTinyDiff <= DOUBLE_DIFF_THRESHOLD )
74
*theReturnRedValue = myColorRampItem.color.red();
75
*theReturnGreenValue = myColorRampItem.color.green();
76
*theReturnBlueValue = myColorRampItem.color.blue();
77
//Cache the shaded value
78
if ( mMaximumColorCacheSize >= mColorCache.size() )
80
mColorCache.insert( theValue, myColorRampItem.color );
84
//Search deeper into the color ramp list
87
mCurrentColorRampItemIndex++;
91
return false; // value not found
94
bool QgsColorRampShader::exactColor( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue )
96
int myColorRampItemCount = mColorRampItemList.count();
97
if ( myColorRampItemCount <= 0 )
102
double myTinyDiff = 0.0;
103
QgsColorRampShader::ColorRampItem myColorRampItem;
104
while ( mCurrentColorRampItemIndex >= 0 && mCurrentColorRampItemIndex < myColorRampItemCount )
106
//Start searching from the last index - assumtion is that neighboring pixels tend to be similar values
107
myColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex );
108
myTinyDiff = fabs( theValue - myColorRampItem.value );
109
if ( theValue == myColorRampItem.value || myTinyDiff <= DOUBLE_DIFF_THRESHOLD )
111
*theReturnRedValue = myColorRampItem.color.red();
112
*theReturnGreenValue = myColorRampItem.color.green();
113
*theReturnBlueValue = myColorRampItem.color.blue();
114
//Cache the shaded value
115
if ( mMaximumColorCacheSize >= mColorCache.size() )
117
mColorCache.insert( theValue, myColorRampItem.color );
121
//pixel value sits between ramp entries so bail
122
else if ( mCurrentColorRampItemIndex != myColorRampItemCount - 1 && theValue > myColorRampItem.value && theValue < mColorRampItemList.at( mCurrentColorRampItemIndex + 1 ).value )
126
//Search deeper into the color ramp list
127
else if ( theValue > myColorRampItem.value )
129
mCurrentColorRampItemIndex++;
131
//Search back toward the beginning of the list
134
mCurrentColorRampItemIndex--;
138
return false; // value not found
141
bool QgsColorRampShader::interpolatedColor( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue )
143
int myColorRampItemCount = mColorRampItemList.count();
144
if ( myColorRampItemCount <= 0 )
149
double myTinyDiff = 0.0;
150
double myCurrentRampRange; //difference between two consecutive entry values
151
double myOffsetInRange; //difference between the previous entry value and value
152
QgsColorRampShader::ColorRampItem myColorRampItem;
153
while ( mCurrentColorRampItemIndex >= 0 && mCurrentColorRampItemIndex < myColorRampItemCount )
155
//Start searching from the last index - assumtion is that neighboring pixels tend to be similar values
156
myColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex );
157
myTinyDiff = fabs( theValue - myColorRampItem.value );
158
//If the previous entry is less, then search closer to the top of the list (assumes mColorRampItemList is sorted)
159
if ( mCurrentColorRampItemIndex != 0 && theValue <= mColorRampItemList.at( mCurrentColorRampItemIndex - 1 ).value )
161
mCurrentColorRampItemIndex--;
163
else if ( mCurrentColorRampItemIndex != 0 && ( theValue <= myColorRampItem.value || myTinyDiff <= DOUBLE_DIFF_THRESHOLD ) )
165
QgsColorRampShader::ColorRampItem myPreviousColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex - 1 );
166
myCurrentRampRange = myColorRampItem.value - myPreviousColorRampItem.value;
167
myOffsetInRange = theValue - myPreviousColorRampItem.value;
169
*theReturnRedValue = ( int )(( double ) myPreviousColorRampItem.color.red() + ((( double )( myColorRampItem.color.red() - myPreviousColorRampItem.color.red() ) / myCurrentRampRange ) * myOffsetInRange ) );
170
*theReturnGreenValue = ( int )(( double ) myPreviousColorRampItem.color.green() + ((( double )( myColorRampItem.color.green() - myPreviousColorRampItem.color.green() ) / myCurrentRampRange ) * myOffsetInRange ) );
171
*theReturnBlueValue = ( int )(( double ) myPreviousColorRampItem.color.blue() + ((( double )( myColorRampItem.color.blue() - myPreviousColorRampItem.color.blue() ) / myCurrentRampRange ) * myOffsetInRange ) );
172
if ( mMaximumColorCacheSize >= mColorCache.size() )
174
QColor myNewColor( *theReturnRedValue, *theReturnGreenValue, *theReturnBlueValue );
175
mColorCache.insert( theValue, myNewColor );
179
else if ( mCurrentColorRampItemIndex == 0 && theValue <= myColorRampItem.value )
181
QgsColorRampShader::ColorRampItem myPreviousColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex - 1 );
182
myCurrentRampRange = myColorRampItem.value - myPreviousColorRampItem.value;
183
myOffsetInRange = theValue - myPreviousColorRampItem.value;
185
*theReturnRedValue = myColorRampItem.color.red();
186
*theReturnGreenValue = myColorRampItem.color.green();
187
*theReturnBlueValue = myColorRampItem.color.blue();
188
if ( mMaximumColorCacheSize >= mColorCache.size() )
190
QColor myNewColor( *theReturnRedValue, *theReturnGreenValue, *theReturnBlueValue );
191
mColorCache.insert( theValue, myNewColor );
195
//Search deeper into the color ramp list
196
else if ( theValue > myColorRampItem.value )
198
mCurrentColorRampItemIndex++;
209
void QgsColorRampShader::setColorRampType( QgsColorRampShader::ColorRamp_TYPE theColorRampType )
211
//When the ramp type changes we need to clear out the cache
213
mColorRampType = theColorRampType;
216
void QgsColorRampShader::setColorRampType( QString theType )
218
//When the type of the ramp changes we need to clear out the cache
220
if ( theType == "INTERPOLATED" )
222
mColorRampType = INTERPOLATED;
224
else if ( theType == "DISCRETE" )
226
mColorRampType = DISCRETE;
230
mColorRampType = EXACT;
234
bool QgsColorRampShader::shade( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue )
237
//Get the shaded value from the cache if it exists already
238
QColor myColor = mColorCache.value( theValue );
239
if ( myColor.isValid() )
241
*theReturnRedValue = myColor.red();
242
*theReturnGreenValue = myColor.green();
243
*theReturnBlueValue = myColor.blue();
247
//pixel value not in cache so generate new value
249
//Check to be sure mCurrentColorRampItemIndex is within the valid range.
250
if ( mCurrentColorRampItemIndex < 0 )
252
mCurrentColorRampItemIndex = 0;
254
else if ( mCurrentColorRampItemIndex >= mColorRampItemList.size() )
256
mCurrentColorRampItemIndex = mColorRampItemList.size() - 1;
259
if ( QgsColorRampShader::EXACT == mColorRampType )
261
return exactColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue );
263
else if ( QgsColorRampShader::INTERPOLATED == mColorRampType )
265
return interpolatedColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue );
268
return discreteColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue );
271
bool QgsColorRampShader::shade( double theRedValue, double theGreenValue, double theBlueValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue )
273
*theReturnRedValue = 0;
274
*theReturnGreenValue = 0;
275
*theReturnBlueValue = 0;