Merge branch 'development_on_RHEL5' (GOES-R) into development

Conflicts:
	cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/rsc/SatBlendedResource.java
	nativeLib/edexBridge/edexBridge.cpp
	rpms/build/i386/build.sh
	rpms/build/x86_64/build.sh

Former-commit-id: 7969ef9648 [formerly 760f215e8c] [formerly f6787c0b9f2cb0cae1c07a2111e91ecfc12f31f5 [formerly f5f75ec629]] [formerly e82e1137f9 [formerly f5f75ec629 [formerly 039d9ecb587338801cdab9cad11b06890517d6a4]]]
Former-commit-id: e82e1137f9
Former-commit-id: cecc12c190bbaa908cbfe835a5a9a64a5ba96dba [formerly 94994868fa]
Former-commit-id: ee03dcf505
This commit is contained in:
Richard Peter 2013-12-03 16:25:31 -06:00
commit 2cafd3a81b
31 changed files with 1362 additions and 667 deletions

View file

@ -76,10 +76,12 @@ import com.vividsolutions.jts.geom.Coordinate;
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jul 18, 2011 2190 mschenke Initial creation
* Oct 2, 2013 2333 mschenke Converted to use IGridGeometryProvider
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Jul 18, 2011 2190 mschenke Initial creation
* Oct 2, 2013 2333 mschenke Converted to use IGridGeometryProvider
* Nov 20, 2013 2492 bsteffen Refactor deprecated references to
* ColorMapParameters.getDataUnit
*
* </pre>
*
@ -389,8 +391,8 @@ public class CloudHeightResource extends
if (rsc != null && rsc.hasCapability(ColorMapCapability.class)) {
ColorMapParameters params = rsc.getCapability(
ColorMapCapability.class).getColorMapParameters();
if (params != null && params.getDataUnit() != null
&& TEMP_UNIT.isCompatible(params.getDataUnit())) {
if (params != null && params.getColorMapUnit() != null
&& TEMP_UNIT.isCompatible(params.getColorMapUnit())) {
return true;
}
}

View file

@ -39,6 +39,7 @@ import com.raytheon.uf.viz.core.maps.scales.MapScales.MapScale;
import com.raytheon.uf.viz.core.maps.scales.MapScalesManager.ManagedMapScale;
import com.raytheon.uf.viz.core.procedures.Bundle;
import com.raytheon.uf.viz.core.rsc.ResourceList;
import com.raytheon.uf.viz.core.rsc.ResourceProperties;
/**
* MapRenderableDisplay associated with a {@link MapScale}
@ -47,10 +48,11 @@ import com.raytheon.uf.viz.core.rsc.ResourceList;
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Mar 22, 2013 mschenke Initial creation
* Oct 10, 2013 2104 mschenke Switched to use MapScalesManager
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Mar 22, 2013 mschenke Initial creation
* Oct 10, 2013 2104 mschenke Switched to use MapScalesManager
* Nov 20, 2013 2492 bsteffen Recycle resources in clear.
*
* </pre>
*
@ -133,9 +135,13 @@ public class MapScaleRenderableDisplay extends PlainMapRenderableDisplay
// non-map/system layers and reset display
ResourceList list = descriptor.getResourceList();
for (ResourcePair rp : list) {
if (rp.getProperties().isMapLayer() == false
&& rp.getProperties().isSystemResource() == false) {
ResourceProperties props = rp.getProperties();
if (props.isMapLayer() == false
&& props.isSystemResource() == false) {
list.remove(rp);
} else {
props.setVisible(true);
rp.getResource().recycle();
}
}

View file

@ -28,7 +28,6 @@ import java.util.List;
import java.util.Map;
import javax.measure.unit.Unit;
import javax.measure.unit.UnitFormat;
import org.geotools.coverage.grid.GridEnvelope2D;
import org.geotools.coverage.grid.GridGeometry2D;
@ -71,11 +70,13 @@ import com.vividsolutions.jts.geom.Coordinate;
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 19, 2013 2122 mschenke Initial creation.
* Oct 16, 2013 2333 mschenke Added method for auto-unit conversion
* interrogating
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Jun 19, 2013 2122 mschenke Initial creation.
* Oct 16, 2013 2333 mschenke Added method for auto-unit conversion
* interrogating
* Nov 20, 2013 2492 bsteffen Move unit converting interrogate into
* TileSetRenderable.
*
* </pre>
*
@ -369,61 +370,12 @@ public class RecordTileSetRenderable extends TileSetRenderable {
return interrogate(coordinate, parameters.getNoDataValue());
}
/**
* Returns the raw image value from tile image that contains the lat/lon
* coordinate in units of desiredUnit
*
* @param coordinate
* in lat/lon space
* @param desiredUnit
* unit to convert data value to if not nanValue
* @return
* @throws VizException
*/
public double interrogate(Coordinate coordinate, Unit<?> desiredUnit)
@Override
public double interrogate(Coordinate coordinate, Unit<?> resultUnit)
throws VizException {
ColorMapParameters parameters = colormapping.getColorMapParameters();
return interrogate(coordinate, parameters.getNoDataValue(), desiredUnit);
}
/**
* Returns the raw image value from tile image that contains the lat/lon
* coordinate in units of desiredUnit
*
* @param coordinate
* in lat/lon space
* @param nanValue
* if interrogated value is equal to nanValue, {@link Double#NaN}
* will be returned
* @param desiredUnit
* unit to convert data value to if not nanValue
* @return
* @throws VizException
*/
public double interrogate(Coordinate coordinate, double nanValue,
Unit<?> desiredUnit) throws VizException {
double dataValue = super.interrogate(coordinate, nanValue);
if (Double.isNaN(dataValue) == false) {
ColorMapParameters params = colormapping.getColorMapParameters();
Unit<?> dataUnit = params.getDataUnit();
if (dataUnit != null && desiredUnit != null
&& dataUnit != desiredUnit) {
if (dataUnit.isCompatible(desiredUnit)) {
dataValue = dataUnit.getConverterTo(desiredUnit).convert(
dataValue);
} else {
throw new IllegalArgumentException(
"Unable to interrogate tile set. "
+ String.format(
"Desired unit (%s) is not compatible with data unit (%s).",
UnitFormat.getUCUMInstance()
.format(desiredUnit),
UnitFormat.getUCUMInstance()
.format(dataUnit)));
}
}
}
return dataValue;
return super.interrogate(coordinate, resultUnit,
parameters.getNoDataValue());
}
/**

View file

@ -27,6 +27,9 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.measure.unit.Unit;
import javax.measure.unit.UnitFormat;
import org.geotools.coverage.grid.GeneralGridGeometry;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.referencing.crs.DefaultGeographicCRS;
@ -67,6 +70,7 @@ import com.vividsolutions.jts.geom.Coordinate;
* Jun 20, 2013 2122 mschenke Fixed null pointer in interrogate and made
* canceling jobs safer
* Oct 16, 2013 2333 mschenke Added auto NaN checking for interrogation
* Nov 14, 2013 2492 mschenke Added more interrogate methods that take units
*
* </pre>
*
@ -475,12 +479,33 @@ public class TileSetRenderable implements IRenderable {
* @throws VizException
*/
public double interrogate(Coordinate coordinate) throws VizException {
return interrogate(coordinate, Double.NaN);
return interrogate(coordinate, null);
}
/**
* Returns the raw image value from tile image that contains the lat/lon
* coordinate. Any values matching nanValue will return {@link Double#NaN}
* coordinate
*
* @param coordinate
* in lat/lon space
* @param resultUnit
* unit result from interrogate will be returned is. If unit is
* not compatible with data unit, {@link Double#NaN} will be
* returned. Null indicates data will not be converted
* @param nanValue
* if interrogated value is equal to nanValue, {@link Double#NaN}
* will be returned
* @return
* @throws VizException
*/
public double interrogate(Coordinate coordinate, Unit<?> resultUnit)
throws VizException {
return interrogate(coordinate, resultUnit, Double.NaN);
}
/**
* Returns the raw image value from tile image that contains the lat/lon
* coordinate
*
* @param coordinate
* in lat/lon space
@ -492,6 +517,27 @@ public class TileSetRenderable implements IRenderable {
*/
public double interrogate(Coordinate coordinate, double nanValue)
throws VizException {
return interrogate(coordinate, null, nanValue);
}
/**
* Returns the raw image value from tile image that contains the lat/lon
* coordinate. Any values matching nanValue will return {@link Double#NaN}
*
* @param coordinate
* in lat/lon space
* @param resultUnit
* unit result from interrogate will be returned is. If unit is
* not compatible with data unit, {@link Double#NaN} will be
* returned. Null indicates data will not be converted
* @param nanValue
* if interrogated value is equal to nanValue, {@link Double#NaN}
* will be returned
* @return
* @throws VizException
*/
public double interrogate(Coordinate coordinate, Unit<?> resultUnit,
double nanValue) throws VizException {
double dataValue = Double.NaN;
try {
double[] local = new double[2];
@ -515,8 +561,27 @@ public class TileSetRenderable implements IRenderable {
% tileSize);
if (dataValue == nanValue) {
dataValue = Double.NaN;
} else {
Unit<?> dataUnit = cmapImage.getDataUnit();
if (resultUnit != null && dataUnit != null
&& dataUnit.equals(resultUnit) == false) {
if (resultUnit.isCompatible(dataUnit)) {
dataValue = dataUnit.getConverterTo(
resultUnit).convert(dataValue);
} else {
throw new IllegalArgumentException(
"Unable to interrogate tile set. "
+ String.format(
"Desired unit (%s) is not compatible with data unit (%s).",
UnitFormat
.getUCUMInstance()
.format(resultUnit),
UnitFormat
.getUCUMInstance()
.format(dataUnit)));
}
}
}
}
}
}

View file

@ -49,7 +49,7 @@ vec4 applyColorBand(int colorband) {
vec2((xy.x / width), (xy.y / height)));
// Lookup raw data value
float dataValue = getDataValue(rawData, gl_TexCoord[0].st);
float dataValue = textureToDataValue(rawData, gl_TexCoord[0].st);
float r = curVal.r;
float g = curVal.g;

View file

@ -232,8 +232,7 @@ public class GLTrueColorImagingExtension extends AbstractGLSLImagingExtension
parameters.put(colorMapParameters, null);
GLSLStructFactory.createDataTexture(program, "rawData", 0,
cmapImage.getDataFormat(),
colorMapParameters.getNoDataValue());
cmapImage);
int numMappingValues = 0;
GLDataMapping mapping = cmapImage.getDataMapping();

View file

@ -7,7 +7,7 @@ uniform ColorMapping colorMapping;
uniform ColorModifiers modifiers;
void main(void) {
float dataValue = getDataValue(rawData, gl_TexCoord[0].st);
float dataValue = textureToDataValue(rawData, gl_TexCoord[0].st);
// No data check/special NaN check
if (dataValue == rawData.noDataValue || dataValue != dataValue) {

View file

@ -14,6 +14,8 @@ struct DataTexture {
int isScaled;
float scaleMin;
float scaleMax;
float width;
float height;
};
/**
@ -51,7 +53,7 @@ struct ColorMapping {
/**
* Returns the data value for the DataTexture at location.
*/
float getDataValue(DataTexture texture, vec2 location) {
float textureToDataValue(DataTexture texture, vec2 location) {
vec4 textureValue = texture2D(texture.rawTex, location);
float dataValue = textureValue.r;
@ -63,6 +65,18 @@ float getDataValue(DataTexture texture, vec2 location) {
return dataValue;
}
/**
* Returns the data value for the DataTexture at location.
*/
float dataToTextureValue(DataTexture texture, float dataValue) {
float textureValue = dataValue;
if (texture.isScaled == 1) {
textureValue = (dataValue - texture.scaleMin)
/ (texture.scaleMax - texture.scaleMin);
}
return textureValue;
}
/**
* Looks up a value in a mapping texture given an index [0-numMappingValues).
*/
@ -103,8 +117,8 @@ float dataToColorMapValue(float dataValue, DataMapping mapping) {
int nextIndex = lowIndex + ((highIndex - lowIndex) / 2);
if (nextIndex > lowIndex && nextIndex < highIndex) {
// Look up next value and determine if it is a high or low
float nextValue = lookupMappingValue(mapping.dataMappingValues, nextIndex,
numMappingValues);
float nextValue = lookupMappingValue(mapping.dataMappingValues,
nextIndex, numMappingValues);
if (nextValue < dataValue) {
if (reversed == 0) {
lowIndex = nextIndex;
@ -132,10 +146,10 @@ float dataToColorMapValue(float dataValue, DataMapping mapping) {
factor = 1.0 - factor;
}
float lowCmapValue = lookupMappingValue(mapping.colorMappingValues, lowIndex,
numMappingValues);
float highCmapValue = lookupMappingValue(mapping.colorMappingValues, highIndex,
numMappingValues);
float lowCmapValue = lookupMappingValue(mapping.colorMappingValues,
lowIndex, numMappingValues);
float highCmapValue = lookupMappingValue(mapping.colorMappingValues,
highIndex, numMappingValues);
return lowCmapValue + (highCmapValue - lowCmapValue) * factor;
}

View file

@ -1,19 +1,27 @@
// this shader program sets values into a mosaic texture
// which is the same size as the screen (frame buffer)
uniform sampler2D imageData;
uniform sampler2D mosaicTexture;
uniform int height;
uniform int width;
#include <mapping>
void main(void)
{
vec2 xy = gl_FragCoord.xy;
vec4 imageVal = texture2D(imageData,gl_TexCoord[0].st);
vec4 curVal = texture2D(mosaicTexture, vec2((xy.x / float(width)), (xy.y / float(height))));
if ( imageVal.r > curVal.r ) {
gl_FragColor = vec4(imageVal.r,0.0,0.0,1.0);
} else {
gl_FragColor = vec4(curVal.r,0.0,0.0,1.0);
uniform DataTexture imageData;
uniform DataMapping imageToMosaic;
uniform DataTexture mosaicData;
void main(void) {
float imageValue = textureToDataValue(imageData, gl_TexCoord[0].st);
vec2 frag_xy = gl_FragCoord.xy;
float mosaicValue = textureToDataValue(mosaicData,
vec2(frag_xy.x / mosaicData.width, frag_xy.y / mosaicData.height));
float newValue = mosaicValue;
// No data check/special NaN check
if (imageValue != imageData.noDataValue && imageValue == imageValue) {
// Convert image value to mosaic value
imageValue = dataToColorMapValue(imageValue, imageToMosaic);
if (imageValue > mosaicValue) {
newValue = imageValue;
}
}
gl_FragColor = vec4(dataToTextureValue(mosaicData, newValue), 0.0, 0.0,
1.0);
}

View file

@ -1,20 +1,26 @@
// this shader program sets values into a mosaic texture
// which is the same size as the screen (frame buffer)
uniform sampler2D imageData;
uniform sampler2D mosaicTexture;
uniform int height;
uniform int width;
#include <mapping>
void main(void)
{
vec2 xy = gl_FragCoord.xy;
vec4 imageVal = texture2D(imageData,gl_TexCoord[0].st);
vec4 curVal = texture2D(mosaicTexture, vec2((xy.x / float(width)), (xy.y / float(height))));
// assume 0 or NaN is No Data and should be replaced if another image has better values.
if ( imageVal.r != 0.0 && imageVal.r == imageVal.r) {
gl_FragColor = vec4(imageVal.r,0.0,0.0,1.0);
uniform DataTexture imageData;
uniform DataMapping imageToMosaic;
uniform DataTexture mosaicData;
void main(void) {
float imageValue = textureToDataValue(imageData, gl_TexCoord[0].st);
vec2 frag_xy = gl_FragCoord.xy;
float mosaicValue = textureToDataValue(mosaicData,
vec2(frag_xy.x / mosaicData.width, frag_xy.y / mosaicData.height));
float newValue;
// No data check/special NaN check
if (imageValue == imageData.noDataValue || imageValue != imageValue) {
// Use existing value
newValue = mosaicValue;
} else {
gl_FragColor = vec4(curVal.r,0.0,0.0,1.0);
newValue = dataToColorMapValue(imageValue, imageToMosaic);
}
gl_FragColor = vec4(dataToTextureValue(mosaicData, newValue), 0.0, 0.0,
1.0);
}

View file

@ -53,9 +53,6 @@
<graphicsExtension
class="com.raytheon.viz.core.gl.ext.imaging.GLDefaultImagingExtension">
</graphicsExtension>
<graphicsExtension
class="com.raytheon.viz.core.gl.internal.ext.mosaic.GLMosaicImageExtension">
</graphicsExtension>
<graphicsExtension
class="com.raytheon.viz.core.gl.internal.ext.mosaic.GLMosaicMaxValImageExtension">
</graphicsExtension>

View file

@ -54,14 +54,16 @@ import com.raytheon.viz.core.gl.objects.GLTextureObject;
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Nov 18, 2011 mschenke Initial creation
* Feb 14, 2013 1616 bsteffen Add option for interpolation of colormap
* parameters, disable colormap interpolation
* by default.
* Oct 16, 2013 2333 mschenke Cleaned up load shader method, used isScaled.
* Added support for colormapping in non-data unit.
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Nov 18, 2011 mschenke Initial creation
* Feb 14, 2013 1616 bsteffen Add option for interpolation of colormap
* parameters, disable colormap interpolation
* by default.
* Oct 16, 2013 2333 mschenke Cleaned up load shader method, used isScaled.
* Added support for colormapping in non-data unit.
* Nov 20, 2013 2492 bsteffen Mosaic in image units.
*
*
* </pre>
*
@ -174,7 +176,8 @@ public class GLColormappedImageExtension extends AbstractGLSLImagingExtension
}
/**
* Sets up a {@link GLDataMapping} for use in image rendering
* Sets up a {@link GLDataMapping} for use in image rendering. Data will be
* mapped to the image's {@link ColorMapParameters#getColorMapUnit()}
*
* @param gl
* @param glImage
@ -185,14 +188,32 @@ public class GLColormappedImageExtension extends AbstractGLSLImagingExtension
public static void setupDataMapping(GL gl,
AbstractGLColormappedImage glImage, int dataMappedTexBinding,
int colorMappedTexBinding) throws VizException {
setupDataMapping(gl, glImage, glImage.getColorMapParameters()
.getColorMapUnit(), dataMappedTexBinding, colorMappedTexBinding);
}
/**
* Sets up a {@link GLDataMapping} for use in image renderingData will be
* mapped to the unit provided
*
* @param gl
* @param glImage
* @param colorMapUnit
* @param dataMappedTexBinding
* @param colorMappedTexBinding
* @throws VizException
*/
public static void setupDataMapping(GL gl,
AbstractGLColormappedImage glImage, Unit<?> colorMapUnit,
int dataMappedTexBinding, int colorMappedTexBinding)
throws VizException {
ColorMapParameters colorMapParameters = glImage.getColorMapParameters();
// Get GLDataMapping and generate if datamapping is not set. If
// datamapping is not set, the data has already been mapped to
// colorMapUnits and we need not do anything
GLDataMapping dataMapping = glImage.getDataMapping();
if (dataMapping == null && colorMapParameters.getDataMapping() == null) {
Unit<?> colorMapUnit = colorMapParameters.getColorMapUnit();
Unit<?> dataUnit = colorMapParameters.getDataUnit();
Unit<?> dataUnit = glImage.getDataUnit();
int colorMapSize = colorMapParameters.getColorMap().getSize();
float colorMapMin = colorMapParameters.getColorMapMin();
float colorMapMax = colorMapParameters.getColorMapMax();
@ -290,8 +311,7 @@ public class GLColormappedImageExtension extends AbstractGLSLImagingExtension
ColorMapParameters colorMapParameters = image.getColorMapParameters();
GLSLStructFactory.createDataTexture(program, "rawData", 0,
image.getDataFormat(), colorMapParameters.getNoDataValue());
GLSLStructFactory.createDataTexture(program, "rawData", 0, image);
int numMappingValues = 0;
GLDataMapping mapping = image.getDataMapping();

View file

@ -21,6 +21,7 @@ package com.raytheon.viz.core.gl.glsl;
import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
import com.raytheon.viz.core.gl.dataformat.AbstractGLColorMapDataFormat;
import com.raytheon.viz.core.gl.images.AbstractGLColormappedImage;
/**
* Factory for creating API defined GLSL structs in a {@link GLShaderProgram}.
@ -49,14 +50,15 @@ public class GLSLStructFactory {
* @param program
* @param name
* @param texBinding
* @param dataFormat
* @param noDataValue
* @param image
*/
public static void createDataTexture(GLShaderProgram program, String name,
int texBinding, AbstractGLColorMapDataFormat dataFormat,
double noDataValue) {
int texBinding, AbstractGLColormappedImage image) {
ColorMapParameters parameters = image.getColorMapParameters();
AbstractGLColorMapDataFormat dataFormat = image.getDataFormat();
setFieldUniform(program, name, "rawTex", texBinding);
setFieldUniform(program, name, "noDataValue", noDataValue);
setFieldUniform(program, name, "noDataValue",
parameters.getNoDataValue());
setFieldUniform(program, name, "isScaled", dataFormat.isScaled());
if (dataFormat.isScaled()) {
setFieldUniform(program, name, "scaleMin",
@ -64,6 +66,8 @@ public class GLSLStructFactory {
setFieldUniform(program, name, "scaleMax",
dataFormat.getDataFormatMax());
}
setFieldUniform(program, name, "width", (float) image.getWidth());
setFieldUniform(program, name, "height", (float) image.getHeight());
}
/**

View file

@ -33,8 +33,12 @@ import com.raytheon.uf.viz.core.drawables.PaintProperties;
import com.raytheon.uf.viz.core.drawables.ext.IMosaicImageExtension;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.viz.core.gl.ext.GLOffscreenRenderingExtension;
import com.raytheon.viz.core.gl.ext.imaging.GLColormappedImageExtension;
import com.raytheon.viz.core.gl.ext.imaging.GLDataMappingFactory.GLDataMapping;
import com.raytheon.viz.core.gl.glsl.AbstractGLSLImagingExtension;
import com.raytheon.viz.core.gl.glsl.GLSLStructFactory;
import com.raytheon.viz.core.gl.glsl.GLShaderProgram;
import com.raytheon.viz.core.gl.images.AbstractGLColormappedImage;
import com.raytheon.viz.core.gl.images.AbstractGLImage;
import com.raytheon.viz.core.gl.images.GLColormappedImage;
import com.raytheon.viz.core.gl.images.GLOffscreenColormappedImage;
@ -46,13 +50,14 @@ import com.raytheon.viz.core.gl.images.GLOffscreenColormappedImage;
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Dec 16, 2011 mschenke Initial creation
* Mar 21, 2013 1806 bsteffen Update GL mosaicing to use dynamic data
* format for offscreen textures.
* Oct 16, 2013 2333 mschenke Cleaned up render logic, switched to
* use GLOffscreenColormappedImage
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Dec 16, 2011 mschenke Initial creation
* Mar 21, 2013 1806 bsteffen Update GL mosaicing to use dynamic data
* format for offscreen textures.
* Oct 16, 2013 2333 mschenke Cleaned up render logic, switched to use
* GLOffscreenColormappedImage
* Nov 20, 2013 2492 bsteffen Mosaic in image units.
*
* </pre>
*
@ -60,8 +65,8 @@ import com.raytheon.viz.core.gl.images.GLOffscreenColormappedImage;
* @version 1.0
*/
public class GLMosaicImageExtension extends AbstractGLSLImagingExtension
implements IMosaicImageExtension {
public abstract class GLMosaicImageExtension extends
AbstractGLSLImagingExtension implements IMosaicImageExtension {
private GLOffscreenColormappedImage writeToImage;
@ -75,19 +80,6 @@ public class GLMosaicImageExtension extends AbstractGLSLImagingExtension
imageExtent, this.getClass());
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.viz.core.gl.ext.AbstractGLImagingExtension#getShaderProgramName
* ()
*/
@Override
public String getShaderProgramName() {
// Default mosaicing algorithm glsl program
return "mosaicOrdered";
}
/*
* (non-Javadoc)
*
@ -142,16 +134,20 @@ public class GLMosaicImageExtension extends AbstractGLSLImagingExtension
new DrawableImage(mosaicImage.getWrappedImage(),
coverage));
}
// Don't actually render this image now since we just did it
return null;
} else {
} else if (image instanceof AbstractGLColormappedImage) {
GL gl = target.getGl();
// activate on texture2 as 0 is radar image and 1 is colormap
gl.glActiveTexture(GL.GL_TEXTURE1);
gl.glBindTexture(writeToImage.getTextureStorageType(),
writeToImage.getTextureid());
GLColormappedImageExtension.setupDataMapping(gl,
(AbstractGLColormappedImage) image,
writeToImage.getDataUnit(), 2, 3);
return image;
}
// Fall through here, no actual rendering will occur
return null;
}
private GLOffscreenColormappedImage getWriteToImage(
@ -208,6 +204,12 @@ public class GLMosaicImageExtension extends AbstractGLSLImagingExtension
// activate on texture2 as 0 is radar image
gl.glActiveTexture(GL.GL_TEXTURE1);
gl.glBindTexture(writeToImage.getTextureStorageType(), 0);
gl.glActiveTexture(GL.GL_TEXTURE2);
gl.glBindTexture(GL.GL_TEXTURE_1D, 0);
gl.glActiveTexture(GL.GL_TEXTURE3);
gl.glBindTexture(GL.GL_TEXTURE_1D, 0);
}
/*
@ -220,14 +222,27 @@ public class GLMosaicImageExtension extends AbstractGLSLImagingExtension
* com.raytheon.uf.viz.core.drawables.PaintProperties)
*/
@Override
public void loadShaderData(GLShaderProgram program, IImage image,
public void loadShaderData(GLShaderProgram program, IImage iimage,
PaintProperties paintProps) throws VizException {
program.setUniform("imageData", 0);
program.setUniform("mosaicTexture", 1);
AbstractGLColormappedImage image = null;
if (iimage instanceof AbstractGLColormappedImage == false) {
throw new VizException(
"Cannot apply glsl mosaicing shader to non gl colormap image");
}
image = (AbstractGLColormappedImage) iimage;
// pass in width and height
program.setUniform("height", writeToImage.getHeight());
program.setUniform("width", writeToImage.getWidth());
GLSLStructFactory.createDataTexture(program, "imageData", 0, image);
int numMappingValues = 0;
GLDataMapping mapping = image.getDataMapping();
if (mapping != null && mapping.isValid()) {
numMappingValues = mapping.getNumMappingValues();
}
GLSLStructFactory.createDataMapping(program, "imageToMosaic", 2, 3,
numMappingValues);
GLSLStructFactory.createDataTexture(program, "mosaicData", 1,
writeToImage);
}
}

View file

@ -24,6 +24,8 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import javax.measure.Measure;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
@ -64,6 +66,7 @@ import com.vividsolutions.jts.geom.Coordinate;
* only check for NaN. SatResource handles fill
* values and returns NaN now
* Nov 18, 2013 2544 bsteffen Override recycleInternal
* Nov 20, 2013 2492 bsteffen Update inspect to use Measure objects
*
* </pre>
*
@ -291,10 +294,12 @@ public class SatBlendedResource extends
for (int i = list.size() - 1; i >= 0; --i) {
AbstractVizResource<?, ?> rsc = list.get(i).getResource();
Map<String, Object> dataMap = rsc.interrogate(coord);
if (dataMap.get(SatResource.RAW_VALUE) instanceof Number) {
double value = ((Number) dataMap.get(SatResource.RAW_VALUE))
Measure<?, ?> value = (Measure<?, ?>) dataMap
.get(SatResource.SATELLITE_DATA_INTERROGATE_ID);
if (value != null && value.getValue() instanceof Number) {
double measuredValue = ((Number) value.getValue())
.doubleValue();
if (Double.isNaN(value) == false) {
if (Double.isNaN(measuredValue) == false) {
// use this resource
inspectString = rsc.inspect(coord);
break;

View file

@ -29,6 +29,7 @@ import java.util.Map;
import javax.measure.Measure;
import javax.measure.converter.UnitConverter;
import javax.measure.quantity.Temperature;
import javax.measure.unit.Unit;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
@ -41,18 +42,14 @@ import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataplugin.satellite.SatMapCoverage;
import com.raytheon.uf.common.dataplugin.satellite.SatelliteRecord;
import com.raytheon.uf.common.dataplugin.satellite.units.SatelliteUnits;
import com.raytheon.uf.common.dataplugin.satellite.units.generic.GenericPixel;
import com.raytheon.uf.common.dataplugin.satellite.units.water.BlendedTPWPixel;
import com.raytheon.uf.common.geospatial.IGridGeometryProvider;
import com.raytheon.uf.common.geospatial.ReferencedCoordinate;
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.uf.common.style.ParamLevelMatchCriteria;
import com.raytheon.uf.common.style.StyleException;
import com.raytheon.uf.common.style.StyleManager;
import com.raytheon.uf.common.style.StyleRule;
import com.raytheon.uf.common.style.image.ColorMapParameterFactory;
import com.raytheon.uf.common.style.image.DataScale;
import com.raytheon.uf.common.style.image.ImagePreferences;
import com.raytheon.uf.common.style.image.SamplePreferences;
import com.raytheon.uf.common.style.level.Level;
@ -82,19 +79,25 @@ import com.vividsolutions.jts.geom.Coordinate;
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Mar 1, 2007 chammack Initial Creation.
* 02/17/2009 njensen Refactored to new rsc architecture.
* 03/02/2009 2032 jsanchez Added check for displayedDate if no data.
* 03/25/2009 2086 jsanchez Mapped correct converter to parameter type.
* Updated the call to ColormapParametersFactory.build
* 03/30/2009 2169 jsanchez Updated numLevels handling.
* - AWIPS2 Baseline Repository --------
* 07/17/2012 798 jkorman Use decimationLevels from SatelliteRecord. Removed hard-coded
* data set names.
* 06/20/2013 2122 mschenke Modified to use SatTileSetRenderable
* 07/31/2013 2190 mschenke Switched to use Measure objects for interrogation
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Mar 01, 2007 chammack Initial Creation.
* Feb 17, 2009 njensen Refactored to new rsc architecture.
* Mar 02, 2009 2032 jsanchez Added check for displayedDate if no
* data.
* Mar 25, 2009 2086 jsanchez Mapped correct converter to parameter
* type. Updated the call to
* ColormapParametersFactory.build
* Mar 30, 2009 2169 jsanchez Updated numLevels handling.
* Jul 17, 2012 798 jkorman Use decimationLevels from
* SatelliteRecord. Removed hard-coded
* data set names.
* Jun 20, 2013 2122 mschenke Modified to use SatTileSetRenderable
* Jul 31, 2013 2190 mschenke Switched to use Measure objects for
* interrogation
* Nov 20, 2013 2492 bsteffen Always get min/max values from style
* rules.
*
* </pre>
*
* @author chammack
@ -103,11 +106,6 @@ import com.vividsolutions.jts.geom.Coordinate;
public class SatResource extends
AbstractPluginDataObjectResource<SatResourceData, IMapDescriptor> {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(SatResource.class);
public static String RAW_VALUE = "rawValue";
/** String id to look for satellite-provided data values */
public static final String SATELLITE_DATA_INTERROGATE_ID = "satelliteDataValue";
@ -215,12 +213,12 @@ public class SatResource extends
}
}
public InterrogationResult interrogate(Coordinate latLon)
throws VizException {
public InterrogationResult interrogate(Coordinate latLon,
Unit<?> requestUnit) throws VizException {
InterrogationResult result = null;
synchronized (tileMap) {
for (SatTileSetRenderable renderable : tileMap.values()) {
double rValue = renderable.interrogate(latLon, fillValue);
double rValue = renderable.interrogate(latLon, requestUnit);
if (Double.isNaN(rValue) == false) {
result = new InterrogationResult(
renderable.getSatelliteRecord(), rValue);
@ -235,7 +233,8 @@ public class SatResource extends
protected SamplePreferences sampleRange;
protected double fillValue = 0;
/** Flag to avoid reinitializing ColorMapParameters from style rules */
private boolean initialized = false;
/**
* Constructor
@ -249,21 +248,19 @@ public class SatResource extends
@Override
protected DataTime getDataObjectTime(PluginDataObject pdo) {
SatelliteRecord record = (SatelliteRecord) pdo;
if (dataTimes.isEmpty()) {
if (initialized == false) {
try {
initializeFirstFrame(record);
initializeFirstFrame((SatelliteRecord) pdo);
} catch (VizException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
throw new IllegalStateException(
"Unable to initialize the satellite resource");
}
initialized = true;
}
DataTime pdoTime = pdo.getDataTime();
if (resourceData.getBinOffset() != null) {
pdoTime = resourceData.getBinOffset().getNormalizedTime(pdoTime);
}
return pdoTime;
}
@ -286,7 +283,6 @@ public class SatResource extends
}
SingleLevel level = new SingleLevel(Level.LevelType.SURFACE);
Unit<?> unit = SatDataRetriever.getRecordUnit(record);
String physicalElement = null;
DerivedParameterRequest request = (DerivedParameterRequest) record
.getMessageData();
@ -301,25 +297,42 @@ public class SatResource extends
match.setParameterName(Arrays.asList(physicalElement));
match.setLevels(Arrays.asList((Level) level));
match.setCreatingEntityNames(Arrays.asList(record.getCreatingEntity()));
StyleRule sr;
Unit<?> unit = SatDataRetriever.getRecordUnit(record);
try {
sr = StyleManager.getInstance().getStyleRule(
StyleRule sr = StyleManager.getInstance().getStyleRule(
StyleManager.StyleType.IMAGERY, match);
} catch (StyleException e) {
throw new VizException(e.getLocalizedMessage(), e);
}
if (sr != null && sr.getPreferences() instanceof ImagePreferences) {
sampleRange = ((ImagePreferences) sr.getPreferences())
.getSamplePrefs();
String lg = ((ImagePreferences) sr.getPreferences()).getLegend();
ImagePreferences preferences = null;
if (sr == null
|| sr.getPreferences() instanceof ImagePreferences == false) {
// No style rule, this is a best guess at what might look good.
preferences = new ImagePreferences();
if (unit != null && unit.isCompatible(Temperature.UNIT)) {
preferences.setDefaultColormap("Sat/IR/CIRA (IR Default)");
} else {
preferences.setDefaultColormap("Sat/VIS/ZA (Vis Default)");
}
DataScale range = new DataScale();
range.setScaleType(DataScale.Type.LINEAR);
range.setMinValue(0.0);
range.setMaxValue(255.0);
preferences.setDataScale(range);
} else {
preferences = (ImagePreferences) sr.getPreferences();
}
colorMapParameters = ColorMapParameterFactory.build(preferences,
unit);
sampleRange = preferences.getSamplePrefs();
String lg = preferences.getLegend();
// test, so legend is not over written with empty string
if (lg != null && !lg.trim().isEmpty()) {
legend = lg;
}
} catch (StyleException e) {
throw new VizException(e.getLocalizedMessage(), e);
}
colorMapParameters = ColorMapParameterFactory.build(sr, null, level,
unit);
// If null, set from style rules
if (cmName == null) {
cmName = colorMapParameters.getColorMapName();
@ -343,26 +356,7 @@ public class SatResource extends
if (persisted != null) {
colorMapParameters.applyPersistedParameters(persisted);
}
// TODO: Figure out data/color map min/max values better
if (unit == null) {
colorMapParameters.setColorMapMin(0.0f);
colorMapParameters.setColorMapMax(255.0f);
}
if (unit instanceof GenericPixel) {
// Derived parameter data will be signed
colorMapParameters.setDataMin(-128.0f);
colorMapParameters.setDataMax(127.0f);
} else if (unit instanceof BlendedTPWPixel) {
colorMapParameters.setDataMin(0.0f);
colorMapParameters.setDataMax(252.0f);
colorMapParameters.setColorMapMin(0.0f);
colorMapParameters.setColorMapMax(252.0f);
} else {
colorMapParameters.setDataMin(0.0f);
colorMapParameters.setDataMax(255.0f);
}
colorMapParameters.setNoDataValue(0);
getCapability(ColorMapCapability.class).setColorMapParameters(
colorMapParameters);
@ -389,10 +383,11 @@ public class SatResource extends
ColorMapParameters parameters = getCapability(ColorMapCapability.class)
.getColorMapParameters();
double dataValue = Double.NaN;
Unit<?> dataUnit = parameters.getColorMapUnit();
if (renderable != null) {
try {
InterrogationResult result = renderable.interrogate(coord
.asLatLon());
InterrogationResult result = renderable.interrogate(
coord.asLatLon(), dataUnit);
if (result != null) {
dataValue = result.getValue();
dataMap.put(IGridGeometryProvider.class.toString(), result
@ -403,9 +398,8 @@ public class SatResource extends
}
}
dataMap.put(RAW_VALUE, dataValue);
dataMap.put(SATELLITE_DATA_INTERROGATE_ID,
Measure.valueOf(dataValue, parameters.getDataUnit()));
Measure.valueOf(dataValue, dataUnit));
return dataMap;
}
@ -413,8 +407,14 @@ public class SatResource extends
@Override
public String inspect(ReferencedCoordinate coord) throws VizException {
Map<String, Object> dataMap = interrogate(coord);
Double value = (Double) dataMap.get(RAW_VALUE);
if (value == null || value.isNaN()) {
Measure<?, ?> value = (Measure<?, ?>) dataMap
.get(SATELLITE_DATA_INTERROGATE_ID);
double measuredValue = Double.NaN;
if (value != null && value.getValue() instanceof Double) {
measuredValue = (Double) value.getValue();
}
if (Double.isNaN(measuredValue)) {
return "NO DATA";
}
ColorMapParameters cmp = getCapability(ColorMapCapability.class)
@ -425,18 +425,21 @@ public class SatResource extends
if (dataMapping != null) {
// if the pixel value matches the data mapping entry use that
// label instead
String label = dataMapping.getLabelValueForDataValue(value);
String label = dataMapping.getLabelValueForDataValue(measuredValue);
if (label != null) {
return label;
}
}
UnitConverter dataToDisplay = cmp.getDataToDisplayConverter();
if (dataToDisplay != null) {
value = dataToDisplay.convert(value);
Unit<?> unit = cmp.getDisplayUnit();
Unit<?> measuredUnit = value.getUnit();
if (unit != null && measuredUnit != null) {
UnitConverter dataToDisplay = measuredUnit.getConverterTo(unit);
if (dataToDisplay != null) {
measuredValue = dataToDisplay.convert(measuredValue);
}
}
Unit<?> unit = cmp.getDisplayUnit();
// Had to use 'bit' as the display unit because
// counts was not an acceptable unit.
String unitString = unit == null ? ""
@ -447,13 +450,13 @@ public class SatResource extends
f1 = sampleRange.getMaxValue();
f2 = sampleRange.getMinValue();
}
if (value > f1 && value > f2) {
if (measuredValue > f1 && measuredValue > f2) {
return String.format(">%.1f%s", Math.max(f1, f2), unitString);
}
if (value < f1 && value < f2) {
if (measuredValue < f1 && measuredValue < f2) {
return String.format("<%.1f%s", Math.min(f1, f2), unitString);
}
return String.format("%.1f%s", value, unitString);
return String.format("%.1f%s", measuredValue, unitString);
}
private String getLegend(PluginDataObject record) {

View file

@ -25,6 +25,7 @@ import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
import java.text.ParseException;
import java.text.ParsePosition;
import java.util.Map;
import javax.measure.unit.Unit;
import javax.measure.unit.UnitFormat;
@ -60,7 +61,9 @@ import com.raytheon.viz.satellite.SatelliteConstants;
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 20, 2013 2122 mschenke Initial creation
* Jun 20, 2013 2122 mschenke Initial creation
* Nov 13, 2013 2492 mschenke Added extraction of scale/offset from
* data record attributes for unit
*
* </pre>
*
@ -92,8 +95,8 @@ public class SatDataRetriever implements IColorMapDataRetrievalCallback {
*/
@Override
public ColorMapData getColorMapData() {
// TODO: Read scale/offset out of attributes?
Buffer data = null;
Unit<?> dataUnit = Unit.ONE;
boolean signed = false;
Request req = Request.buildSlab(new int[] { this.datasetBounds.x,
this.datasetBounds.y }, new int[] {
@ -112,6 +115,7 @@ public class SatDataRetriever implements IColorMapDataRetrievalCallback {
}
Unit<?> recordUnit = getRecordUnit(this.record);
signed = recordUnit instanceof GenericPixel;
dataUnit = getDataUnit(recordUnit, record);
}
} catch (VizDataCubeException e) {
statusHandler.handle(Priority.SIGNIFICANT,
@ -134,7 +138,7 @@ public class SatDataRetriever implements IColorMapDataRetrievalCallback {
}
return new ColorMapData(data, new int[] { datasetBounds.width,
datasetBounds.height }, dataType);
datasetBounds.height }, dataType, dataUnit);
}
/**
@ -150,7 +154,8 @@ public class SatDataRetriever implements IColorMapDataRetrievalCallback {
physicalElement = request.getParameterAbbreviation();
}
if (record.getUnits() != null && record.getUnits().isEmpty() == false && request == null) {
if (record.getUnits() != null && record.getUnits().isEmpty() == false
&& request == null) {
try {
recordUnit = UnitFormat.getUCUMInstance().parseProductUnit(
record.getUnits(), new ParsePosition(0));
@ -181,6 +186,37 @@ public class SatDataRetriever implements IColorMapDataRetrievalCallback {
return recordUnit;
}
/**
* Extracts the data units for the data record given the PDO's base unit
*
* @param recordUnit
* @param dataRecord
* @return
*/
private static Unit<?> getDataUnit(Unit<?> recordUnit,
IDataRecord dataRecord) {
Unit<?> units = recordUnit != null ? recordUnit : Unit.ONE;
Map<String, Object> attrs = dataRecord.getDataAttributes();
if (attrs != null) {
Number offset = (Number) attrs.get(SatelliteRecord.SAT_ADD_OFFSET);
Number scale = (Number) attrs.get(SatelliteRecord.SAT_SCALE_FACTOR);
if (offset != null) {
double offsetVal = offset.doubleValue();
if (offsetVal != 0.0) {
units = units.plus(offsetVal);
}
}
if (scale != null) {
double scaleVal = scale.doubleValue();
if (scaleVal != 0.0) {
units = units.times(scaleVal);
}
}
}
return units;
}
/*
* (non-Javadoc)
*

View file

@ -65,7 +65,7 @@ public class ColorMapSliderComp extends Composite {
private static final int SLIDER_MIN = 0;
private static final int SLIDER_MAX = 255;
private static final int SLIDER_MAX = 250;
private static final int SLIDER_INC = 1;
@ -79,9 +79,9 @@ public class ColorMapSliderComp extends Composite {
private Text maxValueText;
private final float cmapAbsoluteMin;
private float cmapAbsoluteMin;
private final float cmapAbsoluteMax;
private float cmapAbsoluteMax;
private final float origCmapMin;
@ -93,8 +93,6 @@ public class ColorMapSliderComp extends Composite {
private final DecimalFormat format;
private final boolean dataInverted;
private UnitConverter displayToColorMap;
private UnitConverter colorMapToDisplay;
@ -106,8 +104,10 @@ public class ColorMapSliderComp extends Composite {
public ColorMapSliderComp(Composite parent, ColorMapParameters cmap) {
super(parent, SWT.NONE);
this.cmap = cmap;
this.currentCmapMin = this.origCmapMin = cmap.getColorMapMin();
this.currentCmapMax = this.origCmapMax = cmap.getColorMapMax();
this.cmapAbsoluteMin = this.currentCmapMin = this.origCmapMin = cmap
.getColorMapMin();
this.cmapAbsoluteMax = this.currentCmapMax = this.origCmapMax = cmap
.getColorMapMax();
this.displayToColorMap = cmap.getDisplayToColorMapConverter();
this.colorMapToDisplay = cmap.getColorMapToDisplayConverter();
if (displayToColorMap == null) {
@ -116,34 +116,9 @@ public class ColorMapSliderComp extends Composite {
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;
updateAbsolutes(cmapAbsoluteMin, 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();
@ -205,6 +180,7 @@ public class ColorMapSliderComp extends Composite {
}
});
minSlider.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
@ -217,8 +193,7 @@ public class ColorMapSliderComp extends Composite {
@Override
public void keyPressed(KeyEvent e) {
if (e.character == SWT.CR) {
setColorMapMax(textToColorMapValue(maxValueText.getText()
.trim()));
updateMinMaxFromText(maxValueText);
}
}
});
@ -227,8 +202,7 @@ public class ColorMapSliderComp extends Composite {
@Override
public void keyPressed(KeyEvent e) {
if (e.character == SWT.CR) {
setColorMapMin(textToColorMapValue(minValueText.getText()
.trim()));
updateMinMaxFromText(minValueText);
}
}
});
@ -237,6 +211,48 @@ public class ColorMapSliderComp extends Composite {
setColorMapMax(currentCmapMax);
}
private void updateMinMaxFromText(Text text) {
float newCmapValue = textToColorMapValue(text);
if (Float.isNaN(newCmapValue)) {
// Change nothing
if (text == minValueText) {
newCmapValue = currentCmapMin;
} else {
newCmapValue = currentCmapMax;
}
} else {
// Update colormap range
if (text == minValueText) {
currentCmapMin = newCmapValue;
} else {
currentCmapMax = newCmapValue;
}
}
updateAbsolutes(currentCmapMin, currentCmapMax);
setColorMapMin(currentCmapMin);
setColorMapMax(currentCmapMax);
}
/**
*
*/
private void updateAbsolutes(float cmapAbsoluteMin, float cmapAbsoluteMax) {
double displayAbsMax = colorMapToDisplay.convert(cmapAbsoluteMax);
double displayAbsMin = colorMapToDisplay.convert(cmapAbsoluteMin);
if (displayAbsMax < displayAbsMin) {
float tmp = cmapAbsoluteMax;
cmapAbsoluteMax = cmapAbsoluteMin;
cmapAbsoluteMin = tmp;
}
// Add a 1/16 buffer on either side for fine tuning
float buffer = (cmapAbsoluteMax - cmapAbsoluteMin) * .0625f;
this.cmapAbsoluteMin = cmapAbsoluteMin - buffer;
this.cmapAbsoluteMax = cmapAbsoluteMax + buffer;
}
/**
* Converts a slider selection index to a colormap value
*
@ -246,9 +262,6 @@ public class ColorMapSliderComp extends Composite {
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;
@ -263,9 +276,6 @@ public class ColorMapSliderComp extends Composite {
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);
}
@ -275,7 +285,8 @@ public class ColorMapSliderComp extends Composite {
* @param text
* @return
*/
private float textToColorMapValue(String text) {
private float textToColorMapValue(Text textControl) {
String text = textControl.getText().trim();
if (cmap.getDataMapping() != null && text.isEmpty() == false) {
// First check for data mapping entries
for (DataMappingEntry entry : cmap.getDataMapping().getEntries()) {
@ -285,13 +296,28 @@ public class ColorMapSliderComp extends Composite {
}
}
if (NaN_STRING.equals(text)) {
// If special NaN String, try to find first NaN value
// If special NaN String, try to find closest NaN value
float currentColorMapValue = textControl == maxValueText ? currentCmapMax
: currentCmapMin;
int currentSliderValue = colorMapValueToSelection(currentColorMapValue);
int minDist = Integer.MAX_VALUE;
float bestNanValue = currentColorMapValue;
for (int i = SLIDER_MIN; i < SLIDER_MAX; i += SLIDER_INC) {
float colorMapValue = selectionToColorMapValue(i);
if (Double.isNaN(colorMapToDisplay.convert(colorMapValue))) {
return colorMapValue;
int dist = Math.abs(i - currentSliderValue);
if (dist < minDist) {
minDist = dist;
bestNanValue = colorMapValue;
} else if (i > currentSliderValue) {
break;
}
} else {
// For now, assume NaN will live on low end of slider
break;
}
}
return bestNanValue;
} else {
// Attempt to parse and convert
try {

View file

@ -26,13 +26,14 @@ import javax.measure.converter.UnitConverter;
import org.apache.commons.lang.builder.HashCodeBuilder;
/**
* Converts a temperature value in Kelvin to a pixel value from 0 to 255
* Converts a temperature value in Kelvin to a pixel value.
*
* <pre>
* SOFTWARE HISTORY
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Aug 29, 2007 njensen Initial creation
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Aug 29, 2007 njensen Initial creation
* Nov 20, 2013 2492 bsteffen Make conversion unbounded.
*
* </pre>
*
@ -40,45 +41,39 @@ import org.apache.commons.lang.builder.HashCodeBuilder;
*/
public class IRTempToPixelConverter extends UnitConverter {
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 1L;
@Override
public double convert(double aTemperature) throws ConversionException {
double result = 0.0;
@Override
public double convert(double aTemperature) throws ConversionException {
double result = 0.0;
if (aTemperature < 238.15) {
result = 418.15 - aTemperature;
} else {
result = 656.3 - (2.0 * aTemperature);
}
if (aTemperature < 238.15) {
result = 418.15 - aTemperature;
} else {
result = 656.3 - (2.0 * aTemperature);
}
if (result < 0) {
result = 0.0;
} else if (result > 255) {
result = 255.0;
}
return result;
}
return result;
}
@Override
public boolean equals(Object aConverter) {
return (aConverter instanceof IRTempToPixelConverter);
}
@Override
public boolean equals(Object aConverter) {
return (aConverter instanceof IRTempToPixelConverter);
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
@Override
public UnitConverter inverse() {
return new IRPixelToTempConverter();
}
@Override
public UnitConverter inverse() {
return new IRPixelToTempConverter();
}
@Override
public boolean isLinear() {
return false;
}
@Override
public boolean isLinear() {
return false;
}
}

View file

@ -1,118 +0,0 @@
/**
* 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.dataplugin.satellite.units.water;
import javax.measure.converter.ConversionException;
import javax.measure.converter.UnitConverter;
import javax.measure.unit.SI;
import org.apache.commons.lang.builder.HashCodeBuilder;
/**
* TODO Add Description
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Mar 18, 2010 jsanchez Initial creation
*
* </pre>
*
* @author jsanchez
* @version 1.0
*/
public class BlendedTPWLengthToPixelConverter extends UnitConverter {
private static final long serialVersionUID = 1L;
private static UnitConverter meterToMillimeter = SI.METRE.getConverterTo(SI
.MILLI(SI.METRE));
/*
* (non-Javadoc)
*
* @see javax.measure.converter.UnitConverter#convert( double)
*/
@Override
public double convert(double aLength) throws ConversionException {
double result = 0.0;
aLength = meterToMillimeter.convert(aLength);
if (aLength < 1) {
result = 176;
} else {
result = aLength + 176;
}
if (result < 0) {
result = 0;
} else if (result > 255) {
result = 255;
}
return result;
}
/*
* (non-Javadoc)
*
* @see javax.measure.converter.UnitConverter#equals(java.lang.Object)
*/
@Override
public boolean equals(Object aConverter) {
return (aConverter instanceof BlendedTPWLengthToPixelConverter);
}
/*
* (non-Javadoc)
*
* @see javax.measure.converter.UnitConverter#hashCode()
*/
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
/*
* (non-Javadoc)
*
* @see javax.measure.converter.UnitConverter#inverse()
*/
@Override
public UnitConverter inverse() {
return new BlendedTPWPixelToLengthConverter();
}
/*
* (non-Javadoc)
*
* @see javax.measure.converter.UnitConverter#isLinear()
*/
@Override
public boolean isLinear() {
return false;
}
}

View file

@ -19,6 +19,7 @@
**/
package com.raytheon.uf.common.dataplugin.satellite.units.water;
import javax.measure.converter.AddConverter;
import javax.measure.converter.UnitConverter;
import javax.measure.quantity.Length;
import javax.measure.unit.DerivedUnit;
@ -28,15 +29,17 @@ import javax.measure.unit.Unit;
import org.apache.commons.lang.builder.HashCodeBuilder;
/**
* TODO Add Description
* Represents a pixel value on a satellite blended total precipitable water(TPW)
* image.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Mar 18, 2010 jsanchez Initial creation
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Mar 18, 2010 jsanchez Initial creation
* Nov 20, 2013 2492 bsteffen Make conversion unbounded.
*
* </pre>
*
@ -66,6 +69,7 @@ public class BlendedTPWPixel extends DerivedUnit<Length> {
@Override
public UnitConverter toStandardUnit() {
return new BlendedTPWPixelToLengthConverter();
return SI.MILLI(SI.METRE).getConverterTo(SI.METRE)
.concatenate(new AddConverter(-176));
}
}

View file

@ -1,111 +0,0 @@
/**
* 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.dataplugin.satellite.units.water;
import javax.measure.converter.ConversionException;
import javax.measure.converter.UnitConverter;
import javax.measure.unit.SI;
import org.apache.commons.lang.builder.HashCodeBuilder;
/**
* TODO Add Description
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Mar 18, 2010 jsanchez Initial creation
*
* </pre>
*
* @author jsanchez
* @version 1.0
*/
public class BlendedTPWPixelToLengthConverter extends UnitConverter {
private static final long serialVersionUID = 1L;
private static UnitConverter millimeterToMeter = (SI.MILLI(SI.METRE))
.getConverterTo(SI.METRE);
/*
* (non-Javadoc)
*
* @see javax.measure.converter.UnitConverter#convert(double)
*/
@Override
public double convert(double aPixel) throws ConversionException {
double result = 0.0;
if (aPixel <= 176) {
result = 0.0;
} else {
result = aPixel - 176;
}
result = millimeterToMeter.convert(result);
return result;
}
/*
* (non-Javadoc)
*
* @see javax.measure.converter.UnitConverter#equals(java.lang.Object)
*/
@Override
public boolean equals(Object aConverter) {
return (aConverter instanceof BlendedTPWPixelToLengthConverter);
}
/*
* (non-Javadoc)
*
* @see javax.measure.converter.UnitConverter#hashCode()
*/
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
/*
* (non-Javadoc)
*
* @see javax.measure.converter.UnitConverter#inverse()
*/
@Override
public UnitConverter inverse() {
return new BlendedTPWLengthToPixelConverter();
}
/*
* (non-Javadoc)
*
* @see javax.measure.converter.UnitConverter#isLinear()
*/
@Override
public boolean isLinear() {
return false;
}
}

View file

@ -43,8 +43,8 @@
</paramLevelMatches>
<imageStyle>
<range scale="LINEAR">
<minValue>1</minValue>
<maxValue>254</maxValue>
<minValue>0</minValue>
<maxValue>255</maxValue>
</range>
<defaultColormap>Sat/WV/Gray Scale Water Vapor</defaultColormap>
</imageStyle>
@ -75,8 +75,8 @@
</paramLevelMatches>
<imageStyle>
<range scale="LINEAR">
<minValue>1</minValue>
<maxValue>254</maxValue>
<minValue>0</minValue>
<maxValue>255</maxValue>
</range>
<defaultColormap>Sat/VIS/ZA (Vis Default)</defaultColormap>
</imageStyle>
@ -199,8 +199,8 @@
</paramLevelMatches>
<imageStyle>
<range scale="LINEAR">
<minValue>1</minValue>
<maxValue>254</maxValue>
<minValue>0</minValue>
<maxValue>255</maxValue>
</range>
<defaultColormap>Sat/WV/Gray Scale Water Vapor</defaultColormap>
</imageStyle>
@ -211,8 +211,8 @@
</paramLevelMatches>
<imageStyle>
<range scale="LINEAR">
<minValue>1</minValue>
<maxValue>254</maxValue>
<minValue>0</minValue>
<maxValue>255</maxValue>
</range>
<defaultColormap>Sat/WV/Gray Scale Water Vapor</defaultColormap>
</imageStyle>
@ -223,8 +223,8 @@
</paramLevelMatches>
<imageStyle>
<range scale="LINEAR">
<minValue>1</minValue>
<maxValue>254</maxValue>
<minValue>0</minValue>
<maxValue>255</maxValue>
</range>
<defaultColormap>Sat/WV/Gray Scale Water Vapor</defaultColormap>
</imageStyle>
@ -235,10 +235,10 @@
</paramLevelMatches>
<imageStyle>
<range scale="LINEAR">
<minValue>1</minValue>
<maxValue>254</maxValue>
<minValue>0</minValue>
<maxValue>255</maxValue>
</range>
<defaultColormap>Sat/VIS/ZA (Vis Default)</defaultColormap>
<defaultColormap>Sat/VIS/ZA (Vis Default)</defaultColormap>
</imageStyle>
</styleRule>
<styleRule>
@ -248,8 +248,8 @@
<imageStyle>
<displayUnits>C</displayUnits>
<range scale="LINEAR">
<minValue>1</minValue>
<maxValue>254</maxValue>
<minValue>0</minValue>
<maxValue>255</maxValue>
</range>
<defaultColormap>Sat/IR/CIRA (IR Default)</defaultColormap>
<colorbarLabeling>
@ -264,8 +264,8 @@
<imageStyle>
<displayUnits>C</displayUnits>
<range scale="LINEAR">
<minValue>1</minValue>
<maxValue>254</maxValue>
<minValue>0</minValue>
<maxValue>255</maxValue>
</range>
<defaultColormap>Sat/IR/CIRA (IR Default)</defaultColormap>
<colorbarLabeling>
@ -436,7 +436,7 @@
<imageStyle>
<displayUnits>mm</displayUnits>
<range scale="LINEAR">
<minValue>0</minValue>
<minValue>-176</minValue>
<maxValue>76</maxValue>
</range>
<defaultColormap>Sat/Precip Water/Blended Total Precip Water</defaultColormap>
@ -492,8 +492,8 @@
</paramLevelMatches>
<imageStyle>
<range scale="LINEAR">
<minValue>1</minValue>
<maxValue>254</maxValue>
<minValue>0</minValue>
<maxValue>255</maxValue>
</range>
<defaultColormap>Sat/VIS/ZA (Vis Default)</defaultColormap>
</imageStyle>
@ -530,5 +530,4 @@
</colorbarLabeling>
</imageStyle>
</styleRule>
</styleRuleset>

View file

@ -49,10 +49,11 @@ import org.opengis.referencing.operation.MathTransform;
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 27, 2013 mschenke Initial creation
* Oct 02, 2013 2333 mschenke Converted from libproj to CGMS algorithm
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Jun 27, 2013 mschenke Initial creation
* Oct 02, 2013 2333 mschenke Converted from libproj to CGMS algorithm
* Nov 18, 2013 2528 bsteffen Add hashCode/equals.
*
* </pre>
*
@ -212,6 +213,34 @@ public class Geostationary extends MapProjection {
return ptDst;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
long temp;
temp = Double.doubleToLongBits(orbitalHeight);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + (swapAxis ? 1231 : 1237);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
Geostationary other = (Geostationary) obj;
if (Double.doubleToLongBits(orbitalHeight) != Double
.doubleToLongBits(other.orbitalHeight))
return false;
if (swapAxis != other.swapAxis)
return false;
return true;
}
public static class Provider extends AbstractProvider {
private static final long serialVersionUID = 3868187206568280453L;

View file

@ -0,0 +1,416 @@
/**
* 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.geospatial.util;
import java.util.ArrayList;
import java.util.List;
import org.geotools.geometry.jts.JTS;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.opengis.geometry.Envelope;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.geospatial.MapUtil;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.geom.impl.PackedCoordinateSequence;
/**
* Solves the problem of intersecting two envelopes in different coordinate
* systems by reprojecting a grid of points and building polygons out of
* adjacent grid cells. This can be significantly slower than other algorithms
* but will always produce the best result possible for a given width and
* height. Increasing the width/height will slow the algorithm but give better
* results.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Nov 14, 2013 2528 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
class BruteForceEnvelopeIntersection {
private final ReferencedEnvelope sourceEnvelope;
private final ReferencedEnvelope targetEnvelope;
private final WorldWrapChecker wwc;
private final int width;
private final int height;
private final MathTransform latLonToTargetCRS;
private final CoordinateSequence latLonCoords;
private final CoordinateSequence targetCoords;
/**
* Construct a new intersection. This will calculate all fields including
* reprojecting all points in the grid.
*/
private BruteForceEnvelopeIntersection(Envelope sourceEnvelope,
Envelope targetEnvelope, int width, int height)
throws FactoryException, TransformException {
if (sourceEnvelope instanceof ReferencedEnvelope) {
this.sourceEnvelope = (ReferencedEnvelope) sourceEnvelope;
} else {
this.sourceEnvelope = new ReferencedEnvelope(sourceEnvelope);
}
if (targetEnvelope instanceof ReferencedEnvelope) {
this.targetEnvelope = (ReferencedEnvelope) targetEnvelope;
} else {
this.targetEnvelope = new ReferencedEnvelope(targetEnvelope);
}
this.width = width;
this.height = height;
wwc = new WorldWrapChecker(this.targetEnvelope);
double[] latLonCoords = buildLatLonCoords();
this.latLonCoords = new PackedCoordinateSequence.Double(latLonCoords, 2);
latLonToTargetCRS = MapUtil
.getTransformFromLatLon(targetEnvelope
.getCoordinateReferenceSystem());
double[] targetCoords = new double[latLonCoords.length];
latLonToTargetCRS.transform(latLonCoords, 0, targetCoords, 0, width
* height);
this.targetCoords = new PackedCoordinateSequence.Double(targetCoords, 2);
}
/**
* Construct a grid of coordinates and reproject to lat/lon CRS.
*/
private double[] buildLatLonCoords() throws FactoryException,
TransformException {
MathTransform sourceCRSToLatLon = MapUtil
.getTransformToLatLon(sourceEnvelope
.getCoordinateReferenceSystem());
double worldMinX = this.sourceEnvelope.getMinX();
double worldMinY = this.sourceEnvelope.getMinY();
double dXWorld = this.sourceEnvelope.getWidth() / (width - 1);
double dYWorld = this.sourceEnvelope.getHeight() / (height - 1);
int index = 0;
double[] coordinates = new double[width * height * 2];
for (int j = 0; j < height; ++j) {
double y = worldMinY + j * dYWorld;
for (int i = 0; i < width; ++i) {
coordinates[index++] = worldMinX + i * dXWorld;
coordinates[index++] = y;
}
}
sourceCRSToLatLon.transform(coordinates, 0, coordinates, 0, width
* height);
return coordinates;
}
/**
* Perform the actual intersection operation by merging all {@link Cell}s
* into {@link SimplePolygon} and finally converting those into Polygons.
*/
public Geometry reproject() throws MismatchedDimensionException,
TransformException {
/*
* Loop over each cell and split into two groups. First group is the
* "simple" cases that do not world wrap and can all be merged into one
* or more polygons. Second group contains the cells that need to be
* world wrap corrected.
*/
List<SimplePolygon> simpleCases = new ArrayList<SimplePolygon>();
List<Cell> worldWrappCells = new ArrayList<Cell>();
for (int j = 1; j < height; ++j) {
for (int i = 1; i < width; ++i) {
Cell cell = new Cell(i, j);
if (!cell.isValid()) {
// skip it
} else if (cell.worldWrapCheck(wwc)) {
worldWrappCells.add(cell);
} else {
for (SimplePolygon poly : simpleCases) {
if (poly.merge(cell)) {
cell = null;
break;
}
}
if (cell != null) {
simpleCases.add(new SimplePolygon(cell));
}
}
}
}
/* Convert all simple case polygons into JTS polygons */
GeometryFactory gf = new GeometryFactory();
List<Geometry> geoms = new ArrayList<Geometry>(simpleCases.size() + worldWrappCells.size() *2);
for (SimplePolygon poly : simpleCases) {
geoms.add(poly.asGeometry(gf));
}
if(!worldWrappCells.isEmpty()){
/*
* World wrap correct the cells that need it and transform the
* corrected geometries.
*/
WorldWrapCorrector corrector = new WorldWrapCorrector(
targetEnvelope);
for (Cell cell : worldWrappCells) {
Geometry geom = cell.asLatLonGeometry(gf);
geom = corrector.correct(geom);
geom = JTS.transform(geom, latLonToTargetCRS);
if (geom.isValid() && !geom.isEmpty()) {
geoms.add(geom);
}
}
}
return gf.createGeometryCollection(geoms.toArray(new Geometry[0]))
.buffer(0);
}
/**
* A cell represents four connected grid points that form a continous piece
* of an intersecting polygons. Most of the time a cell represents a
* quadrilateral but for cases where one of the corners is invalid in the
* target CRS a cell may represent a triangle. If any more points are
* invalid then the cell is invalid.
*/
private final class Cell {
private final int[] indices;
public Cell(int x, int y) {
int[] indices = new int[] { y * width + x - 1,
(y - 1) * width + x - 1,
(y - 1) * width + x, y * width + x};
int nanCount = 0;
for (int index : indices) {
if (isNaN(index)) {
nanCount += 1;
}
}
if (nanCount == 0) {
this.indices = indices;
} else if (nanCount == 1) {
this.indices = new int[3];
int i = 0;
for (int index : indices) {
if (!isNaN(index)) {
this.indices[i++] = index;
}
}
} else {
this.indices = null;
}
}
private boolean isNaN(int index){
return Double.isNaN(targetCoords.getOrdinate(index, 0))
|| Double.isNaN(targetCoords.getOrdinate(index, 1));
}
public boolean isValid() {
return indices != null;
}
public boolean worldWrapCheck(WorldWrapChecker wwc) {
double prevLon = latLonCoords.getOrdinate(
indices[indices.length - 1], 0);
for (int index : indices) {
double lon = latLonCoords.getOrdinate(index, 0);
if (wwc.check(prevLon, lon)) {
return true;
}
prevLon = lon;
}
return false;
}
public List<Coordinate> getTargetCoords() {
List<Coordinate> result = new ArrayList<Coordinate>(4);
for (int index : indices) {
result.add(targetCoords.getCoordinate(index));
}
return result;
}
public Polygon asLatLonGeometry(GeometryFactory gf) {
Coordinate[] coordinates = new Coordinate[indices.length + 1];
for (int i = 0; i < indices.length; i += 1) {
coordinates[i] = latLonCoords.getCoordinate(indices[i]);
}
coordinates[coordinates.length - 1] = coordinates[0];
return gf.createPolygon(gf.createLinearRing(coordinates), null);
}
public Coordinate getTargetCoord(int index) {
return targetCoords.getCoordinate(indices[index % indices.length]);
}
public int indexOfTarget(Coordinate c) {
for (int i = 0; i < targetCoords.size(); i += 1) {
if (targetCoords.getOrdinate(indices[i], 0) == c.x
&& targetCoords.getOrdinate(indices[i], 1) == c.y) {
return i;
}
}
return -1;
}
public int size() {
return indices.length;
}
}
/**
* This class is used to represent a Polygon with no holes. Additionally it
* provides fast method for merging a cell because it can safely assume that
* any points it shares with the cell are identical.
*/
private static final class SimplePolygon {
private List<Coordinate> coords;
public SimplePolygon(Cell cell) {
this.coords = cell.getTargetCoords();
}
public boolean merge(Cell cell) {
List<Coordinate> toCheck = cell.getTargetCoords();
/*
* Walk coords in order, if any identical coords are found we can
* ceck nearby points to eliminate the duplicates
*/
for (int i = 0; i < coords.size() - 1; i += 1) {
if (toCheck.remove(coords.get(i))) {
int lastFoundIndex = -1;
if (i == 0 && toCheck.remove(coords.get(coords.size() - 1))) {
/*
* For the 0 index the end of coords must be checked,
* all other indices do not need to check previous
* coords.
*/
while (toCheck.remove(coords.get(coords.size() - 2))) {
coords.remove(coords.size() - 1);
}
lastFoundIndex = 0;
} else if (i + 1 < coords.size()
&& toCheck.remove(coords.get(i + 1))) {
/* This check ensures 2 points match. */
lastFoundIndex = i + 1;
}
if (lastFoundIndex != -1) {
while (lastFoundIndex + 1 < coords.size()
&& toCheck.remove(coords
.get(lastFoundIndex + 1))) {
/*
* If more than two points match, remove the common
* interior points.
*/
coords.remove(lastFoundIndex);
}
if (!toCheck.isEmpty()) {
/*
* Add any exterior remaining points from the cell
* into this.
*/
int cellLastFoundIndex = cell.indexOfTarget(coords
.get(lastFoundIndex));
int prevIndex = cellLastFoundIndex + cell.size() - 1;
int nextIndex = cellLastFoundIndex + 1;
if (toCheck
.contains(cell.getTargetCoord(nextIndex))) {
coords.add(lastFoundIndex,
cell.getTargetCoord(nextIndex));
for (int j = nextIndex + 1; j < prevIndex; j += 1) {
Coordinate c = cell.getTargetCoord(j);
if (toCheck.contains(c)) {
coords.add(lastFoundIndex, c);
} else {
break;
}
}
} else if (toCheck.contains(cell
.getTargetCoord(prevIndex))) {
coords.add(lastFoundIndex,
cell.getTargetCoord(prevIndex));
for (int j = prevIndex - 1; j > nextIndex; j -= 1) {
Coordinate c = cell.getTargetCoord(j);
if (toCheck.contains(c)) {
coords.add(lastFoundIndex, c);
} else {
break;
}
}
}
}
return true;
} else {
return false;
}
}
}
return false;
}
public Polygon asGeometry(GeometryFactory gf) {
Coordinate[] coordinates = new Coordinate[this.coords.size() + 1];
this.coords.toArray(coordinates);
coordinates[coordinates.length - 1] = coordinates[0];
return gf.createPolygon(gf.createLinearRing(coordinates), null);
}
}
/**
* Computes an intersection {@link Geometry} between sourceEnvelope and
* targetEnvelope in targetEnvelope's CRS space. The resulting
* {@link Geometry} may contain multiple Geometries within it. But all
* geometries will be {@link Polygon}s
*
* @param sourceEnvelope
* @param targetEnvelope
* @param maxHorDivisions
* @param maxVertDivisions
* @return
* @throws FactoryException
* @throws TransformException
*/
public static Geometry createEnvelopeIntersection(Envelope sourceEnvelope,
Envelope targetEnvelope, int maxHorDivisions, int maxVertDivisions)
throws FactoryException, TransformException {
return new BruteForceEnvelopeIntersection(sourceEnvelope, targetEnvelope,
maxHorDivisions, maxVertDivisions).reproject();
}
}

View file

@ -55,8 +55,10 @@ import com.vividsolutions.jts.geom.Polygon;
* Sep 13, 2013 2309 bsteffen Corrected Lines that are extrapolated to
* intersect the border will use projection
* factor from all 4 corners instead of 3.
* Oct 8, 2013 2104 mschenke Added case for where actual border is
* Oct 08, 2013 2104 mschenke Added case for where actual border is
* inside out by checking interior point
* Nov 18, 2013 2528 bsteffen Fall back to brute force when corner
* points are not found.
*
* </pre>
*
@ -86,11 +88,30 @@ public class EnvelopeIntersection {
int maxVertDivisions) throws TransformException, FactoryException {
ReferencedEnvelope sourceREnvelope = reference(sourceEnvelope);
ReferencedEnvelope targetREnvelope = reference(targetEnvelope);
Geometry border = null;
WorldWrapCorrector corrector = new WorldWrapCorrector(targetREnvelope);
MathTransform sourceCRSToTargetCRS = CRS.findMathTransform(
sourceREnvelope.getCoordinateReferenceSystem(),
targetREnvelope.getCoordinateReferenceSystem());
if (sourceCRSToTargetCRS.isIdentity()) {
com.vividsolutions.jts.geom.Envelope intersection = sourceREnvelope
.intersection(targetREnvelope);
if (intersection == null) {
return gf.createGeometryCollection(new Geometry[0]);
} else {
Coordinate[] border = new Coordinate[5];
border[0] = new Coordinate(intersection.getMinX(),
intersection.getMinY());
border[1] = new Coordinate(intersection.getMinX(),
intersection.getMaxY());
border[2] = new Coordinate(intersection.getMaxX(),
intersection.getMaxY());
border[3] = new Coordinate(intersection.getMaxX(),
intersection.getMinY());
border[4] = border[0];
return gf.createPolygon(gf.createLinearRing(border), null);
}
}
Geometry border = null;
WorldWrapCorrector corrector = new WorldWrapCorrector(targetREnvelope);
MathTransform targetCRSToSourceCRS = sourceCRSToTargetCRS.inverse();
MathTransform targetCRSToLatLon = MapUtil
.getTransformToLatLon(targetREnvelope
@ -136,6 +157,19 @@ public class EnvelopeIntersection {
new double[] { sourceREnvelope.getMinimum(0), midY }, null,
sourceCRSToTargetCRS, true);
if (UL == null || UR == null || LR == null || LL == null) {
/*
* If entire edges of the tile are invalid in target space then the
* algorithms below are not that good. For most cases they produce
* overly large polygons but there are cases where they completely
* miss intersections. For these cases the BruteForce method is
* worth the extra time to get a really accurate envelope.
*/
return BruteForceEnvelopeIntersection.createEnvelopeIntersection(
sourceEnvelope, targetEnvelope, maxHorDivisions,
maxVertDivisions);
}
List<Coordinate> borderPoints = new ArrayList<Coordinate>(
maxVertDivisions * 2 + maxHorDivisions * 2);
double[] out = new double[2];
@ -544,7 +578,9 @@ public class EnvelopeIntersection {
try {
double[] tmp = new double[maxPoint.length];
mt.transform(maxPoint, 0, tmp, 0, 1);
return maxPoint;
if (!Double.isNaN(tmp[0]) && !Double.isNaN(tmp[1])) {
return maxPoint;
}
} catch (TransformException e) {
// Ignore
}
@ -553,13 +589,15 @@ public class EnvelopeIntersection {
try {
double[] tmp = new double[point.length];
mt.transform(point, 0, tmp, 0, 1);
// point is valid, keep looking
double deltaX = (maxPoint[0] - point[0]) / 2.0;
double deltaY = (maxPoint[1] - point[1]) / 2.0;
double[] newPoint = new double[] { point[0] + deltaX,
point[1] + deltaY };
return findNearestValidPoint(maxPoint, newPoint, point, mt,
checkMax);
if (!Double.isNaN(tmp[0]) && !Double.isNaN(tmp[1])) {
// point is valid, keep looking
double deltaX = (maxPoint[0] - point[0]) / 2.0;
double deltaY = (maxPoint[1] - point[1]) / 2.0;
double[] newPoint = new double[] { point[0] + deltaX,
point[1] + deltaY };
return findNearestValidPoint(maxPoint, newPoint, point, mt,
checkMax);
}
} catch (TransformException e) {
// Ignore
}

View file

@ -28,6 +28,8 @@ import javax.measure.unit.Unit;
import org.apache.commons.lang.ArrayUtils;
import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
import com.raytheon.uf.common.colormap.prefs.DataMappingPreferences;
import com.raytheon.uf.common.colormap.prefs.DataMappingPreferences.DataMappingEntry;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
@ -42,7 +44,6 @@ import com.raytheon.uf.common.style.level.RangeLevel;
import com.raytheon.uf.common.style.level.SingleLevel;
import com.raytheon.uf.common.util.GridUtil;
/**
* ColorMapParameterFactory
*
@ -53,10 +54,11 @@ import com.raytheon.uf.common.util.GridUtil;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jul 25, 2007 chammack Initial Creation.
* Mar 26, 2009 2086 jsanchez Added a entityList to the match criteria.
* Mar 26, 2009 2086 jsanchez Added a entityList to the match criteria.
* Feb 15, 2013 1638 mschenke Moved GRID_FILL_VALUE from edex.common Util into GridUtil
* Jun 24, 2013 2122 mschenke Added method for constructing {@link ColorMapParameters} from {@link StyleRule}
* Sep 24, 2013 2404 bclement moved to common.style from viz.core, added build method that takes ParamLevelMatchCriteria, removed unused methods
* Nov 13, 2013 2492 mschenke Create build that does not take data for adaptive building
* </pre>
*
* @author chammack
@ -129,7 +131,17 @@ public class ColorMapParameterFactory {
}
// If a record to convert units exists, use it
params.setDataUnit(parameterUnits);
Unit<?> colorMapUnit = null;
try {
colorMapUnit = preferences.getColorMapUnitsObject();
} catch (StyleException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e);
}
if (colorMapUnit == null) {
params.setColorMapUnit(parameterUnits);
} else {
params.setColorMapUnit(colorMapUnit);
}
params.setDisplayUnit(preferences.getDisplayUnits());
params.setDataMapping(preferences.getDataMapping());
@ -237,9 +249,10 @@ public class ColorMapParameterFactory {
.convert(colormapMax) : colormapMax;
if (preferences.getColorbarLabeling() != null) {
extractLabelValues(sr, displayMax, displayMin, params);
extractLabelValues(preferences, displayMax, displayMin, params);
} else if (preferences.getDataMapping() == null) {
calculateLabelValues(sr, displayMax, displayMin, params);
calculateLabelValues(preferences, displayMax, displayMin,
params);
if (scale != null) {
params.setMirror(scale.isMirror());
}
@ -325,8 +338,8 @@ public class ColorMapParameterFactory {
params.setColorMapMin((float) dataMin);
params.setDataMin((float) dataMin);
extractLabelValues(sr, (float) displayMax, (float) displayMin,
params);
extractLabelValues(preferences, (float) displayMax,
(float) displayMin, params);
params.setColorMapName(preferences.getDefaultColormap());
}
if (preferences.getDataScale() != null) {
@ -338,6 +351,154 @@ public class ColorMapParameterFactory {
}
/**
* Does the same thing as {@link #build(ImagePreferences, Unit)} but first
* unpacks the ImagePreference from a {@link StyleRule}.
*
* @param sr
* @param defaultColorMapUnit
* @return
* @throws StyleException
*/
public static ColorMapParameters build(StyleRule sr,
Unit<?> defaultColorMapUnit) throws StyleException {
if (sr == null) {
throw new IllegalArgumentException(
"StyleRule must not be null when building ColorMapParameters");
}
if (sr.getPreferences() instanceof ImagePreferences == false) {
throw new IllegalArgumentException(
"ImagePreferences are only supported for building ColorMapParameters");
}
return build((ImagePreferences) sr.getPreferences(),
defaultColorMapUnit);
}
/**
* Builds a {@link ColorMapParameters} given {@link ImagePreferences} and a
* unit to colormap in. This method provides for the simplest color mapping
* case. No data or level information is input so the
* {@link ImagePreferences} must specify an exact range or data mapping and
* also no lableing is added unless the colorbar labeling is specifically
* set in the style rule.
*
* @param preferences
* @param defaultColorMapUnit
* @return
* @throws StyleException
*/
public static ColorMapParameters build(ImagePreferences preferences,
Unit<?> defaultColorMapUnit) throws StyleException {
ColorMapParameters params = new ColorMapParameters();
Unit<?> colorMapUnit = preferences.getColorMapUnitsObject();
if (colorMapUnit == null) {
colorMapUnit = defaultColorMapUnit;
}
Unit<?> displayUnit = preferences.getDisplayUnits();
if (displayUnit == null) {
displayUnit = colorMapUnit;
} else if (colorMapUnit == null) {
colorMapUnit = displayUnit;
}
params.setColorMapUnit(colorMapUnit);
params.setDisplayUnit(displayUnit);
params.setDataMapping(preferences.getDataMapping());
params.setColorMapName(preferences.getDefaultColormap());
Float displayMin = null, displayMax = null;
DataScale scale = preferences.getDataScale();
boolean mirrored = false;
Type scaleType = Type.LINEAR;
if (scale != null) {
if (scale.getMinValue() != null) {
displayMin = scale.getMinValue().floatValue();
}
if (scale.getMaxValue() != null) {
displayMax = scale.getMaxValue().floatValue();
}
mirrored = scale.isMirror();
scaleType = scale.getScaleType();
}
if (displayMin == null || displayMax == null) {
// Could not find min/max in DataScale, attempt to get from
// DataMappingPreferences if set
if (params.getDataMapping() != null) {
DataMappingPreferences mapping = params.getDataMapping();
List<DataMappingEntry> entries = mapping.getEntries();
if (entries != null && entries.isEmpty() == false) {
if (displayMin == null) {
DataMappingEntry min = entries.get(0);
if (min.getPixelValue() != null
&& min.getDisplayValue() != null) {
displayMin = min.getDisplayValue().floatValue();
}
}
if (displayMax == null) {
DataMappingEntry max = entries.get(entries.size() - 1);
if (max.getPixelValue() != null
&& max.getDisplayValue() != null) {
displayMax = max.getDisplayValue().floatValue();
}
}
}
} else if (mirrored && (displayMin != null || displayMax != null)) {
// Mirror value set
if (displayMin == null) {
displayMin = -displayMax;
} else {
displayMax = -displayMin;
}
}
}
if (displayMin == null || displayMax == null) {
throw new StyleException("Unable to determine colormap min/max.");
}
params.setMirror(mirrored);
params.setLogarithmic(scaleType == Type.LOG);
// Convert to colormap min/max
float colorMapMin = displayMin;
float colorMapMax = displayMax;
UnitConverter displayToColorMap = params
.getDisplayToColorMapConverter();
if (displayToColorMap != null) {
colorMapMin = (float) displayToColorMap.convert(displayMin);
colorMapMax = (float) displayToColorMap.convert(displayMax);
}
params.setColorMapMin(colorMapMin);
params.setColorMapMax(colorMapMax);
LabelingPreferences labeling = preferences.getColorbarLabeling();
if (labeling != null) {
if (labeling.getValues() != null) {
params.setColorBarIntervals(labeling.getValues());
} else if (labeling.getIncrement() != 0) {
float increment = labeling.getIncrement();
float initialPoint = (float) (Math
.ceil(colorMapMin / increment) * increment);
float finalPoint = (float) (Math.floor(colorMapMin / increment) * increment);
int count = (int) ((finalPoint - initialPoint) / increment) + 1;
float[] vals = new float[count];
for (int i = 0; i < count; i += 1) {
vals[i] = initialPoint + increment * i;
}
}
}
return params;
}
private static Number[] repackData(Object data) {
Number[] numArray = null;
if (data instanceof byte[]) {
@ -375,33 +536,27 @@ public class ColorMapParameterFactory {
return build(data, parameter, parameterUnits, level, null);
}
private static void extractLabelValues(StyleRule sr, float max, float min,
ColorMapParameters parameters) {
if (sr != null) {
ImagePreferences preferences = (ImagePreferences) sr
.getPreferences();
if (preferences.getColorbarLabeling() != null) {
DataScale dataScale = preferences.getDataScale();
if (dataScale != null
&& dataScale.isMirror()
&& !dataScale.isAdaptive()
&& preferences.getColorbarLabeling().getValues() != null) {
// if its mirror and not adaptive and the upper half labels
// have been provided.
createMirror(preferences, parameters);
parameters.setMirror(dataScale.isMirror());
} else if (preferences.getColorbarLabeling().getValues() != null) {
// If a list is provided, use it
float[] vals = preferences.getColorbarLabeling()
.getValues();
private static void extractLabelValues(ImagePreferences preferences,
float max, float min, ColorMapParameters parameters) {
if (preferences.getColorbarLabeling() != null) {
DataScale dataScale = preferences.getDataScale();
if (dataScale != null && dataScale.isMirror()
&& !dataScale.isAdaptive()
&& preferences.getColorbarLabeling().getValues() != null) {
// if its mirror and not adaptive and the upper half labels
// have been provided.
createMirror(preferences, parameters);
parameters.setMirror(dataScale.isMirror());
} else if (preferences.getColorbarLabeling().getValues() != null) {
// If a list is provided, use it
float[] vals = preferences.getColorbarLabeling().getValues();
parameters.setColorBarIntervals(vals);
} else {
// Populate the list using min and max
calculateLabelValues(sr, max, min, parameters);
if (dataScale != null) {
parameters.setMirror(dataScale.isMirror());
}
parameters.setColorBarIntervals(vals);
} else {
// Populate the list using min and max
calculateLabelValues(preferences, max, min, parameters);
if (dataScale != null) {
parameters.setMirror(dataScale.isMirror());
}
}
}
@ -432,29 +587,23 @@ public class ColorMapParameterFactory {
/**
* Derived from ImageDepictable.C::adaptGridImageStyle
*/
private static void calculateLabelValues(StyleRule sr, float max,
float min, ColorMapParameters parameters) {
private static void calculateLabelValues(ImagePreferences preferences,
float max, float min, ColorMapParameters parameters) {
boolean haveIncrement = false;
float increment = 0.1f;
Type dataScaleType = Type.LINEAR;
boolean isMirror = false;
if (sr != null) {
ImagePreferences preferences = (ImagePreferences) sr
.getPreferences();
if (preferences != null) {
LabelingPreferences prefs = preferences.getColorbarLabeling();
if (prefs != null) {
increment = prefs.getIncrement();
haveIncrement = true;
}
LabelingPreferences prefs = preferences.getColorbarLabeling();
if (prefs != null) {
increment = prefs.getIncrement();
haveIncrement = true;
}
DataScale dataScale = preferences.getDataScale();
if (dataScale != null) {
dataScaleType = dataScale.getScaleType();
isMirror = dataScale.isMirror();
}
}
DataScale dataScale = preferences.getDataScale();
if (dataScale != null) {
dataScaleType = dataScale.getScaleType();
isMirror = dataScale.isMirror();
}
if (Math.abs(max - min) / increment > 16) {
increment *= 2;

View file

@ -20,6 +20,11 @@
package com.raytheon.uf.common.style.image;
import java.text.ParseException;
import java.text.ParsePosition;
import javax.measure.unit.Unit;
import javax.measure.unit.UnitFormat;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
@ -28,6 +33,7 @@ import javax.xml.bind.annotation.XmlRootElement;
import com.raytheon.uf.common.colormap.prefs.DataMappingPreferences;
import com.raytheon.uf.common.style.AbstractStylePreferences;
import com.raytheon.uf.common.style.LabelingPreferences;
import com.raytheon.uf.common.style.StyleException;
/**
*
@ -40,6 +46,7 @@ import com.raytheon.uf.common.style.LabelingPreferences;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jul 27, 2007 chammack Initial Creation.
* Nov 25, 2013 2492 bsteffen Add colorMapUnits
*
* </pre>
*
@ -62,15 +69,18 @@ public class ImagePreferences extends AbstractStylePreferences {
@XmlElement
private SamplePreferences samplePrefs;
@XmlElement(name = "dataMapping")
@XmlElement
private DataMappingPreferences dataMapping;
@XmlElement(name = "colorbarLabeling")
@XmlElement
private LabelingPreferences colorbarLabeling;
@XmlElement(name = "interpolate")
@XmlElement
private boolean interpolate = true;
@XmlElement
private String colorMapUnits;
public boolean isInterpolate() {
return interpolate;
}
@ -154,4 +164,37 @@ public class ImagePreferences extends AbstractStylePreferences {
return legend;
}
/**
*
* @return String representation of colorMapUnits for serialization.
* @see ImagePreferences#getColorMapUnitsObject()
*/
public String getColorMapUnits() {
return colorMapUnits;
}
/**
* @param colorMapUnits
* String representation of colorMapUnits for serialization.
* @see ImagePreferences#getColorMapUnitsObject()
*/
public void setColorMapUnits(String colorMapUnits) {
this.colorMapUnits = colorMapUnits;
}
/**
* Units that should be used when color mapping. Mostly useful for cases
* where the colormap should be applied non linearly.
*/
public Unit<?> getColorMapUnitsObject() throws StyleException {
if (colorMapUnits != null && !colorMapUnits.isEmpty()) {
try {
return UnitFormat.getUCUMInstance().parseProductUnit(
colorMapUnits, new ParsePosition(0));
} catch (ParseException e) {
throw new StyleException("Unable to parse colorMap Units.");
}
}
return null;
}
}

View file

@ -266,7 +266,7 @@ if [ "${1}" = "-full" ]; then
buildRPM "awips2-httpd-pypies"
buildJava
buildRPM "awips2-groovy"
#buildRPM "awips2-ldm"
buildRPM "awips2-ldm"
buildRPM "awips2-postgres"
buildRPM "awips2-pgadmin3"
buildRPM "awips2-tools"

View file

@ -256,7 +256,7 @@ if [ "${1}" = "-delta" ]; then
fi
if [ "${1}" = "-full" ]; then
# buildRPM "awips2-common-base"
buildRPM "awips2-common-base"
buildCAVE
if [ $? -ne 0 ]; then
exit 1
@ -277,7 +277,7 @@ if [ "${1}" = "-full" ]; then
buildRPM "awips2-python-pil"
buildRPM "awips2-python-pmw"
buildRPM "awips2-python-pupynere"
# buildRPM "awips2-python-qpid"
buildRPM "awips2-python-qpid"
buildRPM "awips2-python-scientific"
buildRPM "awips2-python-scipy"
buildRPM "awips2-python-tables"

View file

@ -19,17 +19,27 @@
**/
package com.raytheon.uf.common.geospatial.util;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.geotools.factory.FactoryIteratorProvider;
import org.geotools.factory.GeoTools;
import org.geotools.geometry.jts.JTS;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.crs.DefaultProjectedCRS;
import org.geotools.referencing.operation.DefaultMathTransformFactory;
import org.junit.Assert;
import org.junit.Test;
import org.opengis.geometry.Envelope;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.ProjectedCRS;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.geospatial.MapUtil;
import com.raytheon.uf.common.geospatial.projection.Geostationary;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.Geometry;
@ -49,6 +59,7 @@ import com.vividsolutions.jts.simplify.TopologyPreservingSimplifier;
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Sep 13, 2013 2309 bsteffen Initial creation
* Nov 18, 2013 2528 bsteffen Add test for geostationary.
*
* </pre>
*
@ -94,6 +105,49 @@ public class EnvelopeIntersectionTest {
1.0324516833231976E7,
MapUtil.AWIPS_POLARSTEREO_NORTHAMERICA);
}
},
GEOSTATIONARY {
public Envelope getEnvelope() {
try {
// Must manually register geostation
GeoTools.addFactoryIteratorProvider(new FactoryIteratorProvider() {
@Override
public <T> Iterator<T> iterator(Class<T> category) {
if (category
.isAssignableFrom(Geostationary.Provider.class)) {
List<T> tmp = new ArrayList<T>(1);
tmp.add(category
.cast(new Geostationary.Provider()));
return tmp.iterator();
}
return null;
}
});
ParameterValueGroup parameters = new DefaultMathTransformFactory()
.getDefaultParameters(Geostationary.PROJECTION_NAME);
parameters.parameter("semi_major").setValue(6378137.0);
parameters.parameter("semi_minor").setValue(6356732.31414);
parameters.parameter("latitude_of_origin").setValue(0.0);
parameters.parameter("central_meridian").setValue(-137);
parameters.parameter("false_easting").setValue(0);
parameters.parameter("false_northing").setValue(0);
parameters.parameter(Geostationary.ORBITAL_HEIGHT)
.setValue(35785863.0);
parameters.parameter(Geostationary.SWEEP_AXIS)
.setValue(0.0);
DefaultProjectedCRS crs = MapUtil.constructProjection(
Geostationary.PROJECTION_NAME, parameters);
return new ReferencedEnvelope(-5434870.792806381,
-2356713.972039082, -3799599.721331195,
-721442.9005638957, crs);
} catch (Exception e) {
throw new RuntimeException(
"Unable to create geostationary projection", e);
}
}
};
public abstract Envelope getEnvelope();
@ -107,6 +161,7 @@ public class EnvelopeIntersectionTest {
double threshold, int maxHorDivisions, int maxVertDivisions,
float[] expectedPolygonCoords) throws TransformException,
FactoryException {
long startTime = System.currentTimeMillis();
Geometry testGeom = EnvelopeIntersection.createEnvelopeIntersection(
source.getEnvelope(), target.getEnvelope(), threshold,
maxHorDivisions, maxVertDivisions);
@ -141,6 +196,10 @@ public class EnvelopeIntersectionTest {
// toKML(target.getEnvelope(), (Polygon) testGeom, expectedPolygon,
// maxError);
long endTime = System.currentTimeMillis();
System.out.println(source + " intersected with " + target + " took: "
+ (endTime - startTime) + "ms");
Assert.assertTrue(source + " intersected with " + target
+ " is too large.",
expectedPolygon.buffer(maxError).contains(testGeom));
@ -237,6 +296,40 @@ public class EnvelopeIntersectionTest {
288, expected);
}
@Test
public final void testGeostationaryToUkmet() throws TransformException,
FactoryException {
/* This was created using printSimplePolygon. */
float[] expected = { -803884, -836926, 5717769, -737647, 5605322,
-1820270, 5412823, -2767932, 5122653, -3661810, 4764378,
-4405659, 2533964, -4570863, -74925, -4826265, 141761,
-4699883, 265720, -4585495, 398396, -4374090, -401980,
-4451987, -214394, -4335532, -140376, -4231895, -111147,
-4039970, -191289, -3862333, -279094, -3778945, -431268,
-3701630, 203526, -3560640, 5468, -3401972, -348043, -3256781,
130869, -3136911, -224309, -2994515, -678028, -2942195, -31273,
-2816425, -277475, -2750530, 73248, -2647495, -149634,
-2580518, -547236, -2523641, -92802, -2417432, -447576,
-2357760, -82722, -2259030, -453907, -2199805, -112694,
-2104320, -555394, -2047966, -184709, -1952826, 22519,
-1866703, -312976, -1804583, -88257, -1718835, -567370,
-1661644, -78052, -1491513, -585469, -1433545, -305862,
-1348754, -19066, -1190667, -484493, -1128908, -299531,
-1049446, -76719, -896167, -803884, -836926, };
test(KNOWN_ENVELOPES.GEOSTATIONARY, KNOWN_ENVELOPES.UKMET,
19097.596365784917, 64, 49, expected);
}
@Test
public final void testGeostationaryToGeostationary()
throws TransformException, FactoryException {
/* This was created using printSimplePolygon. */
float[] expected = { -5434871, -3799600, -5434871, -721443, -2356714,
-721443, -2356714, -3799600, -5434871, -3799600 };
test(KNOWN_ENVELOPES.GEOSTATIONARY, KNOWN_ENVELOPES.GEOSTATIONARY,
19097.596365784917, 64, 49, expected);
}
/**
* This method can be used to assist in generating test cases. It starts
* with a known good result and minimizes the amount of text to put in the