diff --git a/cave/com.raytheon.viz.core/src/com/raytheon/viz/core/topo/TopoResource.java b/cave/com.raytheon.viz.core/src/com/raytheon/viz/core/topo/TopoResource.java index da86576148..2ab9b9cc6b 100644 --- a/cave/com.raytheon.viz.core/src/com/raytheon/viz/core/topo/TopoResource.java +++ b/cave/com.raytheon.viz.core/src/com/raytheon/viz/core/topo/TopoResource.java @@ -36,6 +36,8 @@ import com.raytheon.uf.common.colormap.prefs.ColorMapParameters; import com.raytheon.uf.common.colormap.prefs.ColorMapParameters.PersistedParameters; import com.raytheon.uf.common.datastorage.DataStoreFactory; import com.raytheon.uf.common.datastorage.IDataStore; +import com.raytheon.uf.common.datastorage.Request; +import com.raytheon.uf.common.datastorage.records.IDataRecord; import com.raytheon.uf.common.geospatial.ReferencedCoordinate; import com.raytheon.uf.common.style.LabelingPreferences; import com.raytheon.uf.common.style.ParamLevelMatchCriteria; @@ -91,6 +93,8 @@ public class TopoResource extends protected TileSetRenderable topoTileSet; + private double noDataValue; + protected TopoResource(TopoResourceData topoData, LoadProperties loadProperties, File dataFile) throws VizException { super(topoData, loadProperties); @@ -189,12 +193,13 @@ public class TopoResource extends } SamplePreferences samplePrefs = prefs.getSamplePrefs(); - if (samplePrefs != null && samplePrefs.getFormatString() != null) { + if ((samplePrefs != null) + && (samplePrefs.getFormatString() != null)) { params.setFormatString(samplePrefs.getFormatString()); } LabelingPreferences labelPrefs = prefs.getColorbarLabeling(); - if (labelPrefs != null && labelPrefs.getValues() != null) { + if ((labelPrefs != null) && (labelPrefs.getValues() != null)) { params.setColorBarIntervals(labelPrefs.getValues()); } } @@ -213,6 +218,16 @@ public class TopoResource extends getCapability(ColorMapCapability.class).setColorMapParameters(params); + IDataStore dataStore = DataStoreFactory.getDataStore(this.dataFile); + try { + IDataRecord rec = dataStore.retrieve("/", "full", + Request.buildPointRequest(new java.awt.Point(0, 0))); + noDataValue = rec.getFillValue().doubleValue(); + } catch (Exception e) { + statusHandler.error(e.getLocalizedMessage(), e); + noDataValue = Double.NaN; + } + topoTileSet = new TileSetRenderable( getCapability(ImagingCapability.class), getTopoGeometry(), getTopoTileImageCreator(), getNumberOfTopoLevels(), 512); @@ -284,7 +299,7 @@ public class TopoResource extends double height; try { // height = TopoQuery.getInstance().getHeight(coord.asLatLon()); - height = topoTileSet.interrogate(coord.asLatLon()); + height = topoTileSet.interrogate(coord.asLatLon(), noDataValue); } catch (Exception e) { throw new VizException("Error transforming", e); } diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/rsc/colorbar/ContinuousColorbar.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/rsc/colorbar/ContinuousColorbar.java index 1d0ba70bea..e91b106d86 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/rsc/colorbar/ContinuousColorbar.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/rsc/colorbar/ContinuousColorbar.java @@ -59,6 +59,8 @@ import com.raytheon.viz.gfe.rsc.GFEResource; * Feb 14, 2013 1616 bsteffen Add option for interpolation of colormap * parameters, disable colormap interpolation * by default. + * 02/11/2014 #2788 randerso Fixed infinite loop in computeIntervalAndPrecision + * when pmax < pmin * * * @@ -186,10 +188,10 @@ public class ContinuousColorbar implements IColorBarDisplay { dstring.font = colorbarResource.getColorbarScaleFont(); dstring.textStyle = TextStyle.NORMAL; - for (int i = 0; (minParm + i * interval) <= maxParm; i++) { + for (int i = 0; (minParm + (i * interval)) <= maxParm; i++) { // check to see whether this colorTable item needs to be // rendered - float labelValue = minParm + i * interval; + float labelValue = minParm + (i * interval); // Check to see if value is same as previous unless float.... if ((tmpValue != (int) labelValue) || (precision > 0)) { @@ -197,7 +199,7 @@ public class ContinuousColorbar implements IColorBarDisplay { labelValue, precision); labelLoc = llx - + ((labelValue - minParm) / (maxParm - minParm) * xExtent); + + (((labelValue - minParm) / (maxParm - minParm)) * xExtent); if (GFEColorbarResource.isLabelWithin(pe.getMinX(), pe.getMaxX(), labelLoc, 0)) { @@ -219,10 +221,10 @@ public class ContinuousColorbar implements IColorBarDisplay { labelValue = labelValueObj.floatValue(); if (precision == 0) { labelLoc = llx - + ((labelValue - minParm) / (maxParm - minParm) * xExtent); + + (((labelValue - minParm) / (maxParm - minParm)) * xExtent); } else { labelLoc = llx - + ((labelValue - minParm) / (maxParm - minParm) * xExtent); + + (((labelValue - minParm) / (maxParm - minParm)) * xExtent); } if (GFEColorbarResource.isLabelWithin(pe.getMinX(), pe.getMaxX(), labelLoc, 0)) { @@ -246,7 +248,7 @@ public class ContinuousColorbar implements IColorBarDisplay { float floatValue = ((ScalarWxValue) wxv).getValue(); if ((floatValue >= minParm) && (floatValue <= maxParm)) { labelLoc = llx - + ((floatValue - minParm) / (maxParm - minParm) * xExtent); + + (((floatValue - minParm) / (maxParm - minParm)) * xExtent); String s = wxv.toString(); dstring.font = colorbarResource.getPickupValueFont(); @@ -261,12 +263,11 @@ public class ContinuousColorbar implements IColorBarDisplay { dstring.shadowColor = new RGB(0, 0, 0); } - double halfWidth = target.getStringsBounds(dstring).getWidth() - * ratio / 2; + double halfWidth = (target.getStringsBounds(dstring).getWidth() * ratio) / 2; - if (labelLoc - halfWidth < pe.getMinX()) { + if ((labelLoc - halfWidth) < pe.getMinX()) { labelLoc = pe.getMinX() + halfWidth; - } else if (labelLoc + halfWidth > pe.getMaxX()) { + } else if ((labelLoc + halfWidth) > pe.getMaxX()) { labelLoc = pe.getMaxX() - halfWidth; } dstring.setCoordinates(labelLoc, @@ -298,7 +299,8 @@ public class ContinuousColorbar implements IColorBarDisplay { // initial values are good if decade < parmExtent // loop is infinite if parmExtent is NaN or 0, so avoid it - if (decade < parmExtent || Float.isNaN(parmExtent) || parmExtent == 0.0) { + if (Float.isNaN(parmExtent) || (parmExtent <= 0.0) + || (decade < parmExtent)) { return new float[] { finterval, precision, labelLength }; } @@ -438,7 +440,7 @@ public class ContinuousColorbar implements IColorBarDisplay { switch (parm.getGridInfo().getGridType()) { case SCALAR: - return new ScalarWxValue(min + (max - min) * fractionX, parm); + return new ScalarWxValue(min + ((max - min) * fractionX), parm); case VECTOR: WxValue previous = parm.getParmState().getPickUpValue(); float mag = 0.0f; @@ -448,7 +450,7 @@ public class ContinuousColorbar implements IColorBarDisplay { dir = ((VectorWxValue) previous).getDir(); } if (mouseButton == 1) { - mag = min + (max - min) * fractionX; + mag = min + ((max - min) * fractionX); } else if (mouseButton == 2) { dir = 360 * fractionX; } diff --git a/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/server/database/TopoDatabaseManager.java b/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/server/database/TopoDatabaseManager.java index ac22c1188c..c4409b0789 100644 --- a/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/server/database/TopoDatabaseManager.java +++ b/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/server/database/TopoDatabaseManager.java @@ -74,6 +74,7 @@ import com.raytheon.uf.common.topo.TopoQuery; * Jun 13, 2013 #2044 randerso Refactored to use non-singleton GridParmManager, * code cleanup * Nov 20, 2013 #2331 randerso Changed return type of getTopoData + * Feb 11, 2014 #2788 randerso Set missing data points to 0 to match A1 * * * @@ -236,6 +237,8 @@ public class TopoDatabaseManager { if (!allowValuesBelowZero && (heights[i] < 0)) { heights[i] = 0.0f; } + } else { + heights[i] = 0.0f; } } diff --git a/edexOsgi/com.raytheon.uf.common.topo/src/com/raytheon/uf/common/topo/TopoQuery.java b/edexOsgi/com.raytheon.uf.common.topo/src/com/raytheon/uf/common/topo/TopoQuery.java index ba67260fde..bb2463d5fd 100644 --- a/edexOsgi/com.raytheon.uf.common.topo/src/com/raytheon/uf/common/topo/TopoQuery.java +++ b/edexOsgi/com.raytheon.uf.common.topo/src/com/raytheon/uf/common/topo/TopoQuery.java @@ -88,6 +88,8 @@ import com.vividsolutions.jts.geom.Coordinate; * Feb 15, 2013 1638 mschenke Moved from edex.topo project (not edex * specific) * Aug 06, 2013 2235 bsteffen Added Caching version of TopoQuery. + * Feb 10, 2014 2788 randerso Removed override of CRS from Topo file. + * Fixed handling of fill values (missing data) * * * @@ -198,10 +200,6 @@ public class TopoQuery { CoordinateReferenceSystem crs = CRSCache.getInstance() .getCoordinateReferenceSystem(crsString); - crs = MapUtil.constructEquidistantCylindrical( - MapUtil.AWIPS_EARTH_RADIUS, MapUtil.AWIPS_EARTH_RADIUS, 0, - 0); - double[] input = new double[] { ulLon, ulLat, lrLon, lrLat }; double[] output = new double[4]; @@ -288,6 +286,7 @@ public class TopoQuery { public double[] getHeight(Coordinate[] coords) { final int size = coords.length; double[] topo = new double[size]; + Arrays.fill(topo, Double.NaN); double[] input = new double[size * 2]; double[] output = new double[input.length]; @@ -310,15 +309,18 @@ public class TopoQuery { Request request = Request.buildPointRequest(points); ShortDataRecord record = (ShortDataRecord) dataStore.retrieve("/", "full", request); + short fillValue = record.getFillValue().shortValue(); short[] data = record.getShortData(); // bounds checking? for (int i = 0; i < size; i++) { - topo[i] = data[i]; + short value = data[i]; + if (value != fillValue) { + topo[i] = value; + } } } catch (Exception e) { statusHandler.handle(Priority.PROBLEM, "Error retriving topo value for lat/lons", e); - Arrays.fill(topo, Double.NaN); } return topo; @@ -367,8 +369,9 @@ public class TopoQuery { if (first) { first = false; - } else if (Math.abs(p1.getOrdinate(0) - prev) > 180.0 - || (Math.abs(p1.getOrdinate(0)) > 180 && Math.abs(prev) < 180)) { + } else if ((Math.abs(p1.getOrdinate(0) - prev) > 180.0) + || ((Math.abs(p1.getOrdinate(0)) > 180) && (Math + .abs(prev) < 180))) { crossedDLHoriz = true; } prev = p1.getOrdinate(0); @@ -424,8 +427,9 @@ public class TopoQuery { if (first) { first = false; - } else if (Math.abs(p1.getOrdinate(0) - prev) > 180.0 - || (Math.abs(p1.getOrdinate(0)) > 180 && Math.abs(prev) < 180)) { + } else if ((Math.abs(p1.getOrdinate(0) - prev) > 180.0) + || ((Math.abs(p1.getOrdinate(0)) > 180) && (Math + .abs(prev) < 180))) { crossedDLVert = true; } prev = p1.getOrdinate(0); @@ -541,7 +545,7 @@ public class TopoQuery { worldRect.getMaxY() }; double[] crsCorners = new double[worldCorners.length]; GeneralEnvelope env = new GeneralEnvelope(2); - if (worldCorners[2] > worldGeomPM.getGridRange().getHigh(0) + 1) { + if (worldCorners[2] > (worldGeomPM.getGridRange().getHigh(0) + 1)) { worldGeomDL.getGridToCRS(PixelInCell.CELL_CORNER) .transform(worldCorners, 0, crsCorners, 0, worldCorners.length / 2); @@ -643,7 +647,7 @@ public class TopoQuery { } // if grid is too big to load into memory - if (width * height > TOPO_LIMIT) { + if ((width * height) > TOPO_LIMIT) { // try the next interpolation level if it exists int level = topoLevel + 1; if (level < numLevels) { @@ -675,15 +679,18 @@ public class TopoQuery { y + intersection.height }); rec = (ShortDataRecord) dataStore.retrieve("", dataset, request); + short fillValue = rec.getFillValue().shortValue(); - int xOffset = intersection.x - worldRect.x + rectOffset; + int xOffset = (intersection.x - worldRect.x) + rectOffset; int yOffset = intersection.y - worldRect.y; int recOffset = 0; for (int j = 0; j < intersection.height; j++) { for (int i = 0; i < intersection.width; i++) { - topoValues[j + yOffset][i + xOffset] = rec - .getShortData()[i + recOffset]; + short value = rec.getShortData()[i + recOffset]; + if (value != fillValue) { + topoValues[j + yOffset][i + xOffset] = value; + } } recOffset += intersection.width; // someData = true; @@ -697,10 +704,6 @@ public class TopoQuery { rectOffset += worldRect.width; } - // if (!someData) { - // throw new EdexException("No topo data available"); - // } - Envelope env = computeEnv(new Rectangle(rectangles[0].x, rectangles[0].y, width, height)); @@ -789,8 +792,10 @@ public class TopoQuery { int sx = (int) Math.round(coord[0]); int sy = (int) Math.round(coord[1]); - if (sx >= 0 && sx < sourceWidth && sy >= 0 && sy < sourceHeight) - output[y * targetWidth + x] = sourceData[sy][sx]; + if ((sx >= 0) && (sx < sourceWidth) && (sy >= 0) + && (sy < sourceHeight)) { + output[(y * targetWidth) + x] = sourceData[sy][sx]; + } } } @@ -812,9 +817,9 @@ public class TopoQuery { MathTransform mt = null; for (MathTransform mti : transforms) { - if (mt == null) + if (mt == null) { mt = mti; - else { + } else { mt = mtFactory.createConcatenatedTransform(mt, mti); } } diff --git a/edexOsgi/com.raytheon.uf.common.topo/src/com/raytheon/uf/common/topo/TopoUtils.java b/edexOsgi/com.raytheon.uf.common.topo/src/com/raytheon/uf/common/topo/TopoUtils.java index 98a51d978b..696016ea35 100644 --- a/edexOsgi/com.raytheon.uf.common.topo/src/com/raytheon/uf/common/topo/TopoUtils.java +++ b/edexOsgi/com.raytheon.uf.common.topo/src/com/raytheon/uf/common/topo/TopoUtils.java @@ -50,7 +50,8 @@ import com.raytheon.uf.common.geospatial.CRSCache; * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Aug 2, 2013 bsteffen Initial creation + * Aug 2, 2013 bsteffen Initial creation + * Feb 10, 2014 #2788 randerso Changed default topo file name * * * @@ -60,7 +61,9 @@ import com.raytheon.uf.common.geospatial.CRSCache; public class TopoUtils { - private static final String DEFAULT_TOPO_PATH = "/topo/srtm30.hdf"; + // NOTE: this file is actually a symbolic link to the desired topo data file + // allowing the topo data set to be changed without updating Java code + private static final String DEFAULT_TOPO_PATH = "/topo/defaultTopo.h5"; private static final String FULL_TOPO_DATASET = "/full"; diff --git a/edexOsgi/com.raytheon.uf.common.topo/utility/common_static/base/styleRules/topoImageryStyleRules.xml b/edexOsgi/com.raytheon.uf.common.topo/utility/common_static/base/styleRules/topoImageryStyleRules.xml index bb6cd39900..46bdf4e5e7 100644 --- a/edexOsgi/com.raytheon.uf.common.topo/utility/common_static/base/styleRules/topoImageryStyleRules.xml +++ b/edexOsgi/com.raytheon.uf.common.topo/utility/common_static/base/styleRules/topoImageryStyleRules.xml @@ -21,7 +21,7 @@ - srtm30.hdf + defaultTopo.h5 kft diff --git a/javaUtilities/com.raytheon.uf.topo.utilities/.classpath b/javaUtilities/com.raytheon.uf.topo.utilities/.classpath new file mode 100644 index 0000000000..1523f3025a --- /dev/null +++ b/javaUtilities/com.raytheon.uf.topo.utilities/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/javaUtilities/com.raytheon.uf.topo.utilities/.project b/javaUtilities/com.raytheon.uf.topo.utilities/.project new file mode 100644 index 0000000000..12bf3361fd --- /dev/null +++ b/javaUtilities/com.raytheon.uf.topo.utilities/.project @@ -0,0 +1,28 @@ + + + com.raytheon.uf.topo.utilities + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/javaUtilities/com.raytheon.uf.topo.utilities/.settings/org.eclipse.jdt.core.prefs b/javaUtilities/com.raytheon.uf.topo.utilities/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..f42de363af --- /dev/null +++ b/javaUtilities/com.raytheon.uf.topo.utilities/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/javaUtilities/com.raytheon.uf.topo.utilities/META-INF/MANIFEST.MF b/javaUtilities/com.raytheon.uf.topo.utilities/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..be93e00407 --- /dev/null +++ b/javaUtilities/com.raytheon.uf.topo.utilities/META-INF/MANIFEST.MF @@ -0,0 +1,11 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Utilities +Bundle-SymbolicName: com.raytheon.uf.topo.utilities +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: RAYTHEON +Bundle-RequiredExecutionEnvironment: JavaSE-1.7 +Require-Bundle: com.raytheon.uf.common.serialization;bundle-version="1.12.1174", + com.raytheon.uf.common.datastorage;bundle-version="1.12.1174", + com.raytheon.uf.common.pypies;bundle-version="1.12.1174", + com.raytheon.uf.common.geospatial;bundle-version="1.12.1174" diff --git a/javaUtilities/com.raytheon.uf.topo.utilities/build.properties b/javaUtilities/com.raytheon.uf.topo.utilities/build.properties new file mode 100644 index 0000000000..f9c250446d --- /dev/null +++ b/javaUtilities/com.raytheon.uf.topo.utilities/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + logback.xml diff --git a/javaUtilities/com.raytheon.uf.topo.utilities/logback.xml b/javaUtilities/com.raytheon.uf.topo.utilities/logback.xml new file mode 100644 index 0000000000..61001a420b --- /dev/null +++ b/javaUtilities/com.raytheon.uf.topo.utilities/logback.xml @@ -0,0 +1,68 @@ + + + + %-5p %d [%t] %c{0}: %m%n + + + INFO + + + + + System.err + + WARN + + + %-5p %d [%t] %c{0}: %m%n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/edexOsgi/com.raytheon.uf.common.topo/src/com/raytheon/uf/common/topo/util/TopoImporter.java b/javaUtilities/com.raytheon.uf.topo.utilities/src/com/raytheon/uf/topo/utilities/TopoImporter.java similarity index 61% rename from edexOsgi/com.raytheon.uf.common.topo/src/com/raytheon/uf/common/topo/util/TopoImporter.java rename to javaUtilities/com.raytheon.uf.topo.utilities/src/com/raytheon/uf/topo/utilities/TopoImporter.java index 5db293a558..5f7bd2ff21 100644 --- a/edexOsgi/com.raytheon.uf.common.topo/src/com/raytheon/uf/common/topo/util/TopoImporter.java +++ b/javaUtilities/com.raytheon.uf.topo.utilities/src/com/raytheon/uf/topo/utilities/TopoImporter.java @@ -17,7 +17,7 @@ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.uf.common.topo.util; +package com.raytheon.uf.topo.utilities; import java.io.BufferedReader; import java.io.DataInputStream; @@ -34,7 +34,8 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import com.raytheon.uf.common.datastorage.DataStoreFactory; +import org.opengis.referencing.crs.ProjectedCRS; + import com.raytheon.uf.common.datastorage.IDataStore; import com.raytheon.uf.common.datastorage.StorageProperties; import com.raytheon.uf.common.datastorage.StorageProperties.Compression; @@ -44,6 +45,8 @@ import com.raytheon.uf.common.datastorage.records.IntegerDataRecord; import com.raytheon.uf.common.datastorage.records.LongDataRecord; import com.raytheon.uf.common.datastorage.records.ShortDataRecord; import com.raytheon.uf.common.geospatial.MapUtil; +import com.raytheon.uf.common.pypies.PyPiesDataStore; +import com.raytheon.uf.common.pypies.PypiesProperties; /** * Import topo data into HDF5 @@ -53,7 +56,8 @@ import com.raytheon.uf.common.geospatial.MapUtil; * SOFTWARE HISTORY * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Oct 22, 2009 #3280 randerso Initial creation + * Oct 22, 2009 #3280 randerso Initial creation + * Feb 11, 2014 #2788 randerso Changed to use PyPiesDataStore * * * @@ -68,22 +72,14 @@ public class TopoImporter { String byteOrder; - String layout; - int nRows; int nCols; - int nBands; - int nBits; - int bandRowBytes; - int totalRowBytes; - int bandGapBytes; - long noData; double ulXmap; @@ -95,6 +91,18 @@ public class TopoImporter { double yDim; public TopoHdr(File file) { + if (file.getName().endsWith(".HDR")) { + readHdrFile(file); + } else if (file.getName().endsWith(".ers")) { + readErsFile(file); + } else { + throw new IllegalArgumentException( + "Unrecognized header file format: " + + file.getAbsolutePath()); + } + } + + private void readHdrFile(File file) { BufferedReader in = null; try { this.file = file; @@ -105,22 +113,14 @@ public class TopoImporter { if ("BYTEORDER".equals(s[0])) { byteOrder = s[1]; - } else if ("LAYOUT".equals(s[0])) { - layout = s[1]; } else if ("NROWS".equals(s[0])) { nRows = Integer.parseInt(s[1]); } else if ("NCOLS".equals(s[0])) { nCols = Integer.parseInt(s[1]); - } else if ("NBANDS".equals(s[0])) { - nBands = Integer.parseInt(s[1]); } else if ("NBITS".equals(s[0])) { nBits = Integer.parseInt(s[1]); - } else if ("BANDROWBYTES".equals(s[0])) { - bandRowBytes = Integer.parseInt(s[1]); } else if ("TOTALROWBYTES".equals(s[0])) { totalRowBytes = Integer.parseInt(s[1]); - } else if ("BANDGAPBYTES".equals(s[0])) { - bandGapBytes = Integer.parseInt(s[1]); } else if ("NODATA".equals(s[0])) { noData = Long.parseLong(s[1]); } else if ("ULXMAP".equals(s[0])) { @@ -149,6 +149,91 @@ public class TopoImporter { } } + private void readErsFile(File file) { + BufferedReader in = null; + try { + this.file = file; + in = new BufferedReader(new FileReader(file)); + String line; + while ((line = in.readLine()) != null) { + line = line.replace(" = ", " "); + String[] s = line.split("\\s+"); + + if ("ByteOrder".equals(s[0])) { + byteOrder = s[1]; + } else if ("NrOfLines".equals(s[0])) { + nRows = Integer.parseInt(s[1]); + } else if ("NrOfCellsPerLine".equals(s[0])) { + nCols = Integer.parseInt(s[1]); + } else if ("CellType".equals(s[0])) { + if (s[1].equals("Signed16BitInteger")) { + nBits = 16; + } else if (s[1].equals("Signed32BitInteger")) { + nBits = 32; + } else if (s[1].equals("Signed64BitInteger")) { + nBits = 64; + } else { + throw new IllegalArgumentException( + "Unrecognized data type: " + s[1]); + } + } else if ("NullCellValue".equals(s[0])) { + noData = Long.parseLong(s[1]); + } else if ("Longitude".equals(s[0])) { + ulXmap = parseDMS(s[1]); + } else if ("Latitude".equals(s[0])) { + ulYmap = parseDMS(s[1]); + } else if ("Xdimension".equals(s[0])) { + xDim = Double.parseDouble(s[1]); + } else if ("Ydimension".equals(s[0])) { + yDim = Double.parseDouble(s[1]); + } else { + // TODO: fully recognize the ers header file + System.out.println("Unrecognized line in file " + + file.getAbsolutePath() + "\n" + line); + } + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + // convert upper left coordinate from corner to + // center of cell + ulXmap += xDim / 2; + ulYmap -= yDim / 2; + + totalRowBytes = (nCols * nBits) / 8; + } + } + } + + private double parseDMS(String dms) { + // parse a string in degrees:minutes:seconds format into decimal + // degrees + double degrees = Double.NaN; + String[] s = dms.split(":"); + if (s.length == 3) { + try { + int deg = Integer.parseInt(s[0]); + int min = Integer.parseInt(s[1]); + double sec = Double.parseDouble(s[2]); + degrees = deg + (min - ((sec / 60.0) / 60.0)); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Unable to parse DMS: " + + dms, e); + } + } else { + throw new IllegalArgumentException("Unable to parse DMS: " + + dms); + } + return degrees; + } + /* * (non-Javadoc) * @@ -176,7 +261,7 @@ public class TopoImporter { @Override public boolean accept(File dir, String name) { - return name.endsWith(".HDR"); + return name.endsWith(".HDR") || name.endsWith(".ers"); } }; @@ -195,6 +280,11 @@ public class TopoImporter { hdrList.add(new TopoHdr(file)); } + if (hdrList.isEmpty()) { + throw new IllegalArgumentException( + "No recognized header files found"); + } + // sort the hdr files by descending lat/ascending lon Collections.sort(hdrList); @@ -202,12 +292,14 @@ public class TopoImporter { // determine the total dataset dimensions double startLat = hdrList.get(0).ulYmap; double startLon = hdrList.get(0).ulXmap; + double xDim = hdrList.get(0).xDim; + double yDim = hdrList.get(0).yDim; int last = hdrList.size() - 1; double endLat = hdrList.get(last).ulYmap - - (hdrList.get(last).nRows - 1) * hdrList.get(last).yDim; + - ((hdrList.get(last).nRows - 1) * hdrList.get(last).yDim); double endLon = hdrList.get(last).ulXmap - + (hdrList.get(last).nCols - 1) * hdrList.get(last).xDim; + + ((hdrList.get(last).nCols - 1) * hdrList.get(last).xDim); int bits = hdrList.get(0).nBits; double expectedLat = startLat; @@ -233,7 +325,7 @@ public class TopoImporter { maxCols = Math.max(cols, maxCols); expectedLat = hdr.ulYmap; - expectedLon = hdr.ulXmap + hdr.nCols * hdr.xDim; + expectedLon = hdr.ulXmap + (hdr.nCols * hdr.xDim); if ((expectedLon - startLon) > (360.0 - TOL)) { expectedLon = startLon; expectedLat -= hdr.nRows * hdr.yDim; @@ -244,8 +336,8 @@ public class TopoImporter { } // create the hdf5 file - File hdf = new File(dir.getParent() + File.separatorChar - + dir.getName().toLowerCase() + "_unpacked.hdf"); + File hdf = new File("topo" + File.separatorChar + + dir.getName().toLowerCase() + "_unpacked.h5"); if (hdf.exists()) { System.out .println(hdf.getAbsolutePath() @@ -253,7 +345,9 @@ public class TopoImporter { System.exit(-1); } - IDataStore store = DataStoreFactory.getDataStore(hdf); + PypiesProperties pypiesProps = new PypiesProperties(); + pypiesProps.setAddress("http://localhost:9582"); + IDataStore store = new PyPiesDataStore(hdf, true, pypiesProps); String dataset = "full"; long[] sizes = new long[] { maxCols, maxRows }; @@ -263,31 +357,47 @@ public class TopoImporter { properties.setChunked(true); IDataRecord record = null; - if (bits <= 8) { - record = new ByteDataRecord(dataset, "/", null, 2, sizes); + if (bits <= Byte.SIZE) { + record = new ByteDataRecord(dataset, null, null, 2, sizes); record.setFillValue(Byte.MIN_VALUE); - } else if (bits <= 16) { - record = new ShortDataRecord(dataset, "/", null, 2, sizes); + } else if (bits <= Short.SIZE) { + record = new ShortDataRecord(dataset, null, null, 2, sizes); record.setFillValue(Short.MIN_VALUE); - } else if (bits <= 32) { - record = new IntegerDataRecord(dataset, "/", null, 2, sizes); + } else if (bits <= Integer.SIZE) { + record = new IntegerDataRecord(dataset, null, null, 2, sizes); record.setFillValue(Integer.MIN_VALUE); - } else if (bits <= 64) { - record = new LongDataRecord(dataset, "/", null, 2, sizes); + } else if (bits <= Long.SIZE) { + record = new LongDataRecord(dataset, null, null, 2, sizes); record.setFillValue(Long.MIN_VALUE); } else { System.out.println("NBITS > 64"); System.exit(-1); } + double centralMeridian = 0.0; + double latOfOrigin = 0.0; + + double cm = (startLon + endLon) / 2; + centralMeridian = Math.round(cm); + + ProjectedCRS crs = MapUtil.constructEquidistantCylindrical( + MapUtil.AWIPS_EARTH_RADIUS, MapUtil.AWIPS_EARTH_RADIUS, + centralMeridian, latOfOrigin); + Map attributes = new LinkedHashMap(); attributes.put("Width", maxCols); attributes.put("Height", maxRows); - attributes.put("ulLat", startLat); - attributes.put("ulLon", startLon); - attributes.put("lrLat", endLat); - attributes.put("lrLon", endLon); - attributes.put("CRS", MapUtil.LATLON_PROJECTION.toWKT()); + + // Using arrays to work around serialization "feature" that returns + // floats when doubles are stored + // H5DataStore created these arrays automatically, Pypies does not + attributes.put("xDim", new double[] { xDim }); + attributes.put("yDim", new double[] { yDim }); + attributes.put("ulLat", new double[] { startLat }); + attributes.put("ulLon", new double[] { startLon }); + attributes.put("lrLat", new double[] { endLat }); + attributes.put("lrLon", new double[] { endLon }); + attributes.put("CRS", crs.toWKT()); record.setProperties(properties); record.setDataAttributes(attributes); @@ -301,8 +411,14 @@ public class TopoImporter { rows = 0; cols = 0; for (TopoHdr hdr : hdrList) { - File dem = new File(hdr.file.getAbsolutePath().replace(".HDR", - ".DEM")); + String demPath = hdr.file.getAbsolutePath(); + if (demPath.endsWith(".HDR")) { + demPath = demPath.replace(".HDR", ".DEM"); + } else if (demPath.endsWith(".ers")) { + demPath = demPath.replace(".ers", ""); + } + + File dem = new File(demPath); System.out.println(cols + ", " + rows + " " + dem.getName()); @@ -311,76 +427,75 @@ public class TopoImporter { in = new DataInputStream(new FileInputStream(dem)); ByteBuffer buffer = ByteBuffer.allocate(hdr.totalRowBytes); - if ("M".equals(hdr.byteOrder)) { + if (hdr.byteOrder.startsWith("M")) { buffer.order(ByteOrder.BIG_ENDIAN); } else { buffer.order(ByteOrder.LITTLE_ENDIAN); - System.out.println("WARNING: unrecognize BYTEORDER \"" - + hdr.byteOrder + "\" assuming LITTLE_ENDIAN"); } sizes[0] = hdr.nCols; sizes[1] = 1; record = null; + long writeSize = 0; for (int i = 0; i < hdr.nRows; i++) { in.read(buffer.array()); buffer.rewind(); - if (bits <= 8) { + if (bits <= Byte.SIZE) { byte[] byteData = new byte[hdr.nCols]; for (int j = 0; j < byteData.length; j++) { byteData[j] = buffer.get(); // replace no data flag with 0 if (byteData[j] == (byte) hdr.noData) { - byteData[j] = 0; + byteData[j] = Byte.MIN_VALUE; } } - record = new ByteDataRecord(dataset, "/", null, 2, + record = new ByteDataRecord(dataset, null, null, 2, sizes); record.setMinIndex(new long[] { cols, rows + i }); record.setFillValue(Byte.MIN_VALUE); ((ByteDataRecord) record).setByteData(buffer.array()); - } else if (bits <= 16) { + } else if (bits <= Short.SIZE) { short[] shortData = new short[hdr.nCols]; for (int j = 0; j < shortData.length; j++) { shortData[j] = buffer.getShort(); // replace no data flag with 0 if (shortData[j] == (short) hdr.noData) { - shortData[j] = 0; + shortData[j] = Short.MIN_VALUE; } } - record = new ShortDataRecord(dataset, "/", null, 2, + record = new ShortDataRecord(dataset, null, null, 2, sizes); record.setMinIndex(new long[] { cols, rows + i }); record.setFillValue(Short.MIN_VALUE); ((ShortDataRecord) record).setShortData(shortData); - } else if (bits <= 32) { + } else if (bits <= Integer.SIZE) { int[] intData = new int[hdr.nCols]; for (int j = 0; j < intData.length; j++) { intData[j] = buffer.getInt(); // replace no data flag with 0 if (intData[j] == (int) hdr.noData) { - intData[j] = 0; + intData[j] = Integer.MIN_VALUE; } } - record = new IntegerDataRecord(dataset, "/", null, 2, + record = new IntegerDataRecord(dataset, null, null, 2, sizes); record.setMinIndex(new long[] { cols, rows + i }); record.setFillValue(Integer.MIN_VALUE); ((IntegerDataRecord) record).setIntData(intData); - } else if (bits <= 64) { + } else if (bits <= Long.SIZE) { long[] longData = new long[hdr.nCols]; for (int j = 0; j < longData.length; j++) { longData[j] = buffer.getLong(); // replace no data flag with 0 if (longData[j] == hdr.noData) { - longData[j] = 0; + longData[j] = Long.MIN_VALUE; } } - record = new LongDataRecord(dataset, "/", null, 2, + record = new LongDataRecord(dataset, null, null, 2, sizes); record.setMinIndex(new long[] { cols, rows + i }); record.setFillValue(Long.MIN_VALUE); @@ -388,6 +503,11 @@ public class TopoImporter { } store.addDataRecord(record, properties); + writeSize += hdr.totalRowBytes; + if (writeSize > (64 * 1024 * 1024)) { + store.store(); + writeSize = 0; + } } store.store(); } catch (Throwable e) { @@ -410,7 +530,7 @@ public class TopoImporter { cols = 0; } } - System.out.println("took " + (System.currentTimeMillis() - t0) / 1000 + System.out.println("took " + ((System.currentTimeMillis() - t0) / 1000) + " seconds"); } } diff --git a/edexOsgi/com.raytheon.uf.common.topo/src/com/raytheon/uf/common/topo/util/TopoInterpolator.java b/javaUtilities/com.raytheon.uf.topo.utilities/src/com/raytheon/uf/topo/utilities/TopoInterpolator.java similarity index 76% rename from edexOsgi/com.raytheon.uf.common.topo/src/com/raytheon/uf/common/topo/util/TopoInterpolator.java rename to javaUtilities/com.raytheon.uf.topo.utilities/src/com/raytheon/uf/topo/utilities/TopoInterpolator.java index 7d332c2a27..1f8449961e 100644 --- a/edexOsgi/com.raytheon.uf.common.topo/src/com/raytheon/uf/common/topo/util/TopoInterpolator.java +++ b/javaUtilities/com.raytheon.uf.topo.utilities/src/com/raytheon/uf/topo/utilities/TopoInterpolator.java @@ -17,7 +17,7 @@ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.uf.common.topo.util; +package com.raytheon.uf.topo.utilities; import java.awt.Point; import java.awt.RenderingHints; @@ -40,7 +40,6 @@ import javax.media.jai.PlanarImage; import javax.media.jai.RasterFactory; import javax.media.jai.TiledImage; -import com.raytheon.uf.common.datastorage.DataStoreFactory; import com.raytheon.uf.common.datastorage.IDataStore; import com.raytheon.uf.common.datastorage.Request; import com.raytheon.uf.common.datastorage.StorageProperties; @@ -50,9 +49,11 @@ import com.raytheon.uf.common.datastorage.records.FloatDataRecord; import com.raytheon.uf.common.datastorage.records.IDataRecord; import com.raytheon.uf.common.datastorage.records.IntegerDataRecord; import com.raytheon.uf.common.datastorage.records.ShortDataRecord; +import com.raytheon.uf.common.pypies.PyPiesDataStore; +import com.raytheon.uf.common.pypies.PypiesProperties; /** - * TODO Add Description + * Interpolator for topo data files * *
  * 
@@ -62,6 +63,8 @@ import com.raytheon.uf.common.datastorage.records.ShortDataRecord;
  * Oct 26, 2009            randerso    Initial creation
  * Feb 12, 2013     #1608  randerso    Remove exlicit references to HDF5DataStore
  *                                     Added explicit calls to deleteGroups
+ * Feb 11, 2014     #2788  randerso    Changed to use PyPiesDataStore
+ *                                     Fixed corner points for interpolated levels
  * 
  * 
* @@ -72,22 +75,17 @@ import com.raytheon.uf.common.datastorage.records.ShortDataRecord; public class TopoInterpolator { private static final int BLOCK_SIZE = 2400; - private static final String DEFAULT_TOPO_FILE = "/topo/srtm30.hdf"; - private IDataStore dataStore; - public TopoInterpolator() { - this(new File(DEFAULT_TOPO_FILE)); - } - /** * Create a TopoInterpolator instance for the specified hdf file * * @param file */ public TopoInterpolator(File hdf) { - dataStore = DataStoreFactory.getDataStore(hdf); - + PypiesProperties pypiesProps = new PypiesProperties(); + pypiesProps.setAddress("http://localhost:9582"); + dataStore = new PyPiesDataStore(hdf, true, pypiesProps); } public void interpolate(String group, String dataSet) { @@ -97,8 +95,18 @@ public class TopoInterpolator { try { IDataRecord record = dataStore.retrieve(group, dataSet, request); Map attributes = record.getDataAttributes(); - int srcWidth = (Integer) attributes.get("Width"); - int srcHeight = (Integer) attributes.get("Height"); + int width = (Integer) attributes.get("Width"); + int height = (Integer) attributes.get("Height"); + + // These attributes are stored as 1x1 arrays in the file to match + // what H5DataStore did + // Pypies automatically returns them as scalars + double xDim = (Double) attributes.get("xDim"); + double yDim = (Double) attributes.get("yDim"); + double startLat = (Double) attributes.get("ulLat"); + double startLon = (Double) attributes.get("ulLon"); + double endLat = (Double) attributes.get("lrLat"); + double endLon = (Double) attributes.get("lrLon"); int level = 1; String srcGroup = group; @@ -120,14 +128,33 @@ public class TopoInterpolator { long t1 = t0; while (level < 6) { System.out.print("\nInterpolating " + srcGroup + srcDataSet - + " (" + srcWidth + ", " + srcHeight + ")"); + + " (" + width + ", " + height + ")"); + + int srcWidth = width; + int srcHeight = height; + + // compute attributes for new level + width /= 2; + height /= 2; + startLon += xDim / 2; + startLat -= yDim / 2; + endLon -= xDim / 2; + endLat += yDim / 2; + xDim *= 2; + yDim *= 2; String dstDataSet = "" + level; record.setName(dstDataSet); record.setGroup(dstGroup); - record.setSizes(new long[] { srcWidth / 2, srcHeight / 2 }); + record.setSizes(new long[] { width, height }); record.setProperties(properties); - attributes.put("Width", srcWidth / 2); - attributes.put("Height", srcHeight / 2); + attributes.put("Width", width); + attributes.put("Height", height); + attributes.put("xDim", new double[] { xDim }); + attributes.put("yDim", new double[] { yDim }); + attributes.put("ulLat", new double[] { startLat }); + attributes.put("ulLon", new double[] { startLon }); + attributes.put("lrLat", new double[] { endLat }); + attributes.put("lrLon", new double[] { endLon }); record.setDataAttributes(attributes); dataStore.createDataset(record); @@ -159,17 +186,15 @@ public class TopoInterpolator { } long t2 = System.currentTimeMillis(); - System.out.print(" took " + (t2 - t1) / 1000 + " s"); + System.out.print(" took " + ((t2 - t1) / 1000) + " s"); t1 = t2; srcGroup = dstGroup; srcDataSet = dstDataSet; level++; - srcWidth /= 2; - srcHeight /= 2; } - System.out.print("\nTotal " + (System.currentTimeMillis() - t0) - / 1000 + " s"); + System.out.print("\nTotal " + + ((System.currentTimeMillis() - t0) / 1000) + " s"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -230,7 +255,7 @@ public class TopoInterpolator { param.setParameter("xScale", 1.0f / scale); param.setParameter("yScale", 1.0f / scale); Interpolation interpol = Interpolation - .getInstance(Interpolation.INTERP_BICUBIC); + .getInstance(Interpolation.INTERP_NEAREST); param.setParameter("interpolation", interpol); RenderingHints hint = new RenderingHints(JAI.KEY_BORDER_EXTENDER, BorderExtender.createInstance(BorderExtender.BORDER_COPY)); @@ -263,14 +288,14 @@ public class TopoInterpolator { public static void main(String[] args) { TopoInterpolator ti; if (args.length < 1) { - ti = new TopoInterpolator(); + System.out.println("usage: TopoInterpolator topofile"); } else { - ti = new TopoInterpolator(new File(args[0])); - } + String fileName = args[0]; + System.out.println("Interpolating " + fileName); + ti = new TopoInterpolator(new File(fileName)); - System.out.println("Interpolating " - + (args.length < 1 ? DEFAULT_TOPO_FILE : args[0])); - ti.interpolate("/", "full"); + ti.interpolate("/", "full"); + } } } diff --git a/rpms/awips2.core/Installer.topo/component.spec b/rpms/awips2.core/Installer.topo/component.spec index fc1c0e1364..ff541c3e5b 100644 --- a/rpms/awips2.core/Installer.topo/component.spec +++ b/rpms/awips2.core/Installer.topo/component.spec @@ -78,7 +78,10 @@ fi TOPO_TO_COPY=\ (\ - 'srtm30.hdf'\ + 'gtopo30.h5'\ + 'srtm30.h5'\ + 'srtm30_plus.h5'\ + 'defaultTopo.h5' \ 'akTopo.dat.gz' \ 'caribTopo.dat.gz' \ 'modelStaticTopo.h5' \ @@ -91,21 +94,13 @@ TOPO_TO_COPY=\ for topoFile in ${TOPO_TO_COPY[*]}; do - cp -r %{_awipscm_share}/${TOPO_SRC_DIR}/${topoFile} \ + cp -Pp %{_awipscm_share}/${TOPO_SRC_DIR}/${topoFile} \ ${RPM_BUILD_ROOT}/awips2/edex/data/hdf5/topo if [ $? -ne 0 ]; then exit 1 fi done -# Copy our hlsTopo -mkdir -p ${RPM_BUILD_ROOT}/awips2/edex/data/hdf5/topo/hlsTopo -cp -r %{_awipscm_share}/${TOPO_SRC_DIR}/hlsTopo/* \ - ${RPM_BUILD_ROOT}/awips2/edex/data/hdf5/topo/hlsTopo -if [ $? -ne 0 ]; then - exit 1 -fi - copyLegal "awips2/edex/data/hdf5/topo" %pre diff --git a/rpms/common/static.versions/LATEST.topo b/rpms/common/static.versions/LATEST.topo index 58bd847d7a..4d578ea235 100644 --- a/rpms/common/static.versions/LATEST.topo +++ b/rpms/common/static.versions/LATEST.topo @@ -1 +1 @@ -20110824 \ No newline at end of file +20140211 \ No newline at end of file