Quantum GIS API Documentation  1.7.4
src/core/raster/qgscolorrampshader.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines