Quantum GIS API Documentation  1.8
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 &&
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines