Issue #2492 Implemented support for colormapping in different units than the data comes in as. Other changes include NPE fix in RecordTileSetRenderable, glsl cleanup to use structs for code sharing, a topo display fix, and moved viirs colormaps to common
Amend: Fixed precision issue with float comparison, made factory better synchronized. Change-Id: Ie72d8d26ca5dc5ee1a0b5c14ca726edbee3bc1a2 Former-commit-id: ae724ecce3d4c65f8845f3278f9b5eeb5b04908a
This commit is contained in:
parent
7156ac5d4f
commit
3369fbec2d
35 changed files with 1934 additions and 907 deletions
|
@ -195,6 +195,7 @@ public class RecordTileSetRenderable extends TileSetRenderable {
|
|||
// All the images need staging, do bulk request
|
||||
ColorMapData data = retrieveRecordData(bigTile);
|
||||
|
||||
if (data != null) {
|
||||
Rectangle bigTileRect = bigTile.getRectangle();
|
||||
for (int i = 0; i < numTiles; i += 1) {
|
||||
Tile tile = subTiles.get(i);
|
||||
|
@ -204,8 +205,9 @@ public class RecordTileSetRenderable extends TileSetRenderable {
|
|||
Rectangle tileRect = tile.getRectangle();
|
||||
ColorMapData subData = new ColorMapData(
|
||||
BufferSlicer.slice(data.getBuffer(),
|
||||
tileRect, bigTileRect), new int[] {
|
||||
tileRect.width, tileRect.height },
|
||||
tileRect, bigTileRect),
|
||||
new int[] { tileRect.width,
|
||||
tileRect.height },
|
||||
data.getDataType(), data.getDataUnit());
|
||||
|
||||
callbacks.get(i).setRetrievedData(subData);
|
||||
|
@ -219,6 +221,7 @@ public class RecordTileSetRenderable extends TileSetRenderable {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < numTiles; i += 1) {
|
||||
Tile tile = subTiles.get(i);
|
||||
|
|
|
@ -424,6 +424,7 @@ public class VIIRSResource extends
|
|||
}
|
||||
|
||||
colorMapParameters.setDataUnit(dataUnit);
|
||||
colorMapParameters.setColorMapUnit(dataUnit);
|
||||
colorMapParameters.setDisplayUnit(displayUnit);
|
||||
|
||||
colorMapParameters.setColorMapMin(colorMapParameters.getDataMin());
|
||||
|
@ -433,12 +434,14 @@ public class VIIRSResource extends
|
|||
if (scale != null) {
|
||||
UnitConverter displayToData = colorMapParameters
|
||||
.getDisplayToDataConverter();
|
||||
UnitConverter displayToColorMap = colorMapParameters
|
||||
.getDisplayToColorMapConverter();
|
||||
if (scale.getMinValue() != null) {
|
||||
colorMapParameters.setColorMapMin((float) displayToData
|
||||
colorMapParameters.setColorMapMin((float) displayToColorMap
|
||||
.convert(scale.getMinValue()));
|
||||
}
|
||||
if (scale.getMaxValue() != null) {
|
||||
colorMapParameters.setColorMapMax((float) displayToData
|
||||
colorMapParameters.setColorMapMax((float) displayToColorMap
|
||||
.convert(scale.getMaxValue()));
|
||||
}
|
||||
if (scale.getMinValue2() != null) {
|
||||
|
|
|
@ -1,48 +1,32 @@
|
|||
#include <colorUtil>
|
||||
#include <indexing>
|
||||
#include <mapping>
|
||||
|
||||
// Multiplier used to store bit mask safely between 0-1
|
||||
const float maskMultiplier = 8.0;
|
||||
const int RED_BAND = 0;
|
||||
const int GREEN_BAND = 1;
|
||||
const int BLUE_BAND = 2;
|
||||
|
||||
uniform sampler2D rawTex;
|
||||
uniform float naturalMin;
|
||||
uniform float naturalMax;
|
||||
uniform float cmapMin;
|
||||
uniform float cmapMax;
|
||||
uniform int isFloat;
|
||||
|
||||
uniform int band;
|
||||
uniform DataTexture rawData;
|
||||
uniform DataMapping dataMapping;
|
||||
uniform ColorMapping colorMapping;
|
||||
|
||||
uniform sampler2D trueColorTexture;
|
||||
uniform int height;
|
||||
uniform int width;
|
||||
uniform float height;
|
||||
uniform float width;
|
||||
|
||||
uniform float noDataValue;
|
||||
uniform float alphaStep;
|
||||
uniform int band;
|
||||
uniform int expectedMask;
|
||||
|
||||
int toBitMask(float alpha) {
|
||||
return int((alpha * maskMultiplier) + 0.5);
|
||||
}
|
||||
|
||||
float getIndex(sampler2D rawTex, float cmapMin, float cmapMax, float naturalMin, float naturalMax, int isFloat) {
|
||||
vec4 textureValue = texture2D(rawTex, gl_TexCoord[0].st);
|
||||
float naturalVal = textureValue.r;
|
||||
if ( isFloat == 0 ) {
|
||||
naturalVal = ((naturalVal * (naturalMax - naturalMin)) + naturalMin);
|
||||
}
|
||||
|
||||
float index = -1.0;
|
||||
if (naturalVal != noDataValue && naturalVal == naturalVal) {
|
||||
index = findIndex(naturalVal, cmapMin, cmapMax);
|
||||
}
|
||||
return index;
|
||||
float fromBitMask(int bitMask) {
|
||||
return bitMask / maskMultiplier;
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
if ( band == -1 ) {
|
||||
vec4 imageVal = texture2D(rawTex,gl_TexCoord[0].st);
|
||||
vec4 getFinalColor() {
|
||||
vec4 imageVal = texture2D(trueColorTexture, gl_TexCoord[0].st);
|
||||
float r = imageVal.r;
|
||||
float g = imageVal.g;
|
||||
float b = imageVal.b;
|
||||
|
@ -50,41 +34,56 @@ void main(void)
|
|||
|
||||
// Round because of 8-bit floating point precision
|
||||
int bitMask = toBitMask(a);
|
||||
if (expectedMask > 0 && bitMask == expectedMask ) {
|
||||
if (expectedMask > 0 && bitMask == expectedMask) {
|
||||
a = 1.0;
|
||||
} else {
|
||||
a = 0.0;
|
||||
}
|
||||
|
||||
gl_FragColor = vec4(r,g,b,a);
|
||||
} else {
|
||||
return vec4(r, g, b, a);
|
||||
}
|
||||
|
||||
vec4 applyColorBand(int colorband) {
|
||||
vec2 xy = gl_FragCoord.xy;
|
||||
vec4 imageVal = texture2D(rawTex,gl_TexCoord[0].st);
|
||||
vec4 curVal = texture2D(trueColorTexture, vec2((xy.x / float(width)), (xy.y / float(height))));
|
||||
vec4 curVal = texture2D(trueColorTexture,
|
||||
vec2((xy.x / width), (xy.y / height)));
|
||||
|
||||
// Lookup raw data value
|
||||
float dataValue = getDataValue(rawData, gl_TexCoord[0].st);
|
||||
|
||||
float r = curVal.r;
|
||||
float g = curVal.g;
|
||||
float b = curVal.b;
|
||||
float a = curVal.a;
|
||||
|
||||
float index = getIndex(rawTex, cmapMin, cmapMax, naturalMin, naturalMax, isFloat);
|
||||
if ( index != -1.0 ) {
|
||||
if (dataValue != rawData.noDataValue && dataValue == dataValue) {
|
||||
// Convert dataValue to cmapValue
|
||||
float cmapValue = dataToColorMapValue(dataValue, dataMapping);
|
||||
float index = getColorMappingIndex(cmapValue, colorMapping);
|
||||
|
||||
int currentMask = toBitMask(a);
|
||||
int bitValue = (1 << band);
|
||||
if ( band == 0 && index > r ) {
|
||||
if (colorband == RED_BAND && index > r) {
|
||||
r = index;
|
||||
} else if ( band == 1 && index > g ) {
|
||||
} else if (colorband == GREEN_BAND && index > g) {
|
||||
g = index;
|
||||
} else if ( band == 2 && index > b ) {
|
||||
} else if (colorband == BLUE_BAND && index > b) {
|
||||
b = index;
|
||||
}
|
||||
|
||||
if ( (currentMask & bitValue) == 0 ) {
|
||||
if ((currentMask & bitValue) == 0) {
|
||||
// alpha does not contain this bit yet!
|
||||
a = (currentMask | bitValue) / maskMultiplier;
|
||||
a = fromBitMask(currentMask | bitValue);
|
||||
}
|
||||
}
|
||||
|
||||
gl_FragColor = vec4(r,g,b,a);
|
||||
return vec4(r, g, b, a);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
if (band == -1) {
|
||||
gl_FragColor = getFinalColor();
|
||||
} else {
|
||||
gl_FragColor = applyColorBand(band);
|
||||
}
|
||||
}
|
|
@ -35,10 +35,13 @@ import com.raytheon.uf.viz.core.exception.VizException;
|
|||
import com.raytheon.uf.viz.truecolor.extension.ITrueColorImagingExtension;
|
||||
import com.raytheon.uf.viz.truecolor.gl.image.GLTrueColorImage;
|
||||
import com.raytheon.viz.core.gl.ext.GLOffscreenRenderingExtension;
|
||||
import com.raytheon.viz.core.gl.ext.imaging.GLColormappedImageExtension;
|
||||
import com.raytheon.viz.core.gl.ext.imaging.GLDataMappingFactory.GLDataMapping;
|
||||
import com.raytheon.viz.core.gl.glsl.AbstractGLSLImagingExtension;
|
||||
import com.raytheon.viz.core.gl.glsl.GLSLStructFactory;
|
||||
import com.raytheon.viz.core.gl.glsl.GLShaderProgram;
|
||||
import com.raytheon.viz.core.gl.images.AbstractGLColormappedImage;
|
||||
import com.raytheon.viz.core.gl.images.AbstractGLImage;
|
||||
import com.raytheon.viz.core.gl.images.GLColormappedImage;
|
||||
|
||||
/**
|
||||
* GL implementation of the {@link ITrueColorImagingExtension}
|
||||
|
@ -64,9 +67,6 @@ public class GLTrueColorImagingExtension extends AbstractGLSLImagingExtension
|
|||
|
||||
private Channel renderingChannel;
|
||||
|
||||
/** The current rendering bit mask, specifies what bands we rendered */
|
||||
private int currentMask = 0;
|
||||
|
||||
private Map<ColorMapParameters, Object> parameters = new IdentityHashMap<ColorMapParameters, Object>();
|
||||
|
||||
/*
|
||||
|
@ -111,7 +111,6 @@ public class GLTrueColorImagingExtension extends AbstractGLSLImagingExtension
|
|||
GLTrueColorImage trueColorImage = (GLTrueColorImage) image;
|
||||
if (trueColorImage.isRepaint()) {
|
||||
// Reset current bit mask
|
||||
currentMask = 0;
|
||||
parameters.clear();
|
||||
writeToImage = trueColorImage;
|
||||
GLOffscreenRenderingExtension extension = target
|
||||
|
@ -125,9 +124,6 @@ public class GLTrueColorImagingExtension extends AbstractGLSLImagingExtension
|
|||
DrawableImage[] imagesToDraw = trueColorImage
|
||||
.getImages(channel);
|
||||
if (imagesToDraw != null && imagesToDraw.length > 0) {
|
||||
// Mark the channel bit in the current bit mask
|
||||
currentMask |= (1 << channel.ordinal());
|
||||
|
||||
// Make sure images are staged before we mosaic them
|
||||
ImagingSupport.prepareImages(target, imagesToDraw);
|
||||
|
||||
|
@ -160,12 +156,17 @@ public class GLTrueColorImagingExtension extends AbstractGLSLImagingExtension
|
|||
imageCoverage));
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
} else if (image instanceof AbstractGLColormappedImage) {
|
||||
GL gl = target.getGl();
|
||||
|
||||
GLColormappedImageExtension.setupDataMapping(gl,
|
||||
(AbstractGLColormappedImage) image, GL.GL_TEXTURE2,
|
||||
GL.GL_TEXTURE3);
|
||||
// bind on GL_TEXTURE1 as 0 is channel image
|
||||
writeToImage.bind(gl, GL.GL_TEXTURE1);
|
||||
return image;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -190,6 +191,13 @@ public class GLTrueColorImagingExtension extends AbstractGLSLImagingExtension
|
|||
// Unbind the writeToImage from GL_TEXTURE1
|
||||
gl.glActiveTexture(GL.GL_TEXTURE1);
|
||||
gl.glBindTexture(writeToImage.getTextureStorageType(), 0);
|
||||
|
||||
// Unbind the data mapped textures
|
||||
gl.glActiveTexture(GL.GL_TEXTURE2);
|
||||
gl.glBindTexture(GL.GL_TEXTURE_1D, 0);
|
||||
|
||||
gl.glActiveTexture(GL.GL_TEXTURE3);
|
||||
gl.glBindTexture(GL.GL_TEXTURE_1D, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,36 +214,41 @@ public class GLTrueColorImagingExtension extends AbstractGLSLImagingExtension
|
|||
public void loadShaderData(GLShaderProgram program, IImage image,
|
||||
PaintProperties paintProps) throws VizException {
|
||||
if (image instanceof GLTrueColorImage) {
|
||||
GLTrueColorImage glImage = (GLTrueColorImage) image;
|
||||
program.setUniform("band", -1);
|
||||
program.setUniform("rawTex", 0);
|
||||
program.setUniform("expectedMask", currentMask);
|
||||
program.setUniform("trueColorTexture", 0);
|
||||
program.setUniform("expectedMask", glImage.getColorMask());
|
||||
} else {
|
||||
if (image instanceof GLColormappedImage == false) {
|
||||
if (image instanceof AbstractGLColormappedImage == false) {
|
||||
throw new VizException(
|
||||
"Can only render colormapped images in true color");
|
||||
}
|
||||
|
||||
GLColormappedImage cmapImage = (GLColormappedImage) image;
|
||||
AbstractGLColormappedImage cmapImage = (AbstractGLColormappedImage) image;
|
||||
ColorMapParameters colorMapParameters = cmapImage
|
||||
.getColorMapParameters();
|
||||
parameters.put(colorMapParameters, null);
|
||||
int textureType = cmapImage.getTextureType();
|
||||
|
||||
// Set the band image data
|
||||
program.setUniform("rawTex", 0);
|
||||
program.setUniform("naturalMin", colorMapParameters.getDataMin());
|
||||
program.setUniform("naturalMax", colorMapParameters.getDataMax());
|
||||
program.setUniform("cmapMin", colorMapParameters.getColorMapMin());
|
||||
program.setUniform("cmapMax", colorMapParameters.getColorMapMax());
|
||||
program.setUniform("isFloat", textureType == GL.GL_FLOAT
|
||||
|| textureType == GL.GL_HALF_FLOAT_ARB ? 1 : 0);
|
||||
program.setUniform("noDataValue",
|
||||
parameters.put(colorMapParameters, null);
|
||||
|
||||
GLSLStructFactory.createDataTexture(program, "rawData", 0,
|
||||
cmapImage.getDataFormat(),
|
||||
colorMapParameters.getNoDataValue());
|
||||
|
||||
int numMappingValues = 0;
|
||||
GLDataMapping mapping = cmapImage.getDataMapping();
|
||||
if (mapping != null && mapping.isValid()) {
|
||||
numMappingValues = mapping.getNumMappingValues();
|
||||
}
|
||||
GLSLStructFactory.createDataMapping(program, "dataMapping", 2, 3,
|
||||
numMappingValues);
|
||||
|
||||
GLSLStructFactory.createColorMapping(program, "colorMapping", -1,
|
||||
-1, colorMapParameters);
|
||||
|
||||
// Set the composite image data
|
||||
program.setUniform("trueColorTexture", 1);
|
||||
program.setUniform("width", writeToImage.getWidth());
|
||||
program.setUniform("height", writeToImage.getHeight());
|
||||
program.setUniform("width", (float) writeToImage.getWidth());
|
||||
program.setUniform("height", (float) writeToImage.getHeight());
|
||||
|
||||
// Set the band we are rendering to
|
||||
program.setUniform("band", renderingChannel.ordinal());
|
||||
|
|
|
@ -97,6 +97,22 @@ public class GLTrueColorImage extends GLDelegateImage<GLImage> implements
|
|||
this.imageExtent = imageExtent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a bitmask of the expected RGB components to render
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getColorMask() {
|
||||
int colorMask = 0;
|
||||
for (Channel channel : Channel.values()) {
|
||||
DrawableImage[] images = getImages(channel);
|
||||
if (images != null && images.length > 0) {
|
||||
colorMask |= (1 << channel.ordinal());
|
||||
}
|
||||
}
|
||||
return colorMask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the imageExtent
|
||||
*/
|
||||
|
|
|
@ -1,24 +1,21 @@
|
|||
// Simple shader program for applying alpha,brightness, and contrast to the
|
||||
// colormap in the same way they are applied to data
|
||||
#include <mapping>
|
||||
#include <coloring>
|
||||
|
||||
#include <colorUtil>
|
||||
#include <indexing>
|
||||
|
||||
uniform float brightness;
|
||||
uniform float contrast;
|
||||
uniform float alphaVal;
|
||||
uniform ColorMapping colorMapping;
|
||||
uniform ColorModifiers modifiers;
|
||||
|
||||
uniform float bkgrndRed;
|
||||
uniform float bkgrndGreen;
|
||||
uniform float bkgrndBlue;
|
||||
|
||||
uniform sampler1D colorMap;
|
||||
uniform sampler2D alphaMask;
|
||||
|
||||
uniform int applyMask;
|
||||
uniform float logFactor;
|
||||
|
||||
void main(void){
|
||||
sampler1D colorMap = colorMapping.colorMap;
|
||||
float logFactor = colorMapping.logFactor;
|
||||
int applyMask = colorMapping.applyMask;
|
||||
sampler1D alphaMask = colorMapping.alphaMask;
|
||||
|
||||
// Lookup color in colorMap for index
|
||||
float index = gl_TexCoord[0].s;
|
||||
if ( logFactor > 0.0 ) {
|
||||
|
@ -29,10 +26,11 @@ void main(void){
|
|||
// Apply alpha mask if set
|
||||
float alpha = color.a;
|
||||
if ( applyMask == 1 ) {
|
||||
if ( texture2D(alphaMask , vec2(index,index) ).r != 0.0 ) {
|
||||
if ( texture1D(alphaMask , index ).r != 0.0 ) {
|
||||
color = vec4(bkgrndRed, bkgrndGreen, bkgrndBlue, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
if(alpha < 1.0){
|
||||
// blend the color with background color, the colorbar should not be transparent
|
||||
alpha = 1.0;
|
||||
|
@ -42,5 +40,5 @@ void main(void){
|
|||
alpha);
|
||||
}
|
||||
|
||||
gl_FragColor = applyContrastAlphaBrightness(color, alphaVal, brightness, contrast);
|
||||
gl_FragColor = applyColorModifiers(color, modifiers);
|
||||
}
|
|
@ -1,56 +1,24 @@
|
|||
#include <colorUtil>
|
||||
#include <indexing>
|
||||
#include <mapping>
|
||||
#include <coloring>
|
||||
|
||||
uniform float alpha;
|
||||
uniform float brightness;
|
||||
uniform float contrast;
|
||||
uniform int applyMask;
|
||||
uniform float naturalMin;
|
||||
uniform float naturalMax;
|
||||
uniform float cmapMin;
|
||||
uniform float cmapMax;
|
||||
uniform sampler1D colorMap;
|
||||
uniform sampler2D alphaMask;
|
||||
uniform sampler2D rawTex;
|
||||
uniform float colorMapSz;
|
||||
uniform int isFloat;
|
||||
uniform int logarithmic;
|
||||
uniform int mirror;
|
||||
uniform float logFactor;
|
||||
uniform DataTexture rawData;
|
||||
uniform DataMapping dataMapping;
|
||||
uniform ColorMapping colorMapping;
|
||||
uniform ColorModifiers modifiers;
|
||||
|
||||
void main(void) {
|
||||
vec4 textureColor = texture2D(rawTex, gl_TexCoord[0].st);
|
||||
float index = 0.0;
|
||||
float rawValue = textureColor.r;
|
||||
if ( isFloat == 1 ) {
|
||||
if ( logarithmic == 1 ) {
|
||||
index = findFloatIndexLog(rawValue, cmapMin, cmapMax, mirror);
|
||||
} else {
|
||||
index = findFloatIndex(rawValue, cmapMin, cmapMax);
|
||||
}
|
||||
float dataValue = getDataValue(rawData, gl_TexCoord[0].st);
|
||||
|
||||
// Special float handling, -1.0 is NaN
|
||||
if (index == -1.0){
|
||||
// No data check/special NaN check
|
||||
if (dataValue == rawData.noDataValue || dataValue != dataValue) {
|
||||
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
float naturalValue = ((rawValue * (naturalMax - naturalMin)) + naturalMin);
|
||||
index = findIndex(naturalValue, cmapMin, cmapMax);
|
||||
}
|
||||
|
||||
// Lookup color in colorMap for index
|
||||
if ( logFactor > 0.0 ) {
|
||||
index = getLogFactorIndex(index, logFactor);
|
||||
}
|
||||
textureColor = texture1D(colorMap, index).rgba;
|
||||
|
||||
// Apply alpha mask
|
||||
if ( applyMask == 1 ) {
|
||||
if ( texture2D(alphaMask , vec2(index,index) ).r != 0.0 ) {
|
||||
textureColor = vec4(textureColor.rgb, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
gl_FragColor = applyContrastAlphaBrightness(textureColor, alpha, brightness, contrast);
|
||||
// Convert dataValue to cmapValue
|
||||
float cmapValue = dataToColorMapValue(dataValue, dataMapping);
|
||||
// Get color for colormapping, given value
|
||||
vec4 textureColor = getColorByValue(cmapValue, colorMapping);
|
||||
// Apply the color modifiers into gl_FragColor
|
||||
gl_FragColor = applyColorModifiers(textureColor, modifiers);
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
|
||||
vec3 AvgLuminance = vec3(0.5, 0.5, 0.5);
|
||||
|
||||
/**
|
||||
* This function applies the specified alpha, brightness, and contrast values
|
||||
* to the color passed in
|
||||
*/
|
||||
vec4 applyContrastAlphaBrightness(vec4 color, float alpha, float brightness, float contrast){
|
||||
vec3 textureColor3 = vec3(color);
|
||||
vec3 adjustedColor = mix(AvgLuminance, textureColor3, contrast);
|
||||
float curAlpha = min(color.a, alpha);
|
||||
return vec4(adjustedColor.r * brightness, adjustedColor.g * brightness, adjustedColor.b * brightness, curAlpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function calculates a new index to use based on the logFactor
|
||||
*/
|
||||
float getLogFactorIndex(float index, float logFactor) {
|
||||
if (logFactor > 0.0){
|
||||
float minLog = log(logFactor);
|
||||
float maxLog = log(logFactor + 1.0);
|
||||
|
||||
float lg = log(logFactor + index);
|
||||
|
||||
index = (lg - minLog) / (maxLog - minLog);
|
||||
if (index < 0.0){
|
||||
index = 0.0;
|
||||
}
|
||||
else if (index > 1.0){
|
||||
index = 1.0;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
struct ColorModifiers {
|
||||
float alpha;
|
||||
float brightness;
|
||||
float contrast;
|
||||
};
|
||||
|
||||
vec3 AvgLuminance = vec3(0.5, 0.5, 0.5);
|
||||
|
||||
/**
|
||||
* This function applies the specified ColorModifier values to the
|
||||
* color passed in
|
||||
*/
|
||||
vec4 applyColorModifiers(vec4 color, ColorModifiers modifiers){
|
||||
float alpha = modifiers.alpha;
|
||||
float brightness = modifiers.brightness;
|
||||
float contrast = modifiers.contrast;
|
||||
|
||||
vec3 textureColor3 = vec3(color);
|
||||
vec3 adjustedColor = mix(AvgLuminance, textureColor3, contrast);
|
||||
float curAlpha = min(color.a, alpha);
|
||||
return vec4(adjustedColor.r * brightness, adjustedColor.g * brightness, adjustedColor.b * brightness, curAlpha);
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
|
||||
float HALF_FLOAT_NaN = 65504.0;
|
||||
|
||||
/**
|
||||
* This function takes an index number and caps it to the range 0-1
|
||||
*/
|
||||
float capIndex(float index) {
|
||||
if ( index < 0.0 ) {
|
||||
index = 0.0;
|
||||
} else if ( index > 1.0 ) {
|
||||
index = 1.0;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function linearly finds the index for the rawValue into cmapMin/cmapMax.
|
||||
* 65504.0 is treated as NaN for half floats and -1 is returned as special case
|
||||
*/
|
||||
float findFloatIndex(float rawValue, float cmapMin, float cmapMax) {
|
||||
if ( rawValue == HALF_FLOAT_NaN || rawValue != rawValue) {
|
||||
return -1.0;
|
||||
}
|
||||
float index = ((rawValue - cmapMin) / abs(cmapMax-cmapMin));
|
||||
return capIndex(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function logarithmically finds the index for the rawValue into cmapMin/cmapMax.
|
||||
* 65504.0 is treated as NaN for half floats and -1 is returned as special case
|
||||
*/
|
||||
float findFloatIndexLog(float rawValue, float cmapMin, float cmapMax, int mirror) {
|
||||
if ( rawValue == HALF_FLOAT_NaN ) {
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
float index = 0.0;
|
||||
// is this strictly negative, strictly positive or neg to pos scaling?
|
||||
if ( cmapMin >= 0.0 && cmapMax >= 0.0 && mirror!=1) {
|
||||
if(rawValue < cmapMin){
|
||||
index = 0.0;
|
||||
}else{
|
||||
// simple calculation
|
||||
index = ((log(rawValue) - log(cmapMin)) / abs(log(cmapMax)-log(cmapMin)));
|
||||
}
|
||||
} else if (cmapMin <= 0.0 && cmapMax <= 0.0 && mirror!=1) {
|
||||
index = ((log(rawValue) - log(cmapMax)) / abs(log(cmapMin)-log(cmapMax)));
|
||||
} else {
|
||||
// special case, neg to pos:
|
||||
float colorMapMin = cmapMin;
|
||||
float colorMapMax = cmapMax;
|
||||
float zeroVal = max(colorMapMax, abs(colorMapMin)) * 0.0001;
|
||||
if (mirror==1 && (colorMapMin > 0.0 || colorMapMax < 0.0)) {
|
||||
if (colorMapMax < 0.0) {
|
||||
colorMapMax = -cmapMax;
|
||||
rawValue = -rawValue;
|
||||
zeroVal = -colorMapMin;
|
||||
} else {
|
||||
zeroVal = cmapMin;
|
||||
}
|
||||
colorMapMin = -cmapMax;
|
||||
}
|
||||
float leftZero = 0.0;
|
||||
float rightZero = 0.0;
|
||||
float absLogZeroVal = abs(log(zeroVal));
|
||||
|
||||
rightZero = absLogZeroVal + log(colorMapMax);
|
||||
|
||||
float cmapMax2 = abs(colorMapMin);
|
||||
|
||||
leftZero = absLogZeroVal + log(cmapMax2);
|
||||
|
||||
float zeroIndex = leftZero / (leftZero + rightZero);
|
||||
|
||||
// figure out index for texture val
|
||||
float absTextureColor = abs(rawValue);
|
||||
if (absTextureColor <= zeroVal) {
|
||||
index = zeroIndex;
|
||||
} else if (rawValue > 0.0) {
|
||||
// positive texture color value, find index from 0 to
|
||||
// cmapMax:
|
||||
float logTexColor = absLogZeroVal + log(rawValue);
|
||||
|
||||
float texIndex = logTexColor / rightZero;
|
||||
index = (zeroIndex + ((1.0 - zeroIndex) * texIndex));
|
||||
} else {
|
||||
// negative texture color value, find index from 0 to
|
||||
// cmapMax:
|
||||
float logTexColor = absLogZeroVal + log(absTextureColor);
|
||||
|
||||
float texIndex = logTexColor / leftZero;
|
||||
index = (zeroIndex - (zeroIndex * texIndex));
|
||||
}
|
||||
}
|
||||
return capIndex(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a raw data value linearly determine the index(0-1) into cmapMin/cmapMax
|
||||
*/
|
||||
float findIndex(float rawValue, float cmapMin, float cmapMax) {
|
||||
float index = ((rawValue - cmapMin) / abs(cmapMax-cmapMin));
|
||||
return capIndex(index);
|
||||
}
|
|
@ -0,0 +1,299 @@
|
|||
/**
|
||||
* Mapping glsl library for use by other glsl programs. Defines
|
||||
* commonly used structures and functions for data and color mapping
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fields for the raw texture mapping is applied to. isScaled
|
||||
* implied data will range 0-1 and need scaling to get raw value
|
||||
* where scaleMin maps to 0 and scaleMax maps to 1.
|
||||
*/
|
||||
struct DataTexture {
|
||||
sampler2D rawTex;
|
||||
float noDataValue;
|
||||
int isScaled;
|
||||
float scaleMin;
|
||||
float scaleMax;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fields used for converting from image data values to
|
||||
* colormapping data values. Done to avoid conversions in
|
||||
* application code. dmv[i] -> cmv[i]. Linear interpolation
|
||||
* is done where non-exact matches are found. Mappings should
|
||||
* be uploaded as floats so no scaling is needed
|
||||
*/
|
||||
struct DataMapping {
|
||||
sampler1D dataMappingValues;
|
||||
sampler1D colorMappingValues;
|
||||
int numMappingValues;
|
||||
};
|
||||
|
||||
struct ColorMapping {
|
||||
/** Fields for color map and size. colorMap contains colors to
|
||||
* use for mapping. cmapMin/Max is range colormap is applied over */
|
||||
sampler1D colorMap;
|
||||
float cmapMin;
|
||||
float cmapMax;
|
||||
|
||||
/** Field for alpha masking the colors. alphaMask is a texture the
|
||||
* same size as colorMap and contains 0s and 1s, 1 indicating alpha
|
||||
* should be set to completely transparent */
|
||||
int applyMask;
|
||||
sampler1D alphaMask;
|
||||
|
||||
/** Fields for logarithmic and mirrored indexing into the colorMap */
|
||||
int isMirrored;
|
||||
float logFactor;
|
||||
int isLogarithmic;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the data value for the DataTexture at location.
|
||||
*/
|
||||
float getDataValue(DataTexture texture, vec2 location) {
|
||||
vec4 textureValue = texture2D(texture.rawTex, location);
|
||||
float dataValue = textureValue.r;
|
||||
|
||||
if (texture.isScaled == 1) {
|
||||
// Convert to non-scaled value
|
||||
dataValue = ((dataValue * (texture.scaleMax - texture.scaleMin))
|
||||
+ texture.scaleMin);
|
||||
}
|
||||
return dataValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a value in a mapping texture given an index [0-numMappingValues).
|
||||
*/
|
||||
float lookupMappingValue(sampler1D mappingTex, int index,
|
||||
int numMappingValues) {
|
||||
return texture1D(mappingTex, float(index) / float(numMappingValues - 1)).r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a data value into a colorMap value given the DataMapping
|
||||
*/
|
||||
float dataToColorMapValue(float dataValue, DataMapping mapping) {
|
||||
int numMappingValues = mapping.numMappingValues;
|
||||
if (numMappingValues == 0) {
|
||||
// Short circuit if no mapping is needed
|
||||
return dataValue;
|
||||
}
|
||||
|
||||
// Convert to colormap value
|
||||
int lowIndex = 0;
|
||||
int highIndex = numMappingValues - 1;
|
||||
|
||||
float lowValue = lookupMappingValue(mapping.dataMappingValues, lowIndex,
|
||||
numMappingValues);
|
||||
float highValue = lookupMappingValue(mapping.dataMappingValues, highIndex,
|
||||
numMappingValues);
|
||||
int reversed = 0;
|
||||
if (lowValue > highValue) {
|
||||
reversed = 1;
|
||||
float tmp = lowValue;
|
||||
lowValue = highValue;
|
||||
highValue = tmp;
|
||||
}
|
||||
|
||||
int done = 0;
|
||||
// While there is at least one index to check
|
||||
while (done == 0) {
|
||||
int nextIndex = lowIndex + ((highIndex - lowIndex) / 2);
|
||||
if (nextIndex > lowIndex && nextIndex < highIndex) {
|
||||
// Look up next value and determine if it is a high or low
|
||||
float nextValue = lookupMappingValue(mapping.dataMappingValues, nextIndex,
|
||||
numMappingValues);
|
||||
if (nextValue < dataValue) {
|
||||
if (reversed == 0) {
|
||||
lowIndex = nextIndex;
|
||||
} else {
|
||||
highIndex = nextIndex;
|
||||
}
|
||||
lowValue = nextValue;
|
||||
} else {
|
||||
if (reversed == 0) {
|
||||
highIndex = nextIndex;
|
||||
} else {
|
||||
lowIndex = nextIndex;
|
||||
}
|
||||
highValue = nextValue;
|
||||
}
|
||||
} else {
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Percentage dataValue is linearly between low and high value
|
||||
float factor = (dataValue - lowValue) / (highValue - lowValue);
|
||||
if (reversed == 1) {
|
||||
// Reverse factor for high->low indexing
|
||||
factor = 1.0 - factor;
|
||||
}
|
||||
|
||||
float lowCmapValue = lookupMappingValue(mapping.colorMappingValues, lowIndex,
|
||||
numMappingValues);
|
||||
float highCmapValue = lookupMappingValue(mapping.colorMappingValues, highIndex,
|
||||
numMappingValues);
|
||||
|
||||
return lowCmapValue + (highCmapValue - lowCmapValue) * factor;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function takes an index number and caps it to the range 0-1
|
||||
*/
|
||||
float capIndex(float index) {
|
||||
if (index < 0.0) {
|
||||
index = 0.0;
|
||||
} else if (index > 1.0) {
|
||||
index = 1.0;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a colorMap value linearly determine the index (capped at 0-1)
|
||||
* into cmapMin/cmapMax
|
||||
*/
|
||||
float getLinearIndex(float cmapValue, float cmapMin, float cmapMax) {
|
||||
float index = (cmapValue - cmapMin) / (cmapMax - cmapMin);
|
||||
return capIndex(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function logarithmically finds the index for the cmapValue into
|
||||
* cmapMin/cmapMax (capped at 0-1).
|
||||
*/
|
||||
float getLogIndex(float cmapValue, float cmapMin, float cmapMax, int mirror) {
|
||||
float index = 0.0;
|
||||
// is this strictly negative, strictly positive or neg to pos scaling?
|
||||
if (cmapMin >= 0.0 && cmapMax >= 0.0 && mirror != 1) {
|
||||
if (cmapValue < cmapMin) {
|
||||
index = 0.0;
|
||||
} else {
|
||||
// simple calculation
|
||||
index = ((log(cmapValue) - log(cmapMin))
|
||||
/ abs(log(cmapMax) - log(cmapMin)));
|
||||
}
|
||||
} else if (cmapMin <= 0.0 && cmapMax <= 0.0 && mirror != 1) {
|
||||
index = ((log(cmapValue) - log(cmapMax))
|
||||
/ abs(log(cmapMin) - log(cmapMax)));
|
||||
} else {
|
||||
// special case, neg to pos:
|
||||
float colorMapMin = cmapMin;
|
||||
float colorMapMax = cmapMax;
|
||||
float zeroVal = max(colorMapMax, abs(colorMapMin)) * 0.0001;
|
||||
if (mirror == 1 && (colorMapMin > 0.0 || colorMapMax < 0.0)) {
|
||||
if (colorMapMax < 0.0) {
|
||||
colorMapMax = -cmapMax;
|
||||
cmapValue = -cmapValue;
|
||||
zeroVal = -colorMapMin;
|
||||
} else {
|
||||
zeroVal = cmapMin;
|
||||
}
|
||||
colorMapMin = -cmapMax;
|
||||
}
|
||||
float leftZero = 0.0;
|
||||
float rightZero = 0.0;
|
||||
float absLogZeroVal = abs(log(zeroVal));
|
||||
|
||||
rightZero = absLogZeroVal + log(colorMapMax);
|
||||
|
||||
float cmapMax2 = abs(colorMapMin);
|
||||
|
||||
leftZero = absLogZeroVal + log(cmapMax2);
|
||||
|
||||
float zeroIndex = leftZero / (leftZero + rightZero);
|
||||
|
||||
// figure out index for texture val
|
||||
float absTextureColor = abs(cmapValue);
|
||||
if (absTextureColor <= zeroVal) {
|
||||
index = zeroIndex;
|
||||
} else if (cmapValue > 0.0) {
|
||||
// positive texture color value, find index from 0 to
|
||||
// cmapMax:
|
||||
float logTexColor = absLogZeroVal + log(cmapValue);
|
||||
|
||||
float texIndex = logTexColor / rightZero;
|
||||
index = (zeroIndex + ((1.0 - zeroIndex) * texIndex));
|
||||
} else {
|
||||
// negative texture color value, find index from 0 to
|
||||
// cmapMax:
|
||||
float logTexColor = absLogZeroVal + log(absTextureColor);
|
||||
|
||||
float texIndex = logTexColor / leftZero;
|
||||
index = (zeroIndex - (zeroIndex * texIndex));
|
||||
}
|
||||
}
|
||||
return capIndex(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function calculates a new index to use based on the logFactor
|
||||
* and passed in index
|
||||
*/
|
||||
float getLogFactorIndex(float index, float logFactor) {
|
||||
if (logFactor > 0.0) {
|
||||
float minLog = log(logFactor);
|
||||
float maxLog = log(logFactor + 1.0);
|
||||
|
||||
float lg = log(logFactor + index);
|
||||
|
||||
index = (lg - minLog) / (maxLog - minLog);
|
||||
if (index < 0.0) {
|
||||
index = 0.0;
|
||||
} else if (index > 1.0) {
|
||||
index = 1.0;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an index for the cmapValue based on the ColorMapping
|
||||
*/
|
||||
float getColorMappingIndex(float cmapValue, ColorMapping colorMapping) {
|
||||
int logarithmic = colorMapping.isLogarithmic;
|
||||
int mirror = colorMapping.isMirrored;
|
||||
float logFactor = colorMapping.logFactor;
|
||||
float cmapMin = colorMapping.cmapMin;
|
||||
float cmapMax = colorMapping.cmapMax;
|
||||
|
||||
float index;
|
||||
if (logarithmic == 1) {
|
||||
index = getLogIndex(cmapValue, cmapMin, cmapMax, mirror);
|
||||
} else {
|
||||
index = getLinearIndex(cmapValue, cmapMin, cmapMax);
|
||||
}
|
||||
|
||||
// Apply logFactor if set
|
||||
if (logFactor > 0.0) {
|
||||
index = getLogFactorIndex(index, logFactor);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a color for the index based on the ColorMapping
|
||||
*/
|
||||
vec4 getColorByIndex(float index, ColorMapping colorMapping) {
|
||||
// Lookup color in colorMap for index
|
||||
vec4 textureColor = texture1D(colorMapping.colorMap, index).rgba;
|
||||
|
||||
// Apply alpha mask
|
||||
if (colorMapping.applyMask == 1) {
|
||||
if (texture1D(colorMapping.alphaMask, index).r != 0.0) {
|
||||
textureColor = vec4(textureColor.rgb, 0.0);
|
||||
}
|
||||
}
|
||||
return textureColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a color for the cmapValue based on the ColorMapping
|
||||
*/
|
||||
vec4 getColorByValue(float cmapValue, ColorMapping colorMapping) {
|
||||
return getColorByIndex(getColorMappingIndex(cmapValue, colorMapping),
|
||||
colorMapping);
|
||||
}
|
|
@ -1,11 +1,9 @@
|
|||
#include <colorUtil>
|
||||
#include <coloring>
|
||||
|
||||
uniform float brightness;
|
||||
uniform float contrast;
|
||||
uniform float alpha;
|
||||
uniform sampler2D rawTex;
|
||||
uniform ColorModifiers modifiers;
|
||||
|
||||
void main(void) {
|
||||
vec4 textureColor = texture2D(rawTex, gl_TexCoord[0].st);
|
||||
gl_FragColor = applyContrastAlphaBrightness(textureColor, alpha, brightness, contrast);
|
||||
gl_FragColor = applyColorModifiers(textureColor, modifiers);
|
||||
}
|
|
@ -1,13 +1,11 @@
|
|||
#include <colorUtil>
|
||||
#include <coloring>
|
||||
|
||||
uniform float brightness;
|
||||
uniform float contrast;
|
||||
uniform float alpha;
|
||||
uniform sampler2D rawTex;
|
||||
uniform vec3 color;
|
||||
uniform ColorModifiers modifiers;
|
||||
|
||||
void main(void) {
|
||||
vec4 textureColor = texture2D(rawTex, gl_TexCoord[0].st);
|
||||
textureColor.rgb = color;
|
||||
gl_FragColor = applyContrastAlphaBrightness(textureColor, alpha, brightness, contrast);
|
||||
gl_FragColor = applyColorModifiers(textureColor, modifiers);
|
||||
}
|
|
@ -217,7 +217,7 @@ public abstract class AbstractGLColorMapDataFormat {
|
|||
protected Buffer handleBufferSizing(GLColorMapData data, Buffer buffer,
|
||||
int[] dimensions) {
|
||||
int sliceWidth = dimensions[0] * getValuesPerPixel();
|
||||
int sliceHeight = dimensions[1];
|
||||
int sliceHeight = dimensions.length > 1 ? dimensions[1] : 1;
|
||||
int paddedSliceWidth = getAlignedWidth(sliceWidth);
|
||||
|
||||
int totalDataSize = buffer.capacity();
|
||||
|
|
|
@ -54,6 +54,10 @@ public class GLColorMapData {
|
|||
this.dimensions = dimensions;
|
||||
}
|
||||
|
||||
public AbstractGLColorMapDataFormat getDataFormat() {
|
||||
return dataFormat;
|
||||
}
|
||||
|
||||
public int getTextureFormat() {
|
||||
return dataFormat.getTextureFormat();
|
||||
}
|
||||
|
@ -93,6 +97,10 @@ public class GLColorMapData {
|
|||
return dimensions[index];
|
||||
}
|
||||
|
||||
public int getNumDimensions() {
|
||||
return dimensions.length;
|
||||
}
|
||||
|
||||
public int[] getDimensions() {
|
||||
return dimensions;
|
||||
}
|
||||
|
|
|
@ -21,9 +21,11 @@ package com.raytheon.viz.core.gl.ext.imaging;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import javax.measure.unit.Unit;
|
||||
import javax.media.opengl.GL;
|
||||
|
||||
import com.raytheon.uf.common.colormap.image.ColorMapData;
|
||||
import com.raytheon.uf.common.colormap.image.ColorMapData.ColorMapDataType;
|
||||
import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
|
||||
import com.raytheon.uf.viz.core.PixelCoverage;
|
||||
import com.raytheon.uf.viz.core.data.IColorMapDataRetrievalCallback;
|
||||
|
@ -32,10 +34,15 @@ import com.raytheon.uf.viz.core.drawables.IImage;
|
|||
import com.raytheon.uf.viz.core.drawables.PaintProperties;
|
||||
import com.raytheon.uf.viz.core.drawables.ext.colormap.IColormappedImageExtension;
|
||||
import com.raytheon.uf.viz.core.exception.VizException;
|
||||
import com.raytheon.viz.core.gl.dataformat.GLByteDataFormat;
|
||||
import com.raytheon.viz.core.gl.ext.imaging.GLDataMappingFactory.GLDataMapping;
|
||||
import com.raytheon.viz.core.gl.glsl.AbstractGLSLImagingExtension;
|
||||
import com.raytheon.viz.core.gl.glsl.GLSLStructFactory;
|
||||
import com.raytheon.viz.core.gl.glsl.GLShaderProgram;
|
||||
import com.raytheon.viz.core.gl.images.AbstractGLColormappedImage;
|
||||
import com.raytheon.viz.core.gl.images.AbstractGLImage;
|
||||
import com.raytheon.viz.core.gl.images.GLBufferCMTextureData;
|
||||
import com.raytheon.viz.core.gl.images.GLCMTextureData;
|
||||
import com.raytheon.viz.core.gl.images.GLColormappedImage;
|
||||
import com.raytheon.viz.core.gl.objects.GLTextureObject;
|
||||
|
||||
|
@ -53,7 +60,8 @@ import com.raytheon.viz.core.gl.objects.GLTextureObject;
|
|||
* Feb 14, 2013 1616 bsteffen Add option for interpolation of colormap
|
||||
* parameters, disable colormap interpolation
|
||||
* by default.
|
||||
* Oct 16, 2013 2333 mschenke Cleaned up load shader method, used isScaled
|
||||
* Oct 16, 2013 2333 mschenke Cleaned up load shader method, used isScaled.
|
||||
* Added support for colormapping in non-data unit.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -65,7 +73,7 @@ public class GLColormappedImageExtension extends AbstractGLSLImagingExtension
|
|||
implements IColormappedImageExtension {
|
||||
|
||||
private static class GLColormappedImageExtensionData {
|
||||
public GLColormappedImage alphaMaskTexture;
|
||||
public GLCMTextureData alphaMask;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -108,31 +116,10 @@ public class GLColormappedImageExtension extends AbstractGLSLImagingExtension
|
|||
return null;
|
||||
}
|
||||
|
||||
if (usedColorMapParameters.isUseMask()) {
|
||||
final byte[] mask = usedColorMapParameters.getAlphaMask();
|
||||
data.alphaMaskTexture = initializeRaster(
|
||||
new IColorMapDataRetrievalCallback() {
|
||||
@Override
|
||||
public ColorMapData getColorMapData()
|
||||
throws VizException {
|
||||
return new ColorMapData(ByteBuffer.wrap(mask),
|
||||
new int[] { mask.length, 1 });
|
||||
}
|
||||
}, usedColorMapParameters);
|
||||
data.alphaMaskTexture.stage();
|
||||
data.alphaMaskTexture.target(target);
|
||||
}
|
||||
|
||||
// Get and stage colormap texture
|
||||
GLTextureObject cmapTexture = target
|
||||
.getColorMapTexture(usedColorMapParameters);
|
||||
|
||||
if (data.alphaMaskTexture != null) {
|
||||
gl.glActiveTexture(GL.GL_TEXTURE2);
|
||||
gl.glBindTexture(data.alphaMaskTexture.getTextureStorageType(),
|
||||
data.alphaMaskTexture.getTextureid());
|
||||
}
|
||||
|
||||
gl.glActiveTexture(GL.GL_TEXTURE1);
|
||||
cmapTexture.bind(gl, GL.GL_TEXTURE_1D);
|
||||
|
||||
|
@ -147,10 +134,97 @@ public class GLColormappedImageExtension extends AbstractGLSLImagingExtension
|
|||
gl.glTexParameteri(GL.GL_TEXTURE_1D, GL.GL_TEXTURE_MAG_FILTER,
|
||||
GL.GL_NEAREST);
|
||||
}
|
||||
|
||||
if (usedColorMapParameters.isUseMask()) {
|
||||
data.alphaMask = setupAlphaMasking(gl, GL.GL_TEXTURE2,
|
||||
usedColorMapParameters.getAlphaMask());
|
||||
}
|
||||
|
||||
setupDataMapping(gl, glImage, GL.GL_TEXTURE3, GL.GL_TEXTURE4);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a {@link GLCMTextureData} for an alpha mask for use in image
|
||||
* rendering
|
||||
*
|
||||
* @param gl
|
||||
* @param maskTexBinding
|
||||
* @param mask
|
||||
* @return The GLCMTextureData the alpha mask is bound to or null if the
|
||||
* texture failed to initialize
|
||||
* @throws VizException
|
||||
*/
|
||||
public static GLCMTextureData setupAlphaMasking(GL gl, int maskTexBinding,
|
||||
byte[] mask) throws VizException {
|
||||
GLBufferCMTextureData maskData = new GLBufferCMTextureData(
|
||||
new ColorMapData(ByteBuffer.wrap(mask),
|
||||
new int[] { mask.length }, ColorMapDataType.BYTE),
|
||||
new GLByteDataFormat());
|
||||
gl.glActiveTexture(maskTexBinding);
|
||||
if (maskData.loadTexture(gl)) {
|
||||
gl.glBindTexture(maskData.getTextureStorageType(),
|
||||
maskData.getTexId());
|
||||
} else {
|
||||
maskData.dispose();
|
||||
maskData = null;
|
||||
}
|
||||
return maskData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a {@link GLDataMapping} for use in image rendering
|
||||
*
|
||||
* @param gl
|
||||
* @param glImage
|
||||
* @param dataMappedTexBinding
|
||||
* @param colorMappedTexBinding
|
||||
* @throws VizException
|
||||
*/
|
||||
public static void setupDataMapping(GL gl,
|
||||
AbstractGLColormappedImage glImage, int dataMappedTexBinding,
|
||||
int colorMappedTexBinding) throws VizException {
|
||||
ColorMapParameters colorMapParameters = glImage.getColorMapParameters();
|
||||
// Get GLDataMapping and generate if datamapping is not set. If
|
||||
// datamapping is not set, the data has already been mapped to
|
||||
// colorMapUnits and we need not do anything
|
||||
GLDataMapping dataMapping = glImage.getDataMapping();
|
||||
if (dataMapping == null && colorMapParameters.getDataMapping() == null) {
|
||||
Unit<?> colorMapUnit = colorMapParameters.getColorMapUnit();
|
||||
Unit<?> dataUnit = colorMapParameters.getDataUnit();
|
||||
int colorMapSize = colorMapParameters.getColorMap().getSize();
|
||||
float colorMapMin = colorMapParameters.getColorMapMin();
|
||||
float colorMapMax = colorMapParameters.getColorMapMax();
|
||||
dataMapping = GLDataMappingFactory.constructGLDataMapping(gl,
|
||||
dataUnit, colorMapUnit, colorMapMin, colorMapMax,
|
||||
colorMapSize);
|
||||
glImage.setDataMapping(dataMapping);
|
||||
}
|
||||
|
||||
if (dataMapping != null && dataMapping.isValid()) {
|
||||
GLCMTextureData glDataMapping = dataMapping.getDataMapping();
|
||||
gl.glActiveTexture(dataMappedTexBinding);
|
||||
if (glDataMapping.isLoaded() == false) {
|
||||
glDataMapping.loadTexture(gl);
|
||||
}
|
||||
if (glDataMapping.isLoaded()) {
|
||||
gl.glBindTexture(glDataMapping.getTextureStorageType(),
|
||||
glDataMapping.getTexId());
|
||||
}
|
||||
|
||||
GLCMTextureData glColorMapping = dataMapping.getColorMapping();
|
||||
gl.glActiveTexture(colorMappedTexBinding);
|
||||
if (glColorMapping.isLoaded() == false) {
|
||||
glColorMapping.loadTexture(gl);
|
||||
}
|
||||
if (glColorMapping.isLoaded()) {
|
||||
gl.glBindTexture(glColorMapping.getTextureStorageType(),
|
||||
glColorMapping.getTexId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
|
@ -164,16 +238,22 @@ public class GLColormappedImageExtension extends AbstractGLSLImagingExtension
|
|||
AbstractGLImage image, Object data) throws VizException {
|
||||
GLColormappedImageExtensionData imageData = (GLColormappedImageExtensionData) data;
|
||||
GL gl = target.getGl();
|
||||
if (imageData.alphaMaskTexture != null) {
|
||||
gl.glActiveTexture(GL.GL_TEXTURE2);
|
||||
gl.glBindTexture(
|
||||
imageData.alphaMaskTexture.getTextureStorageType(), 0);
|
||||
|
||||
imageData.alphaMaskTexture.dispose();
|
||||
}
|
||||
|
||||
gl.glActiveTexture(GL.GL_TEXTURE1);
|
||||
gl.glBindTexture(GL.GL_TEXTURE_1D, 0);
|
||||
|
||||
if (imageData.alphaMask != null) {
|
||||
gl.glActiveTexture(GL.GL_TEXTURE2);
|
||||
gl.glBindTexture(imageData.alphaMask.getTextureStorageType(), 0);
|
||||
|
||||
imageData.alphaMask.dispose();
|
||||
}
|
||||
|
||||
gl.glActiveTexture(GL.GL_TEXTURE3);
|
||||
gl.glBindTexture(GL.GL_TEXTURE_1D, 0);
|
||||
|
||||
gl.glActiveTexture(GL.GL_TEXTURE4);
|
||||
gl.glBindTexture(GL.GL_TEXTURE_1D, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -210,40 +290,22 @@ public class GLColormappedImageExtension extends AbstractGLSLImagingExtension
|
|||
|
||||
ColorMapParameters colorMapParameters = image.getColorMapParameters();
|
||||
|
||||
program.setUniform("colorMapSz", colorMapParameters.getColorMap()
|
||||
.getSize());
|
||||
boolean isScaled = image.isImageFormatScaled();
|
||||
double dataMin = colorMapParameters.getDataMin();
|
||||
double dataMax = colorMapParameters.getDataMax();
|
||||
if (isScaled) {
|
||||
// get format from image and get data min/max from it
|
||||
dataMin = image.getDataMin();
|
||||
dataMax = image.getDataMax();
|
||||
GLSLStructFactory.createDataTexture(program, "rawData", 0,
|
||||
image.getDataFormat(), colorMapParameters.getNoDataValue());
|
||||
|
||||
int numMappingValues = 0;
|
||||
GLDataMapping mapping = image.getDataMapping();
|
||||
if (mapping != null && mapping.isValid()) {
|
||||
numMappingValues = mapping.getNumMappingValues();
|
||||
}
|
||||
GLSLStructFactory.createDataMapping(program, "dataMapping", 3, 4,
|
||||
numMappingValues);
|
||||
|
||||
double cmapMin = colorMapParameters.getColorMapMin();
|
||||
double cmapMax = colorMapParameters.getColorMapMax();
|
||||
GLSLStructFactory.createColorMapping(program, "colorMapping", 1, 2,
|
||||
colorMapParameters);
|
||||
|
||||
program.setUniform("isFloat", !isScaled);
|
||||
program.setUniform("logarithmic",
|
||||
colorMapParameters.isLogarithmic() ? 1 : 0);
|
||||
program.setUniform("logFactor", colorMapParameters.getLogFactor());
|
||||
program.setUniform("mirror", colorMapParameters.isMirror() ? 1 : 0);
|
||||
|
||||
program.setUniform("applyMask", colorMapParameters.isUseMask() ? 1 : 0);
|
||||
|
||||
program.setUniform("naturalMin", dataMin);
|
||||
program.setUniform("naturalMax", dataMax);
|
||||
program.setUniform("cmapMin", cmapMin);
|
||||
program.setUniform("cmapMax", cmapMax);
|
||||
|
||||
program.setUniform("alphaMask", 2);
|
||||
program.setUniform("colorMap", 1);
|
||||
program.setUniform("rawText", 0);
|
||||
|
||||
program.setUniform("brightness", image.getBrightness());
|
||||
program.setUniform("contrast", image.getContrast());
|
||||
program.setUniform("alpha", paintProps.getAlpha());
|
||||
GLSLStructFactory.createColorModifiers(program, "modifiers",
|
||||
paintProps.getAlpha(), image.getBrightness(),
|
||||
image.getContrast());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,343 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.viz.core.gl.ext.imaging;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.measure.converter.UnitConverter;
|
||||
import javax.measure.unit.Unit;
|
||||
import javax.media.opengl.GL;
|
||||
|
||||
import com.raytheon.uf.common.colormap.image.ColorMapData;
|
||||
import com.raytheon.viz.core.gl.dataformat.GLBufferColorMapData;
|
||||
import com.raytheon.viz.core.gl.dataformat.GLFloatDataFormat;
|
||||
import com.raytheon.viz.core.gl.images.GLBufferCMTextureData;
|
||||
import com.raytheon.viz.core.gl.images.GLCMTextureData;
|
||||
|
||||
/**
|
||||
* Factory class for creation {@link GLDataMapping} objects that can convert
|
||||
* between units
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Oct 24, 2013 2492 mschenke Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author mschenke
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class GLDataMappingFactory {
|
||||
|
||||
/**
|
||||
* Key for {@link GLDataMappingFactory#mappingCache}. Stores fields needed
|
||||
* to generate unique mappings
|
||||
*
|
||||
* @author mschenke
|
||||
*/
|
||||
private static class GLDataMappingKey {
|
||||
|
||||
private final Unit<?> dataUnit;
|
||||
|
||||
private final Unit<?> colorMapUnit;
|
||||
|
||||
private final float colorMapMin;
|
||||
|
||||
private final float colorMapMax;
|
||||
|
||||
private final int colorMapSize;
|
||||
|
||||
public GLDataMappingKey(Unit<?> dataUnit, Unit<?> colorMapUnit,
|
||||
float colorMapMin, float colorMapMax, int colorMapSize) {
|
||||
this.dataUnit = dataUnit;
|
||||
this.colorMapUnit = colorMapUnit;
|
||||
this.colorMapMin = colorMapMin;
|
||||
this.colorMapMax = colorMapMax;
|
||||
this.colorMapSize = colorMapSize;
|
||||
}
|
||||
|
||||
public Unit<?> getDataUnit() {
|
||||
return dataUnit;
|
||||
}
|
||||
|
||||
public Unit<?> getColorMapUnit() {
|
||||
return colorMapUnit;
|
||||
}
|
||||
|
||||
public float getColorMapMin() {
|
||||
return colorMapMin;
|
||||
}
|
||||
|
||||
public float getColorMapMax() {
|
||||
return colorMapMax;
|
||||
}
|
||||
|
||||
public int getColorMapSize() {
|
||||
return colorMapSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + Float.floatToIntBits(colorMapMax);
|
||||
result = prime * result + Float.floatToIntBits(colorMapMin);
|
||||
result = prime * result + colorMapSize;
|
||||
result = prime * result
|
||||
+ ((colorMapUnit == null) ? 0 : colorMapUnit.hashCode());
|
||||
result = prime * result
|
||||
+ ((dataUnit == null) ? 0 : dataUnit.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
GLDataMappingKey other = (GLDataMappingKey) obj;
|
||||
if (Float.floatToIntBits(colorMapMax) != Float
|
||||
.floatToIntBits(other.colorMapMax))
|
||||
return false;
|
||||
if (Float.floatToIntBits(colorMapMin) != Float
|
||||
.floatToIntBits(other.colorMapMin))
|
||||
return false;
|
||||
if (colorMapSize != other.colorMapSize)
|
||||
return false;
|
||||
if (colorMapUnit == null) {
|
||||
if (other.colorMapUnit != null)
|
||||
return false;
|
||||
} else if (!colorMapUnit.equals(other.colorMapUnit))
|
||||
return false;
|
||||
if (dataUnit == null) {
|
||||
if (other.dataUnit != null)
|
||||
return false;
|
||||
} else if (!dataUnit.equals(other.dataUnit))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* GL data mapping object, represents a mapping between units for use in GL
|
||||
*
|
||||
* @author mschenke
|
||||
*/
|
||||
public static class GLDataMapping {
|
||||
|
||||
private final GLDataMappingKey key;
|
||||
|
||||
private GLCMTextureData colorMapping;
|
||||
|
||||
private GLCMTextureData dataMapping;
|
||||
|
||||
private int numMappingValues;
|
||||
|
||||
private int refCount = 1;
|
||||
|
||||
private boolean initialized = false;
|
||||
|
||||
public GLDataMapping(GLDataMappingKey key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public GLCMTextureData getColorMapping() {
|
||||
return colorMapping;
|
||||
}
|
||||
|
||||
public GLCMTextureData getDataMapping() {
|
||||
return dataMapping;
|
||||
}
|
||||
|
||||
public int getNumMappingValues() {
|
||||
return numMappingValues;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return numMappingValues > 0 && colorMapping != null
|
||||
&& dataMapping != null;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
synchronized (mappingCache) {
|
||||
refCount -= 1;
|
||||
if (refCount <= 0) {
|
||||
mappingCache.remove(key);
|
||||
if (colorMapping != null) {
|
||||
colorMapping.dispose();
|
||||
}
|
||||
if (dataMapping != null) {
|
||||
dataMapping.dispose();
|
||||
}
|
||||
refCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void use() {
|
||||
if (refCount == 0) {
|
||||
throw new IllegalStateException(
|
||||
"GLDataMapping has already been disposed");
|
||||
}
|
||||
refCount += 1;
|
||||
}
|
||||
|
||||
private synchronized void initialize(GL gl) {
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
Unit<?> dataUnit = key.getDataUnit();
|
||||
Unit<?> colorMapUnit = key.getColorMapUnit();
|
||||
int colorMapSize = key.getColorMapSize();
|
||||
double colorMapMin = key.getColorMapMin();
|
||||
double colorMapMax = key.getColorMapMax();
|
||||
int numMappings = 0;
|
||||
if (dataUnit != null && colorMapUnit != null
|
||||
&& dataUnit.equals(colorMapUnit) == false
|
||||
&& dataUnit.isCompatible(colorMapUnit)) {
|
||||
// Worst case scenario, one mapping per color
|
||||
double[] colorMapping = new double[colorMapSize];
|
||||
Arrays.fill(colorMapping, Float.NaN);
|
||||
double[] dataMapping = new double[colorMapping.length];
|
||||
Arrays.fill(dataMapping, Float.NaN);
|
||||
|
||||
UnitConverter colorMapToData = colorMapUnit
|
||||
.getConverterTo(dataUnit);
|
||||
double dataMin = colorMapToData.convert(colorMapMin);
|
||||
double dataMax = colorMapToData.convert(colorMapMax);
|
||||
colorMapping[0] = colorMapMin;
|
||||
colorMapping[colorMapping.length - 1] = colorMapMax;
|
||||
dataMapping[0] = dataMin;
|
||||
dataMapping[dataMapping.length - 1] = dataMax;
|
||||
|
||||
numMappings = 2;
|
||||
if (colorMapToData.isLinear() == false) {
|
||||
// Populate the dataMapping/colorMapping arrays
|
||||
double increment = (colorMapMax - colorMapMin)
|
||||
/ (colorMapping.length - 1);
|
||||
for (int i = 1; i < colorMapping.length - 1; ++i) {
|
||||
colorMapping[i] = colorMapMin + (i * increment);
|
||||
dataMapping[i] = colorMapToData
|
||||
.convert(colorMapping[i]);
|
||||
}
|
||||
|
||||
// Search for linearness in the dataMappings.
|
||||
int currEndIndex = 1;
|
||||
double currEndValue = dataMapping[currEndIndex];
|
||||
float currDelta = (float) (currEndValue - dataMapping[0]);
|
||||
for (int i = 2; i < dataMapping.length; ++i) {
|
||||
double nextValue = dataMapping[i];
|
||||
float nextDelta = (float) ((nextValue - currEndValue) / (i - currEndIndex));
|
||||
if (nextDelta == currDelta) {
|
||||
// Remove linear entries
|
||||
dataMapping[currEndIndex] = colorMapping[currEndIndex] = Double.NaN;
|
||||
currEndValue = nextValue;
|
||||
currEndIndex = i;
|
||||
} else {
|
||||
// Non-linear entry found, add mapping
|
||||
numMappings += 1;
|
||||
currEndIndex = i;
|
||||
currEndValue = nextValue;
|
||||
currDelta = nextDelta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Condense the mapping arrays removing nans
|
||||
float[] condensedColorMapping = new float[numMappings];
|
||||
float[] condensedDataMapping = new float[numMappings];
|
||||
|
||||
int index = 0;
|
||||
for (int i = 0; i < colorMapSize && index < numMappings; ++i) {
|
||||
double colorMapVal = colorMapping[i];
|
||||
double dataMapVal = dataMapping[i];
|
||||
if (Double.isNaN(colorMapVal) == false
|
||||
&& Double.isNaN(dataMapVal) == false) {
|
||||
condensedColorMapping[index] = (float) colorMapVal;
|
||||
condensedDataMapping[index] = (float) dataMapVal;
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == numMappings) {
|
||||
this.numMappingValues = numMappings;
|
||||
this.colorMapping = new GLBufferCMTextureData(
|
||||
new GLBufferColorMapData(new ColorMapData(
|
||||
FloatBuffer.wrap(condensedColorMapping),
|
||||
new int[] { numMappings }),
|
||||
new GLFloatDataFormat()));
|
||||
this.dataMapping = new GLBufferCMTextureData(
|
||||
new GLBufferColorMapData(new ColorMapData(
|
||||
FloatBuffer.wrap(condensedDataMapping),
|
||||
new int[] { numMappings }),
|
||||
new GLFloatDataFormat()));
|
||||
}
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<GLDataMappingKey, GLDataMapping> mappingCache = new HashMap<GLDataMappingKey, GLDataMapping>();
|
||||
|
||||
/**
|
||||
* Creates a {@link GLDataMapping} object given the dataUnit, colorMapUnit,
|
||||
* color map min/max, and size of the colormap. Object must be disposed of
|
||||
* when no longer used
|
||||
*
|
||||
* @param gl
|
||||
* @param dataUnit
|
||||
* @param colorMapUnit
|
||||
* @param colorMapMin
|
||||
* @param colorMapMax
|
||||
* @param colorMapSize
|
||||
* @return
|
||||
*/
|
||||
public static GLDataMapping constructGLDataMapping(GL gl, Unit<?> dataUnit,
|
||||
Unit<?> colorMapUnit, float colorMapMin, float colorMapMax,
|
||||
int colorMapSize) {
|
||||
GLDataMapping mapping;
|
||||
synchronized (mappingCache) {
|
||||
GLDataMappingKey key = new GLDataMappingKey(dataUnit, colorMapUnit,
|
||||
colorMapMin, colorMapMax, colorMapSize);
|
||||
mapping = mappingCache.get(key);
|
||||
if (mapping == null) {
|
||||
mapping = new GLDataMapping(key);
|
||||
mappingCache.put(key, mapping);
|
||||
} else {
|
||||
mapping.use();
|
||||
}
|
||||
}
|
||||
mapping.initialize(gl);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
}
|
|
@ -22,6 +22,7 @@ package com.raytheon.viz.core.gl.ext.imaging;
|
|||
import com.raytheon.uf.viz.core.drawables.IImage;
|
||||
import com.raytheon.uf.viz.core.drawables.PaintProperties;
|
||||
import com.raytheon.uf.viz.core.exception.VizException;
|
||||
import com.raytheon.viz.core.gl.glsl.GLSLStructFactory;
|
||||
import com.raytheon.viz.core.gl.glsl.GLShaderProgram;
|
||||
import com.raytheon.viz.core.gl.images.AbstractGLImage;
|
||||
|
||||
|
@ -35,6 +36,8 @@ import com.raytheon.viz.core.gl.images.AbstractGLImage;
|
|||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 16, 2011 mschenke Initial creation
|
||||
* Nov 4, 2013 2492 mschenke Switched to use GLSLStructFactory for
|
||||
* common shader structure use
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -76,10 +79,10 @@ public class GLDefaultImagingExtension extends AbstractGLImagingExtension {
|
|||
}
|
||||
image = (AbstractGLImage) iimage;
|
||||
|
||||
program.setUniform("alpha", paintProps.getAlpha());
|
||||
program.setUniform("brightness", image.getBrightness());
|
||||
program.setUniform("contrast", image.getContrast());
|
||||
program.setUniform("rawTex", 0);
|
||||
GLSLStructFactory.createColorModifiers(program, "modifiers",
|
||||
paintProps.getAlpha(), image.getBrightness(),
|
||||
image.getContrast());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import com.raytheon.uf.viz.core.drawables.PaintProperties;
|
|||
import com.raytheon.uf.viz.core.drawables.ext.ISingleColorImageExtension;
|
||||
import com.raytheon.uf.viz.core.exception.VizException;
|
||||
import com.raytheon.viz.core.gl.glsl.AbstractGLSLImagingExtension;
|
||||
import com.raytheon.viz.core.gl.glsl.GLSLStructFactory;
|
||||
import com.raytheon.viz.core.gl.glsl.GLShaderProgram;
|
||||
import com.raytheon.viz.core.gl.images.GLSingleColorImage;
|
||||
|
||||
|
@ -41,6 +42,8 @@ import com.raytheon.viz.core.gl.images.GLSingleColorImage;
|
|||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 15, 2011 mschenke Initial creation
|
||||
* Nov 4, 2013 2492 mschenke Switched to use GLSLStructFactory for
|
||||
* common shader structure use
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -97,11 +100,11 @@ public class GLSingleColorImageExtension extends AbstractGLSLImagingExtension
|
|||
|
||||
image = (GLSingleColorImage) iimage;
|
||||
|
||||
program.setUniform("brightness", image.getBrightness());
|
||||
program.setUniform("contrast", image.getContrast());
|
||||
program.setUniform("alpha", paintProps.getAlpha());
|
||||
program.setUniform("color", image.getColor());
|
||||
program.setUniform("rawTex", 0);
|
||||
GLSLStructFactory.createColorModifiers(program, "modifiers",
|
||||
paintProps.getAlpha(), image.getBrightness(),
|
||||
image.getContrast());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.viz.core.gl.glsl;
|
||||
|
||||
import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
|
||||
import com.raytheon.viz.core.gl.dataformat.AbstractGLColorMapDataFormat;
|
||||
|
||||
/**
|
||||
* Factory for creating GLSL struct mappings
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Oct 31, 2013 2492 mschenke Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author mschenke
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class GLSLStructFactory {
|
||||
|
||||
private static final String FIELD_SEPERATOR = ".";
|
||||
|
||||
/**
|
||||
* Creates a DataTexture structure in the program with the given name
|
||||
*
|
||||
* @param program
|
||||
* @param name
|
||||
* @param texBinding
|
||||
* @param dataFormat
|
||||
* @param noDataValue
|
||||
*/
|
||||
public static void createDataTexture(GLShaderProgram program, String name,
|
||||
int texBinding, AbstractGLColorMapDataFormat dataFormat,
|
||||
double noDataValue) {
|
||||
setFieldUniform(program, name, "rawTex", texBinding);
|
||||
setFieldUniform(program, name, "noDataValue", noDataValue);
|
||||
setFieldUniform(program, name, "isScaled", dataFormat.isScaled());
|
||||
if (dataFormat.isScaled()) {
|
||||
setFieldUniform(program, name, "scaleMin",
|
||||
dataFormat.getDataFormatMin());
|
||||
setFieldUniform(program, name, "scaleMax",
|
||||
dataFormat.getDataFormatMax());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DataMapping structure in the program with the given name
|
||||
*
|
||||
* @param program
|
||||
* @param name
|
||||
* @param dataMappingTexBinding
|
||||
* @param colorMappingTexBinding
|
||||
* @param numMappingValues
|
||||
*/
|
||||
public static void createDataMapping(GLShaderProgram program, String name,
|
||||
int dataMappingTexBinding, int colorMappingTexBinding,
|
||||
int numMappingValues) {
|
||||
setFieldUniform(program, name, "dataMappingValues",
|
||||
dataMappingTexBinding);
|
||||
setFieldUniform(program, name, "colorMappingValues",
|
||||
colorMappingTexBinding);
|
||||
setFieldUniform(program, name, "numMappingValues", numMappingValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ColorMapping structure in the program with the given name
|
||||
*
|
||||
* @param program
|
||||
* @param name
|
||||
* @param colorMapTexBinding
|
||||
* @param alphaMaskTexBinding
|
||||
* @param parameters
|
||||
*/
|
||||
public static void createColorMapping(GLShaderProgram program, String name,
|
||||
int colorMapTexBinding, int alphaMaskTexBinding,
|
||||
ColorMapParameters parameters) {
|
||||
setFieldUniform(program, name, "colorMap", colorMapTexBinding);
|
||||
setFieldUniform(program, name, "cmapMin", parameters.getColorMapMin());
|
||||
setFieldUniform(program, name, "cmapMax", parameters.getColorMapMax());
|
||||
|
||||
setFieldUniform(program, name, "applyMask", parameters.isUseMask());
|
||||
setFieldUniform(program, name, "alphaMask", alphaMaskTexBinding);
|
||||
|
||||
setFieldUniform(program, name, "isMirrored", parameters.isMirror());
|
||||
setFieldUniform(program, name, "isLogarithmic",
|
||||
parameters.isLogarithmic());
|
||||
setFieldUniform(program, name, "logFactor", parameters.getLogFactor());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ColorModifiers structure in the program with the given name
|
||||
*
|
||||
* @param program
|
||||
* @param name
|
||||
* @param alpha
|
||||
* @param brightness
|
||||
* @param contrast
|
||||
*/
|
||||
public static void createColorModifiers(GLShaderProgram program,
|
||||
String name, float alpha, float brightness, float contrast) {
|
||||
setFieldUniform(program, name, "alpha", alpha);
|
||||
setFieldUniform(program, name, "brightness", brightness);
|
||||
setFieldUniform(program, name, "contrast", contrast);
|
||||
}
|
||||
|
||||
private static void setFieldUniform(GLShaderProgram program,
|
||||
String structName, String fieldName, Object fieldValue) {
|
||||
program.setUniform(structName + FIELD_SEPERATOR + fieldName, fieldValue);
|
||||
}
|
||||
}
|
|
@ -155,7 +155,6 @@ public class GLShaderProgram {
|
|||
gl.glUseProgram(0);
|
||||
state = State.INITIALIZED;
|
||||
}
|
||||
loadedUniforms.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -358,6 +357,7 @@ public class GLShaderProgram {
|
|||
glslContext = -1;
|
||||
}
|
||||
state = State.INVALID;
|
||||
loadedUniforms.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@ import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
|
|||
import com.raytheon.uf.viz.core.drawables.IColormappedImage;
|
||||
import com.raytheon.uf.viz.core.drawables.ext.IImagingExtension;
|
||||
import com.raytheon.uf.viz.core.exception.VizException;
|
||||
import com.raytheon.viz.core.gl.dataformat.AbstractGLColorMapDataFormat;
|
||||
import com.raytheon.viz.core.gl.ext.imaging.GLDataMappingFactory.GLDataMapping;
|
||||
import com.sun.opengl.util.texture.TextureCoords;
|
||||
|
||||
/**
|
||||
|
@ -52,6 +54,8 @@ public abstract class AbstractGLColormappedImage extends AbstractGLImage
|
|||
|
||||
protected GLCMTextureData data;
|
||||
|
||||
private GLDataMapping dataMapping;
|
||||
|
||||
public AbstractGLColormappedImage(GLCMTextureData data,
|
||||
ColorMapParameters params,
|
||||
Class<? extends IImagingExtension> extensionClass) {
|
||||
|
@ -143,6 +147,15 @@ public abstract class AbstractGLColormappedImage extends AbstractGLImage
|
|||
return data.getTexId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the GL format of the texture data
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public AbstractGLColorMapDataFormat getDataFormat() {
|
||||
return data.getDataFormat();
|
||||
}
|
||||
|
||||
/**
|
||||
* the absolute minimum value of a pixel in this image. {@link Double#NaN}
|
||||
* if no absolute minimum exists
|
||||
|
@ -233,6 +246,18 @@ public abstract class AbstractGLColormappedImage extends AbstractGLImage
|
|||
data.dispose();
|
||||
data = null;
|
||||
}
|
||||
if (dataMapping != null) {
|
||||
dataMapping.dispose();
|
||||
dataMapping = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setDataMapping(GLDataMapping dataMapping) {
|
||||
this.dataMapping = dataMapping;
|
||||
}
|
||||
|
||||
public GLDataMapping getDataMapping() {
|
||||
return dataMapping;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.viz.core.gl.images;
|
||||
|
||||
import java.nio.Buffer;
|
||||
|
||||
import javax.measure.unit.Unit;
|
||||
import javax.media.opengl.GL;
|
||||
|
||||
import com.raytheon.uf.common.colormap.image.ColorMapData;
|
||||
import com.raytheon.viz.core.gl.dataformat.AbstractGLColorMapDataFormat;
|
||||
import com.raytheon.viz.core.gl.dataformat.GLBufferColorMapData;
|
||||
|
||||
/**
|
||||
* {@link GLCMTextureData} backed by a {@link Buffer}. The initial functions in
|
||||
* here were moved here from {@link GLRetrievableCMTextureData}
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Oct 23, 2013 2492 mschenke Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author mschenke
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class GLBufferCMTextureData extends GLCMTextureData {
|
||||
|
||||
public GLBufferCMTextureData(ColorMapData data,
|
||||
AbstractGLColorMapDataFormat format) {
|
||||
this(new GLBufferColorMapData(data, format));
|
||||
}
|
||||
|
||||
public GLBufferCMTextureData(GLBufferColorMapData data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GLBufferColorMapData getDataObject() {
|
||||
return (GLBufferColorMapData) super.getDataObject();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see com.raytheon.viz.core.gl.images.GLCMTextureData#isStaged()
|
||||
*/
|
||||
@Override
|
||||
public boolean isStaged() {
|
||||
GLBufferColorMapData data = getDataObject();
|
||||
// Override since we have our required data
|
||||
return data != null && data.getData() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
if (isStaged()) {
|
||||
data = null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* com.raytheon.viz.core.gl.images.GLCMTextureData#uploadTexture2D(javax
|
||||
* .media.opengl.GL, int, int, int)
|
||||
*/
|
||||
@Override
|
||||
protected void createTexture2D(GL gl, int type, int w, int h) {
|
||||
gl.glTexImage2D(type, 0, getTextureInternalFormat(), w, h, 0,
|
||||
getTextureFormat(), getTextureType(), getDataObject().getData()
|
||||
.rewind());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* com.raytheon.viz.core.gl.images.GLCMTextureData#uploadTexture1D(javax
|
||||
* .media.opengl.GL, int, int)
|
||||
*/
|
||||
@Override
|
||||
protected void createTexture1D(GL gl, int type, int w) {
|
||||
gl.glTexImage1D(type, 0, getTextureInternalFormat(), w, 0,
|
||||
getTextureFormat(), getTextureType(), getDataObject().getData()
|
||||
.rewind());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data value at the given coordinates. TODO: Add support for 1D
|
||||
* texture sampling, change x,y to int[] index?
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @return
|
||||
*/
|
||||
public double getValue(int x, int y) {
|
||||
double value = Double.NaN;
|
||||
if (isStaged()) {
|
||||
value = getDataObject().getValue(x, y).doubleValue();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Unit} associated with the data
|
||||
*
|
||||
* @return the dataUnit
|
||||
*/
|
||||
public Unit<?> getDataUnit() {
|
||||
GLBufferColorMapData data = getDataObject();
|
||||
return data != null ? data.getDataUnit() : null;
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ import javax.media.opengl.GL;
|
|||
|
||||
import com.raytheon.uf.common.colormap.image.ColorMapData.ColorMapDataType;
|
||||
import com.raytheon.uf.viz.core.exception.VizException;
|
||||
import com.raytheon.viz.core.gl.dataformat.AbstractGLColorMapDataFormat;
|
||||
import com.raytheon.viz.core.gl.dataformat.GLColorMapData;
|
||||
import com.raytheon.viz.core.gl.objects.GLTextureObject;
|
||||
|
||||
|
@ -40,6 +41,7 @@ import com.raytheon.viz.core.gl.objects.GLTextureObject;
|
|||
* format for offscreen textures.
|
||||
* Oct 16, 2013 2333 mschenke Moved retrievable/Buffer parts out and
|
||||
* into separate class.
|
||||
* Oct 23, 2013 2492 mschenke Added support for 1D textures
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -116,6 +118,9 @@ public class GLCMTextureData {
|
|||
return false;
|
||||
}
|
||||
int type = getTextureStorageType();
|
||||
if (type == GL.GL_NONE) {
|
||||
throw new VizException("Unsupported dimension size for texture");
|
||||
}
|
||||
|
||||
tex = new GLTextureObject(this);
|
||||
tex.bind(gl, type);
|
||||
|
@ -125,7 +130,8 @@ public class GLCMTextureData {
|
|||
gl.glTexParameteri(type, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
|
||||
gl.glTexParameteri(type, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
|
||||
|
||||
if (isDataFormatScaled() && isDataFormatSigned()) {
|
||||
boolean changeScaleAndBias = isDataFormatScaled() && isDataFormatSigned();
|
||||
if (changeScaleAndBias) {
|
||||
// GL maps signed data into the range -1 to 1, but gl trims
|
||||
// this to a valid range of 0 to 1, essentially removing
|
||||
// negative values. Adding a scale and bias remaps this from
|
||||
|
@ -135,20 +141,23 @@ public class GLCMTextureData {
|
|||
gl.glPixelTransferf(GL.GL_RED_BIAS, 0.5f);
|
||||
}
|
||||
|
||||
int w = getDimensionSize(0);
|
||||
int h = getDimensionSize(1);
|
||||
|
||||
createTexture2D(gl, type, w, h);
|
||||
if (type == GL.GL_TEXTURE_1D) {
|
||||
createTexture1D(gl, type, getDimensionSize(0));
|
||||
} else if (type == GL.GL_TEXTURE_2D) {
|
||||
createTexture2D(gl, type, getDimensionSize(0), getDimensionSize(1));
|
||||
}
|
||||
|
||||
if (changeScaleAndBias) {
|
||||
gl.glPixelTransferf(GL.GL_RED_SCALE, 1.0f);
|
||||
gl.glPixelTransferf(GL.GL_RED_BIAS, 0.0f);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a 2D texture for type, with width/height w/h. Texture object must
|
||||
* be bound for this call to work using
|
||||
* Creates a 2D texture for type, with width/height, w/h. Texture object
|
||||
* must be bound for this call to work using
|
||||
* {@link GLTextureObject#bind(GL, int)}
|
||||
*
|
||||
* @param gl
|
||||
|
@ -163,6 +172,22 @@ public class GLCMTextureData {
|
|||
getTextureFormat(), getTextureType(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a 1D texture for type, with width, w. Texture object must be
|
||||
* bound for this call to work using {@link GLTextureObject#bind(GL, int)}
|
||||
*
|
||||
* @param gl
|
||||
* @param type
|
||||
* @param w
|
||||
* @param h
|
||||
*/
|
||||
protected void createTexture1D(GL gl, int type, int w) {
|
||||
// Allocate our space on the graphics card, no buffer to upload so it
|
||||
// will be filled with default values initially (0s)
|
||||
gl.glTexImage1D(type, 0, getTextureInternalFormat(), w, 0,
|
||||
getTextureFormat(), getTextureType(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if texture data is staged. If false, a call to
|
||||
* {@link #stageTexture()} is needed before texture can be loaded
|
||||
|
@ -184,6 +209,15 @@ public class GLCMTextureData {
|
|||
return tex != null && tex.isValid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the GL format of the texture data
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public AbstractGLColorMapDataFormat getDataFormat() {
|
||||
return data.getDataFormat();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the dimension index passed in (0=width,1=height)
|
||||
*
|
||||
|
@ -272,12 +306,20 @@ public class GLCMTextureData {
|
|||
}
|
||||
|
||||
/**
|
||||
* The texture storage type of the data (TEXTURE_2D)
|
||||
* The texture storage type of the data. Will return {@link GL#GL_NONE} if
|
||||
* unsupported dimension is detected
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getTextureStorageType() {
|
||||
switch (data.getNumDimensions()) {
|
||||
case 1:
|
||||
return GL.GL_TEXTURE_1D;
|
||||
case 2:
|
||||
return GL.GL_TEXTURE_2D;
|
||||
default:
|
||||
return GL.GL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,8 +38,9 @@ import com.raytheon.viz.core.gl.internal.cache.ImageCache;
|
|||
import com.raytheon.viz.core.gl.internal.cache.ImageCache.CacheType;
|
||||
|
||||
/**
|
||||
* Object that represents a colormapped texture that can be unloaded and
|
||||
* reloaded from main/graphics memory using a retrieval callback
|
||||
* {@link GLCMTextureData} that's backed by a {@link Buffer} that represents a
|
||||
* colormapped texture that is cacheable and can be unloaded and reloaded from
|
||||
* main/graphics memory using a retrieval callback
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
|
@ -48,6 +49,7 @@ import com.raytheon.viz.core.gl.internal.cache.ImageCache.CacheType;
|
|||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 24, 2013 mschenke Initial creation
|
||||
* Oct 23, 2013 2492 mschenke Extracted Buffer backing into super class
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -55,7 +57,7 @@ import com.raytheon.viz.core.gl.internal.cache.ImageCache.CacheType;
|
|||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class GLRetrievableCMTextureData extends GLCMTextureData implements
|
||||
public class GLRetrievableCMTextureData extends GLBufferCMTextureData implements
|
||||
IImageCacheable {
|
||||
|
||||
private static Map<IColorMapDataRetrievalCallback, GLRetrievableCMTextureData> texMap = new HashMap<IColorMapDataRetrievalCallback, GLRetrievableCMTextureData>();
|
||||
|
@ -95,11 +97,6 @@ public class GLRetrievableCMTextureData extends GLCMTextureData implements
|
|||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GLBufferColorMapData getDataObject() {
|
||||
return (GLBufferColorMapData) super.getDataObject();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
|
@ -224,18 +221,6 @@ public class GLRetrievableCMTextureData extends GLCMTextureData implements
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see com.raytheon.viz.core.gl.images.GLCMTextureData#isStaged()
|
||||
*/
|
||||
@Override
|
||||
public boolean isStaged() {
|
||||
GLBufferColorMapData data = getDataObject();
|
||||
// Override since we have our required data
|
||||
return data != null && data.getData() != null;
|
||||
}
|
||||
|
||||
public double getValue(int x, int y) {
|
||||
GLBufferColorMapData data = getDataObject();
|
||||
double value = Double.NaN;
|
||||
|
@ -265,27 +250,4 @@ public class GLRetrievableCMTextureData extends GLCMTextureData implements
|
|||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* com.raytheon.viz.core.gl.images.GLCMTextureData#uploadTexture2D(javax
|
||||
* .media.opengl.GL, int, int, int)
|
||||
*/
|
||||
@Override
|
||||
protected void createTexture2D(GL gl, int type, int w, int h) {
|
||||
gl.glTexImage2D(type, 0, getTextureInternalFormat(), w, h, 0,
|
||||
getTextureFormat(), getTextureType(), getDataObject().getData()
|
||||
.rewind());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Unit} associated with the data
|
||||
*
|
||||
* @return the dataUnit
|
||||
*/
|
||||
public Unit<?> getDataUnit() {
|
||||
GLBufferColorMapData data = getDataObject();
|
||||
return data != null ? data.getDataUnit() : null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ import org.geotools.coverage.grid.GeneralGridGeometry;
|
|||
import com.raytheon.uf.common.colormap.ColorMap;
|
||||
import com.raytheon.uf.common.colormap.IColorMap;
|
||||
import com.raytheon.uf.common.colormap.image.ColorMapData;
|
||||
import com.raytheon.uf.common.colormap.image.ColorMapData.ColorMapDataType;
|
||||
import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
|
||||
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||
import com.raytheon.uf.common.status.UFStatus;
|
||||
|
@ -67,7 +68,6 @@ import com.raytheon.uf.viz.core.DrawableString;
|
|||
import com.raytheon.uf.viz.core.IExtent;
|
||||
import com.raytheon.uf.viz.core.IGraphicsTarget;
|
||||
import com.raytheon.uf.viz.core.IView;
|
||||
import com.raytheon.uf.viz.core.data.IColorMapDataRetrievalCallback;
|
||||
import com.raytheon.uf.viz.core.data.IRenderedImageCallback;
|
||||
import com.raytheon.uf.viz.core.drawables.IDescriptor;
|
||||
import com.raytheon.uf.viz.core.drawables.IFont;
|
||||
|
@ -86,11 +86,12 @@ import com.raytheon.viz.core.gl.GLDisposalManager;
|
|||
import com.raytheon.viz.core.gl.GLStats;
|
||||
import com.raytheon.viz.core.gl.IGLFont;
|
||||
import com.raytheon.viz.core.gl.IGLTarget;
|
||||
import com.raytheon.viz.core.gl.ext.imaging.GLColormappedImageExtension;
|
||||
import com.raytheon.viz.core.gl.dataformat.GLByteDataFormat;
|
||||
import com.raytheon.viz.core.gl.ext.imaging.GLDefaultImagingExtension;
|
||||
import com.raytheon.viz.core.gl.glsl.GLSLFactory;
|
||||
import com.raytheon.viz.core.gl.glsl.GLSLStructFactory;
|
||||
import com.raytheon.viz.core.gl.glsl.GLShaderProgram;
|
||||
import com.raytheon.viz.core.gl.images.GLColormappedImage;
|
||||
import com.raytheon.viz.core.gl.images.GLBufferCMTextureData;
|
||||
import com.raytheon.viz.core.gl.images.GLImage;
|
||||
import com.raytheon.viz.core.gl.objects.GLTextureObject;
|
||||
import com.sun.opengl.util.Screenshot;
|
||||
|
@ -128,6 +129,7 @@ import com.sun.opengl.util.j2d.TextRenderer;
|
|||
* strings are always readable despite extent
|
||||
* May 28, 2013 1638 mschenke Made sure {@link TextStyle#BLANKED} text is drawing correct size
|
||||
* box around text
|
||||
* Nov 4, 2013 2492 mschenke Switched colormap drawing to use 1D texture object for alpha mask
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -517,28 +519,19 @@ public class GLTarget extends AbstractGraphicsTarget implements IGLTarget {
|
|||
|
||||
GLTextureObject i = getColorMapTexture(colorMapParams);
|
||||
|
||||
GLColormappedImage alphaMaskTexture = null;
|
||||
GLBufferCMTextureData alphaMaskTexture = null;
|
||||
if (colorMapParams.isUseMask() && capabilities.cardSupportsShaders) {
|
||||
final byte[] mask = colorMapParams.getAlphaMask();
|
||||
alphaMaskTexture = getExtension(
|
||||
GLColormappedImageExtension.class).initializeRaster(
|
||||
new IColorMapDataRetrievalCallback() {
|
||||
@Override
|
||||
public ColorMapData getColorMapData()
|
||||
throws VizException {
|
||||
return new ColorMapData(ByteBuffer.wrap(mask),
|
||||
new int[] { mask.length, 1 });
|
||||
}
|
||||
|
||||
}, colorMapParams);
|
||||
alphaMaskTexture.stage();
|
||||
alphaMaskTexture.target(this);
|
||||
}
|
||||
|
||||
if (alphaMaskTexture != null) {
|
||||
byte[] mask = colorMapParams.getAlphaMask();
|
||||
alphaMaskTexture = new GLBufferCMTextureData(new ColorMapData(
|
||||
ByteBuffer.wrap(mask), new int[] { mask.length },
|
||||
ColorMapDataType.BYTE), new GLByteDataFormat());
|
||||
gl.glActiveTexture(GL.GL_TEXTURE1);
|
||||
if (alphaMaskTexture.loadTexture(gl)) {
|
||||
gl.glBindTexture(alphaMaskTexture.getTextureStorageType(),
|
||||
alphaMaskTexture.getTextureid());
|
||||
alphaMaskTexture.getTexId());
|
||||
} else {
|
||||
alphaMaskTexture.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
gl.glPolygonMode(GL.GL_BACK, GL.GL_FILL);
|
||||
|
@ -573,14 +566,11 @@ public class GLTarget extends AbstractGraphicsTarget implements IGLTarget {
|
|||
"colormap");
|
||||
if (program != null) {
|
||||
program.startShader();
|
||||
program.setUniform("alphaVal", blendAlpha);
|
||||
program.setUniform("brightness", brightness);
|
||||
program.setUniform("contrast", contrast);
|
||||
program.setUniform("colorMap", 0);
|
||||
program.setUniform("logFactor", logFactor);
|
||||
program.setUniform("alphaMask", 1);
|
||||
program.setUniform("applyMask",
|
||||
colorMapParams.isUseMask() ? 1 : 0);
|
||||
|
||||
GLSLStructFactory.createColorMapping(program,
|
||||
"colorMapping", 0, 1, colorMapParams);
|
||||
GLSLStructFactory.createColorModifiers(program,
|
||||
"modifiers", blendAlpha, brightness, contrast);
|
||||
program.setUniform("bkgrndRed",
|
||||
backgroundColor.red / 255.0f);
|
||||
program.setUniform("bkgrndGreen",
|
||||
|
|
|
@ -25,7 +25,6 @@ import java.text.DecimalFormat;
|
|||
import java.util.Arrays;
|
||||
|
||||
import javax.measure.converter.UnitConverter;
|
||||
import javax.measure.unit.NonSI;
|
||||
import javax.measure.unit.SI;
|
||||
import javax.measure.unit.Unit;
|
||||
import javax.measure.unit.UnitFormat;
|
||||
|
@ -40,10 +39,10 @@ import com.raytheon.uf.common.datastorage.IDataStore;
|
|||
import com.raytheon.uf.common.geospatial.ReferencedCoordinate;
|
||||
import com.raytheon.uf.common.style.LabelingPreferences;
|
||||
import com.raytheon.uf.common.style.ParamLevelMatchCriteria;
|
||||
import com.raytheon.uf.common.style.StyleException;
|
||||
import com.raytheon.uf.common.style.StyleManager;
|
||||
import com.raytheon.uf.common.style.StyleManager.StyleType;
|
||||
import com.raytheon.uf.common.style.StyleRule;
|
||||
import com.raytheon.uf.common.style.StyleException;
|
||||
import com.raytheon.uf.common.style.image.DataScale;
|
||||
import com.raytheon.uf.common.style.image.ImagePreferences;
|
||||
import com.raytheon.uf.common.style.image.SamplePreferences;
|
||||
|
@ -148,7 +147,8 @@ public class TopoResource extends
|
|||
|
||||
// Set data unit, specify in resource data? Look up in data record?
|
||||
params.setDataUnit(SI.METER);
|
||||
params.setDisplayUnit(NonSI.FOOT);
|
||||
params.setDisplayUnit(SI.METER);
|
||||
params.setColorMapUnit(SI.METER);
|
||||
params.setColorMapMin(-19);
|
||||
params.setColorMapMax(5000);
|
||||
params.setDataMin(Short.MIN_VALUE);
|
||||
|
@ -169,15 +169,17 @@ public class TopoResource extends
|
|||
|
||||
DataScale scale = prefs.getDataScale();
|
||||
if (scale != null) {
|
||||
UnitConverter displayToColorMap = params
|
||||
.getDisplayToColorMapConverter();
|
||||
Double minVal = scale.getMinValue();
|
||||
Double maxVal = scale.getMaxValue();
|
||||
if (minVal != null) {
|
||||
params.setColorMapMin((float) params
|
||||
.getDisplayToDataConverter().convert(minVal));
|
||||
params.setColorMapMin((float) displayToColorMap
|
||||
.convert(minVal));
|
||||
}
|
||||
if (maxVal != null) {
|
||||
params.setColorMapMax((float) params
|
||||
.getDisplayToDataConverter().convert(maxVal));
|
||||
params.setColorMapMax((float) displayToColorMap
|
||||
.convert(maxVal));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,13 +35,18 @@ import java.nio.IntBuffer;
|
|||
import java.nio.ShortBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import javax.measure.converter.UnitConverter;
|
||||
import javax.measure.unit.Unit;
|
||||
|
||||
import com.raytheon.uf.common.colormap.Color;
|
||||
import com.raytheon.uf.common.colormap.IColorMap;
|
||||
import com.raytheon.uf.common.colormap.image.ColorMapData.ColorMapDataType;
|
||||
import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
|
||||
|
||||
/**
|
||||
* Colormapper class
|
||||
* Colormapper class, written to mimic colormapRaster.glsl in java. Any changes
|
||||
* to files mapping.glsl or colormapRaster.glsl will probably need to be
|
||||
* reflected here
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
|
@ -50,6 +55,7 @@ import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
|
|||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 13, 2010 mschenke Initial creation
|
||||
* Feb 15, 2013 1638 mschenke Moved IndexColorModel creation to common.colormap utility
|
||||
* Nov 4, 2013 2492 mschenke Rewritten to model glsl equivalent
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -77,39 +83,42 @@ public class Colormapper {
|
|||
int width = cmapData.getDimensions()[0];
|
||||
int height = cmapData.getDimensions()[1];
|
||||
Buffer buf = cmapData.getBuffer();
|
||||
ColorMapDataType dataType = cmapData.getDataType();
|
||||
|
||||
// Parameters ported from raster.glsl
|
||||
boolean log = parameters.isLogarithmic();
|
||||
double logFactor = parameters.getLogFactor();
|
||||
boolean mirror = parameters.isMirror();
|
||||
double cmapMin = parameters.getColorMapMin();
|
||||
double cmapMax = parameters.getColorMapMax();
|
||||
int colorMapSz = parameters.getColorMap().getSize();
|
||||
|
||||
double diff = Math.abs(cmapMax - cmapMin);
|
||||
|
||||
int dataSize = buf.capacity();
|
||||
byte[] cmapedData = new byte[buf.capacity()];
|
||||
ColorMapDataType dataType = cmapData.getDataType();
|
||||
double noDataValue = parameters.getNoDataValue();
|
||||
Unit<?> dataUnit = cmapData.getDataUnit();
|
||||
if (dataUnit == null) {
|
||||
dataUnit = parameters.getDataUnit();
|
||||
}
|
||||
Unit<?> colorMapUnit = parameters.getColorMapUnit();
|
||||
UnitConverter converter = null;
|
||||
if (dataUnit != null && colorMapUnit != null
|
||||
&& parameters.getDataMapping() == null
|
||||
&& dataUnit.equals(colorMapUnit) == false
|
||||
&& dataUnit.isCompatible(colorMapUnit) == true) {
|
||||
converter = dataUnit.getConverterTo(colorMapUnit);
|
||||
}
|
||||
int numColors = parameters.getColorMap().getSize();
|
||||
byte[] indexArray = new byte[dataSize];
|
||||
|
||||
for (int i = 0; i < dataSize; ++i) {
|
||||
double value = getValue(buf, i, dataType);
|
||||
double index = 0.0f;
|
||||
if (log) {
|
||||
index = findIndexLog(value, logFactor, cmapMin, cmapMax, mirror);
|
||||
} else {
|
||||
index = ((value - cmapMin) / diff);
|
||||
double dataValue = getDataValue(buf, i, dataType);
|
||||
if (Double.isNaN(dataValue) || dataValue == noDataValue) {
|
||||
// Skip, need equivalent of setting alpha to 0
|
||||
continue;
|
||||
}
|
||||
if (index < 0.0) {
|
||||
index = 0.0;
|
||||
} else if (index > 1.0) {
|
||||
index = 1.0;
|
||||
double cmapValue = dataValue;
|
||||
if (converter != null) {
|
||||
cmapValue = converter.convert(dataValue);
|
||||
}
|
||||
cmapedData[i] = findColorIndex(index, logFactor, colorMapSz);
|
||||
|
||||
double index = getColorMappingIndex(cmapValue, parameters);
|
||||
indexArray[i] = (byte) (capIndex(index) * (numColors - 1));
|
||||
}
|
||||
|
||||
IndexColorModel cm = buildColorModel(parameters.getColorMap());
|
||||
|
||||
DataBufferByte byteArray = new DataBufferByte(cmapedData, width
|
||||
DataBufferByte byteArray = new DataBufferByte(indexArray, width
|
||||
* height);
|
||||
|
||||
MultiPixelPackedSampleModel sample = new MultiPixelPackedSampleModel(
|
||||
|
@ -123,114 +132,6 @@ public class Colormapper {
|
|||
return bi;
|
||||
}
|
||||
|
||||
private static double getValue(Buffer buffer, int idx,
|
||||
ColorMapDataType dataType) {
|
||||
switch (dataType) {
|
||||
case BYTE: {
|
||||
return ((ByteBuffer) buffer).get(idx) & 0xFF;
|
||||
}
|
||||
case SIGNED_BYTE: {
|
||||
return ((ByteBuffer) buffer).get(idx);
|
||||
}
|
||||
case SHORT: {
|
||||
return ((ShortBuffer) buffer).get(idx);
|
||||
}
|
||||
case UNSIGNED_SHORT: {
|
||||
return ((ShortBuffer) buffer).get(idx) & 0xFFFF;
|
||||
}
|
||||
case INT: {
|
||||
return ((IntBuffer) buffer).get(idx);
|
||||
}
|
||||
case FLOAT: {
|
||||
return ((FloatBuffer) buffer).get(idx);
|
||||
}
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
private static double findIndexLog(double value, double logFactor,
|
||||
double cmapMin, double cmapMax, boolean mirror) {
|
||||
double index = 0.0;
|
||||
// is this strictly negative, strictly positive or neg to pos scaling?
|
||||
if (cmapMin >= 0.0 && cmapMax >= 0.0 && mirror == false) {
|
||||
if (value < cmapMin) {
|
||||
index = 0.0;
|
||||
} else {
|
||||
// simple calculation
|
||||
index = ((Math.log(value) - Math.log(cmapMin)) / Math.abs(Math
|
||||
.log(cmapMax) - Math.log(cmapMin)));
|
||||
}
|
||||
} else if (cmapMin <= 0.0 && cmapMax <= 0.0 && mirror == false) {
|
||||
index = ((Math.log(value) - Math.log(cmapMax)) / Math.abs(Math
|
||||
.log(cmapMin) - Math.log(cmapMax)));
|
||||
} else {
|
||||
// special case, neg to pos:
|
||||
double colorMapMin = cmapMin;
|
||||
double colorMapMax = cmapMax;
|
||||
double zeroVal = Math.max(colorMapMax, Math.abs(colorMapMin)) * 0.0001;
|
||||
if (mirror && (colorMapMin > 0.0 || colorMapMax < 0.0)) {
|
||||
if (colorMapMax < 0.0) {
|
||||
colorMapMax = -cmapMax;
|
||||
value = -value;
|
||||
zeroVal = -colorMapMin;
|
||||
} else {
|
||||
zeroVal = cmapMin;
|
||||
}
|
||||
colorMapMin = -cmapMax;
|
||||
}
|
||||
double leftZero = 0.0;
|
||||
double rightZero = 0.0;
|
||||
double absLogZeroVal = Math.abs(Math.log(zeroVal));
|
||||
|
||||
rightZero = absLogZeroVal + Math.log(colorMapMax);
|
||||
|
||||
double cmapMax2 = Math.abs(colorMapMin);
|
||||
|
||||
leftZero = absLogZeroVal + Math.log(cmapMax2);
|
||||
|
||||
double zeroIndex = leftZero / (leftZero + rightZero);
|
||||
|
||||
// figure out index for texture val
|
||||
double absTextureColor = Math.abs(value);
|
||||
if (absTextureColor <= zeroVal) {
|
||||
index = zeroIndex;
|
||||
} else if (value > 0.0) {
|
||||
// positive texture color value, find index from 0 to
|
||||
// cmapMax:
|
||||
double logTexColor = absLogZeroVal + Math.log(value);
|
||||
|
||||
double texIndex = logTexColor / rightZero;
|
||||
index = (zeroIndex + ((1.0 - zeroIndex) * texIndex));
|
||||
} else {
|
||||
// negative texture color value, find index from 0 to
|
||||
// cmapMax:
|
||||
double logTexColor = absLogZeroVal + Math.log(absTextureColor);
|
||||
|
||||
double texIndex = logTexColor / leftZero;
|
||||
index = (zeroIndex - (zeroIndex * texIndex));
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
private static byte findColorIndex(double index, double logFactor,
|
||||
int colorMapSz) {
|
||||
if (logFactor > 0.0) {
|
||||
double minLog = Math.log(logFactor);
|
||||
double maxLog = Math.log(logFactor + 1.0);
|
||||
|
||||
double lg = Math.log(logFactor + index);
|
||||
|
||||
index = (lg - minLog) / (maxLog - minLog);
|
||||
if (index < 0.0) {
|
||||
index = 0.0;
|
||||
} else if (index > 1.0) {
|
||||
index = 1.0;
|
||||
}
|
||||
}
|
||||
return (byte) (index * (colorMapSz - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a color model from a color map
|
||||
*
|
||||
|
@ -256,4 +157,264 @@ public class Colormapper {
|
|||
return new IndexColorModel(COLOR_MODEL_NUMBER_BITS, size, red, green,
|
||||
blue, alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an index value into the indexArray for use in a Raster with
|
||||
* IndexColorModel set
|
||||
*
|
||||
* @param dataArray
|
||||
* @param idx
|
||||
* @param idxValue
|
||||
*/
|
||||
public static void setIndexValue(Object dataArray, int idx, int idxValue) {
|
||||
if (dataArray instanceof byte[]) {
|
||||
((byte[]) dataArray)[idx] = (byte) idxValue;
|
||||
} else if (dataArray instanceof short[]) {
|
||||
((short[]) dataArray)[idx] = (short) idxValue;
|
||||
} else if (dataArray instanceof int[]) {
|
||||
((int[]) dataArray)[idx] = idxValue;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported dataArray type: "
|
||||
+ (dataArray != null ? dataArray.getClass() : null));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the double representation of the data value for the Buffer at the
|
||||
* given index
|
||||
*
|
||||
* @param buffer
|
||||
* @param idx
|
||||
* @param dataType
|
||||
* @return
|
||||
*/
|
||||
public static double getDataValue(Buffer buffer, int idx,
|
||||
ColorMapDataType dataType) {
|
||||
switch (dataType) {
|
||||
case BYTE: {
|
||||
return ((ByteBuffer) buffer).get(idx) & 0xFF;
|
||||
}
|
||||
case SIGNED_BYTE: {
|
||||
return ((ByteBuffer) buffer).get(idx);
|
||||
}
|
||||
case SHORT: {
|
||||
return ((ShortBuffer) buffer).get(idx);
|
||||
}
|
||||
case UNSIGNED_SHORT: {
|
||||
return ((ShortBuffer) buffer).get(idx) & 0xFFFF;
|
||||
}
|
||||
case INT: {
|
||||
return ((IntBuffer) buffer).get(idx);
|
||||
}
|
||||
case FLOAT: {
|
||||
return ((FloatBuffer) buffer).get(idx);
|
||||
}
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function takes an index value and caps it to the range 0-1
|
||||
*/
|
||||
public static double capIndex(double index) {
|
||||
if (index < 0.0) {
|
||||
index = 0.0;
|
||||
} else if (index > 1.0) {
|
||||
index = 1.0;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a colorMap value linearly determine the index into cmapMin/cmapMax
|
||||
*
|
||||
* @param cmapValue
|
||||
* @param cmapMin
|
||||
* @param cmapMax
|
||||
* @return
|
||||
*/
|
||||
public static double getLinearIndex(double cmapValue, double cmapMin,
|
||||
double cmapMax) {
|
||||
return (cmapValue - cmapMin) / (cmapMax - cmapMin);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function logarithmically finds the index for the cmapValue into
|
||||
* cmapMin/cmapMax.
|
||||
*
|
||||
* @param cmapValue
|
||||
* @param cmapMin
|
||||
* @param cmapMax
|
||||
* @param mirror
|
||||
* @return
|
||||
*/
|
||||
public static double getLogIndex(double cmapValue, double cmapMin,
|
||||
double cmapMax, boolean mirror) {
|
||||
double index = 0.0;
|
||||
// is this strictly negative, strictly positive or neg to pos scaling?
|
||||
if (cmapMin >= 0.0 && cmapMax >= 0.0 && !mirror) {
|
||||
if (cmapValue < cmapMin) {
|
||||
index = 0.0;
|
||||
} else {
|
||||
// simple calculation
|
||||
index = ((Math.log(cmapValue) - Math.log(cmapMin)) / Math
|
||||
.abs(Math.log(cmapMax) - Math.log(cmapMin)));
|
||||
}
|
||||
} else if (cmapMin <= 0.0 && cmapMax <= 0.0 && !mirror) {
|
||||
index = ((Math.log(cmapValue) - Math.log(cmapMax)) / Math.abs(Math
|
||||
.log(cmapMin) - Math.log(cmapMax)));
|
||||
} else {
|
||||
// special case, neg to pos:
|
||||
double colorMapMin = cmapMin;
|
||||
double colorMapMax = cmapMax;
|
||||
double zeroVal = Math.max(colorMapMax, Math.abs(colorMapMin)) * 0.0001;
|
||||
if (mirror && (colorMapMin > 0.0 || colorMapMax < 0.0)) {
|
||||
if (colorMapMax < 0.0) {
|
||||
colorMapMax = -cmapMax;
|
||||
cmapValue = -cmapValue;
|
||||
zeroVal = -colorMapMin;
|
||||
} else {
|
||||
zeroVal = cmapMin;
|
||||
}
|
||||
colorMapMin = -cmapMax;
|
||||
}
|
||||
double leftZero = 0.0;
|
||||
double rightZero = 0.0;
|
||||
double absLogZeroVal = Math.abs(Math.log(zeroVal));
|
||||
|
||||
rightZero = absLogZeroVal + Math.log(colorMapMax);
|
||||
|
||||
double cmapMax2 = Math.abs(colorMapMin);
|
||||
|
||||
leftZero = absLogZeroVal + Math.log(cmapMax2);
|
||||
|
||||
double zeroIndex = leftZero / (leftZero + rightZero);
|
||||
|
||||
// figure out index for texture val
|
||||
double absTextureColor = Math.abs(cmapValue);
|
||||
if (absTextureColor <= zeroVal) {
|
||||
index = zeroIndex;
|
||||
} else if (cmapValue > 0.0) {
|
||||
// positive texture color value, find index from 0 to
|
||||
// cmapMax:
|
||||
double logTexColor = absLogZeroVal + Math.log(cmapValue);
|
||||
|
||||
double texIndex = logTexColor / rightZero;
|
||||
index = (zeroIndex + ((1.0 - zeroIndex) * texIndex));
|
||||
} else {
|
||||
// negative texture color value, find index from 0 to
|
||||
// cmapMax:
|
||||
double logTexColor = absLogZeroVal + Math.log(absTextureColor);
|
||||
|
||||
double texIndex = logTexColor / leftZero;
|
||||
index = (zeroIndex - (zeroIndex * texIndex));
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function calculates a new index to use based on the logFactor and
|
||||
* passed in index
|
||||
*
|
||||
* @param index
|
||||
* @param logFactor
|
||||
* @return
|
||||
*/
|
||||
public static double getLogFactorIndex(double index, double logFactor) {
|
||||
if (logFactor > 0.0) {
|
||||
double minLog = Math.log(logFactor);
|
||||
double maxLog = Math.log(logFactor + 1.0);
|
||||
|
||||
double lg = Math.log(logFactor + index);
|
||||
|
||||
index = (lg - minLog) / (maxLog - minLog);
|
||||
if (index < 0.0) {
|
||||
index = 0.0;
|
||||
} else if (index > 1.0) {
|
||||
index = 1.0;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an index for the cmapValue based on the
|
||||
* {@link ColorMapParameters}
|
||||
*
|
||||
* @param cmapValue
|
||||
* @param colorMapping
|
||||
* @return
|
||||
*/
|
||||
public static double getColorMappingIndex(double cmapValue,
|
||||
ColorMapParameters colorMapParameters) {
|
||||
double logFactor = colorMapParameters.getLogFactor();
|
||||
double cmapMin = colorMapParameters.getColorMapMin();
|
||||
double cmapMax = colorMapParameters.getColorMapMax();
|
||||
|
||||
double index;
|
||||
if (colorMapParameters.isLogarithmic()) {
|
||||
index = getLogIndex(cmapValue, cmapMin, cmapMax,
|
||||
colorMapParameters.isMirror());
|
||||
} else {
|
||||
index = getLinearIndex(cmapValue, cmapMin, cmapMax);
|
||||
}
|
||||
|
||||
// Apply logFactor if set
|
||||
if (logFactor > 0.0) {
|
||||
index = getLogFactorIndex(index, logFactor);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link Color} from the color map in the parameters at the index
|
||||
* (capped 0-1) passed in
|
||||
*
|
||||
* @param index
|
||||
* @param colorMapParameters
|
||||
* @return
|
||||
*/
|
||||
public static Color getColorByIndex(double index,
|
||||
ColorMapParameters colorMapParameters) {
|
||||
index = capIndex(index);
|
||||
IColorMap colorMap = colorMapParameters.getColorMap();
|
||||
if (colorMapParameters.isInterpolate()) {
|
||||
index = 0.5f;
|
||||
index = (index * (colorMap.getSize() - 1));
|
||||
int lowIndex = (int) Math.floor(index);
|
||||
int highIndex = (int) Math.ceil(index);
|
||||
double lowWeight = highIndex - index;
|
||||
double highWeight = 1.0f - lowWeight;
|
||||
Color low = colorMap.getColors().get(lowIndex);
|
||||
Color high = colorMap.getColors().get(highIndex);
|
||||
float r = (float) (lowWeight * low.getRed() + highWeight
|
||||
* high.getRed());
|
||||
float g = (float) (lowWeight * low.getGreen() + highWeight
|
||||
* high.getGreen());
|
||||
float b = (float) (lowWeight * low.getBlue() + highWeight
|
||||
* high.getBlue());
|
||||
float a = (float) (lowWeight * low.getAlpha() + highWeight
|
||||
* high.getAlpha());
|
||||
return new Color(r, g, b, a);
|
||||
} else {
|
||||
return colorMap.getColors().get(
|
||||
(int) (index * (colorMap.getSize() - 1)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Color} for the cmapValue based on the
|
||||
* {@link ColorMapParameters}
|
||||
*
|
||||
* @param cmapValue
|
||||
* @param colorMapParameters
|
||||
* @return
|
||||
*/
|
||||
public static Color getColorByValue(double cmapValue,
|
||||
ColorMapParameters colorMapParameters) {
|
||||
return getColorByIndex(
|
||||
getColorMappingIndex(cmapValue, colorMapParameters),
|
||||
colorMapParameters);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,9 @@ package com.raytheon.uf.common.colormap.prefs;
|
|||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.measure.converter.UnitConverter;
|
||||
|
@ -35,8 +37,8 @@ import javax.xml.bind.annotation.XmlElement;
|
|||
import com.raytheon.uf.common.colormap.AbstractColorMap;
|
||||
import com.raytheon.uf.common.colormap.Color;
|
||||
import com.raytheon.uf.common.colormap.IColorMap;
|
||||
import com.raytheon.uf.common.colormap.image.Colormapper;
|
||||
import com.raytheon.uf.common.colormap.prefs.DataMappingPreferences.DataMappingEntry;
|
||||
import com.raytheon.uf.common.serialization.ISerializableObject;
|
||||
|
||||
/**
|
||||
* Colormap Parameters
|
||||
|
@ -56,14 +58,15 @@ import com.raytheon.uf.common.serialization.ISerializableObject;
|
|||
* Jun 14, 2013 DR 16070 jgerth Utilize data mapping
|
||||
* Aug 2, 2013 2211 mschenke Backed out 16070 changes, made
|
||||
* dataUnit/imageUnit properly commutative.
|
||||
*
|
||||
* Nov 4, 2013 2492 mschenke Cleaned up variable naming to make purpose
|
||||
* clear (image->colormap)
|
||||
* </pre>
|
||||
*
|
||||
* @author chammack
|
||||
* @version 1
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.NONE)
|
||||
public class ColorMapParameters implements Cloneable, ISerializableObject {
|
||||
public class ColorMapParameters {
|
||||
|
||||
@XmlAccessorType(XmlAccessType.NONE)
|
||||
public static class PersistedParameters {
|
||||
|
@ -123,13 +126,13 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
|
|||
|
||||
protected Set<IColorMapParametersListener> listeners = new HashSet<IColorMapParametersListener>();
|
||||
|
||||
/** Units of the colormap parameters (min/max) */
|
||||
/** Units colormapping should be displayed in */
|
||||
protected Unit<?> displayUnit;
|
||||
|
||||
/** Units of the image pixel values */
|
||||
protected Unit<?> imageUnit;
|
||||
/** Units colormapping will occur in */
|
||||
protected Unit<?> colorMapUnit;
|
||||
|
||||
/** Units of the data values */
|
||||
/** Units of the data values to colormap */
|
||||
protected Unit<?> dataUnit;
|
||||
|
||||
/** The maximum value used to apply the colormap */
|
||||
|
@ -158,23 +161,23 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
|
|||
@XmlAttribute
|
||||
protected String colorMapName;
|
||||
|
||||
/** The converter that converts data values to display values * */
|
||||
/** The converter that converts data values to {@link #displayUnit} * */
|
||||
protected UnitConverter dataToDisplayConverter;
|
||||
|
||||
/** The converter that converts display values to data values * */
|
||||
/** The converter that converts display values to {@link #dataUnit} * */
|
||||
protected UnitConverter displayToDataConverter;
|
||||
|
||||
/** The converter that converts data values to image pixels */
|
||||
protected UnitConverter dataToImageConverter;
|
||||
/** The converter that converts data values to {@link #colorMapUnit} */
|
||||
protected UnitConverter dataToColorMapConverter;
|
||||
|
||||
/** The converter that converts image pixels to data values */
|
||||
protected UnitConverter imageToDataConverter;
|
||||
/** The converter that converts color map unit values to {@link #dataUnit} */
|
||||
protected UnitConverter colorMapToDataConverter;
|
||||
|
||||
/** The converter that converts image pixels to display values */
|
||||
protected UnitConverter imageToDisplayConverter;
|
||||
/** The converter that converts color map unit values to {@link #displayUnit} */
|
||||
protected UnitConverter colorMapToDisplayConverter;
|
||||
|
||||
/** The converter that converts display values to image pixels */
|
||||
protected UnitConverter displayToImageConverter;
|
||||
/** The converter that converts display values to {@link #colorMapUnit} */
|
||||
protected UnitConverter displayToColorMapConverter;
|
||||
|
||||
protected DataMappingPreferences dataMapping;
|
||||
|
||||
|
@ -201,7 +204,7 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
|
|||
/** Specify whether the colormap should be interpolated */
|
||||
protected boolean interpolate = false;
|
||||
|
||||
public static class LabelEntry {
|
||||
public static class LabelEntry implements Comparable<LabelEntry> {
|
||||
private float location;
|
||||
|
||||
private String text;
|
||||
|
@ -258,8 +261,25 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Comparable#compareTo(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(LabelEntry o) {
|
||||
return Double.compare(getLocation(), o.getLocation());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link UnitConverter} converting the from unit to the to unit.
|
||||
*
|
||||
* @param from
|
||||
* @param to
|
||||
* @return The unit converter or null of units are not compatible
|
||||
*/
|
||||
private UnitConverter constructConverter(Unit<?> from, Unit<?> to) {
|
||||
UnitConverter converter = null;
|
||||
|
||||
|
@ -270,22 +290,34 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
|
|||
return converter;
|
||||
}
|
||||
|
||||
private void addLabel(float dispValue, String s) {
|
||||
float index = getIndexByValue(dispValue);
|
||||
/**
|
||||
* Adds a label for a {@link #displayUnit} value
|
||||
*
|
||||
* @param colorMapValue
|
||||
* @param s
|
||||
*/
|
||||
private void addDisplayValueLabel(float dispValue, String s) {
|
||||
float colorMapValue = dispValue;
|
||||
UnitConverter displayToColorMap = getDisplayToColorMapConverter();
|
||||
if (displayToColorMap != null) {
|
||||
colorMapValue = (float) displayToColorMap.convert(dispValue);
|
||||
}
|
||||
addColorMapValueLabel(colorMapValue, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a label for a {@link #colorMapUnit} value
|
||||
*
|
||||
* @param colorMapValue
|
||||
* @param s
|
||||
*/
|
||||
private void addColorMapValueLabel(float colorMapValue, String s) {
|
||||
double index = Colormapper.getColorMappingIndex(colorMapValue, this);
|
||||
if (index > 1.0 || index < 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
labels.add(new LabelEntry(s, index));
|
||||
}
|
||||
|
||||
private void addLabel(int pixelValue, String s) {
|
||||
float location = (float) pixelValue / 255;
|
||||
if (location > 1.0 || location < 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
labels.add(new LabelEntry(s, location));
|
||||
labels.add(new LabelEntry(s, (float) index));
|
||||
}
|
||||
|
||||
private void computeLabels() {
|
||||
|
@ -298,7 +330,7 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
|
|||
if (colorMapRange != 0.0) {
|
||||
for (float label : colorBarIntervals) {
|
||||
String s = format.format(label);
|
||||
addLabel(label, s);
|
||||
addDisplayValueLabel(label, s);
|
||||
}
|
||||
}
|
||||
} else if (dataMapping != null) {
|
||||
|
@ -309,14 +341,15 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
|
|||
if (s == null) {
|
||||
s = format.format(dispValue);
|
||||
}
|
||||
addLabel(dispValue, s);
|
||||
addDisplayValueLabel(dispValue, s);
|
||||
} else if (entry.getPixelValue() != null
|
||||
&& !"NO DATA".equals(s)) {
|
||||
double pixelValue = entry.getPixelValue();
|
||||
addLabel((int) pixelValue, s);
|
||||
float pixelValue = entry.getPixelValue().floatValue();
|
||||
addColorMapValueLabel(pixelValue, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(labels);
|
||||
recomputeLabels = false;
|
||||
}
|
||||
|
||||
|
@ -357,22 +390,26 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return the unit
|
||||
* Returns the display unit
|
||||
*
|
||||
* @return The unit colormapping should be displayed in
|
||||
*/
|
||||
public Unit<?> getDisplayUnit() {
|
||||
return displayUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the display units
|
||||
*
|
||||
* @param unit
|
||||
* the unit to set
|
||||
* The unit colormapping should be displayed in
|
||||
*/
|
||||
public void setDisplayUnit(Unit<?> unit) {
|
||||
this.displayUnit = unit;
|
||||
recomputeLabels = true;
|
||||
|
||||
displayToImageConverter = null;
|
||||
imageToDisplayConverter = null;
|
||||
displayToColorMapConverter = null;
|
||||
colorMapToDisplayConverter = null;
|
||||
|
||||
displayToDataConverter = null;
|
||||
dataToDisplayConverter = null;
|
||||
|
@ -380,25 +417,32 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return the colorMapMax
|
||||
* Returns the maximum range value the colormapping occurs over
|
||||
*
|
||||
* @return the maximum range value in {@link #colorMapUnit}
|
||||
*/
|
||||
public float getColorMapMax() {
|
||||
return colorMapMax;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum range value the colormapping occurs over
|
||||
*
|
||||
* @param colorMapMax
|
||||
* the colorMapMax to set
|
||||
* the maximum range value in {@link #colorMapUnit}
|
||||
*/
|
||||
public void setColorMapMax(float colorMapMax) {
|
||||
setColorMapMax(colorMapMax, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum range value the colormapping occurs over
|
||||
*
|
||||
* @param colorMapMax
|
||||
* the colorMapMax to set
|
||||
* the maximum range value in {@link #colorMapUnit}
|
||||
* @param persist
|
||||
* specifies whether to persist this value when saved
|
||||
* true indicates colorMapMax should be persisted through
|
||||
* serialization
|
||||
*/
|
||||
public void setColorMapMax(float colorMapMax, boolean persist) {
|
||||
this.colorMapMax = colorMapMax;
|
||||
|
@ -410,25 +454,32 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return the colorMapMin
|
||||
* Returns the minimum range value the colormapping occurs over
|
||||
*
|
||||
* @return the minimum range value in {@link #colorMapUnit}
|
||||
*/
|
||||
public float getColorMapMin() {
|
||||
return colorMapMin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum range value the colormapping occurs over
|
||||
*
|
||||
* @param colorMapMin
|
||||
* the colorMapMin to set
|
||||
* the minimum range value in {@link #colorMapUnit}
|
||||
*/
|
||||
public void setColorMapMin(float colorMapMin) {
|
||||
setColorMapMin(colorMapMin, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum range value the colormapping occurs over
|
||||
*
|
||||
* @param colorMapMin
|
||||
* the colorMapMin to set
|
||||
* the minimum range value in {@link #colorMapUnit}
|
||||
* @param persist
|
||||
* specifies whether to persist this value when saved
|
||||
* true indicates colorMapMin should be persisted through
|
||||
* serialization
|
||||
*/
|
||||
public void setColorMapMin(float colorMapMin, boolean persist) {
|
||||
this.colorMapMin = colorMapMin;
|
||||
|
@ -510,6 +561,8 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the unit data values to be colormapped are in
|
||||
*
|
||||
* @return the dataUnit
|
||||
*/
|
||||
public Unit<?> getDataUnit() {
|
||||
|
@ -517,18 +570,20 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the unit data values to be colormapped are in
|
||||
*
|
||||
* @param dataUnit
|
||||
* the dataUnit to set
|
||||
*/
|
||||
public void setDataUnit(Unit<?> dataUnit) {
|
||||
this.dataUnit = dataUnit;
|
||||
|
||||
if (dataUnit != null && imageUnit == null) {
|
||||
setImageUnit(dataUnit);
|
||||
if (dataUnit != null && colorMapUnit == null) {
|
||||
setColorMapUnit(dataUnit);
|
||||
}
|
||||
|
||||
dataToImageConverter = null;
|
||||
imageToDataConverter = null;
|
||||
dataToColorMapConverter = null;
|
||||
colorMapToDataConverter = null;
|
||||
|
||||
dataToDisplayConverter = null;
|
||||
displayToDataConverter = null;
|
||||
|
@ -537,6 +592,9 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link UnitConverter} from {@link #dataUnit} to
|
||||
* {@link #displayUnit}
|
||||
*
|
||||
* @return the dataToDisplayConverter
|
||||
*/
|
||||
public UnitConverter getDataToDisplayConverter() {
|
||||
|
@ -550,6 +608,9 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link UnitConverter} from {@link #displayUnit} to
|
||||
* {@link #dataUnit}
|
||||
*
|
||||
* @return the displayToDataConverter
|
||||
*/
|
||||
public UnitConverter getDisplayToDataConverter() {
|
||||
|
@ -562,7 +623,7 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
|
|||
return displayToDataConverter;
|
||||
}
|
||||
|
||||
public java.util.List<LabelEntry> getLabels() {
|
||||
public List<LabelEntry> getLabels() {
|
||||
if (recomputeLabels) {
|
||||
computeLabels();
|
||||
notifyListener();
|
||||
|
@ -570,10 +631,22 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
|
|||
return labels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the colormapping is logarithmically scaled from
|
||||
* {@link #colorMapMin} to {@link #colorMapMax}
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isLogarithmic() {
|
||||
return logarithmic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the colormapping should logarithmically scaled from
|
||||
* {@link #colorMapMin} to {@link #colorMapMax}
|
||||
*
|
||||
* @param logarithmic
|
||||
*/
|
||||
public void setLogarithmic(boolean logarithmic) {
|
||||
recomputeLabels = recomputeLabels | this.logarithmic != logarithmic;
|
||||
this.logarithmic = logarithmic;
|
||||
|
@ -581,83 +654,162 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return the dataToImageConverter
|
||||
* @deprecated Use {@link #getDataToColorMapConverter()} instead
|
||||
*
|
||||
* @return the dataToColorMapConverter
|
||||
*/
|
||||
@Deprecated
|
||||
public UnitConverter getDataToImageConverter() {
|
||||
if (dataToImageConverter == null) {
|
||||
dataToImageConverter = constructConverter(dataUnit, imageUnit);
|
||||
if (dataToImageConverter != null) {
|
||||
notifyListener();
|
||||
}
|
||||
}
|
||||
return dataToImageConverter;
|
||||
return getDataToColorMapConverter();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the imageToDisplayConverter
|
||||
* Returns a {@link UnitConverter} converting {@link #dataUnit} values to
|
||||
* the {@link #colorMapUnit} if compatible or null otherwise
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public UnitConverter getDataToColorMapConverter() {
|
||||
if (dataToColorMapConverter == null) {
|
||||
dataToColorMapConverter = constructConverter(dataUnit, colorMapUnit);
|
||||
if (dataToColorMapConverter != null) {
|
||||
notifyListener();
|
||||
}
|
||||
}
|
||||
return dataToColorMapConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getColorMapToDisplayConverter()} instead
|
||||
*
|
||||
* @return the colorMapToDisplayConverter
|
||||
*/
|
||||
@Deprecated
|
||||
public UnitConverter getImageToDisplayConverter() {
|
||||
if (imageToDisplayConverter == null) {
|
||||
imageToDisplayConverter = constructConverter(imageUnit, displayUnit);
|
||||
if (imageToDisplayConverter != null) {
|
||||
return getColorMapToDisplayConverter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link UnitConverter} converting {@link #colorMapUnit} values
|
||||
* to the {@link #displayUnit} if compatible or null otherwise
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public UnitConverter getColorMapToDisplayConverter() {
|
||||
if (colorMapToDisplayConverter == null) {
|
||||
colorMapToDisplayConverter = constructConverter(colorMapUnit,
|
||||
displayUnit);
|
||||
if (colorMapToDisplayConverter != null) {
|
||||
notifyListener();
|
||||
}
|
||||
}
|
||||
return imageToDisplayConverter;
|
||||
return colorMapToDisplayConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the imageUnit
|
||||
* @deprecated Use {@link #getColorMapUnit()} instead
|
||||
*
|
||||
* @return the colorMapUnit
|
||||
*/
|
||||
@Deprecated
|
||||
public Unit<?> getImageUnit() {
|
||||
return imageUnit;
|
||||
return getColorMapUnit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param imageUnit
|
||||
* the imageUnit to set
|
||||
* Returns the unit colormapping will occur in
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public void setImageUnit(Unit<?> imageUnit) {
|
||||
this.imageUnit = imageUnit;
|
||||
public Unit<?> getColorMapUnit() {
|
||||
return colorMapUnit;
|
||||
}
|
||||
|
||||
if (imageUnit != null && dataUnit == null) {
|
||||
setDataUnit(imageUnit);
|
||||
/**
|
||||
* @deprecated Use {@link #setColorMapUnit(Unit)} instead
|
||||
*
|
||||
* @param imageUnit
|
||||
* the colorMapUnit to set
|
||||
*/
|
||||
@Deprecated
|
||||
public void setImageUnit(Unit<?> imageUnit) {
|
||||
setColorMapUnit(imageUnit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the unit colormapping will occur in. {@link #colorMapMin} and
|
||||
* {@link #colorMapMax} are expected to be in this unit
|
||||
*
|
||||
* @param colorMapUnit
|
||||
*/
|
||||
public void setColorMapUnit(Unit<?> colorMapUnit) {
|
||||
this.colorMapUnit = colorMapUnit;
|
||||
|
||||
if (colorMapUnit != null && dataUnit == null) {
|
||||
setDataUnit(colorMapUnit);
|
||||
}
|
||||
|
||||
recomputeLabels = true;
|
||||
|
||||
imageToDataConverter = null;
|
||||
dataToImageConverter = null;
|
||||
colorMapToDataConverter = null;
|
||||
dataToColorMapConverter = null;
|
||||
|
||||
imageToDisplayConverter = null;
|
||||
displayToImageConverter = null;
|
||||
colorMapToDisplayConverter = null;
|
||||
displayToColorMapConverter = null;
|
||||
notifyListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the imageToDataConverter
|
||||
* @deprecated Use {@link #getColorMapToDataConverter()} instead
|
||||
*
|
||||
* @return the colorMapToDataConverter
|
||||
*/
|
||||
@Deprecated
|
||||
public UnitConverter getImageToDataConverter() {
|
||||
if (imageToDataConverter == null) {
|
||||
imageToDataConverter = constructConverter(imageUnit, dataUnit);
|
||||
if (imageToDataConverter != null) {
|
||||
notifyListener();
|
||||
}
|
||||
}
|
||||
return imageToDataConverter;
|
||||
return getColorMapToDataConverter();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the displayToImageConverter
|
||||
* Returns a {@link UnitConverter} converting {@link #colorMapUnit} values
|
||||
* to the {@link #dataUnit} if compatible or null otherwise
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public UnitConverter getDisplayToImageConverter() {
|
||||
if (displayToImageConverter == null) {
|
||||
displayToImageConverter = constructConverter(displayUnit, imageUnit);
|
||||
if (displayToImageConverter != null) {
|
||||
public UnitConverter getColorMapToDataConverter() {
|
||||
if (colorMapToDataConverter == null) {
|
||||
colorMapToDataConverter = constructConverter(colorMapUnit, dataUnit);
|
||||
if (colorMapToDataConverter != null) {
|
||||
notifyListener();
|
||||
}
|
||||
}
|
||||
return displayToImageConverter;
|
||||
return colorMapToDataConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getDisplayToColorMapConverter()} instead
|
||||
*
|
||||
* @return the displayToColorMapConverter
|
||||
*/
|
||||
@Deprecated
|
||||
public UnitConverter getDisplayToImageConverter() {
|
||||
return getDisplayToColorMapConverter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link UnitConverter} converting {@link #displayUnit} values to
|
||||
* the {@link #colorMapUnit} if compatible or null otherwise
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public UnitConverter getDisplayToColorMapConverter() {
|
||||
if (displayToColorMapConverter == null) {
|
||||
displayToColorMapConverter = constructConverter(displayUnit,
|
||||
colorMapUnit);
|
||||
if (displayToColorMapConverter != null) {
|
||||
notifyListener();
|
||||
}
|
||||
}
|
||||
return displayToColorMapConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -668,7 +820,7 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
|
|||
this.dataMapping = dataMapping;
|
||||
recomputeLabels = true;
|
||||
if (dataMapping != null && displayUnit != null) {
|
||||
setImageUnit(dataMapping.getImageUnit(displayUnit));
|
||||
setColorMapUnit(dataMapping.getImageUnit(displayUnit));
|
||||
}
|
||||
notifyListener();
|
||||
}
|
||||
|
@ -707,12 +859,12 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
|
|||
cmp.dataMax = dataMax;
|
||||
cmp.dataMin = dataMin;
|
||||
cmp.dataToDisplayConverter = dataToDisplayConverter;
|
||||
cmp.dataToImageConverter = dataToImageConverter;
|
||||
cmp.dataToColorMapConverter = dataToColorMapConverter;
|
||||
cmp.dataUnit = dataUnit;
|
||||
cmp.formatString = formatString;
|
||||
cmp.imageToDataConverter = imageToDataConverter;
|
||||
cmp.imageToDisplayConverter = imageToDisplayConverter;
|
||||
cmp.imageUnit = imageUnit;
|
||||
cmp.colorMapToDataConverter = colorMapToDataConverter;
|
||||
cmp.colorMapToDisplayConverter = colorMapToDisplayConverter;
|
||||
cmp.colorMapUnit = colorMapUnit;
|
||||
cmp.labels = labels;
|
||||
cmp.recomputeLabels = recomputeLabels;
|
||||
cmp.persisted = persisted.clone();
|
||||
|
@ -779,196 +931,19 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
|
|||
return mirror;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
float[] testValues = { -3.622782E-10f, -1.6778468E-8f, -3.3110254E-8f,
|
||||
-3.7973948E-8f, -2.7633986E-8f, -9.904648E-9f, -7.5229956E-10f,
|
||||
7.5189455E-10f, 1.20609505E-8f, 2.9364383E-8f, 2.7346168E-8f,
|
||||
1.3699442E-10f, -2.9937E-8f, -3.6884128E-8f, -1.6217847E-8f,
|
||||
1.1931893E-8f, 2.252287E-8f, 1.3290519E-8f, -2.4843547E-9f,
|
||||
-1.0386745E-8f, -6.1300884E-9f, 3.266153E-9f, 1.078073E-8f,
|
||||
1.2696603E-8f, 4.315502E-9f, -7.2422215E-9f, -1.2054819E-8f,
|
||||
-9.100724E-9f, -2.2520505E-9f, 4.031535E-9f, 6.908326E-9f,
|
||||
4.5536255E-9f, 5.3565863E-10f, -6.767242E-11f, 1.7508048E-9f,
|
||||
1.2594312E-9f, -3.5915362E-9f, -6.42762E-9f, -6.295979E-9f,
|
||||
-3.857202E-9f, -2.2052171E-9f, 6.51567E-10f, 3.1020404E-9f,
|
||||
3.2179108E-9f, 2.080211E-9f, 2.5326197E-10f, -2.181367E-9f,
|
||||
-3.2126295E-9f, -2.2162419E-9f, -5.682299E-10f, 7.367537E-11f,
|
||||
1.7393351E-9f, 3.2000091E-9f, 2.82146E-9f, 1.9214115E-9f,
|
||||
1.2637547E-9f, 1.1449517E-9f, 9.570286E-10f, 2.4719807E-10f,
|
||||
7.4189294E-11f, -1.9902982E-10f, -1.6482227E-9f, -2.645924E-9f,
|
||||
-1.4331059E-9f, -2.6336155E-10f, -1.5215194E-9f,
|
||||
-1.5059594E-9f, 2.014035E-10f, 3.565288E-10f, -1.5582429E-9f,
|
||||
-1.3200975E-9f, 1.2632209E-10f, 1.0882992E-9f, 1.5682087E-9f,
|
||||
4.24027E-9f, 3.1678654E-10f, -3.9073598E-9f, -3.4730894E-9f,
|
||||
-9.989449E-10f, -4.0364423E-9f, -6.3506116E-9f, -2.8335263E-9f,
|
||||
-3.1253768E-9f, -1.1271912E-9f, -3.0793168E-10f, 2.2091975E-9f,
|
||||
4.9031823E-9f, 1.0454194E-8f, 1.6462849E-8f, 1.339688E-8f,
|
||||
6.4451755E-9f, 3.820775E-9f, 1.7874671E-9f, -4.5423043E-9f,
|
||||
-4.7599173E-9f, -3.718451E-9f, 2.086526E-10f, 4.4792867E-9f,
|
||||
-5.1967337E-9f, -1.0332604E-8f };
|
||||
|
||||
ColorMapParameters colorMapParameters = new ColorMapParameters();
|
||||
float min = -2.6945168e-7f;
|
||||
float max = 2.1146788e-7f;
|
||||
colorMapParameters.setColorMapMin(-2.6945168e-7f);
|
||||
colorMapParameters.setColorMapMax(2.1146788e-7f);
|
||||
colorMapParameters.setLogarithmic(true);
|
||||
DecimalFormat format = new DecimalFormat("0.###");
|
||||
int i = 0;
|
||||
for (float dispValue : testValues) {
|
||||
String s = format.format(dispValue);
|
||||
colorMapParameters.addLabel(dispValue, s);
|
||||
if (dispValue > max) {
|
||||
System.out.println(colorMapParameters.labels.get(i).location
|
||||
+ "to high");
|
||||
} else if (dispValue < min) {
|
||||
System.out.println(colorMapParameters.labels.get(i).location
|
||||
+ "to low");
|
||||
} else {
|
||||
System.out.println(colorMapParameters.labels.get(i).location);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
private float getIndexByValue(float dispValue) {
|
||||
UnitConverter displayToImage = getDisplayToImageConverter();
|
||||
float colorMapRange;
|
||||
if (logarithmic) {
|
||||
// float colorMapMin = this.colorMapMin * 1.25f;
|
||||
// float colorMapMax = this.colorMapMax * 1.25f;
|
||||
if (displayToImage != null) {
|
||||
dispValue = (float) displayToImage.convert(dispValue);
|
||||
}
|
||||
float index = 0.0f;
|
||||
// is this strictly negative, strictly positive or neg to pos
|
||||
// scaling?
|
||||
if (colorMapMin >= 0.0 && colorMapMax >= 0.0 && !isMirror()) {
|
||||
// simple calculation
|
||||
index = ((float) Math.log(dispValue) - (float) Math
|
||||
.log(colorMapMin))
|
||||
/ (float) Math.abs((float) Math.log(colorMapMax)
|
||||
- (float) Math.log(colorMapMin));
|
||||
} else if (colorMapMin <= 0.0 && colorMapMax <= 0.0 && !isMirror()) {
|
||||
index = ((float) (Math.log(dispValue) - (float) Math
|
||||
.log(colorMapMax)) / (float) Math.abs((float) Math
|
||||
.log(colorMapMin) - (float) Math.log(colorMapMax)));
|
||||
} else {
|
||||
// special case, neg to pos:
|
||||
float cmapMin = colorMapMin;
|
||||
float cmapMax = colorMapMax;
|
||||
float zeroVal = (float) Math.max(cmapMax,
|
||||
(float) Math.abs(cmapMin)) * 0.0001f;
|
||||
;
|
||||
|
||||
if (isMirror() && (cmapMin > 0 || cmapMax < 0)) {
|
||||
if (cmapMax < 0) {
|
||||
cmapMax = -cmapMax;
|
||||
dispValue = -dispValue;
|
||||
zeroVal = -cmapMin;
|
||||
} else {
|
||||
zeroVal = cmapMin;
|
||||
}
|
||||
cmapMin = -cmapMax;
|
||||
|
||||
}
|
||||
float leftZero = 0;
|
||||
float rightZero = 0;
|
||||
float absLogZeroVal = (float) Math.abs((float) Math
|
||||
.log(zeroVal));
|
||||
|
||||
rightZero = absLogZeroVal + (float) Math.log(cmapMax);
|
||||
|
||||
float cmapMax2 = -1 * cmapMin;
|
||||
|
||||
leftZero = absLogZeroVal + (float) Math.log(cmapMax2);
|
||||
|
||||
float zeroIndex = leftZero / (leftZero + rightZero);
|
||||
|
||||
// figure out index for texture val
|
||||
float absTextureColor = (float) Math.abs(dispValue);
|
||||
if (dispValue == 0) {
|
||||
index = zeroIndex;
|
||||
} else if (absTextureColor <= zeroVal) {
|
||||
index = (float) zeroIndex;
|
||||
} else if (dispValue > 0.0) {
|
||||
// positive texture color value, find index from 0 to
|
||||
// cmapMax:
|
||||
float logTexColor = absLogZeroVal
|
||||
+ (float) Math.log(dispValue);
|
||||
|
||||
float texIndex = logTexColor / rightZero;
|
||||
index = (float) (zeroIndex + ((1.0 - zeroIndex) * texIndex));
|
||||
} else {
|
||||
// negative texture color value, find index from 0 to
|
||||
// cmapMax:
|
||||
float logTexColor = absLogZeroVal
|
||||
+ (float) Math.log(absTextureColor);
|
||||
|
||||
float texIndex = logTexColor / leftZero;
|
||||
index = (zeroIndex - (zeroIndex * texIndex));
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
} else {
|
||||
colorMapRange = colorMapMax - colorMapMin;
|
||||
|
||||
if (colorMapRange != 0.0) {
|
||||
double pixelValue;
|
||||
if (displayToImage != null) {
|
||||
pixelValue = displayToImage.convert(dispValue);
|
||||
} else {
|
||||
pixelValue = dispValue;
|
||||
}
|
||||
float location;
|
||||
if (logarithmic) {
|
||||
location = (float) ((Math.log(pixelValue) - Math
|
||||
.log(colorMapMin)) / colorMapRange);
|
||||
} else {
|
||||
|
||||
location = ((float) pixelValue - colorMapMin)
|
||||
/ colorMapRange;
|
||||
}
|
||||
return location;
|
||||
} else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Color object of the value
|
||||
*
|
||||
* @param value
|
||||
* value to get Color for in {@link #displayUnit}
|
||||
* @return
|
||||
*/
|
||||
public Color getColorByValue(float value) {
|
||||
float index = getIndexByValue(value);
|
||||
if (index < 0.0f) {
|
||||
index = 0.0f;
|
||||
} else if (index > 1.0f) {
|
||||
index = 1.0f;
|
||||
}
|
||||
if (isInterpolate()) {
|
||||
index = 0.5f;
|
||||
index = (index * (colorMap.getSize() - 1));
|
||||
int lowIndex = (int) Math.floor(index);
|
||||
int highIndex = (int) Math.ceil(index);
|
||||
float lowWeight = highIndex - index;
|
||||
float highWeight = 1.0f - lowWeight;
|
||||
Color low = colorMap.getColors().get(lowIndex);
|
||||
Color high = colorMap.getColors().get(highIndex);
|
||||
float r = lowWeight * low.getRed() + highWeight * high.getRed();
|
||||
float g = lowWeight * low.getGreen() + highWeight * high.getGreen();
|
||||
float b = lowWeight * low.getBlue() + highWeight * high.getBlue();
|
||||
float a = lowWeight * low.getAlpha() + highWeight * high.getAlpha();
|
||||
return new Color(r, g, b, a);
|
||||
} else {
|
||||
return colorMap.getColors().get(
|
||||
(int) (index * (colorMap.getSize() - 1)));
|
||||
|
||||
UnitConverter displayToColorMap = getDisplayToColorMapConverter();
|
||||
if (displayToColorMap != null) {
|
||||
value = (float) displayToColorMap.convert(value);
|
||||
}
|
||||
return Colormapper.getColorByValue(value, this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -378,7 +378,7 @@ public class FileLocker {
|
|||
// locking, can't do any locking
|
||||
if (parentDir.canWrite() == false) {
|
||||
UFStatus.getHandler()
|
||||
.handle(Priority.PROBLEM,
|
||||
.handle(Priority.DEBUG,
|
||||
"Cannot write to directory: "
|
||||
+ parentDir.getAbsolutePath());
|
||||
return false;
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
<displayUnits>kft</displayUnits>
|
||||
<range scale="LINEAR">
|
||||
<!-- This kft range matches original -19m to 5000m from code -->
|
||||
<minValue>-0.0062</minValue>
|
||||
<minValue>-0.062</minValue>
|
||||
<maxValue>16.404</maxValue>
|
||||
</range>
|
||||
<defaultColormap>topo</defaultColormap>
|
||||
|
|
Loading…
Add table
Reference in a new issue