From 815ab796b9475a563c5e598a6048dc95e793fd57 Mon Sep 17 00:00:00 2001 From: Max Schenkelberg Date: Mon, 24 Jun 2013 09:21:43 -0500 Subject: [PATCH] Issue #2122 Refactored satellite to use tile set renderable. Deleted old code Amend: Added fix for issue 2103 Amend: Added software history Change-Id: I1e09bcbf28aaffbf602431a09af50da447e4cf2b Former-commit-id: 78c0e1684e8a3d22762298ff5731561848877b41 [formerly b4c0d1f715abef40f0e072c56c8a9a1167cd68e6] [formerly 47b55981c8cf4791edb5a6d530954f16ca1fb047] [formerly 78c0e1684e8a3d22762298ff5731561848877b41 [formerly b4c0d1f715abef40f0e072c56c8a9a1167cd68e6] [formerly 47b55981c8cf4791edb5a6d530954f16ca1fb047] [formerly 2f03c38ca05b35e99a162be39b673b794d1d47e1 [formerly 47b55981c8cf4791edb5a6d530954f16ca1fb047 [formerly e98002c1d18eefe039f0bfc9f1b90ef577d42547]]]] Former-commit-id: 2f03c38ca05b35e99a162be39b673b794d1d47e1 Former-commit-id: 6b4982e8a30cf51ff5e6410ea994c1429fc1af18 [formerly c912e8e6c57db450db01eee84317d6db696a6109] [formerly 81f10786b9755a530e3615de10b091e1f0022d78 [formerly bc4ebb4f0821301147c53e1013085c1c656ae040]] Former-commit-id: d7196e32710e3cc8969f238de14a54ee542ee1fa [formerly 20caab72f91b7eb107f5dd4d1bfc8014dc06da11] Former-commit-id: 539bbe2cb58398acb013231d91f82cc67136d7cf --- .../raytheon/uf/viz/core/IMeshCallback.java | 50 -- .../uf/viz/core/data/BufferSlicer.java | 22 +- .../rsc/AbstractPluginDataObjectResource.java | 167 +++--- .../uf/viz/core/rsc/AbstractVizResource.java | 8 +- .../core/tile/RecordTileSetRenderable.java | 381 +++++++++++++ .../uf/viz/core/tile/TileSetRenderable.java | 49 +- .../viz/core/rsc/hdf5/AbstractTileSet.java | 22 +- .../viz/core/rsc/hdf5/MemoryBasedTileSet.java | 254 --------- .../satellite/data/prep/SatDataRetriever.java | 2 +- .../satellite/rsc/SatFileBasedTileSet.java | 3 + .../viz/satellite/rsc/SatResource.java | 538 +++++++++--------- .../satellite/tileset/SatDataRetriever.java | 181 ++++++ .../tileset/SatTileSetRenderable.java | 82 +++ .../res/scripts/units.sql | 1 + .../common/colormap/image/ColorMapData.java | 2 +- .../satellite/units/SatelliteUnits.java | 4 +- 16 files changed, 1066 insertions(+), 700 deletions(-) delete mode 100644 cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/IMeshCallback.java create mode 100644 cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/tile/RecordTileSetRenderable.java delete mode 100644 cave/com.raytheon.viz.core/src/com/raytheon/viz/core/rsc/hdf5/MemoryBasedTileSet.java create mode 100644 cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/tileset/SatDataRetriever.java create mode 100644 cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/tileset/SatTileSetRenderable.java diff --git a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/IMeshCallback.java b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/IMeshCallback.java deleted file mode 100644 index d8f82214ca..0000000000 --- a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/IMeshCallback.java +++ /dev/null @@ -1,50 +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.viz.core; - -import com.raytheon.uf.viz.core.rsc.hdf5.ImageTile; - -/** - * Interface for notification when a mesh calculation has completed - * - *
- * 
- * SOFTWARE HISTORY
- * Date         Ticket#    Engineer    Description
- * ------------ ---------- ----------- --------------------------
- * Jun 19, 2010            mschenke     Initial creation
- * 
- * 
- * - * @author mschenke - * @version 1.0 - */ - -public interface IMeshCallback { - - /** - * Notification of when the calculation for the mesh of the tile has been - * completed - * - * @param tile - */ - public void meshCalculated(ImageTile tile); - -} diff --git a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/data/BufferSlicer.java b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/data/BufferSlicer.java index 238846b4b5..edcb52d04d 100644 --- a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/data/BufferSlicer.java +++ b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/data/BufferSlicer.java @@ -35,7 +35,9 @@ import java.nio.ShortBuffer; * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Nov 22, 2011 mschenke Initial creation + * Nov 22, 2011 mschenke Initial creation + * Jun 20, 2013 2122 mschenke Made work with slicing from data with + * bounds not starting at 0,0 * * * @@ -61,7 +63,7 @@ public class BufferSlicer { || dataBounds.getMinY() < totalBounds.getMinY() || dataBounds.getMaxX() > totalBounds.getMaxX() || dataBounds.getMaxY() > totalBounds.getMaxY()) { - throw new RuntimeException( + throw new IndexOutOfBoundsException( "Data bounds defines region outside of buffer's total bounds"); } @@ -111,10 +113,12 @@ public class BufferSlicer { newData = ByteBuffer.allocate(dataSize); } + int xOffset = (dataBounds.x - totalBounds.x); + int yOffset = (dataBounds.y - totalBounds.y); newData.position(0); byte[] bytes = new byte[dataBounds.width]; for (int i = 0; i < dataBounds.height; ++i) { - data.position((dataBounds.y * totalBounds.width + dataBounds.x) + i + data.position((yOffset * totalBounds.width + xOffset) + i * totalBounds.width); data.get(bytes); newData.put(bytes); @@ -134,10 +138,12 @@ public class BufferSlicer { newData = ShortBuffer.allocate(dataSize); } + int xOffset = (dataBounds.x - totalBounds.x); + int yOffset = (dataBounds.y - totalBounds.y); newData.position(0); short[] shorts = new short[dataBounds.width]; for (int i = 0; i < dataBounds.height; ++i) { - data.position((dataBounds.y * totalBounds.width + dataBounds.x) + i + data.position((yOffset * totalBounds.width + xOffset) + i * totalBounds.width); data.get(shorts); newData.put(shorts); @@ -157,10 +163,12 @@ public class BufferSlicer { newData = IntBuffer.allocate(dataSize); } + int xOffset = (dataBounds.x - totalBounds.x); + int yOffset = (dataBounds.y - totalBounds.y); newData.position(0); int[] ints = new int[dataBounds.width]; for (int i = 0; i < dataBounds.height; ++i) { - data.position((dataBounds.y * totalBounds.width + dataBounds.x) + i + data.position((yOffset * totalBounds.width + xOffset) + i * totalBounds.width); data.get(ints); newData.put(ints); @@ -180,10 +188,12 @@ public class BufferSlicer { newData = FloatBuffer.allocate(dataSize); } + int xOffset = (dataBounds.x - totalBounds.x); + int yOffset = (dataBounds.y - totalBounds.y); newData.position(0); float[] floats = new float[dataBounds.width]; for (int i = 0; i < dataBounds.height; ++i) { - data.position((dataBounds.y * totalBounds.width + dataBounds.x) + i + data.position((yOffset * totalBounds.width + xOffset) + i * totalBounds.width); data.get(floats); newData.put(floats); diff --git a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/rsc/AbstractPluginDataObjectResource.java b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/rsc/AbstractPluginDataObjectResource.java index 5c40a0fef7..139d38a21a 100644 --- a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/rsc/AbstractPluginDataObjectResource.java +++ b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/rsc/AbstractPluginDataObjectResource.java @@ -20,6 +20,7 @@ package com.raytheon.uf.viz.core.rsc; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -34,6 +35,7 @@ import com.raytheon.uf.viz.core.drawables.IDescriptor; import com.raytheon.uf.viz.core.drawables.IRenderable; import com.raytheon.uf.viz.core.drawables.PaintProperties; import com.raytheon.uf.viz.core.exception.VizException; +import com.raytheon.uf.viz.core.rsc.IResourceDataChanged.ChangeType; import com.raytheon.uf.viz.core.rsc.capabilities.AbstractCapability; /** @@ -45,7 +47,9 @@ import com.raytheon.uf.viz.core.rsc.capabilities.AbstractCapability; * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Dec 21, 2011 mschenke Initial creation + * Dec 21, 2011 mschenke Initial creation + * Jun 24, 2013 2122 mschenke Made use built in resource data changed listener + * updates will not be lost from construction to initInternal * * * @@ -66,38 +70,6 @@ public abstract class AbstractPluginDataObjectResource pdos = new ArrayList(); - for (Object obj : (Object[]) object) { - if (obj instanceof PluginDataObject) { - pdos.add((PluginDataObject) obj); - } - } - if (pdos.size() > 0) { - addDataObject(pdos.toArray(new PluginDataObject[0])); - } - } - } else if (type == ChangeType.CAPABILITY) { - if (object instanceof AbstractCapability) { - AbstractCapability capability = (AbstractCapability) object; - for (Frame frame : frames.values()) { - if (frame.renderable != null) { - capabilityChanged(frame.renderable, capability); - } - } - } - } - } - }; - private Map frames = new HashMap(); /** @@ -110,6 +82,37 @@ public abstract class AbstractPluginDataObjectResource(); } + @Override + protected void resourceDataChanged(ChangeType type, Object object) { + if (type == ChangeType.DATA_UPDATE) { + if (object instanceof PluginDataObject) { + addDataObject((PluginDataObject) object); + } else if (object instanceof PluginDataObject[]) { + addDataObject((PluginDataObject[]) object); + } else if (object instanceof Object[]) { + List pdos = new ArrayList(); + for (Object obj : (Object[]) object) { + if (obj instanceof PluginDataObject) { + pdos.add((PluginDataObject) obj); + } + } + if (pdos.isEmpty() == false) { + addDataObject(pdos.toArray(new PluginDataObject[0])); + } + } + } else if (type == ChangeType.CAPABILITY) { + if (object instanceof AbstractCapability) { + AbstractCapability capability = (AbstractCapability) object; + for (Frame frame : frames.values()) { + if (frame.renderable != null) { + capabilityChanged(frame.renderable, capability); + } + } + } + } + issueRefresh(); + } + /** * Adds the pdo to the appropriate time and removes any renderable or data * cached for that time. @@ -153,12 +156,14 @@ public abstract class AbstractPluginDataObjectResource( + frame.records)); + } + } + } + } + + return renderable; + } + + /** + * Gets the IRenderable for the given time or null if none exists yet + * + * @param time + * @return + */ + protected IRenderable getRenderable(DataTime time) { + Frame frame = null; + synchronized (this) { + frame = frames.get(time); + } + if (frame != null) { + synchronized (frame.lock) { + return frame.renderable; + } + } + return null; + } + /* * (non-Javadoc) * @@ -260,18 +313,8 @@ public abstract class AbstractPluginDataObjectResource( - currFrame.records)); - } - if (renderable != null) { - renderable.paint(target, paintProps); - } - } - } + IRenderable renderable = getOrCreateRenderable(time); + if (renderable != null) { + renderable.paint(target, paintProps); } } @@ -333,7 +361,6 @@ public abstract class AbstractPluginDataObjectResource(); paintStatusListeners = new CopyOnWriteArraySet(); disposeListeners = new CopyOnWriteArraySet(); + + if (resourceData != null) { + resourceData.addChangeListener(changeListener); + } } /** @@ -344,10 +348,6 @@ public abstract class AbstractVizResource + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Jun 19, 2013 2122 mschenke Initial creation. + * + * + * + * @author mschenke + * @version 1.0 + */ + +public class RecordTileSetRenderable extends TileSetRenderable { + + private class RecordTileDataCallback implements + IColorMapDataRetrievalCallback { + + private final Tile tile; + + private ColorMapData data; + + private RecordTileDataCallback(Tile tile) { + this.tile = tile; + } + + private void setRetrievedData(ColorMapData data) { + this.data = data; + } + + @Override + public ColorMapData getColorMapData() throws VizException { + ColorMapData rval = data; + if (rval != null) { + // Once retrieved, null out + data = null; + } else { + rval = data = retrieveRecordData(tile); + } + return rval; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + getOuterType().hashCode(); + result = prime * result + ((tile == null) ? 0 : tile.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + RecordTileDataCallback other = (RecordTileDataCallback) obj; + if (!getOuterType().equals(other.getOuterType())) + return false; + if (tile == null) { + if (other.tile != null) + return false; + } else if (!tile.equals(other.tile)) + return false; + return true; + } + + private RecordTileSetRenderable getOuterType() { + // Only compares outer type class to ensure calls to + // retrieveRecordData will be the same + return RecordTileSetRenderable.this; + } + + } + + private class RecordTileImageCreatorTask implements Runnable { + + private final IGraphicsTarget target; + + private final Tile bigTile; + + private final List subTiles; + + public RecordTileImageCreatorTask(IGraphicsTarget target, Tile bigTile, + List subTiles) { + this.target = target; + this.bigTile = bigTile; + this.subTiles = subTiles; + } + + @Override + public void run() { + int numTiles = subTiles.size(); + int numNeedStaging = 0; + + List callbacks = new ArrayList( + numTiles); + List images = new ArrayList(numTiles); + + for (Tile tile : subTiles) { + RecordTileDataCallback callback = new RecordTileDataCallback( + tile); + callbacks.add(callback); + DrawableImage image = null; + try { + image = createTileImage(target, tile, callback); + } catch (VizException e) { + statusHandler.handle(Priority.PROBLEM, + e.getLocalizedMessage(), e); + } + images.add(image); + + if (image != null + && image.getImage().getStatus() == Status.UNLOADED) { + numNeedStaging += 1; + } + } + + if (numNeedStaging == numTiles) { + // All the images need staging, do bulk request + ColorMapData data = retrieveRecordData(bigTile); + + Rectangle bigTileRect = bigTile.getRectangle(); + for (int i = 0; i < numTiles; i += 1) { + Tile tile = subTiles.get(i); + DrawableImage image = images.get(i); + if (image != null) { + if (image.getImage().getStatus() == Status.UNLOADED) { + Rectangle tileRect = tile.getRectangle(); + ColorMapData subData = new ColorMapData( + BufferSlicer.slice(data.getBuffer(), + tileRect, bigTileRect), new int[] { + tileRect.width, tileRect.height }, + data.getDataType()); + + callbacks.get(i).setRetrievedData(subData); + try { + image.getImage().stage(); + } catch (VizException e) { + statusHandler.handle(Priority.PROBLEM, + e.getLocalizedMessage(), e); + } + } + } + } + } + + for (int i = 0; i < numTiles; i += 1) { + Tile tile = subTiles.get(i); + DrawableImage image = images.get(i); + addTileImage(tile, image); + } + target.setNeedsRefresh(true); + } + + public DrawableImage createTileImage(IGraphicsTarget target, Tile tile, + RecordTileDataCallback callback) throws VizException { + IColormappedImage image = target.getExtension( + IColormappedImageExtension.class).initializeRaster( + callback, colormapping.getColorMapParameters()); + IMesh mesh = target.getExtension(IMapMeshExtension.class) + .constructMesh(tile.tileGeometry, + tileSet.getTargetGeometry()); + return new DrawableImage(image, new PixelCoverage(mesh), + RasterMode.ASYNCHRONOUS); + } + + } + + protected final ColorMapCapability colormapping; + + protected final PluginDataObject record; + + public RecordTileSetRenderable(AbstractVizResource resource, + PluginDataObject record, ISpatialObject spatialObject, + int tileLevels) { + this(resource, record, MapUtil.getGridGeometry(spatialObject), + tileLevels); + } + + public RecordTileSetRenderable(AbstractVizResource resource, + PluginDataObject record, GridGeometry2D tileSetGeometry, + int tileLevels) { + this(resource, record, tileSetGeometry, tileLevels, 512); + } + + public RecordTileSetRenderable(AbstractVizResource resource, + PluginDataObject record, GridGeometry2D tileSetGeometry, + int tileLevels, int tileSize) { + super(resource.getCapability(ImagingCapability.class), tileSetGeometry, + null, tileLevels, tileSize); + this.record = record; + this.colormapping = resource.getCapability(ColorMapCapability.class); + } + + @Override + protected void createTileImages(IGraphicsTarget target, + Collection tilesToCreate) { + Map> mapped = new HashMap>(); + for (Tile tile : tilesToCreate) { + // Ensure no job already scheduled for tile + if (jobMap.get(tile) == null) { + List tiles = mapped.get(tile.tileLevel); + if (tiles == null) { + tiles = new ArrayList(); + mapped.put(tile.tileLevel, tiles); + } + tiles.add(tile); + } + } + + for (Integer tileLevel : mapped.keySet()) { + List tiles = mapped.get(tileLevel); + List rectangles = new ArrayList(); + List envelopes = new ArrayList(); + + for (Tile tile : tiles) { + rectangles.add(tile.tileGeometry.getGridRange2D()); + envelopes.add(tile.tileGeometry.getEnvelope2D()); + } + + // Join together any adjacent rectangles + for (int i = 0; i < rectangles.size(); i++) { + Rectangle r1 = rectangles.get(i); + Envelope2D e1 = envelopes.get(i); + for (int j = i + 1; j < rectangles.size(); j++) { + Rectangle r2 = rectangles.get(j); + Envelope2D e2 = envelopes.get(j); + boolean joinable = true; + if (r1.x == r2.x && r1.width == r2.width) { + if (r1.getMaxY() == r2.getMinY() + || r1.getMinY() == r2.getMaxY()) { + joinable = true; + } + } else if (r1.y == r2.y && r1.height == r2.height) { + if (r1.getMaxX() == r2.getMinX() + || r1.getMinX() == r2.getMaxX()) { + joinable = true; + } + } + if (joinable) { + // Join the rectangles + rectangles.remove(r1); + rectangles.remove(r2); + Rectangle2D joined = new GridEnvelope2D(); + Rectangle2D.union(r1, r2, joined); + rectangles.add((GridEnvelope2D) joined); + + // Join the envelopes + envelopes.remove(e1); + envelopes.remove(e2); + joined = new Envelope2D(); + Rectangle2D.union(e1, e2, joined); + envelopes.add((Envelope2D) joined); + + // start all over. + i = -1; + break; + } + } + } + + // start a separate job for every big rectangle + for (int i = 0; i < rectangles.size(); i++) { + Tile joinedTile = new Tile(tileLevel, new GridGeometry2D( + (GridEnvelope) rectangles.get(i), envelopes.get(i))); + RecordTileImageCreatorTask task = new RecordTileImageCreatorTask( + target, joinedTile, tiles); + for (Tile tile : tiles) { + jobMap.put(tile, task); + } + tileCreationPool.schedule(task); + } + } + } + + /** + * @param tile + * @return + */ + protected ColorMapData retrieveRecordData(Tile tile) { + return new HDF5DataRetriever(HDF5Util.findHDF5Location(record), + DataStoreFactory.createDataSetName(record.getDataURI(), + DataStoreFactory.DEF_DATASET_NAME, tile.tileLevel), + tile.getRectangle()).getColorMapData(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((record == null) ? 0 : record.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + RecordTileSetRenderable other = (RecordTileSetRenderable) obj; + if (record == null) { + if (other.record != null) + return false; + } else if (!record.equals(other.record)) + return false; + return true; + } + +} diff --git a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/tile/TileSetRenderable.java b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/tile/TileSetRenderable.java index 90b1801cc1..de0ff17d01 100644 --- a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/tile/TileSetRenderable.java +++ b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/tile/TileSetRenderable.java @@ -22,6 +22,7 @@ package com.raytheon.uf.viz.core.tile; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -63,7 +64,9 @@ import com.vividsolutions.jts.geom.Coordinate; * ------------ ---------- ----------- -------------------------- * Aug 8, 2012 mschenke Initial creation * May 28, 2013 2037 njensen Made imageMap concurrent to fix leak - * + * Jun 20, 2013 2122 mschenke Fixed null pointer in interrogate and made + * canceling jobs safer + * * * * @author mschenke @@ -297,7 +300,21 @@ public class TileSetRenderable implements IRenderable { lastPaintedLevel = usedTileLevel; return getImagesWithinExtent(target, paintProps.getView().getExtent(), - usedTileLevel, 0); + usedTileLevel); + } + + /** + * Gets the images to render within the extent in target grid space + * + * @param target + * @param extent + * @param level + * @return + * @throws VizException + */ + protected List getImagesWithinExtent(IGraphicsTarget target, + IExtent extent, int level) { + return getImagesWithinExtent(target, extent, level, 0); } /** @@ -309,8 +326,8 @@ public class TileSetRenderable implements IRenderable { * @return * @throws VizException */ - protected List getImagesWithinExtent(IGraphicsTarget target, - IExtent extent, int level, int depth) throws VizException { + private List getImagesWithinExtent(IGraphicsTarget target, + IExtent extent, int level, int depth) { if (tileSet == null) { // Early exit condition, disposed or haven't projected yet return Collections.emptyList(); @@ -366,10 +383,13 @@ public class TileSetRenderable implements IRenderable { // All intersecting tiles are loaded for this level, cancel any // jobs running for tiles we don't need anymore (may be case if // zooming or panning) - for (Runnable job : jobMap.values()) { - tileCreationPool.cancel(job); + Iterator iterator = jobMap.values().iterator(); + while (iterator.hasNext()) { + Runnable job = iterator.next(); + if (tileCreationPool.cancel(job)) { + iterator.remove(); + } } - jobMap.clear(); } else { target.setNeedsRefresh(true); // Create tiles needing images @@ -446,12 +466,15 @@ public class TileSetRenderable implements IRenderable { TileLevel level = tileSet.getTileLevel(lastPaintedLevel); double[] grid = level.crsToGrid(localX, localY); Tile tile = level.getTile(grid[0], grid[1]); - DrawableImage di = imageMap.get(tile); - if (di != null) { - IImage image = di.getImage(); - if (image instanceof IColormappedImage) { - return ((IColormappedImage) image).getValue((int) grid[0] - % tileSize, (int) grid[1] % tileSize); + if (tile != null) { + DrawableImage di = imageMap.get(tile); + if (di != null) { + IImage image = di.getImage(); + if (image instanceof IColormappedImage) { + return ((IColormappedImage) image).getValue( + (int) grid[0] % tileSize, (int) grid[1] + % tileSize); + } } } } catch (TransformException e) { diff --git a/cave/com.raytheon.viz.core/src/com/raytheon/viz/core/rsc/hdf5/AbstractTileSet.java b/cave/com.raytheon.viz.core/src/com/raytheon/viz/core/rsc/hdf5/AbstractTileSet.java index 34e430f142..3c1cfc1b68 100644 --- a/cave/com.raytheon.viz.core/src/com/raytheon/viz/core/rsc/hdf5/AbstractTileSet.java +++ b/cave/com.raytheon.viz.core/src/com/raytheon/viz/core/rsc/hdf5/AbstractTileSet.java @@ -24,10 +24,8 @@ import java.awt.Rectangle; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.collections.keyvalue.MultiKey; @@ -53,7 +51,6 @@ import com.raytheon.uf.viz.core.DrawableImage; import com.raytheon.uf.viz.core.IExtent; import com.raytheon.uf.viz.core.IGraphicsTarget; import com.raytheon.uf.viz.core.IGraphicsTarget.RasterMode; -import com.raytheon.uf.viz.core.IMeshCallback; import com.raytheon.uf.viz.core.PixelCoverage; import com.raytheon.uf.viz.core.VizApp; import com.raytheon.uf.viz.core.drawables.IColormappedImage; @@ -83,13 +80,14 @@ import com.vividsolutions.jts.geom.Coordinate; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Feb 15, 2007 chammack Initial Creation. + * Jun 24, 2013 2122 mschenke Removed unused IMeshCallback listeners * * * * @author chammack * @version 1 */ -public abstract class AbstractTileSet implements IRenderable, IMeshCallback { +public abstract class AbstractTileSet implements IRenderable { private static final transient IUFStatusHandler statusHandler = UFStatus .getHandler(AbstractTileSet.class); @@ -147,8 +145,6 @@ public abstract class AbstractTileSet implements IRenderable, IMeshCallback { private boolean disposed = true; - private Set meshCallbacks = new HashSet(); - public AbstractTileSet(int levels, int tileSize, GridGeometry2D gridGeometry, AbstractVizResource rsc, PixelInCell pixelOrientation, String viewType) throws VizException { @@ -905,18 +901,4 @@ public abstract class AbstractTileSet implements IRenderable, IMeshCallback { return jobMap.isEmpty(); } - public void addMeshCallback(IMeshCallback meshCallback) { - this.meshCallbacks.add(meshCallback); - } - - public void removeMeshCallback(IMeshCallback meshCallback) { - this.meshCallbacks.remove(meshCallback); - } - - public void meshCalculated(ImageTile tile) { - for (IMeshCallback meshCallback : meshCallbacks) { - meshCallback.meshCalculated(tile); - } - } - } diff --git a/cave/com.raytheon.viz.core/src/com/raytheon/viz/core/rsc/hdf5/MemoryBasedTileSet.java b/cave/com.raytheon.viz.core/src/com/raytheon/viz/core/rsc/hdf5/MemoryBasedTileSet.java deleted file mode 100644 index 47968ca8a6..0000000000 --- a/cave/com.raytheon.viz.core/src/com/raytheon/viz/core/rsc/hdf5/MemoryBasedTileSet.java +++ /dev/null @@ -1,254 +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.viz.core.rsc.hdf5; - -import java.io.File; -import java.io.FileNotFoundException; - -import javax.measure.converter.UnitConverter; - -import org.geotools.coverage.grid.GridGeometry2D; -import org.opengis.referencing.datum.PixelInCell; - -import com.raytheon.uf.common.dataplugin.PluginDataObject; -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.StorageException; -import com.raytheon.uf.common.datastorage.records.FloatDataRecord; -import com.raytheon.uf.common.datastorage.records.IDataRecord; -import com.raytheon.uf.viz.core.IGraphicsTarget; -import com.raytheon.uf.viz.core.data.IDataPreparer; -import com.raytheon.uf.viz.core.data.prep.CMDataPreparerManager; -import com.raytheon.uf.viz.core.datastructure.DataCubeContainer; -import com.raytheon.uf.viz.core.datastructure.VizDataCubeException; -import com.raytheon.uf.viz.core.drawables.IImage; -import com.raytheon.uf.viz.core.exception.VizException; -import com.raytheon.uf.viz.core.rsc.AbstractVizResource; -import com.raytheon.uf.viz.core.rsc.capabilities.ColorMapCapability; - -/** - * Memory based tileset. - * - * This memory-based tileset pulls a small raster from an hdf5 file and - * interpolates it to a larger size. The raster is then split once it is already - * loaded in memory.git pull - * - *
- * 
- *  SOFTWARE HISTORY
- * 
- *  Date         Ticket#     Engineer    Description
- *  ------------ ----------  ----------- --------------------------
- *  Feb 15, 2007             chammack    Initial Creation.
- * 
- * 
- * - * @author chammack - * @version 1 - */ -public class MemoryBasedTileSet extends AbstractTileSet { - - protected Object[] loadedData; - - protected int[][] dims; - - protected boolean[] isLoaded; - - protected UnitConverter converter; - - protected PluginDataObject pdo; - - protected String hdf5File; - - protected String group; - - protected String dataset; - - public MemoryBasedTileSet(String hdf5File, String group, String dataset, - AbstractTileSet sharedGeometryTileset, UnitConverter converter, - PluginDataObject pdo) throws VizException { - super(sharedGeometryTileset); - this.converter = converter; - this.isLoaded = new boolean[sharedGeometryTileset.levels]; - this.pdo = pdo; - this.hdf5File = hdf5File; - this.group = group; - this.dataset = dataset; - } - - public MemoryBasedTileSet(String hdf5File, String group, String dataset, - int levels, int tileSize, GridGeometry2D gridGeometry, - AbstractVizResource rsc, UnitConverter converter, - PixelInCell orientation, PluginDataObject pdo, String viewType) - throws VizException { - super(levels, tileSize, gridGeometry, rsc, orientation, viewType); - this.converter = converter; - this.isLoaded = new boolean[levels]; - this.pdo = pdo; - this.hdf5File = hdf5File; - this.group = group; - this.dataset = dataset; - } - - /* - * (non-Javadoc) - * - * @see - * com.raytheon.viz.core.rsc.tiling.AbstractTileSet#preloadDataObject(int) - */ - @Override - protected void preloadDataObject(int level) throws StorageException { - synchronized (isLoaded) { - if (isLoaded[level]) { - return; - } - IDataRecord rec = getDataRecord(); - - if (loadedData == null) { - loadedData = new Object[levels]; - dims = new int[levels][]; - } - - if (rec != null) { - - loadedData[level] = rec.getDataObject(); - - long[] d = rec.getSizes(); - dims[level] = new int[] { (int) d[0], (int) d[1] }; - - } - - isLoaded[level] = true; - } - } - - protected IDataRecord getDataRecord() throws StorageException { - if (pdo != null) { - try { - IDataRecord[] records = DataCubeContainer.getDataRecord(pdo); - if (records != null && records.length > 0) { - return records[0]; - } - } catch (VizDataCubeException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } else { - try { - IDataStore ds = DataStoreFactory - .getDataStore(new File(hdf5File)); - return ds.retrieve("", group + "/" + dataset, Request.ALL); - // (float) this.interpolationFactorOnLoad - // * (float) (Math.pow(2, this.levels - // - level - 1))); - } catch (FileNotFoundException e) { - throw new StorageException("Unable to open file", null, e); - } - } - return null; - } - - /* - * (non-Javadoc) - * - * @see - * com.raytheon.viz.core.rsc.tiling.AbstractTileSet#createTile(com.raytheon - * .viz.core.IGraphicsTarget, int, int, int) - */ - @Override - protected IImage createTile(IGraphicsTarget target, int level, int i, int j) - throws VizException { - IDataPreparer preparer = CMDataPreparerManager.getDataPreparer( - loadedData[level], this.tileSet.getTile(level, i, j) - .getRectangle(), dims[level]); - return target.initializeRaster(preparer, - rsc.getCapability(ColorMapCapability.class) - .getColorMapParameters()); - } - - public float getDataMin() { - float dataMin = Float.POSITIVE_INFINITY; - - if (loadedData[0] instanceof float[]) { - float[] floatData = (float[]) loadedData[0]; - for (int i = 0; i < floatData.length; i++) { - if (!Float.isNaN(floatData[i]) && floatData[i] != -999999) { - dataMin = Math.min(dataMin, floatData[i]); - } - } - } - return dataMin; - - } - - public float getDataMax() { - float dataMax = Float.NEGATIVE_INFINITY; - - if (loadedData[0] instanceof float[]) { - float[] floatData = (float[]) loadedData[0]; - for (int i = 0; i < floatData.length; i++) { - if (!Float.isNaN(floatData[i]) && floatData[i] != -999999) { - dataMax = Math.max(dataMax, floatData[i]); - } - } - } - return dataMax; - - } - - protected IDataRecord getFullDataSet() throws StorageException, - FileNotFoundException { - - IDataStore ds = DataStoreFactory.getDataStore(new File(hdf5File)); - IDataRecord dr = ds.retrieve(group, dataset, Request.ALL); - - if (converter == null) { - return dr; - } - - if (dr instanceof FloatDataRecord) { - float[] fd = ((FloatDataRecord) dr).getFloatData(); - for (int i = 0; i < fd.length; i++) { - fd[i] = (float) converter.convert(fd[i]); - } - } - - return dr; - } - - /* - * (non-Javadoc) - * - * @see - * com.raytheon.viz.core.rsc.tiling.AbstractTileSet#hasDataPreloaded(int) - */ - @Override - public boolean hasDataPreloaded(int level) { - return this.isLoaded[level]; - } - - @Override - public void cancelRequest(int level, int i, int j) { - // TODO Auto-generated method stub - - } - -} \ No newline at end of file diff --git a/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/data/prep/SatDataRetriever.java b/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/data/prep/SatDataRetriever.java index 12a2465082..e3e6006093 100644 --- a/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/data/prep/SatDataRetriever.java +++ b/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/data/prep/SatDataRetriever.java @@ -53,7 +53,7 @@ import com.raytheon.uf.viz.core.datastructure.VizDataCubeException; * @author mschenke * @version 1.0 */ - +@Deprecated public class SatDataRetriever implements IColorMapDataRetrievalCallback { private static final transient IUFStatusHandler statusHandler = UFStatus .getHandler(SatDataRetriever.class); diff --git a/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/rsc/SatFileBasedTileSet.java b/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/rsc/SatFileBasedTileSet.java index 100e081fec..2261ff82bf 100644 --- a/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/rsc/SatFileBasedTileSet.java +++ b/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/rsc/SatFileBasedTileSet.java @@ -50,7 +50,10 @@ import com.raytheon.viz.core.rsc.hdf5.AbstractTileSet; import com.raytheon.viz.core.rsc.hdf5.CreateTileJob; import com.raytheon.viz.core.rsc.hdf5.FileBasedTileSet; import com.raytheon.viz.satellite.data.prep.SatDataRetriever; +import com.raytheon.viz.satellite.tileset.SatTileSetRenderable; +/** Use {@link SatTileSetRenderable} instead */ +@Deprecated public class SatFileBasedTileSet extends FileBasedTileSet { private static final transient IUFStatusHandler statusHandler = UFStatus .getHandler(SatFileBasedTileSet.class); diff --git a/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/rsc/SatResource.java b/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/rsc/SatResource.java index beee2420f1..d2c3a3ef74 100644 --- a/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/rsc/SatResource.java +++ b/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/rsc/SatResource.java @@ -23,8 +23,8 @@ import java.text.ParseException; import java.text.ParsePosition; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -33,9 +33,7 @@ import javax.measure.converter.UnitConverter; import javax.measure.unit.Unit; import javax.measure.unit.UnitFormat; -import org.opengis.coverage.grid.GridGeometry; import org.opengis.referencing.crs.CoordinateReferenceSystem; -import org.opengis.referencing.datum.PixelInCell; import com.raytheon.uf.common.colormap.IColorMap; import com.raytheon.uf.common.colormap.prefs.ColorMapParameters; @@ -47,26 +45,23 @@ import com.raytheon.uf.common.dataplugin.satellite.units.counts.DerivedWVPixel; import com.raytheon.uf.common.dataplugin.satellite.units.generic.GenericPixel; import com.raytheon.uf.common.dataplugin.satellite.units.goes.PolarPrecipWaterPixel; import com.raytheon.uf.common.dataplugin.satellite.units.water.BlendedTPWPixel; -import com.raytheon.uf.common.datastorage.DataStoreFactory; import com.raytheon.uf.common.geospatial.ISpatialObject; -import com.raytheon.uf.common.geospatial.MapUtil; 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.time.BinOffset; import com.raytheon.uf.common.time.DataTime; import com.raytheon.uf.viz.core.DrawableImage; import com.raytheon.uf.viz.core.IGraphicsTarget; -import com.raytheon.uf.viz.core.IMeshCallback; +import com.raytheon.uf.viz.core.drawables.ColorMapLoader; +import com.raytheon.uf.viz.core.drawables.IRenderable; import com.raytheon.uf.viz.core.drawables.PaintProperties; import com.raytheon.uf.viz.core.exception.VizException; -import com.raytheon.uf.viz.core.map.MapDescriptor; -import com.raytheon.uf.viz.core.rsc.AbstractVizResource; -import com.raytheon.uf.viz.core.rsc.IResourceDataChanged; +import com.raytheon.uf.viz.core.map.IMapDescriptor; +import com.raytheon.uf.viz.core.rsc.AbstractPluginDataObjectResource; import com.raytheon.uf.viz.core.rsc.LoadProperties; +import com.raytheon.uf.viz.core.rsc.capabilities.AbstractCapability; import com.raytheon.uf.viz.core.rsc.capabilities.ColorMapCapability; -import com.raytheon.uf.viz.core.rsc.hdf5.ImageTile; import com.raytheon.uf.viz.core.style.ParamLevelMatchCriteria; import com.raytheon.uf.viz.core.style.StyleManager; import com.raytheon.uf.viz.core.style.StyleRule; @@ -74,11 +69,11 @@ import com.raytheon.uf.viz.core.style.level.Level; import com.raytheon.uf.viz.core.style.level.SingleLevel; import com.raytheon.uf.viz.derivparam.library.DerivedParameterRequest; import com.raytheon.viz.core.drawables.ColorMapParameterFactory; -import com.raytheon.viz.core.rsc.hdf5.AbstractTileSet; -import com.raytheon.viz.core.rsc.hdf5.FileBasedTileSet; import com.raytheon.viz.core.style.image.ImagePreferences; import com.raytheon.viz.core.style.image.SamplePreferences; import com.raytheon.viz.satellite.SatelliteConstants; +import com.raytheon.viz.satellite.tileset.SatTileSetRenderable; +import com.vividsolutions.jts.geom.Coordinate; /** * Provides satellite raster rendering support @@ -93,49 +88,151 @@ import com.raytheon.viz.satellite.SatelliteConstants; * 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 + * 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. + * 07/17/2012 798 jkorman Use decimationLevels from SatelliteRecord. Removed hard-coded + * data set names. + * 06/20/2013 2122 mschenke Modified to use SatTileSetRenderable * * * @author chammack * @version 1 */ public class SatResource extends - AbstractVizResource implements - IResourceDataChanged, IMeshCallback { - - public static String RAW_VALUE = "rawValue"; + AbstractPluginDataObjectResource { private static final transient IUFStatusHandler statusHandler = UFStatus .getHandler(SatResource.class); - protected Map tileSet; + public static String RAW_VALUE = "rawValue"; - private Map recordMap = new HashMap(); + private static class InterrogationResult { - protected DataTime displayedDate; + private final SatelliteRecord record; - protected SatFileBasedTileSet baseTile; + private final double value; + + public InterrogationResult(SatelliteRecord record, double value) { + this.record = record; + this.value = value; + } + + public SatelliteRecord getRecord() { + return record; + } + + public double getValue() { + return value; + } + + } + + private class SatRenderable implements IRenderable { + + private Map tileMap = new HashMap(); + + private DataTime renderableTime; + + public SatRenderable(DataTime renderableTime) { + this.renderableTime = renderableTime; + } + + @Override + public void paint(IGraphicsTarget target, PaintProperties paintProps) + throws VizException { + Collection images = getImagesToRender(target, + paintProps); + if (images.isEmpty() == false) { + target.drawRasters(paintProps, + images.toArray(new DrawableImage[0])); + } + } + + public Collection getImagesToRender( + IGraphicsTarget target, PaintProperties paintProps) + throws VizException { + List images = new ArrayList(); + synchronized (tileMap) { + for (SatTileSetRenderable renderable : tileMap.values()) { + images.addAll(renderable.getImagesToRender(target, + paintProps)); + } + } + return images; + } + + public void addRecord(SatelliteRecord record) { + synchronized (tileMap) { + SatTileSetRenderable tileSet = tileMap.get(record + .getSpatialObject()); + if (tileSet != null) { + SatelliteRecord existingRecord = tileSet + .getSatelliteRecord(); + if (existingRecord.equals(record) == false) { + // Different record, same spatial area for same frame + // Determine if new one is better than existing + long existingTimeMillis = existingRecord.getDataTime() + .getMatchRef(); + long newRecordTimeMillis = record.getDataTime() + .getMatchRef(); + long normalTimeMillis = renderableTime.getMatchRef(); + if (Math.abs(normalTimeMillis - newRecordTimeMillis) < Math + .abs(normalTimeMillis - existingTimeMillis)) { + // New is better since it's data time is closer to + // the normal time than the existing record's time! + tileSet.dispose(); + tileSet = null; + } + } + } + if (tileSet == null) { + tileSet = new SatTileSetRenderable(SatResource.this, record); + tileSet.project(descriptor.getGridGeometry()); + tileMap.put(record.getSpatialObject(), tileSet); + } + } + } + + public void project() { + synchronized (tileMap) { + for (SatTileSetRenderable renderable : tileMap.values()) { + renderable.project(descriptor.getGridGeometry()); + } + } + } + + public void dispose() { + synchronized (tileMap) { + for (SatTileSetRenderable renderable : tileMap.values()) { + renderable.dispose(); + } + tileMap.clear(); + } + } + + public InterrogationResult interrogate(Coordinate latLon) + throws VizException { + InterrogationResult result = null; + synchronized (tileMap) { + for (SatTileSetRenderable renderable : tileMap.values()) { + double rValue = renderable.interrogate(latLon); + if (Double.isNaN(rValue) == false && rValue != fillValue) { + result = new InterrogationResult( + renderable.getSatelliteRecord(), rValue); + } + } + } + return result; + } + } protected String legend; - protected IGraphicsTarget target; - - protected boolean hasBeenInited; - - protected int numLevels; - - protected String viewType; - - protected SatFileBasedTileSet currentTile; - - protected GridGeometry recordGeometry; - protected SamplePreferences sampleRange; + protected double fillValue = 0; + /** * Constructor * @@ -143,28 +240,27 @@ public class SatResource extends */ public SatResource(SatResourceData data, LoadProperties props) { super(data, props); - data.addChangeListener(this); - this.tileSet = new HashMap(); - this.dataTimes = new ArrayList(); - this.legend = null; - SatelliteRecord[] records = data.getRecords(); - Arrays.sort(records, new SatelliteRecordComparator()); + addDataObject(data.getRecords()); + } - for (SatelliteRecord record : records) { + @Override + protected DataTime getDataObjectTime(PluginDataObject pdo) { + SatelliteRecord record = (SatelliteRecord) pdo; + if (dataTimes.isEmpty()) { try { - addRecord(record); + initializeFirstFrame(record); } catch (VizException e) { - statusHandler.handle(Priority.PROBLEM, - "Error adding satellite record", e); + statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), + e); } } - /* - * This handles if there is no data for East & West CONUS simultaneously - */ - if (dataTimes.size() > 1) { - displayedDate = dataTimes.get(dataTimes.size() - 1); + DataTime pdoTime = pdo.getDataTime(); + if (resourceData.getBinOffset() != null) { + pdoTime = resourceData.getBinOffset().getNormalizedTime(pdoTime); } + + return pdoTime; } private void initializeFirstFrame(SatelliteRecord record) @@ -219,6 +315,7 @@ public class SatResource extends cmName = colorMapParameters.getColorMapName(); } } + // Grab the sampleRange from the preferences ParamLevelMatchCriteria match = new ParamLevelMatchCriteria(); match.setParameterName(Arrays.asList(physicalElement)); @@ -229,17 +326,16 @@ public class SatResource extends if (sr != null && sr.getPreferences() instanceof ImagePreferences) { sampleRange = ((ImagePreferences) sr.getPreferences()) .getSamplePrefs(); - String lg = ((ImagePreferences) sr.getPreferences()) - .getLegend(); + String lg = ((ImagePreferences) sr.getPreferences()).getLegend(); // test, so legend is not over written with empty string if (lg != null && !lg.trim().isEmpty()) { legend = lg; } } - colorMapParameters = ColorMapParameterFactory.build(null, - record.getDataURI() + "/Data", physicalElement, unit, level, - creatingEntity); + colorMapParameters = ColorMapParameterFactory.build((Object) null, + physicalElement, unit, level, creatingEntity); + // TODO: Figure out data/color map min/max values better if (unit == null) { colorMapParameters.setColorMapMin(0.0f); colorMapParameters.setColorMapMax(255.0f); @@ -259,18 +355,21 @@ public class SatResource extends colorMapParameters.setDataMax(255.0f); } + if (colorMap == null) { + if (cmName == null) { + cmName = "Sat/VIS/ZA (Vis Default)"; + } + colorMap = ColorMapLoader.loadColorMap(cmName); + } + if (colorMap != null) { colorMapParameters.setColorMap(colorMap); } - if (cmName != null) { - colorMapParameters.setColorMapName(cmName); - } getCapability(ColorMapCapability.class).setColorMapParameters( colorMapParameters); - // number of interpolation levels plus the base level! - numLevels = record.getInterpolationLevels() + 1; + this.legend = getLegend(record); } @Override @@ -281,110 +380,32 @@ public class SatResource extends return ""; } - @Override - protected void disposeInternal() { - if (baseTile != null) - baseTile.dispose(); - for (AbstractTileSet tile : this.tileSet.values()) - if (tile != baseTile) - tile.dispose(); - } - - @Override - protected void initInternal(IGraphicsTarget target) throws VizException { - synchronized (this) { - this.viewType = target.getViewType(); - this.hasBeenInited = true; - this.target = target; - - if (this.baseTile != null) { - this.baseTile.init(target); - } - for (AbstractTileSet tile : this.tileSet.values()) { - if (tile != baseTile) { - tile.init(target); - } - } - } - - ColorMapParameters params = getCapability(ColorMapCapability.class) - .getColorMapParameters(); - if (params.getColorMap() == null) { - String colorMapName = params.getColorMapName(); - if (colorMapName == null) - colorMapName = "Sat/VIS/ZA (Vis Default)"; - - params.setColorMap(target.buildColorMap(colorMapName)); - } - } - - /* - * (non-Javadoc) - * - * @seecom.raytheon.viz.core.rsc.IVizResource#paint(com.raytheon.viz.core. - * IGraphicsTarget, com.raytheon.viz.core.PixelExtent, double, float) - */ - @Override - protected void paintInternal(IGraphicsTarget target, - PaintProperties paintProps) throws VizException { - this.target = target; - this.displayedDate = paintProps.getDataTime(); - if (this.displayedDate == null) - return; - - currentTile = this.tileSet.get(this.displayedDate); - if (currentTile != null) { - currentTile.paint(target, paintProps); - } - // System.out.println("Time to paint: " - // + (System.currentTimeMillis() - t0)); - } - - @Override - public void setDescriptor(MapDescriptor descriptor) { - if (this.baseTile != null) { - this.baseTile.setMapDescriptor(descriptor); - } - for (AbstractTileSet tile : this.tileSet.values()) - tile.setMapDescriptor(descriptor); - - this.descriptor = descriptor; - } - - @Override - public void project(CoordinateReferenceSystem mapData) throws VizException { - if (this.baseTile != null) - this.baseTile.reproject(); - - for (AbstractTileSet tile : tileSet.values()) - tile.reproject(); - } - @Override public Map interrogate(ReferencedCoordinate coord) throws VizException { + DataTime displayedDate = descriptor.getFramesInfo().getTimeForResource( + this); Map dataMap = new HashMap(); - SatelliteRecord record = recordMap.get(displayedDate); - if (record != null) { - dataMap.put(ISpatialObject.class.toString(), - record.getSpatialObject()); - AbstractTileSet tile = tileSet.get(displayedDate); - if (tile != null) { - try { - Double raw = tile.interrogate(coord.asLatLon(), true); - if (raw != 0 && raw.isNaN() == false) { - UnitConverter dataToDisplay = getCapability( - ColorMapCapability.class) - .getColorMapParameters() - .getDataToDisplayConverter(); - if (dataToDisplay != null) { - raw = dataToDisplay.convert(raw); - } - dataMap.put(RAW_VALUE, raw); + + SatRenderable renderable = (SatRenderable) getRenderable(displayedDate); + if (renderable != null) { + try { + InterrogationResult result = renderable.interrogate(coord + .asLatLon()); + if (result != null) { + double dataValue = result.getValue(); + UnitConverter dataToDisplay = getCapability( + ColorMapCapability.class).getColorMapParameters() + .getDataToDisplayConverter(); + if (dataToDisplay != null) { + dataValue = dataToDisplay.convert(dataValue); } - } catch (Exception e) { - throw new VizException("Error interrogating raw data", e); + dataMap.put(RAW_VALUE, dataValue); + dataMap.put(ISpatialObject.class.toString(), result + .getRecord().getSpatialObject()); } + } catch (Exception e) { + throw new VizException("Error interrogating raw data", e); } } return dataMap; @@ -434,116 +455,7 @@ public class SatResource extends return String.format("%.1f%s", value, unitString); } - public class SatelliteRecordComparator implements - Comparator { - - public int compare(SatelliteRecord o1, SatelliteRecord o2) { - return o1.getDataTime().getRefTime() - .compareTo(o2.getDataTime().getRefTime()); - } - } - - public void addRecord(PluginDataObject record) throws VizException { - synchronized (this) { - SatFileBasedTileSet tile; - DataTime recordTime = null; - if (resourceData.getBinOffset() != null || resourceData.equals(0)) { - BinOffset binOffset = resourceData.getBinOffset(); - DataTime recTime = record.getDataTime(); - DataTime normTime = binOffset.getNormalizedTime(recTime); - if (recordMap.containsKey(normTime)) { - // a normalized time was found... - // if this record's time is closer than the existing - // record's - // then replace the existing record with the new record - SatelliteRecord satRec = recordMap.get(normTime); - DataTime existingTime = satRec.getDataTime(); - long existingTimeMillis = existingTime - .getRefTimeAsCalendar().getTimeInMillis(); - long recTimeMillies = recTime.getRefTimeAsCalendar() - .getTimeInMillis(); - long normTimeMillies = normTime.getRefTimeAsCalendar() - .getTimeInMillis(); - if (Math.abs(normTimeMillies - existingTimeMillis) > Math - .abs(normTimeMillies - recTimeMillies)) { - // System.out.println("For " + normTime + - // "\n\treplaced " - // + existingTime + "\n\twith " + recTime); - recordMap.remove(normTime); - FileBasedTileSet oldTile = tileSet.remove(normTime); - if (oldTile != null) { - oldTile.dispose(); - } - } - } - recordTime = normTime; - } else { - recordTime = record.getDataTime(); - } - recordMap.put(recordTime, (SatelliteRecord) record); - if (baseTile == null) { - initializeFirstFrame((SatelliteRecord) record); - } - - if (baseTile == null) { - tile = baseTile = new SatFileBasedTileSet(record, DataStoreFactory.DEF_DATASET_NAME, - numLevels, 256, - MapUtil.getGridGeometry(((SatelliteRecord) record) - .getSpatialObject()), this, - PixelInCell.CELL_CORNER, viewType); - } else { - tile = new SatFileBasedTileSet(record, DataStoreFactory.DEF_DATASET_NAME, baseTile); - } - tile.addMeshCallback(this); - tile.setMapDescriptor(this.descriptor); - if (hasBeenInited) - tile.init(target); - - if (this.legend == null) { - this.legend = getLegend(record); - } - FileBasedTileSet oldTile = tileSet.put(recordTime, tile); - if (oldTile != null) { - oldTile.dispose(); - } - dataTimes.add(recordTime); - - Collections.sort(this.dataTimes); - } - } - - @Override - public void remove(DataTime dataTime) { - synchronized (this) { - if (!this.dataTimes.contains(dataTime)) - return; - - this.dataTimes.remove(dataTime); - - FileBasedTileSet tile = tileSet.remove(dataTime); - if (tile != baseTile && tile != null) - tile.dispose(); - } - } - - @Override - public void resourceChanged(ChangeType type, Object object) { - if (type.equals(ChangeType.DATA_UPDATE)) { - PluginDataObject[] pdos = (PluginDataObject[]) object; - for (PluginDataObject pdo : pdos) { - try { - this.addRecord(pdo); - } catch (VizException e) { - statusHandler.handle(Priority.PROBLEM, - "Error updating satellite resource", e); - } - } - } - issueRefresh(); - } - private String getLegend(PluginDataObject record) { - String productName = null; DerivedParameterRequest request = (DerivedParameterRequest) record .getMessageData(); @@ -556,23 +468,87 @@ public class SatResource extends ((SatelliteRecord) record).getCreatingEntity()); } - @Override - public void meshCalculated(ImageTile tile) { - issueRefresh(); - } - public List getImages(IGraphicsTarget target, PaintProperties paintProps) throws VizException { - this.target = target; - this.displayedDate = paintProps.getDataTime(); - if (this.displayedDate == null) - return Collections.emptyList(); - - currentTile = this.tileSet.get(this.displayedDate); - if (currentTile != null) { - return currentTile.getImages(target, paintProps); + SatRenderable renderable = (SatRenderable) getOrCreateRenderable(paintProps + .getDataTime()); + if (renderable != null) { + return new ArrayList(renderable.getImagesToRender( + target, paintProps)); } return Collections.emptyList(); } + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.viz.core.rsc.AbstractPluginDataObjectResource# + * capabilityChanged(com.raytheon.uf.viz.core.drawables.IRenderable, + * com.raytheon.uf.viz.core.rsc.capabilities.AbstractCapability) + */ + @Override + protected void capabilityChanged(IRenderable renderable, + AbstractCapability capability) { + issueRefresh(); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.viz.core.rsc.AbstractPluginDataObjectResource# + * disposeRenderable(com.raytheon.uf.viz.core.drawables.IRenderable) + */ + @Override + protected void disposeRenderable(IRenderable renderable) { + ((SatRenderable) renderable).dispose(); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.viz.core.rsc.AbstractPluginDataObjectResource# + * projectRenderable(com.raytheon.uf.viz.core.drawables.IRenderable, + * org.opengis.referencing.crs.CoordinateReferenceSystem) + */ + @Override + protected boolean projectRenderable(IRenderable renderable, + CoordinateReferenceSystem crs) throws VizException { + ((SatRenderable) renderable).project(); + return true; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.viz.core.rsc.AbstractPluginDataObjectResource# + * constructRenderable(com.raytheon.uf.common.time.DataTime, java.util.List) + */ + @Override + protected IRenderable constructRenderable(DataTime time, + List records) throws VizException { + SatRenderable renderable = new SatRenderable(time); + updateRenderable(renderable, records.toArray(new PluginDataObject[0])); + renderable.project(); + return renderable; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.viz.core.rsc.AbstractPluginDataObjectResource# + * updateRenderable(com.raytheon.uf.viz.core.drawables.IRenderable, + * com.raytheon.uf.common.dataplugin.PluginDataObject[]) + */ + @Override + protected boolean updateRenderable(IRenderable renderable, + PluginDataObject... pdos) { + SatRenderable sr = (SatRenderable) renderable; + for (PluginDataObject object : pdos) { + if (object instanceof SatelliteRecord) { + sr.addRecord((SatelliteRecord) object); + } + } + return true; + } + } diff --git a/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/tileset/SatDataRetriever.java b/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/tileset/SatDataRetriever.java new file mode 100644 index 0000000000..7f021000bb --- /dev/null +++ b/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/tileset/SatDataRetriever.java @@ -0,0 +1,181 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.viz.satellite.tileset; + +import java.awt.Rectangle; +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.ShortBuffer; + +import com.raytheon.uf.common.colormap.image.ColorMapData; +import com.raytheon.uf.common.colormap.image.ColorMapData.ColorMapDataType; +import com.raytheon.uf.common.dataplugin.PluginDataObject; +import com.raytheon.uf.common.dataplugin.satellite.SatelliteRecord; +import com.raytheon.uf.common.datastorage.DataStoreFactory; +import com.raytheon.uf.common.datastorage.Request; +import com.raytheon.uf.common.datastorage.records.ByteDataRecord; +import com.raytheon.uf.common.datastorage.records.IDataRecord; +import com.raytheon.uf.common.datastorage.records.ShortDataRecord; +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.viz.core.data.IColorMapDataRetrievalCallback; +import com.raytheon.uf.viz.core.datastructure.DataCubeContainer; +import com.raytheon.uf.viz.core.datastructure.VizDataCubeException; + +/** + * {@link IColorMapDataRetrievalCallback} for satellite imagery data. Supports + * signed and unsigned byte and short data + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 20, 2013       2122 mschenke     Initial creation
+ * 
+ * 
+ * + * @author mschenke + * @version 1.0 + */ +public class SatDataRetriever implements IColorMapDataRetrievalCallback { + private static final transient IUFStatusHandler statusHandler = UFStatus + .getHandler(SatDataRetriever.class); + + protected Rectangle datasetBounds; + + protected PluginDataObject pdo; + + protected String dataset; + + protected boolean signed = false; + + public SatDataRetriever(PluginDataObject pdo, int level, + Rectangle dataSetBounds, boolean signed) { + this.pdo = pdo; + this.datasetBounds = dataSetBounds; + dataset = DataStoreFactory.createDataSetName(null, + SatelliteRecord.SAT_DATASET_NAME, level); + this.signed = signed; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.viz.core.data.IDataRetrievalCallback#getData() + */ + @Override + public ColorMapData getColorMapData() { + // TODO: Read scale/offset out of attributes? + Buffer data = null; + Request req = Request.buildSlab(new int[] { this.datasetBounds.x, + this.datasetBounds.y }, new int[] { + this.datasetBounds.x + this.datasetBounds.width, + this.datasetBounds.y + this.datasetBounds.height }); + IDataRecord[] dataRecord = null; + try { + dataRecord = DataCubeContainer + .getDataRecord(pdo, req, this.dataset); + if (dataRecord != null && dataRecord.length == 1) { + IDataRecord record = dataRecord[0]; + if (record instanceof ByteDataRecord) { + data = ByteBuffer.wrap((byte[]) record.getDataObject()); + } else if (record instanceof ShortDataRecord) { + data = ShortBuffer.wrap((short[]) record.getDataObject()); + } + } + } catch (VizDataCubeException e) { + statusHandler.handle(Priority.SIGNIFICANT, + "Error retrieving satellite data", e); + } + + if (data == null) { + return null; + } + + ColorMapDataType dataType = null; + if (data instanceof ByteBuffer) { + dataType = signed ? ColorMapDataType.SIGNED_BYTE + : ColorMapDataType.BYTE; + } else if (data instanceof ShortBuffer) { + dataType = signed ? ColorMapDataType.SHORT + : ColorMapDataType.UNSIGNED_SHORT; + } else { + dataType = ColorMapData.getDataType(data); + } + + return new ColorMapData(data, new int[] { datasetBounds.width, + datasetBounds.height }, dataType); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((dataset == null) ? 0 : dataset.hashCode()); + result = prime * result + + ((datasetBounds == null) ? 0 : datasetBounds.hashCode()); + result = prime * result + ((pdo == null) ? 0 : pdo.hashCode()); + result = prime * result + (signed ? 1231 : 1237); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + SatDataRetriever other = (SatDataRetriever) obj; + if (dataset == null) { + if (other.dataset != null) + return false; + } else if (!dataset.equals(other.dataset)) + return false; + if (datasetBounds == null) { + if (other.datasetBounds != null) + return false; + } else if (!datasetBounds.equals(other.datasetBounds)) + return false; + if (pdo == null) { + if (other.pdo != null) + return false; + } else if (!pdo.equals(other.pdo)) + return false; + if (signed != other.signed) + return false; + return true; + } + +} diff --git a/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/tileset/SatTileSetRenderable.java b/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/tileset/SatTileSetRenderable.java new file mode 100644 index 0000000000..826dcfdd62 --- /dev/null +++ b/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/tileset/SatTileSetRenderable.java @@ -0,0 +1,82 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.viz.satellite.tileset; + +import com.raytheon.uf.common.colormap.image.ColorMapData; +import com.raytheon.uf.common.dataplugin.satellite.SatelliteRecord; +import com.raytheon.uf.common.dataplugin.satellite.units.generic.GenericPixel; +import com.raytheon.uf.viz.core.rsc.AbstractVizResource; +import com.raytheon.uf.viz.core.rsc.capabilities.ColorMapCapability; +import com.raytheon.uf.viz.core.tile.RecordTileSetRenderable; +import com.raytheon.uf.viz.core.tile.Tile; + +/** + * Satellite tile set renderable, uses {@link SatDataRetriever} for {@link Tile} + * data retrieval + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 19, 2013            mschenke     Initial creation
+ * 
+ * 
+ * + * @author mschenke + * @version 1.0 + */ + +public class SatTileSetRenderable extends RecordTileSetRenderable { + + private final boolean signed; + + private final AbstractVizResource resource; + + /** + * Create satellite tile set renderable + * + * @param resource + * @param record + * @param signed + */ + public SatTileSetRenderable(AbstractVizResource resource, SatelliteRecord record) { + // Total levels = Number of interpolation levels + base level + super(resource, record, record.getSpatialObject(), record + .getInterpolationLevels() + 1); + this.resource = resource; + // TODO: Better way of determining this (taken from SatFileBasedTileSet) + this.signed = resource.getCapability(ColorMapCapability.class) + .getColorMapParameters().getDataUnit() instanceof GenericPixel; + } + + @Override + protected ColorMapData retrieveRecordData(Tile tile) { + ColorMapData data = new SatDataRetriever(record, tile.tileLevel, + tile.getRectangle(), signed).getColorMapData(); + resource.issueRefresh(); + return data; + } + + public SatelliteRecord getSatelliteRecord() { + return (SatelliteRecord) record; + } +} diff --git a/edexOsgi/com.raytheon.edex.plugin.satellite/res/scripts/units.sql b/edexOsgi/com.raytheon.edex.plugin.satellite/res/scripts/units.sql index 312f78ba85..edb627883e 100644 --- a/edexOsgi/com.raytheon.edex.plugin.satellite/res/scripts/units.sql +++ b/edexOsgi/com.raytheon.edex.plugin.satellite/res/scripts/units.sql @@ -29,5 +29,6 @@ insert into awips.satellite_units values (27,'SounderCloudTopHeightPixel'); insert into awips.satellite_units values (28,'SounderCloudAmountPixel'); insert into awips.satellite_units values (29,'RainfallRatePixel'); insert into awips.satellite_units values (43,'IRPixel'); +insert into awips.satellite_units values (48,'IRPixel'); insert into awips.satellite_units values (60,'PercentOfNormalTPWPixel'); insert into awips.satellite_units values (64,'IRPixel'); diff --git a/edexOsgi/com.raytheon.uf.common.colormap/src/com/raytheon/uf/common/colormap/image/ColorMapData.java b/edexOsgi/com.raytheon.uf.common.colormap/src/com/raytheon/uf/common/colormap/image/ColorMapData.java index d440787b1f..9833a9f715 100644 --- a/edexOsgi/com.raytheon.uf.common.colormap/src/com/raytheon/uf/common/colormap/image/ColorMapData.java +++ b/edexOsgi/com.raytheon.uf.common.colormap/src/com/raytheon/uf/common/colormap/image/ColorMapData.java @@ -97,7 +97,7 @@ public class ColorMapData { return dataType; } - private static ColorMapData.ColorMapDataType getDataType(Buffer buffer) { + public static ColorMapData.ColorMapDataType getDataType(Buffer buffer) { if (buffer instanceof FloatBuffer) { return ColorMapData.ColorMapDataType.FLOAT; } else if (buffer instanceof IntBuffer) { diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.satellite/src/com/raytheon/uf/common/dataplugin/satellite/units/SatelliteUnits.java b/edexOsgi/com.raytheon.uf.common.dataplugin.satellite/src/com/raytheon/uf/common/dataplugin/satellite/units/SatelliteUnits.java index f3319abf51..16b7c5bdaa 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.satellite/src/com/raytheon/uf/common/dataplugin/satellite/units/SatelliteUnits.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.satellite/src/com/raytheon/uf/common/dataplugin/satellite/units/SatelliteUnits.java @@ -24,6 +24,7 @@ import javax.measure.quantity.Dimensionless; import javax.measure.quantity.Length; import javax.measure.quantity.Temperature; import javax.measure.quantity.Velocity; +import javax.measure.unit.SI; import javax.measure.unit.Unit; import javax.measure.unit.UnitFormat; @@ -49,6 +50,7 @@ import com.raytheon.uf.common.dataplugin.satellite.units.water.RainfallRatePixel * Sep 4, 2007 njensen Initial creation * Mar 23, 2009 2086 jsanchez Updated RainfallRatePixel to be velocity. * Added PolarPrecipWaterPixel. + * Jun 20, 2013 2122 mschenke Added alias for degrees celsius to "C" * * * @@ -83,8 +85,8 @@ public class SatelliteUnits { public static final Unit GENERIC_PIXEL = new GenericPixel(); public static void register() { + UnitFormat.getUCUMInstance().alias(SI.CELSIUS, "C"); UnitFormat.getUCUMInstance().label(SatelliteUnits.IR_PIXEL, "IRPixel"); - UnitFormat.getUCUMInstance().label(SatelliteUnits.PRECIP_PIXEL, "PrecipPixel"); UnitFormat.getUCUMInstance().label(SatelliteUnits.RAINFALL_RATE_PIXEL,