Quantum GIS API Documentation  1.7.5-Wroclaw
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
qgscolorrampshader.cpp
Go to the documentation of this file.
1 /* **************************************************************************
2  qgscolorrampshader.cpp - description
3  -------------------
4 begin : Fri Dec 28 2007
5 copyright : (C) 2007 by Peter J. Ersts
6 email : ersts@amnh.org
7 
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 ****************************************************************************/
11 
12 /* **************************************************************************
13  * *
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. *
18  * *
19  ***************************************************************************/
20 #define DOUBLE_DIFF_THRESHOLD 0.0000001
21 
22 #include "qgslogger.h"
23 
24 #include "qgscolorrampshader.h"
25 
26 #include <cmath>
27 
28 QgsColorRampShader::QgsColorRampShader( double theMinimumValue, double theMaximumValue ) : QgsRasterShaderFunction( theMinimumValue, theMaximumValue )
29 {
30  QgsDebugMsg( "called." );
31  mMaximumColorCacheSize = 1024; //good starting value
33 }
34 
36 {
37  switch ( mColorRampType )
38  {
39  case INTERPOLATED:
40  return QString( "INTERPOLATED" );
41  break;
42  case DISCRETE:
43  return QString( "DISCRETE" );
44  break;
45  case EXACT:
46  return QString( "EXACT" );
47  break;
48  }
49  return QString( "Unknown" );
50 }
51 
52 bool QgsColorRampShader::discreteColor( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue )
53 {
54  int myColorRampItemCount = mColorRampItemList.count();
55  if ( myColorRampItemCount <= 0 )
56  {
57  return false;
58  }
59 
60  double myTinyDiff = 0.0;
61  QgsColorRampShader::ColorRampItem myColorRampItem;
62  while ( mCurrentColorRampItemIndex >= 0 && mCurrentColorRampItemIndex < myColorRampItemCount )
63  {
64  //Start searching from the last index - assumtion is that neighboring pixels tend to be similar values
65  myColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex );
66  myTinyDiff = qAbs( 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 &&
69  theValue <= mColorRampItemList.at( mCurrentColorRampItemIndex - 1 ).value )
70  {
72  }
73  else if ( theValue <= myColorRampItem.value || myTinyDiff <= DOUBLE_DIFF_THRESHOLD )
74  {
75  *theReturnRedValue = myColorRampItem.color.red();
76  *theReturnGreenValue = myColorRampItem.color.green();
77  *theReturnBlueValue = myColorRampItem.color.blue();
78  //Cache the shaded value
79  if ( mMaximumColorCacheSize >= mColorCache.size() )
80  {
81  mColorCache.insert( theValue, myColorRampItem.color );
82  }
83  return true;
84  }
85  //Search deeper into the color ramp list
86  else
87  {
89  }
90  }
91 
92  return false; // value not found
93 }
94 
95 bool QgsColorRampShader::exactColor( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue )
96 {
97  int myColorRampItemCount = mColorRampItemList.count();
98  if ( myColorRampItemCount <= 0 )
99  {
100  return false;
101  }
102 
103  double myTinyDiff = 0.0;
104  QgsColorRampShader::ColorRampItem myColorRampItem;
105  while ( mCurrentColorRampItemIndex >= 0 && mCurrentColorRampItemIndex < myColorRampItemCount )
106  {
107  //Start searching from the last index - assumtion is that neighboring pixels tend to be similar values
108  myColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex );
109  myTinyDiff = qAbs( theValue - myColorRampItem.value );
110  if ( theValue == myColorRampItem.value || myTinyDiff <= DOUBLE_DIFF_THRESHOLD )
111  {
112  *theReturnRedValue = myColorRampItem.color.red();
113  *theReturnGreenValue = myColorRampItem.color.green();
114  *theReturnBlueValue = myColorRampItem.color.blue();
115  //Cache the shaded value
116  if ( mMaximumColorCacheSize >= mColorCache.size() )
117  {
118  mColorCache.insert( theValue, myColorRampItem.color );
119  }
120  return true;
121  }
122  //pixel value sits between ramp entries so bail
123  else if ( mCurrentColorRampItemIndex != myColorRampItemCount - 1 &&
124  theValue > myColorRampItem.value && theValue < mColorRampItemList.at(
125  mCurrentColorRampItemIndex + 1 ).value )
126  {
127  return false;
128  }
129  //Search deeper into the color ramp list
130  else if ( theValue > myColorRampItem.value )
131  {
133  }
134  //Search back toward the beginning of the list
135  else
136  {
138  }
139  }
140 
141  return false; // value not found
142 }
143 
144 bool QgsColorRampShader::interpolatedColor( double theValue, int*
145  theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue )
146 {
147  int myColorRampItemCount = mColorRampItemList.count();
148  if ( myColorRampItemCount <= 0 )
149  {
150  return false;
151  }
152 
153  double myTinyDiff = 0.0;
154  double myCurrentRampRange; //difference between two consecutive entry values
155  double myOffsetInRange; //difference between the previous entry value and value
156  QgsColorRampShader::ColorRampItem myColorRampItem;
157  while ( mCurrentColorRampItemIndex >= 0 && mCurrentColorRampItemIndex < myColorRampItemCount )
158  {
159  //Start searching from the last index - assumtion is that neighboring pixels tend to be similar values
160  myColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex );
161  myTinyDiff = qAbs( theValue - myColorRampItem.value );
162  //If the previous entry is less, then search closer to the top of the list (assumes mColorRampItemList is sorted)
163  if ( mCurrentColorRampItemIndex != 0 && theValue <= mColorRampItemList.at( mCurrentColorRampItemIndex - 1 ).value )
164  {
166  }
167  else if ( mCurrentColorRampItemIndex != 0 && ( theValue <= myColorRampItem.value || myTinyDiff <= DOUBLE_DIFF_THRESHOLD ) )
168  {
170  myCurrentRampRange = myColorRampItem.value - myPreviousColorRampItem.value;
171  myOffsetInRange = theValue - myPreviousColorRampItem.value;
172 
173  *theReturnRedValue = ( int )(( double ) myPreviousColorRampItem.color.red() + ((( double )( myColorRampItem.color.red() - myPreviousColorRampItem.color.red() ) / myCurrentRampRange ) * myOffsetInRange ) );
174  *theReturnGreenValue = ( int )(( double ) myPreviousColorRampItem.color.green() + ((( double )( myColorRampItem.color.green() - myPreviousColorRampItem.color.green() ) / myCurrentRampRange ) * myOffsetInRange ) );
175  *theReturnBlueValue = ( int )(( double ) myPreviousColorRampItem.color.blue() + ((( double )( myColorRampItem.color.blue() - myPreviousColorRampItem.color.blue() ) / myCurrentRampRange ) * myOffsetInRange ) );
176  if ( mMaximumColorCacheSize >= mColorCache.size() )
177  {
178  QColor myNewColor( *theReturnRedValue, *theReturnGreenValue, *theReturnBlueValue );
179  mColorCache.insert( theValue, myNewColor );
180  }
181  return true;
182  }
183  else if ( mCurrentColorRampItemIndex == 0 && theValue <= myColorRampItem.value )
184  {
186  myCurrentRampRange = myColorRampItem.value - myPreviousColorRampItem.value;
187  myOffsetInRange = theValue - myPreviousColorRampItem.value;
188 
189  *theReturnRedValue = myColorRampItem.color.red();
190  *theReturnGreenValue = myColorRampItem.color.green();
191  *theReturnBlueValue = myColorRampItem.color.blue();
192  if ( mMaximumColorCacheSize >= mColorCache.size() )
193  {
194  QColor myNewColor( *theReturnRedValue, *theReturnGreenValue, *theReturnBlueValue );
195  mColorCache.insert( theValue, myNewColor );
196  }
197  return true;
198  }
199  //Search deeper into the color ramp list
200  else if ( theValue > myColorRampItem.value )
201  {
203  }
204  else
205  {
206  return false;
207  }
208  }
209 
210  return false;
211 }
212 
213 void QgsColorRampShader::setColorRampItemList( const QList<QgsColorRampShader::ColorRampItem>& theList )
214 {
215  mColorRampItemList = theList;
216  //Clear the cache
217  mColorCache.clear();
218 }
219 
221 {
222  //When the ramp type changes we need to clear out the cache
223  mColorCache.clear();
224  mColorRampType = theColorRampType;
225 }
226 
228 {
229  //When the type of the ramp changes we need to clear out the cache
230  mColorCache.clear();
231  if ( theType == "INTERPOLATED" )
232  {
234  }
235  else if ( theType == "DISCRETE" )
236  {
238  }
239  else
240  {
242  }
243 }
244 
245 bool QgsColorRampShader::shade( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue )
246 {
247 
248  //Get the shaded value from the cache if it exists already
249  QColor myColor = mColorCache.value( theValue );
250  if ( myColor.isValid() )
251  {
252  *theReturnRedValue = myColor.red();
253  *theReturnGreenValue = myColor.green();
254  *theReturnBlueValue = myColor.blue();
255  return true;
256  }
257 
258  //pixel value not in cache so generate new value
259 
260  //Check to be sure mCurrentColorRampItemIndex is within the valid range.
261  if ( mCurrentColorRampItemIndex < 0 )
262  {
264  }
265  else if ( mCurrentColorRampItemIndex >= mColorRampItemList.size() )
266  {
268  }
269 
271  {
272  return exactColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue );
273  }
275  {
276  return interpolatedColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue );
277  }
278 
279  return discreteColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue );
280 }
281 
282 bool QgsColorRampShader::shade( double theRedValue, double theGreenValue,
283  double theBlueValue, int* theReturnRedValue, int* theReturnGreenValue, int*
284  theReturnBlueValue )
285 {
286  *theReturnRedValue = 0;
287  *theReturnGreenValue = 0;
288  *theReturnBlueValue = 0;
289 
290  return false;
291 }