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