[QGIS Commit] r9254 - trunk/qgis/src/core/raster

svn_qgis at osgeo.org svn_qgis at osgeo.org
Wed Sep 3 18:09:13 EDT 2008


Author: ersts
Date: 2008-09-03 18:09:13 -0400 (Wed, 03 Sep 2008)
New Revision: 9254

Modified:
   trunk/qgis/src/core/raster/qgscolorrampshader.cpp
   trunk/qgis/src/core/raster/qgscolorrampshader.h
Log:
-More intelligent search through color ramp item list
-Fix bug that prevented color cache from working
-Results in significant improvement in rendering speeds for paletted images

Modified: trunk/qgis/src/core/raster/qgscolorrampshader.cpp
===================================================================
--- trunk/qgis/src/core/raster/qgscolorrampshader.cpp	2008-09-03 10:31:46 UTC (rev 9253)
+++ trunk/qgis/src/core/raster/qgscolorrampshader.cpp	2008-09-03 22:09:13 UTC (rev 9254)
@@ -25,14 +25,16 @@
 QgsColorRampShader::QgsColorRampShader( double theMinimumValue, double theMaximumValue ) : QgsRasterShaderFunction( theMinimumValue, theMaximumValue )
 {
   QgsDebugMsg( "called." );
-  mMaximumColorCacheSize = 256; //good starting value
+  mMaximumColorCacheSize = 1024; //good starting value
+  mCurrentColorRampItemIndex = 0;
 }
 
 bool QgsColorRampShader::generateShadedValue( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue )
 {
-  //Get the shaded from the cache if it exists already
+ 
+  //Get the shaded value from the cache if it exists already
   QColor myColor = mColorCache.value(theValue);
-  if(myColor.isValid())
+  if ( myColor.isValid() )
   {
     *theReturnRedValue = myColor.red();
     *theReturnGreenValue = myColor.green();
@@ -40,17 +42,28 @@
     return true;
   }
   
-  //Else we have to generate the shaded value
-  if ( QgsColorRampShader::INTERPOLATED == mColorRampType )
+  //pixel value not in cache so generate new value
+  
+  //Check to be sure mCurrentColorRampItemIndex is within the valid range.
+  if ( mCurrentColorRampItemIndex < 0 )
   {
-    return getInterpolatedColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue );
+    mCurrentColorRampItemIndex = 0;
   }
-  else if ( QgsColorRampShader::DISCRETE == mColorRampType )
+  else if ( mCurrentColorRampItemIndex >= mColorRampItemList.size() )
   {
-    return getDiscreteColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue );
+    mCurrentColorRampItemIndex = mColorRampItemList.size() - 1;
   }
-
-  return getExactColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue );
+  
+  if ( QgsColorRampShader::EXACT == mColorRampType )
+  {
+    return getExactColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue );
+  }
+  else if ( QgsColorRampShader::INTERPOLATED == mColorRampType )
+  {
+    return getInterpolatedColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue );
+  }
+  
+  return getDiscreteColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue );
 }
 
 bool QgsColorRampShader::generateShadedValue( double theRedValue, double theGreenValue, double theBlueValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue )
@@ -81,54 +94,84 @@
 
 bool QgsColorRampShader::getDiscreteColor( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue )
 {
-  if ( mColorRampItemList.count() <= 0 )
+  int myColorRampItemCount = mColorRampItemList.count();
+  if ( myColorRampItemCount <= 0 )
   {
     return false;
   }
-  QList<QgsColorRampShader::ColorRampItem>::const_iterator it;
-  QList<QgsColorRampShader::ColorRampItem>::const_iterator last_it = mColorRampItemList.begin();
-  double myCurrentRampValue;
-  for ( it = mColorRampItemList.begin(); it != mColorRampItemList.end(); ++it )
+  
+  QgsColorRampShader::ColorRampItem myColorRampItem;
+  while ( mCurrentColorRampItemIndex >= 0 && mCurrentColorRampItemIndex < myColorRampItemCount )
   {
-    myCurrentRampValue = it->value;
-    if ( theValue <= myCurrentRampValue )
+    //Start searching from the last index - assumtion is that neighboring pixels tend to be similar values
+    myColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex );
+    //If the previous entry is less, then search closer to the top of the list (assumes mColorRampItemList is sorted)
+    if ( mCurrentColorRampItemIndex != 0 && theValue <= mColorRampItemList.at( mCurrentColorRampItemIndex - 1 ).value )
     {
-      *theReturnRedValue = it->color.red();
-      *theReturnGreenValue = it->color.green();
-      *theReturnBlueValue = it->color.blue();
+      mCurrentColorRampItemIndex--;
+    }
+    else if ( theValue <= myColorRampItem.value )
+    {
+      *theReturnRedValue = myColorRampItem.color.red();
+      *theReturnGreenValue = myColorRampItem.color.green();
+      *theReturnBlueValue = myColorRampItem.color.blue();
       //Cache the shaded value
-      if(mMaximumColorCacheSize <= mColorCache.size())
+      if ( mMaximumColorCacheSize >= mColorCache.size() )
       {
-        mColorCache.insert(theValue, it->color);
+        mColorCache.insert( theValue, myColorRampItem.color );
       }
       return true;
     }
+    //Search deeper into the color ramp list
+    else 
+    {
+      mCurrentColorRampItemIndex++;
+    }
   }
-
+  
   return false; // value not found
 }
 
 bool QgsColorRampShader::getExactColor( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue )
 {
-  if ( mColorRampItemList.count() <= 0 )
+  int myColorRampItemCount = mColorRampItemList.count();
+  if ( myColorRampItemCount <= 0 )
   {
     return false;
   }
-  QList<QgsColorRampShader::ColorRampItem>::const_iterator it;
-  for ( it = mColorRampItemList.begin(); it != mColorRampItemList.end(); ++it )
+  
+  QgsColorRampShader::ColorRampItem myColorRampItem;
+  while ( mCurrentColorRampItemIndex >= 0 && mCurrentColorRampItemIndex < myColorRampItemCount )
   {
-    if ( theValue == it->value )
+    //Start searching from the last index - assumtion is that neighboring pixels tend to be similar values
+    myColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex );
+    if ( theValue == myColorRampItem.value )
     {
-      *theReturnRedValue = it->color.red();
-      *theReturnGreenValue = it->color.green();
-      *theReturnBlueValue = it->color.blue();
+      *theReturnRedValue = myColorRampItem.color.red();
+      *theReturnGreenValue = myColorRampItem.color.green();
+      *theReturnBlueValue = myColorRampItem.color.blue();
       //Cache the shaded value
-      if(mMaximumColorCacheSize <= mColorCache.size())
+      if ( mMaximumColorCacheSize >= mColorCache.size() )
       {
-        mColorCache.insert(theValue, it->color);
+        mColorCache.insert( theValue, myColorRampItem.color );
       }
       return true;
     }
+    //pixel value sits between ramp entries so bail
+    else if ( mCurrentColorRampItemIndex != myColorRampItemCount - 1 && theValue > myColorRampItem.value && theValue < mColorRampItemList.at( mCurrentColorRampItemIndex + 1 ).value )
+    {
+      return false;
+    }
+    //Search deeper into the color ramp list
+    else if ( theValue > myColorRampItem.value )
+    {
+      mCurrentColorRampItemIndex++;
+    }
+    //Search back toward the begining of the list
+    else
+    {
+      mCurrentColorRampItemIndex--; 
+    }
   }
 
   return false; // value not found
@@ -136,47 +179,82 @@
 
 bool QgsColorRampShader::getInterpolatedColor( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue )
 {
-  if ( mColorRampItemList.count() <= 0 )
+
+  int myColorRampItemCount = mColorRampItemList.count();
+  if ( myColorRampItemCount <= 0 )
   {
     return false;
   }
-  QList<QgsColorRampShader::ColorRampItem>::const_iterator it;
-  QList<QgsColorRampShader::ColorRampItem>::const_iterator last_it = mColorRampItemList.end();
-  double myCurrentRampValue;
+  
   double myCurrentRampRange; //difference between two consecutive entry values
-  double myDiffTheValueLastRampValue; //difference between value and last entry value
-  double myDiffCurrentRampValueTheValue; //difference between this entry value and value
-
-  for ( it = mColorRampItemList.begin(); it != mColorRampItemList.end(); ++it )
+  double myOffsetInRange; //difference between the previous entry value and value
+  QgsColorRampShader::ColorRampItem myColorRampItem;
+  while ( mCurrentColorRampItemIndex >= 0 && mCurrentColorRampItemIndex < myColorRampItemCount )
   {
-    myCurrentRampValue = it->value;
-    if ( theValue <= myCurrentRampValue )
+    //Start searching from the last index - assumtion is that neighboring pixels tend to be similar values
+    myColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex );
+    //If the previous entry is less, then search closer to the top of the list (assumes mColorRampItemList is sorted)
+    if ( mCurrentColorRampItemIndex != 0 && theValue <= mColorRampItemList.at( mCurrentColorRampItemIndex - 1 ).value )
     {
-      if ( last_it != mColorRampItemList.end() )
+      mCurrentColorRampItemIndex--;
+    }
+    else if ( mCurrentColorRampItemIndex != 0 && theValue <= myColorRampItem.value )
+    {
+      QgsColorRampShader::ColorRampItem myPreviousColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex - 1 );
+      myCurrentRampRange = myColorRampItem.value - myPreviousColorRampItem.value;
+      myOffsetInRange = theValue - myPreviousColorRampItem.value;
+
+      *theReturnRedValue = ( int )(( double ) myPreviousColorRampItem.color.red() + ((( double ) (myColorRampItem.color.red() - myPreviousColorRampItem.color.red()) / myCurrentRampRange ) * myOffsetInRange ));
+      *theReturnGreenValue = ( int )(( double ) myPreviousColorRampItem.color.green() + ((( double ) (myColorRampItem.color.green() - myPreviousColorRampItem.color.green()) / myCurrentRampRange) * myOffsetInRange ));
+      *theReturnBlueValue = ( int )(( double ) myPreviousColorRampItem.color.blue() + ((( double ) (myColorRampItem.color.blue() - myPreviousColorRampItem.color.blue()) / myCurrentRampRange ) * myOffsetInRange));
+      if ( mMaximumColorCacheSize >= mColorCache.size() )
       {
-        myCurrentRampRange = myCurrentRampValue - last_it->value;
-        myDiffTheValueLastRampValue = theValue - last_it->value;
-        myDiffCurrentRampValueTheValue = myCurrentRampValue - theValue;
+        QColor myNewColor( *theReturnRedValue, *theReturnGreenValue, *theReturnBlueValue );
+        mColorCache.insert( theValue, myNewColor );
+      }
+      return true;
+    }
+    else if ( mCurrentColorRampItemIndex == 0 && theValue <= myColorRampItem.value )
+    {
+      QgsColorRampShader::ColorRampItem myPreviousColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex - 1 );
+      myCurrentRampRange = myColorRampItem.value - myPreviousColorRampItem.value;
+      myOffsetInRange = theValue - myPreviousColorRampItem.value;
 
-        *theReturnRedValue = ( int )(( it->color.red() * myDiffTheValueLastRampValue + last_it->color.red() * myDiffCurrentRampValueTheValue ) / myCurrentRampRange );
-        *theReturnGreenValue = ( int )(( it->color.green() * myDiffTheValueLastRampValue + last_it->color.green() * myDiffCurrentRampValueTheValue ) / myCurrentRampRange );
-        *theReturnBlueValue = ( int )(( it->color.blue() * myDiffTheValueLastRampValue + last_it->color.blue() * myDiffCurrentRampValueTheValue ) / myCurrentRampRange );
-        //Cache the shaded value
-        if(mMaximumColorCacheSize <= mColorCache.size())
-        {
-          mColorCache.insert(theValue, it->color);
-        }
-        return true;
+      *theReturnRedValue = myColorRampItem.color.red();
+      *theReturnGreenValue = myColorRampItem.color.green();
+      *theReturnBlueValue = myColorRampItem.color.blue();
+      if ( mMaximumColorCacheSize >= mColorCache.size() )
+      {
+        QColor myNewColor( *theReturnRedValue, *theReturnGreenValue, *theReturnBlueValue );
+        mColorCache.insert( theValue, myNewColor );
       }
+      return true;
     }
-    last_it = it;
+    //Search deeper into the color ramp list
+    else if ( theValue > myColorRampItem.value )
+    {
+      mCurrentColorRampItemIndex++;
+    }
+    else
+    {
+      return false;
+    }
   }
 
   return false;
 }
 
+void QgsColorRampShader::setColorRampType( QgsColorRampShader::COLOR_RAMP_TYPE theColorRampType ) 
+{
+  //When the ramp type changes we need to clear out the cache
+  mColorCache.clear();
+  mColorRampType = theColorRampType;
+}
+
 void QgsColorRampShader::setColorRampType( QString theType )
 {
+  //When the type of the ramp changes we need to clear out the cache
+  mColorCache.clear();
   if ( theType == "INTERPOLATED" )
   {
     mColorRampType = INTERPOLATED;

Modified: trunk/qgis/src/core/raster/qgscolorrampshader.h
===================================================================
--- trunk/qgis/src/core/raster/qgscolorrampshader.h	2008-09-03 10:31:46 UTC (rev 9253)
+++ trunk/qgis/src/core/raster/qgscolorrampshader.h	2008-09-03 22:09:13 UTC (rev 9254)
@@ -67,10 +67,10 @@
     int getMaximumColorCacheSize() { return mMaximumColorCacheSize; }
 
     /**Set custom colormap */
-    void setColorRampItemList( const QList<QgsColorRampShader::ColorRampItem>& theList ) { mColorRampItemList = theList; }
+    void setColorRampItemList( const QList<QgsColorRampShader::ColorRampItem>& theList ) { mColorRampItemList = theList; } //TODO: sort on set
 
     /**Set the color ramp type*/
-    void setColorRampType( QgsColorRampShader::COLOR_RAMP_TYPE theColorRampType ) {mColorRampType = theColorRampType;}
+    void setColorRampType( QgsColorRampShader::COLOR_RAMP_TYPE theColorRampType );
 
     /**Set the color ramp type*/
     void setColorRampType( QString );
@@ -93,7 +93,11 @@
 
     QgsColorRampShader::COLOR_RAMP_TYPE mColorRampType;
     QMap<double, QColor> mColorCache;
-    int mMaximumColorCacheSize; //The color cache could eat a ton of memory if you have 32-bit data
+    
+    /** Maximum size of the color cache. The color cache could eat a ton of memory if you have 32-bit data */
+    int mMaximumColorCacheSize;
+    /** Current index to start searching the color table*/
+    int mCurrentColorRampItemIndex;
 };
 
 #endif



More information about the QGIS-commit mailing list