Quantum GIS API Documentation
1.7.4
|
00001 /* ************************************************************************** 00002 qgscolorrampshader.cpp - description 00003 ------------------- 00004 begin : Fri Dec 28 2007 00005 copyright : (C) 2007 by Peter J. Ersts 00006 email : ersts@amnh.org 00007 00008 This class is based off of code that was originally written by Marco Hugentobler and 00009 originally part of the larger QgsRasterLayer class 00010 ****************************************************************************/ 00011 00012 /* ************************************************************************** 00013 * * 00014 * This program is free software; you can redistribute it and/or modify * 00015 * it under the terms of the GNU General Public License as published by * 00016 * the Free Software Foundation; either version 2 of the License, or * 00017 * (at your option) any later version. * 00018 * * 00019 ***************************************************************************/ 00020 #define DOUBLE_DIFF_THRESHOLD 0.0000001 00021 00022 #include "qgslogger.h" 00023 00024 #include "qgscolorrampshader.h" 00025 00026 #include <cmath> 00027 00028 QgsColorRampShader::QgsColorRampShader( double theMinimumValue, double theMaximumValue ) : QgsRasterShaderFunction( theMinimumValue, theMaximumValue ) 00029 { 00030 QgsDebugMsg( "called." ); 00031 mMaximumColorCacheSize = 1024; //good starting value 00032 mCurrentColorRampItemIndex = 0; 00033 } 00034 00035 QString QgsColorRampShader::colorRampTypeAsQString() 00036 { 00037 switch ( mColorRampType ) 00038 { 00039 case INTERPOLATED: 00040 return QString( "INTERPOLATED" ); 00041 break; 00042 case DISCRETE: 00043 return QString( "DISCRETE" ); 00044 break; 00045 case EXACT: 00046 return QString( "EXACT" ); 00047 break; 00048 } 00049 return QString( "Unknown" ); 00050 } 00051 00052 bool QgsColorRampShader::discreteColor( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue ) 00053 { 00054 int myColorRampItemCount = mColorRampItemList.count(); 00055 if ( myColorRampItemCount <= 0 ) 00056 { 00057 return false; 00058 } 00059 00060 double myTinyDiff = 0.0; 00061 QgsColorRampShader::ColorRampItem myColorRampItem; 00062 while ( mCurrentColorRampItemIndex >= 0 && mCurrentColorRampItemIndex < myColorRampItemCount ) 00063 { 00064 //Start searching from the last index - assumtion is that neighboring pixels tend to be similar values 00065 myColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex ); 00066 myTinyDiff = qAbs( theValue - myColorRampItem.value ); 00067 //If the previous entry is less, then search closer to the top of the list (assumes mColorRampItemList is sorted) 00068 if ( mCurrentColorRampItemIndex != 0 && theValue <= mColorRampItemList.at( mCurrentColorRampItemIndex - 1 ).value ) 00069 { 00070 mCurrentColorRampItemIndex--; 00071 } 00072 else if ( theValue <= myColorRampItem.value || myTinyDiff <= DOUBLE_DIFF_THRESHOLD ) 00073 { 00074 *theReturnRedValue = myColorRampItem.color.red(); 00075 *theReturnGreenValue = myColorRampItem.color.green(); 00076 *theReturnBlueValue = myColorRampItem.color.blue(); 00077 //Cache the shaded value 00078 if ( mMaximumColorCacheSize >= mColorCache.size() ) 00079 { 00080 mColorCache.insert( theValue, myColorRampItem.color ); 00081 } 00082 return true; 00083 } 00084 //Search deeper into the color ramp list 00085 else 00086 { 00087 mCurrentColorRampItemIndex++; 00088 } 00089 } 00090 00091 return false; // value not found 00092 } 00093 00094 bool QgsColorRampShader::exactColor( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue ) 00095 { 00096 int myColorRampItemCount = mColorRampItemList.count(); 00097 if ( myColorRampItemCount <= 0 ) 00098 { 00099 return false; 00100 } 00101 00102 double myTinyDiff = 0.0; 00103 QgsColorRampShader::ColorRampItem myColorRampItem; 00104 while ( mCurrentColorRampItemIndex >= 0 && mCurrentColorRampItemIndex < myColorRampItemCount ) 00105 { 00106 //Start searching from the last index - assumtion is that neighboring pixels tend to be similar values 00107 myColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex ); 00108 myTinyDiff = qAbs( theValue - myColorRampItem.value ); 00109 if ( theValue == myColorRampItem.value || myTinyDiff <= DOUBLE_DIFF_THRESHOLD ) 00110 { 00111 *theReturnRedValue = myColorRampItem.color.red(); 00112 *theReturnGreenValue = myColorRampItem.color.green(); 00113 *theReturnBlueValue = myColorRampItem.color.blue(); 00114 //Cache the shaded value 00115 if ( mMaximumColorCacheSize >= mColorCache.size() ) 00116 { 00117 mColorCache.insert( theValue, myColorRampItem.color ); 00118 } 00119 return true; 00120 } 00121 //pixel value sits between ramp entries so bail 00122 else if ( mCurrentColorRampItemIndex != myColorRampItemCount - 1 && theValue > myColorRampItem.value && theValue < mColorRampItemList.at( mCurrentColorRampItemIndex + 1 ).value ) 00123 { 00124 return false; 00125 } 00126 //Search deeper into the color ramp list 00127 else if ( theValue > myColorRampItem.value ) 00128 { 00129 mCurrentColorRampItemIndex++; 00130 } 00131 //Search back toward the beginning of the list 00132 else 00133 { 00134 mCurrentColorRampItemIndex--; 00135 } 00136 } 00137 00138 return false; // value not found 00139 } 00140 00141 bool QgsColorRampShader::interpolatedColor( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue ) 00142 { 00143 int myColorRampItemCount = mColorRampItemList.count(); 00144 if ( myColorRampItemCount <= 0 ) 00145 { 00146 return false; 00147 } 00148 00149 double myTinyDiff = 0.0; 00150 double myCurrentRampRange; //difference between two consecutive entry values 00151 double myOffsetInRange; //difference between the previous entry value and value 00152 QgsColorRampShader::ColorRampItem myColorRampItem; 00153 while ( mCurrentColorRampItemIndex >= 0 && mCurrentColorRampItemIndex < myColorRampItemCount ) 00154 { 00155 //Start searching from the last index - assumtion is that neighboring pixels tend to be similar values 00156 myColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex ); 00157 myTinyDiff = qAbs( theValue - myColorRampItem.value ); 00158 //If the previous entry is less, then search closer to the top of the list (assumes mColorRampItemList is sorted) 00159 if ( mCurrentColorRampItemIndex != 0 && theValue <= mColorRampItemList.at( mCurrentColorRampItemIndex - 1 ).value ) 00160 { 00161 mCurrentColorRampItemIndex--; 00162 } 00163 else if ( mCurrentColorRampItemIndex != 0 && ( theValue <= myColorRampItem.value || myTinyDiff <= DOUBLE_DIFF_THRESHOLD ) ) 00164 { 00165 QgsColorRampShader::ColorRampItem myPreviousColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex - 1 ); 00166 myCurrentRampRange = myColorRampItem.value - myPreviousColorRampItem.value; 00167 myOffsetInRange = theValue - myPreviousColorRampItem.value; 00168 00169 *theReturnRedValue = ( int )(( double ) myPreviousColorRampItem.color.red() + ((( double )( myColorRampItem.color.red() - myPreviousColorRampItem.color.red() ) / myCurrentRampRange ) * myOffsetInRange ) ); 00170 *theReturnGreenValue = ( int )(( double ) myPreviousColorRampItem.color.green() + ((( double )( myColorRampItem.color.green() - myPreviousColorRampItem.color.green() ) / myCurrentRampRange ) * myOffsetInRange ) ); 00171 *theReturnBlueValue = ( int )(( double ) myPreviousColorRampItem.color.blue() + ((( double )( myColorRampItem.color.blue() - myPreviousColorRampItem.color.blue() ) / myCurrentRampRange ) * myOffsetInRange ) ); 00172 if ( mMaximumColorCacheSize >= mColorCache.size() ) 00173 { 00174 QColor myNewColor( *theReturnRedValue, *theReturnGreenValue, *theReturnBlueValue ); 00175 mColorCache.insert( theValue, myNewColor ); 00176 } 00177 return true; 00178 } 00179 else if ( mCurrentColorRampItemIndex == 0 && theValue <= myColorRampItem.value ) 00180 { 00181 QgsColorRampShader::ColorRampItem myPreviousColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex - 1 ); 00182 myCurrentRampRange = myColorRampItem.value - myPreviousColorRampItem.value; 00183 myOffsetInRange = theValue - myPreviousColorRampItem.value; 00184 00185 *theReturnRedValue = myColorRampItem.color.red(); 00186 *theReturnGreenValue = myColorRampItem.color.green(); 00187 *theReturnBlueValue = myColorRampItem.color.blue(); 00188 if ( mMaximumColorCacheSize >= mColorCache.size() ) 00189 { 00190 QColor myNewColor( *theReturnRedValue, *theReturnGreenValue, *theReturnBlueValue ); 00191 mColorCache.insert( theValue, myNewColor ); 00192 } 00193 return true; 00194 } 00195 //Search deeper into the color ramp list 00196 else if ( theValue > myColorRampItem.value ) 00197 { 00198 mCurrentColorRampItemIndex++; 00199 } 00200 else 00201 { 00202 return false; 00203 } 00204 } 00205 00206 return false; 00207 } 00208 00209 void QgsColorRampShader::setColorRampItemList( const QList<QgsColorRampShader::ColorRampItem>& theList ) 00210 { 00211 mColorRampItemList = theList; 00212 //Clear the cache 00213 mColorCache.clear(); 00214 } 00215 00216 void QgsColorRampShader::setColorRampType( QgsColorRampShader::ColorRamp_TYPE theColorRampType ) 00217 { 00218 //When the ramp type changes we need to clear out the cache 00219 mColorCache.clear(); 00220 mColorRampType = theColorRampType; 00221 } 00222 00223 void QgsColorRampShader::setColorRampType( QString theType ) 00224 { 00225 //When the type of the ramp changes we need to clear out the cache 00226 mColorCache.clear(); 00227 if ( theType == "INTERPOLATED" ) 00228 { 00229 mColorRampType = INTERPOLATED; 00230 } 00231 else if ( theType == "DISCRETE" ) 00232 { 00233 mColorRampType = DISCRETE; 00234 } 00235 else 00236 { 00237 mColorRampType = EXACT; 00238 } 00239 } 00240 00241 bool QgsColorRampShader::shade( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue ) 00242 { 00243 00244 //Get the shaded value from the cache if it exists already 00245 QColor myColor = mColorCache.value( theValue ); 00246 if ( myColor.isValid() ) 00247 { 00248 *theReturnRedValue = myColor.red(); 00249 *theReturnGreenValue = myColor.green(); 00250 *theReturnBlueValue = myColor.blue(); 00251 return true; 00252 } 00253 00254 //pixel value not in cache so generate new value 00255 00256 //Check to be sure mCurrentColorRampItemIndex is within the valid range. 00257 if ( mCurrentColorRampItemIndex < 0 ) 00258 { 00259 mCurrentColorRampItemIndex = 0; 00260 } 00261 else if ( mCurrentColorRampItemIndex >= mColorRampItemList.size() ) 00262 { 00263 mCurrentColorRampItemIndex = mColorRampItemList.size() - 1; 00264 } 00265 00266 if ( QgsColorRampShader::EXACT == mColorRampType ) 00267 { 00268 return exactColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue ); 00269 } 00270 else if ( QgsColorRampShader::INTERPOLATED == mColorRampType ) 00271 { 00272 return interpolatedColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue ); 00273 } 00274 00275 return discreteColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue ); 00276 } 00277 00278 bool QgsColorRampShader::shade( double theRedValue, double theGreenValue, double theBlueValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue ) 00279 { 00280 *theReturnRedValue = 0; 00281 *theReturnGreenValue = 0; 00282 *theReturnBlueValue = 0; 00283 00284 return false; 00285 }