package org.jcae.viewer3d.post;
import java.awt.Color;
/**
* Map colors on values.
* This class properly handle set of values including Float.NEGATIVE_INFINITY,
* but positive infinity will lead to unexpected behavior.
* @author Jerome Robert
*/
public class DefaultColorMapper implements ColorMapper
{
private float min=0;
private float max=1;
private boolean haveInfinity=false;
private float minInf=0;
private int paletteSize=1;
/**
* Create a color mapper with the following caracteristics:
* <ul>
* <li>min=0</li>
* <li>max=1</li>
* <li>palletteSize=1</li>
* </ul>
*/
public DefaultColorMapper()
{
//nothing
}
/**
* Create a mapper for a given set of values
* @param values Extract the min and max value from this array
* @param paletteSize The number of color to generate
* @todo Call DefaultColorMapper(float, float, boolean, int)
*/
public DefaultColorMapper(float[] values, int paletteSize)
{
ArrayTool at=new ArrayTool(values);
setMin(at.getMin());
setMax(at.getMax());
setNegativeInfinity(at.haveNegativeInfinity());
this.paletteSize=paletteSize;
}
/**
* Create a mapper for a set of values whose only min and max are known
* @param max greated value
* @param min smallest <strong>finit</strong> value
* @param infinity true if the values include Float.NEGATIVE_INFINITY
*/
public DefaultColorMapper( float min, float max, boolean infinity, int paletteSize)
{
setMin(min);
setMax(max);
setNegativeInfinity(infinity);
this.paletteSize=paletteSize;
}
/**
* Return the palette in the RGB format.
* The size of the return array is 3 times the size of the palette.
* Note that this method do not use min and max values as it always
* return an HSB palette from red to blue through green.
*/
public byte[] getPalette()
{
byte[] palette=new byte[paletteSize*3];
if(paletteSize>1)
for(int i=0; i<paletteSize; i++)
{
Color c=Color.getHSBColor((1f-(float)i/(paletteSize-1))*2f/3f, 1f, 1f);
palette[3*i]=(byte) c.getRed();
palette[3*i+1]=(byte) c.getGreen();
palette[3*i+2]=(byte) c.getBlue();
}
return palette;
}
/**
* Return the color index in the palette for the given value.
* This is a discret mapping.
*/
public int map(float value)
{
if(value==Float.NEGATIVE_INFINITY)
value=minInf;
int toReturn=(int) (paletteSize*(value-minInf)/(max-minInf));
if(toReturn>=paletteSize)
toReturn=paletteSize-1;
if(toReturn<0)
toReturn=0;
//System.out.println(value +"=>"+ toReturn );
return toReturn;
}
/**
* Return the color for the given value.
* This is a continues mapping (i.e. the returned value may not be in
* the palette).
*/
public Color mapColor(float value)
{
if(value==Float.NEGATIVE_INFINITY)
value=minInf;
float v=(value-minInf)/(max-minInf);
if(v<0f) v=0f;
if(v>1f) v=1f;
return Color.getHSBColor((1f-v)*2f/3f, 1f, 1f);
}
/**
* Set the color associated to the value into the destination array
* This is a continues mapping (.e. the returned value may not be in
* the palette).
* This methods aims at being use in loop to fill large destination
* arrays. Each element of the destination array is a ARGB color
* encoded on one integer: 0xffRRGGBB.
*/
public void mapColor(float value, int[] dst, int index)
{
if (value == Float.NEGATIVE_INFINITY) value = minInf;
float v = (value - minInf) / (max - minInf);
if (v < 0f) v = 0f;
if (v > 1f) v = 1f;
float hue = (1f - v) * 2f / 3f;
int r = 0, g = 0, b = 0;
float h = (hue - (float) Math.floor(hue)) * 6.0f;
float f = h - (float) java.lang.Math.floor(h);
float q = (1.0f - f);
float t = f;
switch ((int) h)
{
case 0 :
r = 255;
g = (int) (t * 255.0f + 0.5f);
break;
case 1 :
r = (int) (q * 255.0f + 0.5f);
g = 255;
break;
case 2 :
g = 255;
b = (int) (t * 255.0f + 0.5f);
break;
case 3 :
g = (int) (q * 255.0f + 0.5f);
b = 255;
break;
case 4 :
r = (int) (t * 255.0f + 0.5f);
b = 255;
break;
case 5 :
r = 255;
b = (int) (q * 255.0f + 0.5f);
break;
}
dst[index] = 0xff000000 | (r << 16) | (g << 8) | (b << 0);
}
/**
* Set the <strong>finit</strong> smallest value
*/
public void setMin(float min)
{
this.min=min;
setNegativeInfinity(haveInfinity);
}
/**
* Set the greatest value
*/
public void setMax(float max)
{
this.max=max;
}
/**
* Specifiy that the working set of value contains Float.NEGATIVE_INFINITY.
*/
public void setNegativeInfinity(boolean b)
{
haveInfinity=b;
if(b)
{
minInf=min-(max-min)/10;
}
else
minInf=min;
}
/**
* Get the <strong>finit</strong> smallest value
*/
public float getMin()
{
return min;
}
/**
* Get the greatest value
*/
public float getMax()
{
return max;
}
/**
* Return true is the set of value contains Float.NEGATIVE_INFINITY
*/
public boolean isNegativeInfinity()
{
return haveInfinity;
}
}