Omaha #5539 Fix GFE issues with Wx/Discretes with more than 128 Wx types

Change-Id: I8c66fdcbc8925c23863d6d1e0a8ec5fce67f87c8

Former-commit-id: 81a57e1d4d2062bfcf8acdcc92fbbab062fa9cbf
This commit is contained in:
Ron Anderson 2016-04-18 14:22:16 -05:00
parent 3d1bee4532
commit 0ffd97f7d3
11 changed files with 190 additions and 115 deletions

View file

@ -78,7 +78,8 @@
# Sep 11, 2015 4858 dgilling Remove notification processing from publishElements.
# Jan 20, 2016 4751 randerso Fix type of mask returned from getComposite() to work with numpy 1.9.2
# Jan 28, 2016 5129 dgilling Support changes to IFPClient.
# 02/22/2016 5374 randerso Added support for sendWFOMessage
# Feb 22, 2016 5374 randerso Added support for sendWFOMessage
# Apr 05, 2016 5539 randerso Added exception when attempting create more than 256 Wx keys
#
########################################################################
import types, string, time, sys
@ -2198,6 +2199,10 @@ class SmartScript(BaseTool.BaseTool):
for str in keys:
if sortedUglyStr == self.sortUglyStr(str):
return keys.index(str)
if len(keys) >= 256:
raise IndexError("Attempt to create more than 256 Wx keys")
keys.append(uglyStr)
return len(keys) - 1

View file

@ -72,6 +72,7 @@ import com.vividsolutions.jts.geom.MultiPolygon;
* 02/19/2013 1637 randerso Added throws declarations to translateDataFrom
* 10/31/2013 2508 randerso Change to use DiscreteGridSlice.getKeys()
* Apr 23, 2015 4259 njensen Removed unused INumpyable
* Apr 04, 2016 5539 randerso Fix unsigned byte issues
*
* </pre>
*
@ -918,7 +919,7 @@ public class DiscreteGridData extends AbstractGridData {
for (int j = 0; j < dim.y; j++) {
if (points.get(i, j) == 1) {
DiscreteKey combined = DiscreteKey.combine(
key.get(values.get(i, j)),
key.get(0xFF & values.get(i, j)),
doGetDiscreteValue(i, j));
grid.set(i, j, lookupKeyValue(combined));
}

View file

@ -76,6 +76,7 @@ import com.vividsolutions.jts.geom.Coordinate;
* 10/31/2013 2508 randerso Change to use DiscreteGridSlice.getKeys()
* 09/01/2014 3572 randerso Removed ourSiteMap as it was unused and the only
* thing that used Grid2DBoolean
* 04/04/2016 5539 randerso Fix unsigned byte issues
*
* </pre>
*
@ -462,7 +463,7 @@ public class ISCDataAccess implements IISCDataAccess {
for (int i = 0; i < siteMask.getXdim(); i++) {
if (siteMask.getAsBoolean(i, j)) {
byte index = lookupKeyValue(keyIndexMap,
iscKey[iscGrid.get(i, j)]);
iscKey[0xFF & iscGrid.get(i, j)]);
slice.getWeatherGrid().set(i, j, index);
}
}
@ -551,7 +552,7 @@ public class ISCDataAccess implements IISCDataAccess {
for (int i = 0; i < siteMask.getXdim(); i++) {
if (siteMask.getAsBoolean(i, j)) {
byte index = lookupKeyValue(keyIndexMap,
iscKey[iscGrid.get(i, j)]);
iscKey[0xFF & iscGrid.get(i, j)]);
slice.getDiscreteGrid().set(i, j, index);
}
}

View file

@ -191,6 +191,7 @@ import com.vividsolutions.jts.geom.Coordinate;
* Sep 10, 2015 #4782 randerso Converted inParmEdit to ReentrantLock to force
* updates to be run consecutively.
* Cleaned up TODOs, FIXMEs and deprecations.
* Apr 04, 2016 #5539 randerso Fix unsigned byte issues
*
* </pre>
*
@ -2161,10 +2162,9 @@ public abstract class Parm implements Comparable<Parm> {
.getGridSlice()).getKeys();
Grid2DByte grid1 = ((WeatherGridSlice) grids[k]
.getGridSlice()).getWeatherGrid();
WeatherKey tmpKey = key1[grid1.get(i, j)];
WeatherKey tmpKey = key1[0xFF & grid1.get(i, j)];
WeatherSubKey gpkeys[] = tmpKey.getSubKeys().toArray(
new WeatherSubKey[tmpKey.getSubKeys().size()]);
// key1[grid1(i, j)].subKeys();
for (int m = 0; m < gpkeys.length; m++) {
int index = subKeys.indexOf(gpkeys[m]);
if (index == -1) {
@ -2236,8 +2236,7 @@ public abstract class Parm implements Comparable<Parm> {
.getGridSlice()).getKeys();
Grid2DByte grid1 = ((DiscreteGridSlice) grids[k]
.getGridSlice()).getDiscreteGrid();
// TextString kv = key1[grid1(i, j)].keyAsString();
DiscreteKey kv = key1[grid1.get(i, j)];
DiscreteKey kv = key1[0xFF & grid1.get(i, j)];
// add it to the dictionary
MutableInteger cnt = values.get(kv);
if (cnt == null) {
@ -3706,7 +3705,7 @@ public abstract class Parm implements Comparable<Parm> {
.getGridSlice());
WeatherKey[] key1 = slice.getKeys();
Grid2DByte grid1 = slice.getWeatherGrid();
WeatherKey key1ij = key1[grid1.get(i, j)];
WeatherKey key1ij = key1[0xFF & grid1.get(i, j)];
subkeys.addAll(key1ij.getSubKeys());
}
@ -3760,7 +3759,7 @@ public abstract class Parm implements Comparable<Parm> {
.getGridSlice()).getKeys();
Grid2DByte grid1 = ((DiscreteGridSlice) grids[k]
.getGridSlice()).getDiscreteGrid();
DiscreteKey dkv = key1[grid1.get(i, j)];
DiscreteKey dkv = key1[0xFF & grid1.get(i, j)];
String dks = dkv.toString();
// add it to the dictionary
Integer count = values.get(dks);

View file

@ -121,10 +121,11 @@ import com.raytheon.viz.gfe.Activator;
*
* <pre>
* SOFTWARE HISTORY
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 2, 2008 #1161 randerso Initial creation
* Oct 31, 2013 #2508 randerso Change to use DiscreteGridSlice.getKeys()
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 2, 2008 #1161 randerso Initial creation
* Oct 31, 2013 #2508 randerso Change to use DiscreteGridSlice.getKeys()
* Apr 04, 2016 #5539 randerso Fix unsigned byte issues
*
* </pre>
*
@ -479,7 +480,7 @@ public class DiscreteInterp extends Interp {
// input byte index grids, but with values for the weatherKeys
// in _allKeys.
byte index;
int index;
DiscreteKey key;
// For every grid point in the grids, load the new working grids
@ -488,7 +489,7 @@ public class DiscreteInterp extends Interp {
for (i = 0; i < _xDim; i++) {
for (j = 0; j < _yDim; j++) {
// get the index value from the actual first input grid of bytes
index = grid1.get(i, j);
index = 0xFF & grid1.get(i, j);
// Can save a lot of processing here if index=0
// ALWAYS means "no weather": the workGrid1 and 2 values
@ -508,7 +509,7 @@ public class DiscreteInterp extends Interp {
// get the index value from the actual second input grid of
// bytes
index = grid2.get(i, j);
index = 0xFF & grid2.get(i, j);
// get its key
key = keys2[index];
// find this key in the new list, and save the corresponding

View file

@ -75,12 +75,13 @@ import com.vividsolutions.jts.geom.Coordinate;
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 13, 2011 #8393 dgilling Initial creation
* 02/19/13 #1637 randerso Added exception handling for Discrete and Weather
* 10/31/2013 #2508 randerso Change to use DiscreteGridSlice.getKeys()
* 04/22/2014 #3050 randerso Allow exceptions to propagate to caller from readASCIIGridData
* Jan 14, 2016 #5237 tgurney Allow outputAsciiGridData to take
* OutputStream as well as File
* Apr 13, 2011 #8393 dgilling Initial creation
* 02/19/13 #1637 randerso Added exception handling for Discrete and Weather
* 10/31/2013 #2508 randerso Change to use DiscreteGridSlice.getKeys()
* 04/22/2014 #3050 randerso Allow exceptions to propagate to caller from readASCIIGridData
* 01/14/2016 #5237 tgurney Allow outputAsciiGridData to take
* OutputStream as well as File
* 04/04/2016 #5539 randerso Fixed unsigned byte issues
*
* </pre>
*
@ -341,7 +342,7 @@ public class ASCIIGrid {
WeatherGridSlice weather = (WeatherGridSlice) gs;
for (int i = weather.getWeatherGrid().getYdim() - 1; i >= 0; i--) {
for (int j = 0; j < weather.getWeatherGrid().getXdim(); j++) {
String key = weather.getKeys()[weather
String key = weather.getKeys()[0xFF & weather
.getWeatherGrid().get(j, i)].toString();
printStream.println(key);
}
@ -352,7 +353,7 @@ public class ASCIIGrid {
for (int i = discrete.getDiscreteGrid().getYdim() - 1; i >= 0; i--) {
for (int j = 0; j < discrete.getDiscreteGrid()
.getXdim(); j++) {
String key = discrete.getKeys()[discrete
String key = discrete.getKeys()[0xFF & discrete
.getDiscreteGrid().get(j, i)].toString();
printStream.println(key);
}

View file

@ -35,8 +35,8 @@ import javax.measure.unit.Unit;
import com.raytheon.edex.plugin.gfe.server.IFPServer;
import com.raytheon.edex.plugin.gfe.server.database.GridDatabase;
import com.raytheon.uf.common.dataplugin.gfe.db.objects.DatabaseID;
import com.raytheon.uf.common.dataplugin.gfe.db.objects.GridParmInfo.GridType;
import com.raytheon.uf.common.dataplugin.gfe.db.objects.GridLocation;
import com.raytheon.uf.common.dataplugin.gfe.db.objects.GridParmInfo.GridType;
import com.raytheon.uf.common.dataplugin.gfe.db.objects.ParmID;
import com.raytheon.uf.common.dataplugin.gfe.point.GFEPointDataContainer;
import com.raytheon.uf.common.dataplugin.gfe.point.GFEPointDataContainers;
@ -70,6 +70,7 @@ import com.vividsolutions.jts.geom.Coordinate;
* Jun 13, 2013 #2044 randerso Refactored to use IFPServer
* Oct 31, 2013 #2508 randerso Change to use DiscreteGridSlice.getKeys()
* Apr 23, 2014 #3006 randerso Restructured code to work with multi-hour grids
* Apr 04, 2016 #5539 randerso Fixed unsigned byte issues
*
* </pre>
*
@ -209,7 +210,7 @@ public class GetPointDataHandler extends BaseGfeRequestHandler implements
byte discreteValue = discreteSlice
.getDiscreteGrid().get(x, y);
String discreteKey = discreteSlice
.getKeys()[discreteValue]
.getKeys()[0xFF & discreteValue]
.toString();
type = Type.STRING;
view.setData(param, type, unit, discreteKey);
@ -218,7 +219,7 @@ public class GetPointDataHandler extends BaseGfeRequestHandler implements
WeatherGridSlice weatherSlice = (WeatherGridSlice) slice;
byte wxValue = weatherSlice
.getWeatherGrid().get(x, y);
String wxKey = weatherSlice.getKeys()[wxValue]
String wxKey = weatherSlice.getKeys()[0xFF & wxValue]
.toString();
type = Type.STRING;
view.setData(param, type, unit, wxKey);

View file

@ -41,6 +41,8 @@
# 05/13/2015 4427 dgilling Add siteIdOverride field.
# 08/06/2015 4718 dgilling Optimize casting when using where with
# NumPy 1.9.
# 04/07/2016 5539 randerso Reversed order of parameters/return value in collapseKey
# to match order of Wx/Discrete tuple
#
##
@ -924,21 +926,20 @@ def storeVectorWE(we, trList, file, timeRange,
###-------------------------------------------------------------------------###
# Collapse key and bytes. (for discrete and weather)
### Returns tuple of (updated key, updated grid)
def collapseKey(keys, grid):
### Returns tuple of (updated grid, updated key)
def collapseKey(grid, keys):
#make list of unique indexes in the grid
flatGrid = grid.flat
used = []
used = numpy.zeros((len(keys)), dtype=numpy.bool)
for n in range(flatGrid.__array__().shape[0]):
if flatGrid[n] not in used:
used.append(flatGrid[n])
used[0xFF & flatGrid[n]] = True
#make reverse map
map = []
newKeys = []
j = 0
for i in range(len(keys)):
if i in used:
if used[i]:
map.append(j)
newKeys.append(keys[i])
j = j + 1
@ -948,10 +949,10 @@ def collapseKey(keys, grid):
# modify the data
newGrid = grid
for k in range(len(map)):
mask = numpy.equal(k, grid)
mask = numpy.equal(numpy.int8(k), grid)
newGrid = numpy.where(mask, numpy.int8(map[k]), newGrid).astype(numpy.int8)
return (newKeys, newGrid)
return (newGrid, newKeys)
###-------------------------------------------------------------------------###
# Stores the specified Weather WE in the netCDF file whose grids fall within
@ -987,7 +988,7 @@ def storeWeatherWE(we, trList, file, timeRange, databaseID, invMask, clipArea, s
# Process the weather keys so we store only what is necessary
for g in range(byteCube.shape[0]):
(keyList[g], byteCube[g]) = collapseKey(keyList[g], byteCube[g])
(byteCube[g], keyList[g]) = collapseKey(byteCube[g], keyList[g])
# Mask the values
fillValue = -127
@ -1072,7 +1073,7 @@ def storeDiscreteWE(we, trList, file, timeRange, databaseID, invMask, clipArea,
# Process the discrete keys so we store only what is necessary
for g in range(byteCube.shape[0]):
(keyList[g], byteCube[g]) = collapseKey(keyList[g], byteCube[g])
(byteCube[g], keyList[g]) = collapseKey(byteCube[g], keyList[g])
# Mask the values
fillValue = -127

View file

@ -39,7 +39,7 @@ import LogStream, fcntl
# 11/05/13 2517 randerso Improve memory utilization
# 08/06/2015 4718 dgilling Optimize casting when using where with
# NumPy 1.9.
#
# 04/07/2016 5539 randerso Fixed issues with Wx/Discretes with large number of keys
#
#
@ -79,6 +79,9 @@ class MergeGrid:
index = keyMap.index(key)
return index
except:
if (len(keyMap) >= 256):
raise IndexError("Attempt to create more than 256 Wx keys")
keyMap.append(key)
return len(keyMap) - 1
@ -186,6 +189,36 @@ class MergeGrid:
return (magGrid, dirGrid)
###-------------------------------------------------------------------------###
# Collapse key and bytes. (for discrete and weather)
### Returns tuple of (updated grid, updated key)
def __collapseKey(self, grid, keys):
#make list of unique indexes in the grid
flatGrid = grid.flat
used = numpy.zeros((len(keys)), dtype=numpy.bool)
for n in range(flatGrid.__array__().shape[0]):
used[0xFF & flatGrid[n]] = True
#make reverse map
map = []
newKeys = []
j = 0
for i in range(len(keys)):
if used[i]:
map.append(j)
newKeys.append(keys[i])
j = j + 1
else:
map.append(-1)
# modify the data
newGrid = grid
for k in range(len(map)):
mask = numpy.equal(numpy.int8(k), grid)
newGrid = numpy.where(mask, numpy.int8(map[k]), newGrid).astype(numpy.int8)
return (newGrid, newKeys)
#---------------------------------------------------------------------
# merge weather grid
#
@ -208,6 +241,11 @@ class MergeGrid:
noWxGrid = numpy.empty_like(gridA[0])
noWxGrid.fill(self.__findKey(noWx, noWxKeys))
gridB = (noWxGrid, noWxKeys)
else:
# clear out the masked area in gridB and collapse gridB's keys
grid, keys = gridB
grid[mask]= self.__findKey(noWx, keys)
gridB = self.__collapseKey(grid, keys)
(commonkey, remapG, dbG) = self.__commonizeKey(gridA, gridB)
mergedGrid = numpy.where(mask, remapG, dbG)
return (mergedGrid, commonkey)
@ -242,6 +280,11 @@ class MergeGrid:
noGrid = numpy.empty_like(gridA[0])
noGrid.fill(self.__findKey(noKey, noKeys))
gridB = (noGrid, noKeys)
else:
# clear out the masked area in gridB and collapse gridB's keys
grid, keys = gridB
grid[mask] = self.__findKey(noKey, keys)
gridB = self.__collapseKey(grid, keys)
(commonkey, remapG, dbG) = \
self.__commonizeKey(gridA, gridB)

View file

@ -42,6 +42,7 @@ import com.vividsolutions.jts.geom.Coordinate;
* Oct 22, 2008 1624 wdougherty Speed up translate method
* Sep 01, 2014 3572 randerso Changed getNumpy to use getBytes()
* Apr 23, 2015 4259 njensen Updated for new JEP API
* Apr 04, 2016 5539 randerso Fixed toString method to handle unsigned bytes
*
* </pre>
*
@ -103,7 +104,7 @@ public class Grid2DByte implements IGrid2D, Cloneable {
*/
public Grid2DByte(int xDim, int yDim, byte[] data) {
this(xDim, yDim);
if (xDim * yDim != data.length) {
if ((xDim * yDim) != data.length) {
throw new IllegalArgumentException(
"Dimensions do not match data length (" + xDim + "," + yDim
+ ") " + data.length);
@ -122,7 +123,7 @@ public class Grid2DByte implements IGrid2D, Cloneable {
* ByteBuffer of initialization data
*/
public Grid2DByte(int xDim, int yDim, ByteBuffer data) {
if (xDim * yDim != data.limit()) {
if ((xDim * yDim) != data.limit()) {
throw new IllegalArgumentException(
"Dimensions do not match data length (" + xDim + "," + yDim
+ ") " + data.limit());
@ -165,7 +166,7 @@ public class Grid2DByte implements IGrid2D, Cloneable {
if (!isValid(xDim, yDim)) {
throw new IllegalArgumentException("Dimensions not valid");
}
return buffer.get(yDim * this.xdim + xDim);
return buffer.get((yDim * this.xdim) + xDim);
}
/**
@ -180,7 +181,7 @@ public class Grid2DByte implements IGrid2D, Cloneable {
if (!isValid(xDim, yDim)) {
throw new IllegalArgumentException("Dimensions not valid");
}
buffer.put(yDim * this.xdim + xDim, aValue);
buffer.put((yDim * this.xdim) + xDim, aValue);
}
public void set(int xDim, int yDim, int aValue) {
@ -205,7 +206,7 @@ public class Grid2DByte implements IGrid2D, Cloneable {
@Override
public boolean isValid(int x, int y) {
return (x < xdim && y < ydim && x >= 0 && y >= 0);
return ((x < xdim) && (y < ydim) && (x >= 0) && (y >= 0));
}
/**
@ -224,7 +225,7 @@ public class Grid2DByte implements IGrid2D, Cloneable {
* y coordinate to clear
*/
public void clear(int x, int y) {
buffer.put(y * xdim + x, (byte) 0);
buffer.put((y * xdim) + x, (byte) 0);
}
/**
@ -241,7 +242,7 @@ public class Grid2DByte implements IGrid2D, Cloneable {
// make another Grid2DByte
Grid2DByte rVal = new Grid2DByte(this.xdim, this.ydim, (byte) 0);
if (Math.abs(deltaCoord.x) < xdim && Math.abs(deltaCoord.y) < ydim) {
if ((Math.abs(deltaCoord.x) < xdim) && (Math.abs(deltaCoord.y) < ydim)) {
// Find iteration limits for X
int fromXStart;
int toXStart;
@ -275,8 +276,8 @@ public class Grid2DByte implements IGrid2D, Cloneable {
byte[] toA = rVal.getBuffer().array();
// Calculate from/to array offsets of the first point.
int fromOffset = fromYStart * xdim + fromXStart;
int toOffset = toYStart * xdim + toXStart;
int fromOffset = (fromYStart * xdim) + fromXStart;
int toOffset = (toYStart * xdim) + toXStart;
// For each row, copy cols bytes of data.
// Then update offsets for next row.
@ -328,9 +329,9 @@ public class Grid2DByte implements IGrid2D, Cloneable {
@Override
public Grid2DByte subGrid(int minX, int minY, int maxX, int maxY) {
Grid2DByte rVal = new Grid2DByte(maxX + 1 - minX, maxY + 1 - minY);
for (int y = minY; y < maxY + 1; y++) {
for (int x = minX; x < maxX + 1; x++) {
Grid2DByte rVal = new Grid2DByte((maxX + 1) - minX, (maxY + 1) - minY);
for (int y = minY; y < (maxY + 1); y++) {
for (int x = minX; x < (maxX + 1); x++) {
rVal.buffer.put(this.get(x, y));
}
}
@ -345,7 +346,8 @@ public class Grid2DByte implements IGrid2D, Cloneable {
Grid2DByte rhsGrid2DByte = (Grid2DByte) rhs;
if (this.xdim != rhsGrid2DByte.xdim || this.ydim != rhsGrid2DByte.ydim) {
if ((this.xdim != rhsGrid2DByte.xdim)
|| (this.ydim != rhsGrid2DByte.ydim)) {
return false;
}
@ -374,9 +376,10 @@ public class Grid2DByte implements IGrid2D, Cloneable {
Grid2DByte sourceGrid2DByte = (Grid2DByte) sourceGrid;
if (this.xdim != sourceGrid2DByte.xdim || this.xdim != maskGrid.xdim
|| this.ydim != sourceGrid2DByte.ydim
|| this.ydim != maskGrid.ydim) {
if ((this.xdim != sourceGrid2DByte.xdim)
|| (this.xdim != maskGrid.xdim)
|| (this.ydim != sourceGrid2DByte.ydim)
|| (this.ydim != maskGrid.ydim)) {
throw new IllegalArgumentException(
"This grid, the input grid, and the input mask grid must have equal dimensions");
}
@ -407,7 +410,7 @@ public class Grid2DByte implements IGrid2D, Cloneable {
rVal += xdim + "X" + ydim + "\n[\n";
for (int y = 0; y < ydim; y++) {
for (int x = 0; x < xdim; x++) {
rVal += this.get(x, y) + (x + 1 == xdim ? "" : ",");
rVal += (0xFF & this.get(x, y)) + ((x + 1) == xdim ? "" : ",");
}
rVal += "\n";
}

View file

@ -53,13 +53,14 @@ import com.raytheon.uf.common.time.TimeRange;
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Mar 15, 2011 randerso Initial creation
* Jan 30, 2013 15719 jdynina Allowed more than 128 char wx string
* Aug 13, 2013 1571 randerso Removed toString to stop it from hanging the
* debugger when trying to display the grid
* Oct 29, 2013 2476 njensen Updated getNumpy() and added getKeyList()
* Apr 23, 2015 4259 njensen Updated for new JEP API
* Nov 03, 2015 5061 randerso Fixed null pointer in equals()
* Mar 15, 2011 randerso Initial creation
* Jan 30, 2013 15719 jdynina Allowed more than 128 char wx string
* Aug 13, 2013 1571 randerso Removed toString to stop it from hanging the
* debugger when trying to display the grid
* Oct 29, 2013 2476 njensen Updated getNumpy() and added getKeyList()
* Apr 23, 2015 4259 njensen Updated for new JEP API
* Nov 03, 2015 5061 randerso Fixed null pointer in equals()
* Apr 05, 2016 5539 randerso Cleaned up collapse method
*
* </pre>
*
@ -645,63 +646,81 @@ public class WeatherGridSlice extends AbstractGridSlice {
return;
}
// make a histogram, indicating what is and what isn't
// used in the weather keys
boolean[] used = new boolean[keys.length];
int[] invMapping = new int[keys.length];
for (int i = 0; i < used.length; i++) {
invMapping[i] = i;
used[i] = false;
}
// process the grid
for (int i = 0; i < weatherGrid.getXdim(); i++) {
for (int j = 0; j < weatherGrid.getYdim(); j++) {
used[0xFF & weatherGrid.get(i, j)] = true;
}
} // indicate used
// clear the invmapping if not used
for (int i = 0; i < used.length; i++) {
if (!used[i]) {
invMapping[i] = -1;
}
}
// eliminate duplicate keys
int nk = 0;
List<WeatherKey> tmpKeys = new ArrayList<WeatherKey>();
for (int i = 0; i < used.length; i++) {
if (used[i]) {
tmpKeys.add(keys[i]);
invMapping[i] = nk;
for (int j = i + 1; j < used.length; j++) {
if (keys[i].equals(keys[j])) {
invMapping[j] = nk; // key index
used[j] = false; // to prevent reprocessing
}
try {
int max = 0;
for (byte b : weatherGrid.getBytes()) {
int unsigned = 0xFF & b;
if (unsigned > max) {
max = unsigned;
}
nk++;
}
}
WeatherKey[] newKeys = tmpKeys.toArray(new WeatherKey[tmpKeys.size()]);
// anything to do?
if (Arrays.equals(newKeys, keys)) {
return;
}
// now remap the data
for (int i = 0; i < weatherGrid.getXdim(); i++) {
for (int j = 0; j < weatherGrid.getYdim(); j++) {
weatherGrid.set(i, j,
(byte) invMapping[0xFF & weatherGrid.get(i, j)]);
if (max >= keys.length) {
throw new IndexOutOfBoundsException("Grid contains index ("
+ max + ") > keys.length (" + keys.length + ")");
}
}
// store the grid
setWeatherGrid(weatherGrid);
keys = newKeys;
// make a histogram, indicating what is and what isn't
// used in the weather keys
boolean[] used = new boolean[keys.length];
int[] invMapping = new int[keys.length];
for (int i = 0; i < used.length; i++) {
invMapping[i] = i;
used[i] = false;
}
// process the grid
for (int i = 0; i < weatherGrid.getXdim(); i++) {
for (int j = 0; j < weatherGrid.getYdim(); j++) {
used[0xFF & weatherGrid.get(i, j)] = true; // indicate used
}
}
// clear the invmapping if not used
for (int i = 0; i < used.length; i++) {
if (!used[i]) {
invMapping[i] = -1;
}
}
// eliminate duplicate keys
int nk = 0;
List<WeatherKey> tmpKeys = new ArrayList<WeatherKey>();
for (int i = 0; i < used.length; i++) {
if (used[i]) {
tmpKeys.add(keys[i]);
invMapping[i] = nk;
for (int j = i + 1; j < used.length; j++) {
if (keys[i].equals(keys[j])) {
invMapping[j] = nk; // key index
used[j] = false; // to prevent reprocessing
}
}
nk++;
}
}
WeatherKey[] newKeys = tmpKeys.toArray(new WeatherKey[tmpKeys
.size()]);
// anything to do?
if (Arrays.equals(newKeys, keys)) {
return;
}
// now remap the data
for (int i = 0; i < weatherGrid.getXdim(); i++) {
for (int j = 0; j < weatherGrid.getYdim(); j++) {
weatherGrid.set(i, j,
(byte) invMapping[0xFF & weatherGrid.get(i, j)]);
}
}
// store the grid
setWeatherGrid(weatherGrid);
keys = newKeys;
} catch (IndexOutOfBoundsException e) {
statusHandler.error(e.getLocalizedMessage(), e);
throw e;
}
}
@Override