Quantum GIS API Documentation
1.8
|
00001 /* ************************************************************************** 00002 qgscolorrampshader.cpp - description 00003 ------------------- 00004 begin : Fri Dec 28 2007 00005 copyright : (C) 2007 by Peter J. Ersts 00006 email : [email protected] 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 && 00069 theValue <= mColorRampItemList.at( mCurrentColorRampItemIndex - 1 ).value ) 00070 { 00071 mCurrentColorRampItemIndex--; 00072 } 00073 else if ( theValue <= myColorRampItem.value || myTinyDiff <= DOUBLE_DIFF_THRESHOLD ) 00074 { 00075 *theReturnRedValue = myColorRampItem.color.red(); 00076 *theReturnGreenValue = myColorRampItem.color.green(); 00077 *theReturnBlueValue = myColorRampItem.color.blue(); 00078 //Cache the shaded value 00079 if ( mMaximumColorCacheSize >= mColorCache.size() ) 00080 { 00081 mColorCache.insert( theValue, myColorRampItem.color ); 00082 } 00083 return true; 00084 } 00085 //Search deeper into the color ramp list 00086 else 00087 { 00088 mCurrentColorRampItemIndex++; 00089 } 00090 } 00091 00092 return false; // value not found 00093 } 00094 00095 bool QgsColorRampShader::exactColor( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue ) 00096 { 00097 int myColorRampItemCount = mColorRampItemList.count(); 00098 if ( myColorRampItemCount <= 0 ) 00099 { 00100 return false; 00101 } 00102 00103 double myTinyDiff = 0.0; 00104 QgsColorRampShader::ColorRampItem myColorRampItem; 00105 while ( mCurrentColorRampItemIndex >= 0 && mCurrentColorRampItemIndex < myColorRampItemCount ) 00106 { 00107 //Start searching from the last index - assumtion is that neighboring pixels tend to be similar values 00108 myColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex ); 00109 myTinyDiff = qAbs( theValue - myColorRampItem.value ); 00110 if ( theValue == myColorRampItem.value || myTinyDiff <= DOUBLE_DIFF_THRESHOLD ) 00111 { 00112 *theReturnRedValue = myColorRampItem.color.red(); 00113 *theReturnGreenValue = myColorRampItem.color.green(); 00114 *theReturnBlueValue = myColorRampItem.color.blue(); 00115 //Cache the shaded value 00116 if ( mMaximumColorCacheSize >= mColorCache.size() ) 00117 { 00118 mColorCache.insert( theValue, myColorRampItem.color ); 00119 } 00120 return true; 00121 } 00122 //pixel value sits between ramp entries so bail 00123 else if ( mCurrentColorRampItemIndex != myColorRampItemCount - 1 && 00124 theValue > myColorRampItem.value && theValue < mColorRampItemList.at( 00125 mCurrentColorRampItemIndex + 1 ).value ) 00126 { 00127 return false; 00128 } 00129 //Search deeper into the color ramp list 00130 else if ( theValue > myColorRampItem.value ) 00131 { 00132 mCurrentColorRampItemIndex++; 00133 } 00134 //Search back toward the beginning of the list 00135 else 00136 { 00137 mCurrentColorRampItemIndex--; 00138 } 00139 } 00140 00141 return false; // value not found 00142 } 00143 00144 bool QgsColorRampShader::interpolatedColor( double theValue, int* 00145 theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue ) 00146 { 00147 int myColorRampItemCount = mColorRampItemList.count(); 00148 if ( myColorRampItemCount <= 0 ) 00149 { 00150 return false; 00151 } 00152 00153 double myTinyDiff = 0.0; 00154 double myCurrentRampRange; //difference between two consecutive entry values 00155 double myOffsetInRange; //difference between the previous entry value and value 00156 QgsColorRampShader::ColorRampItem myColorRampItem; 00157 while ( mCurrentColorRampItemIndex >= 0 && mCurrentColorRampItemIndex < myColorRampItemCount ) 00158 { 00159 //Start searching from the last index - assumtion is that neighboring pixels tend to be similar values 00160 myColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex ); 00161 myTinyDiff = qAbs( theValue - myColorRampItem.value ); 00162 //If the previous entry is less, then search closer to the top of the list (assumes mColorRampItemList is sorted) 00163 if ( mCurrentColorRampItemIndex != 0 && theValue <= mColorRampItemList.at( mCurrentColorRampItemIndex - 1 ).value ) 00164 { 00165 mCurrentColorRampItemIndex--; 00166 } 00167 else if ( mCurrentColorRampItemIndex != 0 && ( theValue <= myColorRampItem.value || myTinyDiff <= DOUBLE_DIFF_THRESHOLD ) ) 00168 { 00169 QgsColorRampShader::ColorRampItem myPreviousColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex - 1 ); 00170 myCurrentRampRange = myColorRampItem.value - myPreviousColorRampItem.value; 00171 myOffsetInRange = theValue - myPreviousColorRampItem.value; 00172 00173 *theReturnRedValue = ( int )(( double ) myPreviousColorRampItem.color.red() + ((( double )( myColorRampItem.color.red() - myPreviousColorRampItem.color.red() ) / myCurrentRampRange ) * myOffsetInRange ) ); 00174 *theReturnGreenValue = ( int )(( double ) myPreviousColorRampItem.color.green() + ((( double )( myColorRampItem.color.green() - myPreviousColorRampItem.color.green() ) / myCurrentRampRange ) * myOffsetInRange ) ); 00175 *theReturnBlueValue = ( int )(( double ) myPreviousColorRampItem.color.blue() + ((( double )( myColorRampItem.color.blue() - myPreviousColorRampItem.color.blue() ) / myCurrentRampRange ) * myOffsetInRange ) ); 00176 if ( mMaximumColorCacheSize >= mColorCache.size() ) 00177 { 00178 QColor myNewColor( *theReturnRedValue, *theReturnGreenValue, *theReturnBlueValue ); 00179 mColorCache.insert( theValue, myNewColor ); 00180 } 00181 return true; 00182 } 00183 else if ( mCurrentColorRampItemIndex == 0 && theValue <= myColorRampItem.value ) 00184 { 00185 QgsColorRampShader::ColorRampItem myPreviousColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex - 1 ); 00186 myCurrentRampRange = myColorRampItem.value - myPreviousColorRampItem.value; 00187 myOffsetInRange = theValue - myPreviousColorRampItem.value; 00188 00189 *theReturnRedValue = myColorRampItem.color.red(); 00190 *theReturnGreenValue = myColorRampItem.color.green(); 00191 *theReturnBlueValue = myColorRampItem.color.blue(); 00192 if ( mMaximumColorCacheSize >= mColorCache.size() ) 00193 { 00194 QColor myNewColor( *theReturnRedValue, *theReturnGreenValue, *theReturnBlueValue ); 00195 mColorCache.insert( theValue, myNewColor ); 00196 } 00197 return true; 00198 } 00199 //Search deeper into the color ramp list 00200 else if ( theValue > myColorRampItem.value ) 00201 { 00202 mCurrentColorRampItemIndex++; 00203 } 00204 else 00205 { 00206 return false; 00207 } 00208 } 00209 00210 return false; 00211 } 00212 00213 void QgsColorRampShader::setColorRampItemList( const QList<QgsColorRampShader::ColorRampItem>& theList ) 00214 { 00215 mColorRampItemList = theList; 00216 //Clear the cache 00217 mColorCache.clear(); 00218 } 00219 00220 void QgsColorRampShader::setColorRampType( QgsColorRampShader::ColorRamp_TYPE theColorRampType ) 00221 { 00222 //When the ramp type changes we need to clear out the cache 00223 mColorCache.clear(); 00224 mColorRampType = theColorRampType; 00225 } 00226 00227 void QgsColorRampShader::setColorRampType( QString theType ) 00228 { 00229 //When the type of the ramp changes we need to clear out the cache 00230 mColorCache.clear(); 00231 if ( theType == "INTERPOLATED" ) 00232 { 00233 mColorRampType = INTERPOLATED; 00234 } 00235 else if ( theType == "DISCRETE" ) 00236 { 00237 mColorRampType = DISCRETE; 00238 } 00239 else 00240 { 00241 mColorRampType = EXACT; 00242 } 00243 } 00244 00245 bool QgsColorRampShader::shade( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue ) 00246 { 00247 00248 //Get the shaded value from the cache if it exists already 00249 QColor myColor = mColorCache.value( theValue ); 00250 if ( myColor.isValid() ) 00251 { 00252 *theReturnRedValue = myColor.red(); 00253 *theReturnGreenValue = myColor.green(); 00254 *theReturnBlueValue = myColor.blue(); 00255 return true; 00256 } 00257 00258 //pixel value not in cache so generate new value 00259 00260 //Check to be sure mCurrentColorRampItemIndex is within the valid range. 00261 if ( mCurrentColorRampItemIndex < 0 ) 00262 { 00263 mCurrentColorRampItemIndex = 0; 00264 } 00265 else if ( mCurrentColorRampItemIndex >= mColorRampItemList.size() ) 00266 { 00267 mCurrentColorRampItemIndex = mColorRampItemList.size() - 1; 00268 } 00269 00270 if ( QgsColorRampShader::EXACT == mColorRampType ) 00271 { 00272 return exactColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue ); 00273 } 00274 else if ( QgsColorRampShader::INTERPOLATED == mColorRampType ) 00275 { 00276 return interpolatedColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue ); 00277 } 00278 00279 return discreteColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue ); 00280 } 00281 00282 bool QgsColorRampShader::shade( double theRedValue, double theGreenValue, 00283 double theBlueValue, int* theReturnRedValue, int* theReturnGreenValue, int* 00284 theReturnBlueValue ) 00285 { 00286 Q_UNUSED( theRedValue ); 00287 Q_UNUSED( theGreenValue ); 00288 Q_UNUSED( theBlueValue ); 00289 00290 *theReturnRedValue = 0; 00291 *theReturnGreenValue = 0; 00292 *theReturnBlueValue = 0; 00293 00294 return false; 00295 }