package nl.wldelft.util.io;
import nl.wldelft.util.BinaryUtils;
import nl.wldelft.util.ByteArrayUtils;
import nl.wldelft.util.DateUtils;
import nl.wldelft.util.FloatArrayUtils;
import nl.wldelft.util.IOUtils;
import nl.wldelft.util.NumberType;
import nl.wldelft.util.ShortArrayUtils;
import nl.wldelft.util.TextUtils;
import nl.wldelft.util.coverage.Geometry;
import nl.wldelft.util.coverage.GridUtils;
import nl.wldelft.util.coverage.RegularGridGeometry;
import nl.wldelft.util.geodatum.GeoDatum;
import nl.wldelft.util.geodatum.GeoPoint;
import nl.wldelft.util.geodatum.Wgs1984Point;
import nl.wldelft.util.timeseries.DefaultTimeSeriesHeader;
import nl.wldelft.util.timeseries.TimeSeriesContentHandler;
import org.apache.log4j.Logger;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.nio.ByteOrder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
public class MosaicRadarTimeSeriesParser implements BinaryParser<TimeSeriesContentHandler> {
private static final Logger log = Logger.getLogger(MosaicRadarTimeSeriesParser.class);
private Geometry geometry = null;
private int nx1 = 0;
private int ny1 = 0;
private int nz1 = 0;
private String projection = null;
private int scale = 0;
private int trulat1 = 0;
private int trulat2 = 0;
private int trulon = 0;
private float nwLon = 0.0F;
private float nwLat = 0.0F;
private float xyScale = 0.0F;
private float dx1 = 0.0F;
private float dy2 = 0.0F;
private int iBbMode = 0;
private String varName = null;
private String varUnit = null;
private int varScale = 0;
private int imissing = 0;
private int nradars = 0;
private String[] radarNames = null;
private float dxyScale = 0.0F;
private int size = 0;
private long time = Long.MIN_VALUE;
private float[] values = FloatArrayUtils.EMPTY_ARRAY;
private byte[] byteBuffer = ByteArrayUtils.EMPTY_ARRAY;
private short[] shortBuffer = ShortArrayUtils.EMPTY_ARRAY;
private LittleEndianDataInputStream is = null;
private TimeSeriesContentHandler contentHandler = null;
@Override
public void parse(BufferedInputStream inputStream, String virtualFileName, TimeSeriesContentHandler contentHandler) throws Exception {
this.contentHandler = contentHandler;
this.is = new LittleEndianDataInputStream(inputStream);
parseHeader();
if (contentHandler.isCurrentTimeSeriesHeaderForCurrentTimeRejected()) return;
if (values.length != geometry.size()) {
values = new float[geometry.size()];
byteBuffer = new byte[geometry.size() * NumberType.INT16_SIZE];
shortBuffer = new short[geometry.size()];
}
if (values.length != geometry.size()) {
values = new float[geometry.size()];
byteBuffer = new byte[geometry.size() * NumberType.INT16_SIZE];
shortBuffer = new short[geometry.size()];
}
// read all the complete grid at once for optimal performance
is.readFully(byteBuffer);
BinaryUtils.copy(byteBuffer, 0, size * NumberType.INT16_SIZE, shortBuffer, 0, size, ByteOrder.LITTLE_ENDIAN);
if (is.available() > 0) log.error("Too many bytes available in " + virtualFileName);
for (int i = 0; i < values.length; i++) {
short shortValue = shortBuffer[i];
values[i] = shortValue == imissing ? Float.NaN : shortValue / varScale;
}
// content handle expect the rows from top to bottom
GridUtils.reverseOrderRows(values, geometry.getCols(), geometry.getRows());
contentHandler.setCoverageValues(values);
contentHandler.applyCurrentFields();
}
@SuppressWarnings({"OverlyLongMethod"})
private void parseHeader() throws IOException {
DefaultTimeSeriesHeader header = new DefaultTimeSeriesHeader();
int year = is.readInt();
int month = is.readInt();
int day = is.readInt();
int hour = is.readInt();
int minute = is.readInt();
int second = is.readInt();
Calendar gmtCalendar = new GregorianCalendar(DateUtils.GMT);
gmtCalendar.set(year, month - 1, day, hour, minute, second);
contentHandler.setTime(gmtCalendar.getTimeInMillis());
nx1 = is.readInt();
ny1 = is.readInt();
nz1 = is.readInt();
projection = IOUtils.readText(is, 4).trim();
scale = is.readInt();
trulat1 = is.readInt();
trulat2 = is.readInt();
trulon = is.readInt();
nwLon = (float) is.readInt() / (float) scale;
nwLat = (float) is.readInt() / (float) scale;
xyScale = is.readInt();
int dx1int = is.readInt();
int dy2int = is.readInt();
dxyScale = (float) is.readInt();
dx1 = (float) dx1int / dxyScale;
dy2 = (float) dy2int / dxyScale;
IOUtils.skipFully(is, 4 * nz1);
iBbMode = is.readInt();
IOUtils.skipFully(is, 4 * 9);
IOUtils.skipFully(is, 4);
varName = IOUtils.readText(is, 20);
varUnit = IOUtils.readText(is, 6);
varScale = is.readInt();
imissing = is.readInt();
nradars = is.readInt();
if (nradars > 0) {
radarNames = new String[nradars];
for (int i = 0; i < nradars; i++) {
radarNames[i] = IOUtils.readText(is, 4).trim();
}
}
size = nx1 * ny1 * nz1;
GeoPoint firstCellCenter = new Wgs1984Point(nwLat - dy2 / 2, nwLon + dx1 / 2);
geometry = RegularGridGeometry.create(GeoDatum.WGS_1984, firstCellCenter, dx1, dy2, ny1, nx1);
contentHandler.setGeometry(geometry);
contentHandler.setValueResolution(1.0f / varScale);
header.setParameterId(varName);
header.setUnit(varUnit);
contentHandler.setTimeSeriesHeader(header);
debugHeader();
}
private void debugHeader() {
if (!log.isDebugEnabled()) return;
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
dateFormat.setTimeZone(DateUtils.GMT);
List<String> header = new ArrayList<String>(10);
header.add(dateFormat.format(new Date(time)));
header.add("nx1 = " + nx1);
header.add("ny1 = " + ny1);
header.add("nz1 = " + nz1);
header.add("size = " + size);
header.add("projection = " + projection);
header.add("scale = " + scale);
header.add("trulat1 = " + trulat1);
header.add("trulat2 = " + trulat2);
header.add("trulon = " + trulon);
header.add("nw_lon = " + nwLon);
header.add("nw_lat = " + nwLat);
header.add("xy_scale = " + xyScale);
header.add("dx1 = " + dx1);
header.add("dy2 = " + dy2);
header.add("i_bb_mode = " + iBbMode);
header.add("varName = " + varName);
header.add("varUnit = " + varUnit);
header.add("var_scale = " + varScale);
header.add("imissing = " + imissing);
header.add("nradars = " + nradars);
if (radarNames != null) {
for (int i = 0; i < radarNames.length; i++) {
String radarName = radarNames[i];
header.add("radarName = " + radarName);
}
}
header.add("dxyScale = " + dxyScale);
log.debug(TextUtils.join(header, '\n'));
}
}
|