Skip to content

Commit 710b581

Browse files
author
ersts
committed
-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 git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@9254 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent 321a84b commit 710b581

File tree

2 files changed

+142
-60
lines changed

2 files changed

+142
-60
lines changed

src/core/raster/qgscolorrampshader.cpp

Lines changed: 135 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -25,32 +25,45 @@ originally part of the larger QgsRasterLayer class
2525
QgsColorRampShader::QgsColorRampShader( double theMinimumValue, double theMaximumValue ) : QgsRasterShaderFunction( theMinimumValue, theMaximumValue )
2626
{
2727
QgsDebugMsg( "called." );
28-
mMaximumColorCacheSize = 256; //good starting value
28+
mMaximumColorCacheSize = 1024; //good starting value
29+
mCurrentColorRampItemIndex = 0;
2930
}
3031

3132
bool QgsColorRampShader::generateShadedValue( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue )
3233
{
33-
//Get the shaded from the cache if it exists already
34+
35+
//Get the shaded value from the cache if it exists already
3436
QColor myColor = mColorCache.value(theValue);
35-
if(myColor.isValid())
37+
if ( myColor.isValid() )
3638
{
3739
*theReturnRedValue = myColor.red();
3840
*theReturnGreenValue = myColor.green();
3941
*theReturnBlueValue = myColor.blue();
4042
return true;
4143
}
4244

43-
//Else we have to generate the shaded value
44-
if ( QgsColorRampShader::INTERPOLATED == mColorRampType )
45+
//pixel value not in cache so generate new value
46+
47+
//Check to be sure mCurrentColorRampItemIndex is within the valid range.
48+
if ( mCurrentColorRampItemIndex < 0 )
4549
{
46-
return getInterpolatedColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue );
50+
mCurrentColorRampItemIndex = 0;
4751
}
48-
else if ( QgsColorRampShader::DISCRETE == mColorRampType )
52+
else if ( mCurrentColorRampItemIndex >= mColorRampItemList.size() )
4953
{
50-
return getDiscreteColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue );
54+
mCurrentColorRampItemIndex = mColorRampItemList.size() - 1;
5155
}
52-
53-
return getExactColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue );
56+
57+
if ( QgsColorRampShader::EXACT == mColorRampType )
58+
{
59+
return getExactColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue );
60+
}
61+
else if ( QgsColorRampShader::INTERPOLATED == mColorRampType )
62+
{
63+
return getInterpolatedColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue );
64+
}
65+
66+
return getDiscreteColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue );
5467
}
5568

5669
bool QgsColorRampShader::generateShadedValue( double theRedValue, double theGreenValue, double theBlueValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue )
@@ -81,102 +94,167 @@ QString QgsColorRampShader::getColorRampTypeAsQString()
8194

8295
bool QgsColorRampShader::getDiscreteColor( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue )
8396
{
84-
if ( mColorRampItemList.count() <= 0 )
97+
int myColorRampItemCount = mColorRampItemList.count();
98+
if ( myColorRampItemCount <= 0 )
8599
{
86100
return false;
87101
}
88-
QList<QgsColorRampShader::ColorRampItem>::const_iterator it;
89-
QList<QgsColorRampShader::ColorRampItem>::const_iterator last_it = mColorRampItemList.begin();
90-
double myCurrentRampValue;
91-
for ( it = mColorRampItemList.begin(); it != mColorRampItemList.end(); ++it )
102+
103+
QgsColorRampShader::ColorRampItem myColorRampItem;
104+
while ( mCurrentColorRampItemIndex >= 0 && mCurrentColorRampItemIndex < myColorRampItemCount )
92105
{
93-
myCurrentRampValue = it->value;
94-
if ( theValue <= myCurrentRampValue )
106+
//Start searching from the last index - assumtion is that neighboring pixels tend to be similar values
107+
myColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex );
108+
//If the previous entry is less, then search closer to the top of the list (assumes mColorRampItemList is sorted)
109+
if ( mCurrentColorRampItemIndex != 0 && theValue <= mColorRampItemList.at( mCurrentColorRampItemIndex - 1 ).value )
95110
{
96-
*theReturnRedValue = it->color.red();
97-
*theReturnGreenValue = it->color.green();
98-
*theReturnBlueValue = it->color.blue();
111+
mCurrentColorRampItemIndex--;
112+
}
113+
else if ( theValue <= myColorRampItem.value )
114+
{
115+
*theReturnRedValue = myColorRampItem.color.red();
116+
*theReturnGreenValue = myColorRampItem.color.green();
117+
*theReturnBlueValue = myColorRampItem.color.blue();
99118
//Cache the shaded value
100-
if(mMaximumColorCacheSize <= mColorCache.size())
119+
if ( mMaximumColorCacheSize >= mColorCache.size() )
101120
{
102-
mColorCache.insert(theValue, it->color);
121+
mColorCache.insert( theValue, myColorRampItem.color );
103122
}
104123
return true;
105124
}
125+
//Search deeper into the color ramp list
126+
else
127+
{
128+
mCurrentColorRampItemIndex++;
129+
}
106130
}
107-
131+
108132
return false; // value not found
109133
}
110134

111135
bool QgsColorRampShader::getExactColor( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue )
112136
{
113-
if ( mColorRampItemList.count() <= 0 )
137+
int myColorRampItemCount = mColorRampItemList.count();
138+
if ( myColorRampItemCount <= 0 )
114139
{
115140
return false;
116141
}
117-
QList<QgsColorRampShader::ColorRampItem>::const_iterator it;
118-
for ( it = mColorRampItemList.begin(); it != mColorRampItemList.end(); ++it )
142+
143+
QgsColorRampShader::ColorRampItem myColorRampItem;
144+
while ( mCurrentColorRampItemIndex >= 0 && mCurrentColorRampItemIndex < myColorRampItemCount )
119145
{
120-
if ( theValue == it->value )
146+
//Start searching from the last index - assumtion is that neighboring pixels tend to be similar values
147+
myColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex );
148+
if ( theValue == myColorRampItem.value )
121149
{
122-
*theReturnRedValue = it->color.red();
123-
*theReturnGreenValue = it->color.green();
124-
*theReturnBlueValue = it->color.blue();
150+
*theReturnRedValue = myColorRampItem.color.red();
151+
*theReturnGreenValue = myColorRampItem.color.green();
152+
*theReturnBlueValue = myColorRampItem.color.blue();
125153
//Cache the shaded value
126-
if(mMaximumColorCacheSize <= mColorCache.size())
154+
if ( mMaximumColorCacheSize >= mColorCache.size() )
127155
{
128-
mColorCache.insert(theValue, it->color);
156+
mColorCache.insert( theValue, myColorRampItem.color );
129157
}
130158
return true;
131159
}
160+
//pixel value sits between ramp entries so bail
161+
else if ( mCurrentColorRampItemIndex != myColorRampItemCount - 1 && theValue > myColorRampItem.value && theValue < mColorRampItemList.at( mCurrentColorRampItemIndex + 1 ).value )
162+
{
163+
return false;
164+
}
165+
//Search deeper into the color ramp list
166+
else if ( theValue > myColorRampItem.value )
167+
{
168+
mCurrentColorRampItemIndex++;
169+
}
170+
//Search back toward the begining of the list
171+
else
172+
{
173+
mCurrentColorRampItemIndex--;
174+
}
132175
}
133176

134177
return false; // value not found
135178
}
136179

137180
bool QgsColorRampShader::getInterpolatedColor( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue )
138181
{
139-
if ( mColorRampItemList.count() <= 0 )
182+
183+
int myColorRampItemCount = mColorRampItemList.count();
184+
if ( myColorRampItemCount <= 0 )
140185
{
141186
return false;
142187
}
143-
QList<QgsColorRampShader::ColorRampItem>::const_iterator it;
144-
QList<QgsColorRampShader::ColorRampItem>::const_iterator last_it = mColorRampItemList.end();
145-
double myCurrentRampValue;
188+
146189
double myCurrentRampRange; //difference between two consecutive entry values
147-
double myDiffTheValueLastRampValue; //difference between value and last entry value
148-
double myDiffCurrentRampValueTheValue; //difference between this entry value and value
149-
150-
for ( it = mColorRampItemList.begin(); it != mColorRampItemList.end(); ++it )
190+
double myOffsetInRange; //difference between the previous entry value and value
191+
QgsColorRampShader::ColorRampItem myColorRampItem;
192+
while ( mCurrentColorRampItemIndex >= 0 && mCurrentColorRampItemIndex < myColorRampItemCount )
151193
{
152-
myCurrentRampValue = it->value;
153-
if ( theValue <= myCurrentRampValue )
194+
//Start searching from the last index - assumtion is that neighboring pixels tend to be similar values
195+
myColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex );
196+
//If the previous entry is less, then search closer to the top of the list (assumes mColorRampItemList is sorted)
197+
if ( mCurrentColorRampItemIndex != 0 && theValue <= mColorRampItemList.at( mCurrentColorRampItemIndex - 1 ).value )
198+
{
199+
mCurrentColorRampItemIndex--;
200+
}
201+
else if ( mCurrentColorRampItemIndex != 0 && theValue <= myColorRampItem.value )
202+
{
203+
QgsColorRampShader::ColorRampItem myPreviousColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex - 1 );
204+
myCurrentRampRange = myColorRampItem.value - myPreviousColorRampItem.value;
205+
myOffsetInRange = theValue - myPreviousColorRampItem.value;
206+
207+
*theReturnRedValue = ( int )(( double ) myPreviousColorRampItem.color.red() + ((( double ) (myColorRampItem.color.red() - myPreviousColorRampItem.color.red()) / myCurrentRampRange ) * myOffsetInRange ));
208+
*theReturnGreenValue = ( int )(( double ) myPreviousColorRampItem.color.green() + ((( double ) (myColorRampItem.color.green() - myPreviousColorRampItem.color.green()) / myCurrentRampRange) * myOffsetInRange ));
209+
*theReturnBlueValue = ( int )(( double ) myPreviousColorRampItem.color.blue() + ((( double ) (myColorRampItem.color.blue() - myPreviousColorRampItem.color.blue()) / myCurrentRampRange ) * myOffsetInRange));
210+
if ( mMaximumColorCacheSize >= mColorCache.size() )
211+
{
212+
QColor myNewColor( *theReturnRedValue, *theReturnGreenValue, *theReturnBlueValue );
213+
mColorCache.insert( theValue, myNewColor );
214+
}
215+
return true;
216+
}
217+
else if ( mCurrentColorRampItemIndex == 0 && theValue <= myColorRampItem.value )
154218
{
155-
if ( last_it != mColorRampItemList.end() )
219+
QgsColorRampShader::ColorRampItem myPreviousColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex - 1 );
220+
myCurrentRampRange = myColorRampItem.value - myPreviousColorRampItem.value;
221+
myOffsetInRange = theValue - myPreviousColorRampItem.value;
222+
223+
*theReturnRedValue = myColorRampItem.color.red();
224+
*theReturnGreenValue = myColorRampItem.color.green();
225+
*theReturnBlueValue = myColorRampItem.color.blue();
226+
if ( mMaximumColorCacheSize >= mColorCache.size() )
156227
{
157-
myCurrentRampRange = myCurrentRampValue - last_it->value;
158-
myDiffTheValueLastRampValue = theValue - last_it->value;
159-
myDiffCurrentRampValueTheValue = myCurrentRampValue - theValue;
160-
161-
*theReturnRedValue = ( int )(( it->color.red() * myDiffTheValueLastRampValue + last_it->color.red() * myDiffCurrentRampValueTheValue ) / myCurrentRampRange );
162-
*theReturnGreenValue = ( int )(( it->color.green() * myDiffTheValueLastRampValue + last_it->color.green() * myDiffCurrentRampValueTheValue ) / myCurrentRampRange );
163-
*theReturnBlueValue = ( int )(( it->color.blue() * myDiffTheValueLastRampValue + last_it->color.blue() * myDiffCurrentRampValueTheValue ) / myCurrentRampRange );
164-
//Cache the shaded value
165-
if(mMaximumColorCacheSize <= mColorCache.size())
166-
{
167-
mColorCache.insert(theValue, it->color);
168-
}
169-
return true;
228+
QColor myNewColor( *theReturnRedValue, *theReturnGreenValue, *theReturnBlueValue );
229+
mColorCache.insert( theValue, myNewColor );
170230
}
231+
return true;
232+
}
233+
//Search deeper into the color ramp list
234+
else if ( theValue > myColorRampItem.value )
235+
{
236+
mCurrentColorRampItemIndex++;
237+
}
238+
else
239+
{
240+
return false;
171241
}
172-
last_it = it;
173242
}
174243

175244
return false;
176245
}
177246

247+
void QgsColorRampShader::setColorRampType( QgsColorRampShader::COLOR_RAMP_TYPE theColorRampType )
248+
{
249+
//When the ramp type changes we need to clear out the cache
250+
mColorCache.clear();
251+
mColorRampType = theColorRampType;
252+
}
253+
178254
void QgsColorRampShader::setColorRampType( QString theType )
179255
{
256+
//When the type of the ramp changes we need to clear out the cache
257+
mColorCache.clear();
180258
if ( theType == "INTERPOLATED" )
181259
{
182260
mColorRampType = INTERPOLATED;

src/core/raster/qgscolorrampshader.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ class CORE_EXPORT QgsColorRampShader : public QgsRasterShaderFunction
6767
int getMaximumColorCacheSize() { return mMaximumColorCacheSize; }
6868

6969
/**Set custom colormap */
70-
void setColorRampItemList( const QList<QgsColorRampShader::ColorRampItem>& theList ) { mColorRampItemList = theList; }
70+
void setColorRampItemList( const QList<QgsColorRampShader::ColorRampItem>& theList ) { mColorRampItemList = theList; } //TODO: sort on set
7171

7272
/**Set the color ramp type*/
73-
void setColorRampType( QgsColorRampShader::COLOR_RAMP_TYPE theColorRampType ) {mColorRampType = theColorRampType;}
73+
void setColorRampType( QgsColorRampShader::COLOR_RAMP_TYPE theColorRampType );
7474

7575
/**Set the color ramp type*/
7676
void setColorRampType( QString );
@@ -93,7 +93,11 @@ class CORE_EXPORT QgsColorRampShader : public QgsRasterShaderFunction
9393

9494
QgsColorRampShader::COLOR_RAMP_TYPE mColorRampType;
9595
QMap<double, QColor> mColorCache;
96-
int mMaximumColorCacheSize; //The color cache could eat a ton of memory if you have 32-bit data
96+
97+
/** Maximum size of the color cache. The color cache could eat a ton of memory if you have 32-bit data */
98+
int mMaximumColorCacheSize;
99+
/** Current index to start searching the color table*/
100+
int mCurrentColorRampItemIndex;
97101
};
98102

99103
#endif

0 commit comments

Comments
 (0)