Issue #2492 Added getDataUnit to IColormappedImage and implementing classes. Deprecated dataUnit methods in ColorMapParameters. Fixed colormap slider to work with data and colormap units differing.

Change-Id: Ic82f45447113425a08909be4c5229502882db022

Former-commit-id: 58ccc575973ea9a1778659e17daff8577747dec5
This commit is contained in:
Max Schenkelberg 2013-11-11 11:09:00 -06:00
parent 0dbc31b756
commit e58a5df04b
19 changed files with 610 additions and 427 deletions

View file

@ -19,8 +19,9 @@
**/
package com.raytheon.uf.viz.core.drawables;
import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
import javax.measure.unit.Unit;
import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
/**
* Describes a Colormapped Image
@ -64,4 +65,12 @@ public interface IColormappedImage extends IImage {
*/
public abstract double getValue(int x, int y);
/**
* Get the unit associated with the data in the image. Values returned from
* {@link #getValue(int, int)} will be in this unit
*
* @return
*/
public abstract Unit<?> getDataUnit();
}

View file

@ -21,6 +21,8 @@ package com.raytheon.uf.viz.core.drawables.ext.colormap;
import java.awt.image.RenderedImage;
import javax.measure.unit.Unit;
import com.raytheon.uf.common.colormap.image.ColorMapData;
import com.raytheon.uf.common.colormap.image.Colormapper;
import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
@ -59,6 +61,8 @@ public class ColormappedImage implements IColormappedImage,
private ColorMapParameters parameters;
private Unit<?> dataUnit;
public ColormappedImage(IGraphicsTarget target,
IColorMapDataRetrievalCallback callback,
ColorMapParameters parameters) {
@ -103,9 +107,7 @@ public class ColormappedImage implements IColormappedImage,
*/
@Override
public void dispose() {
if (image != null) {
image.dispose();
}
image.dispose();
}
/*
@ -209,11 +211,15 @@ public class ColormappedImage implements IColormappedImage,
*/
@Override
public RenderedImage getImage() throws VizException {
if (parameters == null || parameters.getColorMap() == null) {
return null;
RenderedImage image = null;
if (parameters != null && parameters.getColorMap() != null) {
ColorMapData colorMapData = callback.getColorMapData();
if (colorMapData != null) {
this.dataUnit = colorMapData.getDataUnit();
image = Colormapper.colorMap(colorMapData, parameters);
}
}
ColorMapData colorMapData = callback.getColorMapData();
return Colormapper.colorMap(colorMapData, parameters);
return image;
}
/*
@ -237,4 +243,15 @@ public class ColormappedImage implements IColormappedImage,
image.stage();
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.core.drawables.IColormappedImage#getDataUnit()
*/
@Override
public Unit<?> getDataUnit() {
return dataUnit == null ? getColorMapParameters().getDataUnit()
: dataUnit;
}
}

View file

@ -24,6 +24,8 @@ import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import javax.measure.unit.Unit;
import org.geotools.coverage.grid.GridGeometry2D;
import com.raytheon.uf.common.colormap.image.ColorMapData;
@ -64,6 +66,8 @@ public class KmlColormappedImage extends KmlImage implements IColormappedImage {
private ColorMapParameters colorMapParameters;
private Unit<?> dataUnit;
public KmlColormappedImage(IColorMapDataRetrievalCallback dataCallback,
ColorMapParameters colorMapParameters) {
this.dataCallback = dataCallback;
@ -72,6 +76,7 @@ public class KmlColormappedImage extends KmlImage implements IColormappedImage {
public DataSource getData(GridGeometry2D geometry) throws VizException {
ColorMapData data = dataCallback.getColorMapData();
this.dataUnit = data.getDataUnit();
switch (data.getDataType()) {
case FLOAT:
return new FloatBufferWrapper(((FloatBuffer) data.getBuffer()),
@ -122,4 +127,15 @@ public class KmlColormappedImage extends KmlImage implements IColormappedImage {
return 0;
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.core.drawables.IColormappedImage#getDataUnit()
*/
@Override
public Unit<?> getDataUnit() {
return dataUnit == null ? getColorMapParameters().getDataUnit()
: dataUnit;
}
}

View file

@ -21,6 +21,8 @@ package com.raytheon.uf.viz.kml.export.graphics.ext;
import java.util.Comparator;
import javax.measure.unit.Unit;
import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
import com.raytheon.uf.viz.core.DrawableImage;
import com.raytheon.uf.viz.core.IExtent;
@ -146,4 +148,14 @@ class KmlMosaicImage implements IMosaicImage {
this.imageExtent = imageExtent;
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.core.drawables.IColormappedImage#getDataUnit()
*/
@Override
public Unit<?> getDataUnit() {
return getColorMapParameters().getColorMapUnit();
}
}

View file

@ -10,12 +10,12 @@ Eclipse-BuddyPolicy: dependent
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
com.raytheon.uf.viz.core;bundle-version="1.12.1174",
org.geotools;bundle-version="2.6.4",
com.raytheon.uf.common.colormap;bundle-version="1.12.1174",
com.raytheon.viz.ui;bundle-version="1.12.1174",
javax.vecmath;bundle-version="1.3.1",
com.raytheon.uf.common.util;bundle-version="1.12.1174",
com.raytheon.uf.common.geospatial;bundle-version="1.12.1174"
com.raytheon.uf.common.geospatial;bundle-version="1.12.1174",
javax.measure;bundle-version="1.0.0",
javax.vecmath;bundle-version="1.3.1"
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ActivationPolicy: lazy
Export-Package: com.raytheon.uf.viz.remote.graphics,

View file

@ -19,6 +19,8 @@
**/
package com.raytheon.uf.viz.remote.graphics.objects;
import javax.measure.unit.Unit;
import com.raytheon.uf.common.colormap.IColorMap;
import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
import com.raytheon.uf.common.colormap.prefs.IColorMapParametersListener;
@ -150,4 +152,14 @@ public class DispatchingColormappedImage<T extends IColormappedImage> extends
}
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.core.drawables.IColormappedImage#getDataUnit()
*/
@Override
public Unit<?> getDataUnit() {
return wrappedObject.getDataUnit();
}
}

View file

@ -52,7 +52,8 @@ import com.raytheon.viz.core.gl.images.AbstractGLImage;
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Aug 6, 2012 mschenke Initial creation
* Aug 6, 2012 mschenke Initial creation
* Nov 4, 2013 2492 mschenke Reworked to use GLSL Data mapping
*
* </pre>
*

View file

@ -161,69 +161,111 @@ float getLinearIndex(float cmapValue, float cmapMin, float cmapMax) {
return capIndex(index);
}
/**
* Converts a colormap value to a log index
*/
float valueToLogIndex(float value, float rangeMin, float rangeMax) {
// Account for 0 min index
if (rangeMin == 0) {
rangeMin = 0.0000001;
if (rangeMax < 0) {
rangeMin = -rangeMin;
}
}
int reverse = 0;
if ((value < rangeMin && rangeMin > 0)
|| (value > rangeMin && rangeMin < 0)) {
reverse = 1;
}
value = abs(value);
rangeMin = abs(rangeMin);
rangeMax = abs(rangeMax);
// Check uncomputable index value, everything between this range is 0,
// rangeMin->rangeMax 0 -> 1, -rangeMin->-rangeMax 0 -> -1
if (value <= rangeMin && value >= -rangeMin) {
return 0;
}
double index = (log(value) - log(rangeMin))
/ (log(rangeMax) - log(rangeMin));
if (reverse != 0) {
index = -index;
}
return 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) {
int inverted = 0;
float rangeMin = abs(cmapMin);
float rangeMax = abs(cmapMax);
float rangeValue = abs(cmapValue);
if (rangeMin > rangeMax) {
// Inverted colormapping range (cmapMax is closest to 0)
inverted = 1;
float tmp = rangeMin;
rangeMin = rangeMax;
rangeMax = tmp;
}
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)));
// Flag if min/max values are on opposite sides of zero
int minMaxOpposite = 0;
if ((cmapMin < 0 && cmapMax > 0) || (cmapMin > 0 && cmapMax < 0)) {
minMaxOpposite = 1;
}
if (mirror != 0 || minMaxOpposite != 0) {
if (cmapMax < 0) {
// Invert colormapping if negative range was given
cmapValue = -cmapValue;
}
} 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;
// Log scaling is happening on both sides of zero, need to compute
// our zero index value
float zeroVal = rangeMin;
if (minMaxOpposite == 1) {
// Min/Max are on opposite sides of zero, compute a zero value
zeroVal = max(rangeMin, rangeMax) * 0.0001;
}
float leftZero = 0.0;
float rightZero = 0.0;
float negCmapMax = rangeMin;
float posCmapMax = rangeMax;
if (mirror != 0) {
negCmapMax = posCmapMax = rangeMax;
}
// Compute log zero val and log neg/pos max vals
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));
float logNegCmapMax = absLogZeroVal + log(negCmapMax);
float logPosCmapMax = absLogZeroVal + log(posCmapMax);
// Calculate index which zeroVal is at based on neg max and pos max
float zeroValIndex = logNegCmapMax / (logNegCmapMax + logPosCmapMax);
if (cmapValue > 0) {
index = valueToLogIndex(rangeValue, zeroVal, posCmapMax);
index = zeroValIndex + (1 - zeroValIndex) * index;
} else {
// negative texture color value, find index from 0 to
// cmapMax:
float logTexColor = absLogZeroVal + log(absTextureColor);
float texIndex = logTexColor / leftZero;
index = (zeroIndex - (zeroIndex * texIndex));
index = valueToLogIndex(rangeValue, zeroVal, negCmapMax);
index = zeroValIndex - zeroValIndex * index;
}
if (inverted != 0) {
index = 1.0 - index;
}
} else {
// Simple case, just use log converter to get index
index = valueToLogIndex(rangeValue, rangeMin, rangeMax);
if (inverted == 1) {
index = 1.0 - index;
}
if (cmapMin > 0 && cmapValue < rangeMin
|| (cmapMin < 0 && cmapValue > -rangeMin)) {
index = -index;
}
}
return capIndex(index);

View file

@ -256,6 +256,10 @@ public class GLDataMappingFactory {
float currDelta = (float) (currEndValue - dataMapping[0]);
for (int i = 2; i < dataMapping.length; ++i) {
double nextValue = dataMapping[i];
// Deltas are compared in float space because it
// minimizes the precision errors and the mapping will
// occur in floats in GLSL so no need for the extra
// precision
float nextDelta = (float) ((nextValue - currEndValue) / (i - currEndIndex));
if (nextDelta == currDelta) {
// Remove linear entries

View file

@ -27,7 +27,8 @@ import com.raytheon.viz.core.gl.glsl.GLShaderProgram;
import com.raytheon.viz.core.gl.images.AbstractGLImage;
/**
* TODO Add Description
* Default GL imaging extension. Renders RGB images in GL applying alpha,
* brightness, and contrast settings.
*
* <pre>
*

View file

@ -23,7 +23,7 @@ import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
import com.raytheon.viz.core.gl.dataformat.AbstractGLColorMapDataFormat;
/**
* Factory for creating GLSL struct mappings
* Factory for creating API defined GLSL structs in a {@link GLShaderProgram}.
*
* <pre>
*

View file

@ -39,7 +39,8 @@ import com.sun.opengl.util.texture.TextureCoords;
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 16, 2013 2333 mschenke Initial creation
* Oct 16, 2013 2333 mschenke Initial creation
* Nov 4, 2013 2492 mschenke Reworked to use GLSL Data mapping
*
* </pre>
*

View file

@ -19,6 +19,7 @@
**/
package com.raytheon.viz.core.gl.images;
import javax.measure.unit.Unit;
import javax.media.opengl.GL;
import com.raytheon.uf.common.colormap.image.ColorMapData.ColorMapDataType;
@ -102,4 +103,12 @@ public class GLColormappedImage extends AbstractGLColormappedImage {
super.usaAsFrameBuffer();
}
@Override
public Unit<?> getDataUnit() {
if (data != null && data.getDataUnit() != null) {
return data.getDataUnit();
}
return getColorMapParameters().getDataUnit();
}
}

View file

@ -19,6 +19,8 @@
**/
package com.raytheon.viz.core.gl.images;
import javax.measure.unit.Unit;
import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
import com.raytheon.uf.viz.core.drawables.ext.IImagingExtension;
import com.raytheon.viz.core.gl.dataformat.GLColorMapData;
@ -66,4 +68,9 @@ public class GLOffscreenColormappedImage extends AbstractGLColormappedImage {
return Double.NaN;
}
@Override
public Unit<?> getDataUnit() {
return getColorMapParameters().getColorMapUnit();
}
}

View file

@ -19,6 +19,8 @@
**/
package com.raytheon.viz.core.gl.internal.ext.mosaic;
import javax.measure.unit.Unit;
import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
import com.raytheon.uf.viz.core.DrawableImage;
import com.raytheon.uf.viz.core.IExtent;
@ -172,4 +174,14 @@ public class GLMosaicImage extends GLDelegateImage<GLOffscreenColormappedImage>
this.image = wrappedImage;
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.core.drawables.IColormappedImage#getDataUnit()
*/
@Override
public Unit<?> getDataUnit() {
return image.getDataUnit();
}
}

View file

@ -21,12 +21,12 @@ package com.raytheon.viz.ui.dialogs;
import java.text.DecimalFormat;
import javax.measure.converter.ConversionException;
import javax.measure.converter.UnitConverter;
import javax.measure.unit.Unit;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
@ -36,11 +36,9 @@ import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Scale;
import org.eclipse.swt.widgets.Text;
import com.raytheon.uf.common.colormap.image.Colormapper;
import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.viz.ui.dialogs.colordialog.ColorUtil;
import com.raytheon.uf.common.colormap.prefs.DataMappingPreferences.DataMappingEntry;
/**
* Composite for slider bars for ColorMapParameters
@ -51,7 +49,9 @@ import com.raytheon.viz.ui.dialogs.colordialog.ColorUtil;
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jan 3, 2012 mschenke Initial creation
* Jan 3, 2012 mschenke Initial creation
* Nov 8, 2013 2492 mschenke Rewritten to work with colormap
* units different from data units
*
* </pre>
*
@ -61,8 +61,13 @@ import com.raytheon.viz.ui.dialogs.colordialog.ColorUtil;
public class ColorMapSliderComp extends Composite {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(ColorMapSliderComp.class);
private static final String NaN_STRING = "NO DATA";
private static final int SLIDER_MIN = 0;
private static final int SLIDER_MAX = 255;
private static final int SLIDER_INC = 1;
private ColorMapParameters cmap;
@ -74,25 +79,25 @@ public class ColorMapSliderComp extends Composite {
private Text maxValueText;
private String[] sliderText;
private final float cmapAbsoluteMin;
private float cmapMin;
private final float cmapAbsoluteMax;
private float cmapMax;
private final float origCmapMin;
private float cmapWidth;
private final float origCmapMax;
private float cmapIncrement;
private float currentCmapMin;
private DecimalFormat format = null;
private float currentCmapMax;
private float currentMin;
private final DecimalFormat format;
private float currentMax;
private final boolean dataInverted;
private float origCmapMin;
private UnitConverter displayToColorMap;
private float origCmapMax;
private UnitConverter colorMapToDisplay;
/**
* @param parent
@ -101,8 +106,46 @@ public class ColorMapSliderComp extends Composite {
public ColorMapSliderComp(Composite parent, ColorMapParameters cmap) {
super(parent, SWT.NONE);
this.cmap = cmap;
this.origCmapMin = cmap.getColorMapMin();
this.origCmapMax = cmap.getColorMapMax();
this.currentCmapMin = this.origCmapMin = cmap.getColorMapMin();
this.currentCmapMax = this.origCmapMax = cmap.getColorMapMax();
this.displayToColorMap = cmap.getDisplayToColorMapConverter();
this.colorMapToDisplay = cmap.getColorMapToDisplayConverter();
if (displayToColorMap == null) {
displayToColorMap = Unit.ONE.getConverterTo(Unit.ONE);
}
if (colorMapToDisplay == null) {
colorMapToDisplay = Unit.ONE.getConverterTo(Unit.ONE);
}
float cmapAbsoluteMin, cmapAbsoluteMax;
if (cmap.getDataMapping() != null) {
cmapAbsoluteMin = cmap.getColorMapMin();
cmapAbsoluteMax = cmap.getColorMapMax();
} else {
UnitConverter dataToColorMap = cmap.getDataToColorMapConverter();
cmapAbsoluteMin = cmap.getDataMin();
cmapAbsoluteMax = cmap.getDataMax();
if (dataToColorMap != null) {
cmapAbsoluteMin = (float) dataToColorMap.convert(cmap
.getDataMin());
cmapAbsoluteMax = (float) dataToColorMap.convert(cmap
.getDataMax());
}
}
this.cmapAbsoluteMin = cmapAbsoluteMin;
this.cmapAbsoluteMax = cmapAbsoluteMax;
boolean dataInverted = false;
if ((cmapAbsoluteMin > cmapAbsoluteMax && cmap.getDataMin() < cmap
.getDataMax())
|| (cmapAbsoluteMin < cmapAbsoluteMax && cmap.getDataMin() > cmap
.getDataMax())) {
dataInverted = true;
}
this.dataInverted = dataInverted;
this.format = getTextFormat();
initializeComponents();
}
@ -115,16 +158,15 @@ public class ColorMapSliderComp extends Composite {
*
*/
private void initializeComponents() {
buildColorMapData();
setLayout(new GridLayout(3, false));
Label maxLabel = new Label(this, SWT.None);
maxLabel.setText("Max:");
maxSlider = new Scale(this, SWT.HORIZONTAL);
maxSlider.setMaximum(255);
maxSlider.setMinimum(0);
maxSlider.setIncrement(1);
maxSlider.setMaximum(SLIDER_MAX);
maxSlider.setMinimum(SLIDER_MIN);
maxSlider.setIncrement(SLIDER_INC);
maxSlider.setSelection(maxSlider.getMaximum());
GridData layoutData = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
layoutData.minimumWidth = 250;
@ -142,9 +184,9 @@ public class ColorMapSliderComp extends Composite {
minLabel.setText("Min:");
minSlider = new Scale(this, SWT.HORIZONTAL);
minSlider.setMaximum(255);
minSlider.setMinimum(0);
minSlider.setIncrement(1);
minSlider.setMaximum(SLIDER_MAX);
minSlider.setMinimum(SLIDER_MIN);
minSlider.setIncrement(SLIDER_INC);
minSlider.setSelection(minSlider.getMinimum());
layoutData = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
layoutData.minimumWidth = 250;
@ -156,286 +198,186 @@ public class ColorMapSliderComp extends Composite {
minValueText.setLayoutData(labelLayoutData);
maxSlider.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (maxSlider.getSelection() <= minSlider.getSelection()) {
maxSlider.setSelection(minSlider.getSelection() + 1);
}
maxValueText.setText(selectionToText(maxSlider.getSelection()));
changeMax(maxSlider.getSelection());
setColorMapMax(selectionToColorMapValue(maxSlider
.getSelection()));
}
});
minSlider.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (minSlider.getSelection() >= maxSlider.getSelection()) {
minSlider.setSelection(maxSlider.getSelection() - 1);
}
minValueText.setText(selectionToText(minSlider.getSelection()));
changeMin(minSlider.getSelection());
setColorMapMin(selectionToColorMapValue(minSlider
.getSelection()));
}
});
maxValueText.addKeyListener(new KeyListener() {
maxValueText.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.character == SWT.CR) {
maxTextChanged();
setColorMapMax(textToColorMapValue(maxValueText.getText()
.trim()));
}
}
@Override
public void keyReleased(KeyEvent e) {
// do nothing
}
});
minValueText.addKeyListener(new KeyListener() {
minValueText.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.character == SWT.CR) {
minTextChanged();
setColorMapMin(textToColorMapValue(minValueText.getText()
.trim()));
}
}
@Override
public void keyReleased(KeyEvent e) {
// do nothing
}
});
// set initial values
currentMax = cmap.getColorMapMax();
currentMin = cmap.getColorMapMin();
maxSlider.setSelection(cmapToSelection(currentMax));
minSlider.setSelection(cmapToSelection(currentMin));
setMaxText();
setMinText();
setColorMapMin(currentCmapMin);
setColorMapMax(currentCmapMax);
}
private void setMaxText() {
maxValueText.setText(cmapToText(currentMax));
}
private void setMinText() {
minValueText.setText(cmapToText(currentMin));
}
private void setColorMapMax(float f) {
if (currentMax != f) {
currentMax = f;
cmap.setColorMapMax(f, true);
/**
* Converts a slider selection index to a colormap value
*
* @param selection
* @return
*/
private float selectionToColorMapValue(int selection) {
double indexValue = Colormapper.getLinearIndex(selection, SLIDER_MIN,
SLIDER_MAX);
if (dataInverted) {
indexValue = 1 - indexValue;
}
double colorMapValue = cmapAbsoluteMin
+ (cmapAbsoluteMax - cmapAbsoluteMin) * indexValue;
return (float) colorMapValue;
}
private void setColorMapMin(float f) {
if (currentMin != f) {
currentMin = f;
cmap.setColorMapMin(f, true);
/**
* Converts a colormap value to a slider selection index
*
* @param colorMapValue
* @return
*/
private int colorMapValueToSelection(float colorMapValue) {
double indexValue = Colormapper.getLinearIndex(colorMapValue,
cmapAbsoluteMin, cmapAbsoluteMax);
if (dataInverted) {
indexValue = 1 - indexValue;
}
return (int) (SLIDER_MIN + (SLIDER_MAX - SLIDER_MIN) * indexValue);
}
private void minTextChanged() {
String text = minValueText.getText().trim().split(" ")[0];
try {
float f = Float.valueOf(text);
UnitConverter unitConv = cmap.getImageToDisplayConverter();
if (unitConv != null) {
f = (float) unitConv.inverse().convert(f);
}
if (f >= currentMax) {
setMinText();
statusHandler.handle(Priority.ERROR,
"Minimum of colormap range cannot exceed the maximum.");
} else if (cmapMin >= f) {
setColorMapMin(cmapMin);
minSlider.setSelection(0);
setMinText();
} else {
setColorMapMin(f);
minSlider.setSelection(cmapToSelection(f));
}
} catch (NumberFormatException ex) {
statusHandler.handle(Priority.ERROR,
"Minimum of colormap range cannot be parsed: " + text);
setMinText();
} catch (ConversionException ex) {
statusHandler.handle(Priority.ERROR, "Unit converter error.", ex);
setMinText();
}
}
private void maxTextChanged() {
String text = maxValueText.getText().trim().split(" ")[0];
try {
float f = Float.valueOf(text);
UnitConverter unitConv = cmap.getImageToDisplayConverter();
if (unitConv != null) {
f = (float) unitConv.inverse().convert(f);
}
if (currentMin >= f) {
statusHandler
.handle(Priority.ERROR,
"Maximum of colormap range cannot be below the minimum.");
setMaxText();
} else if (f >= cmapMax) {
setColorMapMax(cmapMax);
maxSlider.setSelection(255);
setMaxText();
} else {
setColorMapMax(f);
maxSlider.setSelection(cmapToSelection(f));
}
} catch (NumberFormatException ex) {
statusHandler.handle(Priority.ERROR,
"Maximum of colormap range cannot be parsed: " + text);
setMaxText();
} catch (ConversionException ex) {
statusHandler.handle(Priority.ERROR, "Unit converter error.", ex);
setMaxText();
}
}
private void changeMax(int position) {
// slider min and max is based on the color map, so position is the new
// color map max
currentMax = selectionToCmap(position);
cmap.setColorMapMax(currentMax, true);
}
private void changeMin(int position) {
// slider min and max is based on the color map, so position is the new
// color map min
currentMin = selectionToCmap(position);
cmap.setColorMapMin(currentMin, true);
}
private String cmapToText(double value) {
UnitConverter unitConv = cmap.getImageToDisplayConverter();
String textStr = "";
if (unitConv != null) {
value = unitConv.convert(value);
if (((Double) value).isNaN()) {
textStr = "NO DATA";
/**
* Converts a text string to a colormap value
*
* @param text
* @return
*/
private float textToColorMapValue(String text) {
if (cmap.getDataMapping() != null && text.isEmpty() == false) {
// First check for data mapping entries
for (DataMappingEntry entry : cmap.getDataMapping().getEntries()) {
if (entry.getLabel() != null && text.equals(entry.getLabel())) {
return entry.getPixelValue().floatValue();
}
}
}
String txt;
if (textStr.length() == 0) {
txt = format.format(value);
if (NaN_STRING.equals(text)) {
// If special NaN String, try to find first NaN value
for (int i = SLIDER_MIN; i < SLIDER_MAX; i += SLIDER_INC) {
float colorMapValue = selectionToColorMapValue(i);
if (Double.isNaN(colorMapToDisplay.convert(colorMapValue))) {
return colorMapValue;
}
}
} else {
txt = textStr;
}
return txt;
}
private String selectionToText(int selection) {
String rval = "ERR";
if (selection > -1 && selection < sliderText.length) {
// exact match into sliderText array
rval = sliderText[selection];
} else {
statusHandler.handle(Priority.CRITICAL, "index " + selection
+ " out of range, max " + (sliderText.length - 1));
}
return rval;
}
private float selectionToCmap(int selection) {
float percentOffset = selection / 255.0f;
float value = percentOffset * cmapWidth + cmapMin;
return value;
}
private int cmapToSelection(float value) {
int selection = (int) ((value - cmapMin) * 255.0f / cmapWidth);
return selection;
}
// modified from logic in ColorBar.java
private void buildColorMapData() {
sliderText = new String[256];
cmapWidth = cmap.getDataMax() - cmap.getDataMin();
cmapIncrement = cmapWidth / ColorUtil.MAX_VALUE;
cmapMin = cmap.getDataMin();
cmapMax = cmap.getDataMax();
float start = cmap.getDataMin();
String units = "";
UnitConverter unitConv = cmap.getImageToDisplayConverter();
Double lastVal = Double.NaN;
// TODO: Handle piecewise pixel converts to show ranges (for radar)
for (int i = 0; i < sliderText.length; ++i) {
double value = start;
// handle precision errors
if (value > cmapMax) {
// if the difference is .1 the increment between steps assume
// that cmapMax is ok
if ((value - cmapMax) < (.1 * cmapIncrement)) {
value = cmapMax;
}
// Attempt to parse and convert
try {
float displayValue = Float.parseFloat(text);
return (float) displayToColorMap.convert(displayValue);
} catch (Throwable t) {
// Ignore, NaN will be returned and text will be reverted
}
}
return Float.NaN;
}
String textStr = "";
if (cmap.isLogarithmic()) {
// TODO: Handle case where min/max go from neg to pos
if (cmap.getColorMapMax() >= 0 && cmap.getColorMapMin() >= 0) {
double index = (i) / ColorUtil.MAX_VALUE;
value = Math.pow(Math.E,
(Math.log(cmap.getColorMapMin()) + (index * (Math
.log(cmap.getColorMapMax()) - Math.log(cmap
.getColorMapMin())))));
}
if (format == null) {
format = new DecimalFormat("0.000");
}
}
if (unitConv != null) {
value = unitConv.convert(value);
/*
* Check if the last value is non a number.
*/
if (lastVal.isNaN()) {
// If value is not a number then set the text to
// "NO DATA".
if (((Double) value).isNaN()) {
textStr = "NO DATA";
}
lastVal = value;
} else {
// If value is not a number then prepend ">"
// to the value.
if (((Double) value).isNaN()) {
textStr = "> " + lastVal;
} else {
lastVal = value;
/**
* Converts a colormap value into a text display string
*
* @param colorMapValue
* @return
*/
private String colorMapValueToText(float colorMapValue) {
String text = null;
if (cmap.getDataMapping() != null) {
text = cmap.getDataMapping().getLabelValueForDataValue(
colorMapValue);
}
if (text == null || text.trim().isEmpty()) {
float displayValue = (float) colorMapToDisplay
.convert(colorMapValue);
if (Float.isNaN(displayValue) == false) {
text = format.format(displayValue);
} else {
text = NaN_STRING;
int selection = colorMapValueToSelection(colorMapValue);
for (int i = selection; i >= SLIDER_MIN; i -= SLIDER_INC) {
displayValue = (float) colorMapToDisplay
.convert(selectionToColorMapValue(i));
if (Float.isNaN(displayValue) == false) {
text = "> " + format.format(displayValue);
break;
}
}
}
}
return text;
}
/**
* Sets the colormap min value, updates the text and slider
*
* @param colorMapMin
*/
private void setColorMapMin(float colorMapMin) {
if (Float.isNaN(colorMapMin) == false) {
currentCmapMin = colorMapMin;
}
minSlider.setSelection(colorMapValueToSelection(currentCmapMin));
minValueText.setText(colorMapValueToText(currentCmapMin));
cmap.setColorMapMin(currentCmapMin, true);
}
/**
* Sets the colormap max value, updates the text and slider
*
* @param colorMapMax
*/
private void setColorMapMax(float colorMapMax) {
if (Float.isNaN(colorMapMax) == false) {
currentCmapMax = colorMapMax;
}
maxSlider.setSelection(colorMapValueToSelection(currentCmapMax));
maxValueText.setText(colorMapValueToText(currentCmapMax));
cmap.setColorMapMax(currentCmapMax, true);
}
private DecimalFormat getTextFormat() {
if (cmap.isLogarithmic() == false) {
for (int i = SLIDER_MIN; i < SLIDER_MAX; ++i) {
double cmapValue = selectionToColorMapValue(i);
double displayValue = colorMapToDisplay.convert(cmapValue);
if (Double.isNaN(displayValue)) {
continue;
}
if (format == null && new Double(value).isNaN() == false) {
int zeros = 0;
String val = "" + value;
String val = "" + displayValue;
char[] vals = val.substring(val.indexOf(".") + 1).toCharArray();
for (int j = 0; j < vals.length; ++j) {
if (vals[j] == '0') {
@ -451,28 +393,10 @@ public class ColorMapSliderComp extends Composite {
for (int j = 0; j < zeros; ++j) {
f += "0";
}
format = new DecimalFormat(f);
return new DecimalFormat(f);
}
String txt;
/*
* If textStr doesn't have any text then set txt to the value in the
* value variable.
*/
if (textStr.length() == 0) {
txt = format.format(value);
} else {
txt = textStr;
}
if (units != null && units.length() != 0) {
txt += " " + units;
}
sliderText[i] = txt;
start += cmapIncrement;
}
return new DecimalFormat("0.000");
}
}

View file

@ -0,0 +1,103 @@
/**
* 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.uf.common.colormap;
/**
* Converter that can do simple log scaling given a start/end range on either
* side of zero.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Nov 7, 2013 2492 mschenke Initial creation
*
* </pre>
*
* @author mschenke
* @version 1.0
*/
public class LogConverter {
private static double EFFECTIVE_ZERO = Double.MIN_VALUE;
public static double valueToIndex(double value, double rangeMin,
double rangeMax) {
// Account for 0 min index
if (rangeMin == 0) {
rangeMin = EFFECTIVE_ZERO;
if (rangeMax < 0) {
rangeMin = -rangeMin;
}
}
boolean reverse = false;
if ((value < rangeMin && rangeMin > 0)
|| (value > rangeMin && rangeMin < 0)) {
reverse = true;
}
value = Math.abs(value);
rangeMin = Math.abs(rangeMin);
rangeMax = Math.abs(rangeMax);
// Check uncomputable index value, everything between this range is 0,
// rangeMin->rangeMax 0 -> 1, -rangeMin->-rangeMax 0 -> -1
if (value <= rangeMin && value >= -rangeMin) {
return 0;
}
double index = (Math.log(value) - Math.log(rangeMin))
/ (Math.log(rangeMax) - Math.log(rangeMin));
if (reverse) {
index = -index;
}
return index;
}
public static double indexToValue(double index, double rangeMin,
double rangeMax) {
// Account for 0 min index
if (rangeMin == 0) {
rangeMin = EFFECTIVE_ZERO;
if (rangeMax < 0) {
rangeMin = -rangeMin;
}
}
boolean reverse = index < 0;
index = Math.abs(index);
rangeMin = Math.abs(rangeMin);
rangeMax = Math.abs(rangeMax);
double value = Math.exp(Math.log(rangeMin)
+ (index * (Math.log(rangeMax) - Math.log(rangeMin))));
if (reverse) {
value = -value;
}
return value;
}
}

View file

@ -40,6 +40,7 @@ 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.LogConverter;
import com.raytheon.uf.common.colormap.image.ColorMapData.ColorMapDataType;
import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
@ -158,27 +159,6 @@ public class Colormapper {
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
@ -250,64 +230,70 @@ public class Colormapper {
*/
public static double getLogIndex(double cmapValue, double cmapMin,
double cmapMax, boolean mirror) {
boolean inverted = false;
double rangeMin = Math.abs(cmapMin);
double rangeMax = Math.abs(cmapMax);
double rangeValue = Math.abs(cmapValue);
if (rangeMin > rangeMax) {
// Inverted colormapping range (cmapMax is closest to 0)
inverted = true;
double tmp = rangeMin;
rangeMin = rangeMax;
rangeMax = tmp;
}
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)));
// Flag if min/max values are on opposite sides of zero
boolean minMaxOpposite = (cmapMin < 0 && cmapMax > 0)
|| (cmapMin > 0 && cmapMax < 0);
if (mirror || minMaxOpposite) {
if (cmapMax < 0) {
// Invert colormapping if negative range was given
cmapValue = -cmapValue;
}
} 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;
// Log scaling is happening on both sides of zero, need to compute
// our zero index value
double zeroVal = rangeMin;
if (minMaxOpposite) {
// Min/Max are on opposite sides of zero, compute a zero value
zeroVal = Math.max(rangeMin, rangeMax) * 0.0001;
}
double leftZero = 0.0;
double rightZero = 0.0;
double negCmapMax = rangeMin;
double posCmapMax = rangeMax;
if (mirror) {
negCmapMax = posCmapMax = rangeMax;
}
// Compute log zero val and log neg/pos max vals
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));
double logNegCmapMax = absLogZeroVal + Math.log(negCmapMax);
double logPosCmapMax = absLogZeroVal + Math.log(posCmapMax);
// Calculate index which zeroVal is at based on neg max and pos max
double zeroValIndex = logNegCmapMax
/ (logNegCmapMax + logPosCmapMax);
if (cmapValue > 0) {
index = LogConverter.valueToIndex(rangeValue, zeroVal,
posCmapMax);
index = zeroValIndex + (1 - zeroValIndex) * index;
} 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));
index = LogConverter.valueToIndex(rangeValue, zeroVal,
negCmapMax);
index = zeroValIndex - zeroValIndex * index;
}
if (inverted) {
index = 1.0 - index;
}
} else {
// Simple case, just use log converter to get index
index = LogConverter.valueToIndex(rangeValue, rangeMin, rangeMax);
if (inverted) {
index = 1.0 - index;
}
if (cmapMin > 0 && cmapValue < rangeMin
|| (cmapMin < 0 && cmapValue > -rangeMin)) {
index = -index;
}
}
return index;

View file

@ -133,6 +133,7 @@ public class ColorMapParameters {
protected Unit<?> colorMapUnit;
/** Units of the data values to colormap */
@Deprecated
protected Unit<?> dataUnit;
/** The maximum value used to apply the colormap */
@ -142,9 +143,11 @@ public class ColorMapParameters {
protected float colorMapMin;
/** The maximum (usually theoretical) value of the data */
@Deprecated
protected float dataMax;
/** The minimum (usually theoretical) value of the data */
@Deprecated
protected float dataMin;
/** The intervals upon which to apply labeling to the color bar */
@ -162,15 +165,19 @@ public class ColorMapParameters {
protected String colorMapName;
/** The converter that converts data values to {@link #displayUnit} * */
@Deprecated
protected UnitConverter dataToDisplayConverter;
/** The converter that converts display values to {@link #dataUnit} * */
@Deprecated
protected UnitConverter displayToDataConverter;
/** The converter that converts data values to {@link #colorMapUnit} */
@Deprecated
protected UnitConverter dataToColorMapConverter;
/** The converter that converts color map unit values to {@link #dataUnit} */
@Deprecated
protected UnitConverter colorMapToDataConverter;
/** The converter that converts color map unit values to {@link #displayUnit} */
@ -491,32 +498,40 @@ public class ColorMapParameters {
}
/**
* @deprecated data max is not important for general colormapping use
* @return the dataMax
*/
@Deprecated
public float getDataMax() {
return dataMax;
}
/**
* @deprecated data max is not important for general colormapping use
* @param dataMax
* the dataMax to set
*/
@Deprecated
public void setDataMax(float dataMax) {
this.dataMax = dataMax;
notifyListener();
}
/**
* @deprecated data min is not important for general colormapping use
* @return the dataMin
*/
@Deprecated
public float getDataMin() {
return dataMin;
}
/**
* @deprecated data min is not important for general colormapping use
* @param dataMin
* the dataMin to set
*/
@Deprecated
public void setDataMin(float dataMin) {
this.dataMin = dataMin;
notifyListener();
@ -563,8 +578,10 @@ public class ColorMapParameters {
/**
* Returns the unit data values to be colormapped are in
*
* @deprecated data unit is not important for general colormapping use
* @return the dataUnit
*/
@Deprecated
public Unit<?> getDataUnit() {
return dataUnit;
}
@ -572,9 +589,11 @@ public class ColorMapParameters {
/**
* Sets the unit data values to be colormapped are in
*
* @deprecated data unit is not important for general colormapping use
* @param dataUnit
* the dataUnit to set
*/
@Deprecated
public void setDataUnit(Unit<?> dataUnit) {
this.dataUnit = dataUnit;
@ -595,8 +614,10 @@ public class ColorMapParameters {
* Returns the {@link UnitConverter} from {@link #dataUnit} to
* {@link #displayUnit}
*
* @deprecated data unit is not important for general colormapping use
* @return the dataToDisplayConverter
*/
@Deprecated
public UnitConverter getDataToDisplayConverter() {
if (dataToDisplayConverter == null) {
dataToDisplayConverter = constructConverter(dataUnit, displayUnit);
@ -611,8 +632,10 @@ public class ColorMapParameters {
* Returns the {@link UnitConverter} from {@link #displayUnit} to
* {@link #dataUnit}
*
* @deprecated data unit is not important for general colormapping use
* @return the displayToDataConverter
*/
@Deprecated
public UnitConverter getDisplayToDataConverter() {
if (displayToDataConverter == null) {
displayToDataConverter = constructConverter(displayUnit, dataUnit);
@ -667,8 +690,10 @@ public class ColorMapParameters {
* Returns a {@link UnitConverter} converting {@link #dataUnit} values to
* the {@link #colorMapUnit} if compatible or null otherwise
*
* @deprecated data unit is not important for general colormapping use
* @return
*/
@Deprecated
public UnitConverter getDataToColorMapConverter() {
if (dataToColorMapConverter == null) {
dataToColorMapConverter = constructConverter(dataUnit, colorMapUnit);
@ -773,8 +798,10 @@ public class ColorMapParameters {
* Returns a {@link UnitConverter} converting {@link #colorMapUnit} values
* to the {@link #dataUnit} if compatible or null otherwise
*
* @deprecated data unit is not important for general colormapping use
* @return
*/
@Deprecated
public UnitConverter getColorMapToDataConverter() {
if (colorMapToDataConverter == null) {
colorMapToDataConverter = constructConverter(colorMapUnit, dataUnit);