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:
parent
0dbc31b756
commit
e58a5df04b
19 changed files with 610 additions and 427 deletions
|
@ -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();
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
*
|
||||
|
|
|
@ -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>
|
||||
*
|
||||
|
|
|
@ -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>
|
||||
*
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue