VLab Issue #4865 - MISC/ASCT latest Data string appears incorrectly
This commit fixes #4865; refs #4864 Change-Id: I024a86831425f7eae776a00b9d6cf07993e74932 Former-commit-id: 9559830d4cbcf9e77cb269403c4ac6cca8a88796
This commit is contained in:
parent
6309e62c8f
commit
8156498dda
7 changed files with 558 additions and 502 deletions
|
@ -0,0 +1,220 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package gov.noaa.nws.ncep.common.dataplugin.ncscat;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* NcscatMode - Enum class to centralize and encapsulate all the things that
|
||||
* vary among different satellite and data feed types.
|
||||
*
|
||||
* //TODO: Consider moving this information entirely to the bundle and/or
|
||||
* preferences (.xml/.prm) files, so the Java code can be completely agnostic
|
||||
* about satellite data types; would allow extended 'configurability', at the
|
||||
* expense of slightly longer bundle/preference files...
|
||||
*
|
||||
* This code has been developed by the SIB for use in the AWIPS2 system.
|
||||
*
|
||||
* <pre>
|
||||
* SOFTWARE HISTORY
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* 02 Jun 2010 235B B. Hebbard Initial creation.
|
||||
* 03 Feb 2011 235E B. Hebbard Add support for ambiguity variants.
|
||||
* 16 Aug 2012 B. Hebbard Add OSCAT / OSCAT_HI
|
||||
* 11 Apr 2014 1128 B. Hebbard Add longitudeCoding field; change wind sense from boolean to enum.
|
||||
* 21 Oct 2014 R4865 B. Hebbard (TTR 984) Add file-header length and reportType fields to enable refactor to make decoding more robust (and thereby prevent date and other corruption)
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bhebbard
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public enum NcscatMode {
|
||||
|
||||
// The only ordering constraint here is that if A.pointsPerRow divides
|
||||
// B.pointsPerRow and A and B have the same byteOrder, then A should come
|
||||
// before B. (Currently, no such cases exist.) This is so that we can check
|
||||
// an unknown data file for 'consistency' with these types, in order, and
|
||||
// choose the first one that matches. (In the hypothetical case above, A and
|
||||
// B could both pass consistency checking, but we'd want to choose A.)
|
||||
|
||||
// @formatter:off ppr hdr
|
||||
QUIKSCAT ( 76, 0, WindDirectionSense.METEOROLOGICAL, LongitudeCoding.UNSIGNED, ByteOrder.BIG_ENDIAN, "quikscat" ),
|
||||
QUIKSCAT_HI ( 152, 0, WindDirectionSense.METEOROLOGICAL, LongitudeCoding.UNSIGNED, ByteOrder.BIG_ENDIAN, "quikscat-hi"),
|
||||
ASCAT ( 42, 0, WindDirectionSense.OCEANOGRAPHIC, LongitudeCoding.UNSIGNED, ByteOrder.BIG_ENDIAN, "ascat"),
|
||||
ASCAT_HI ( 82, 0, WindDirectionSense.OCEANOGRAPHIC, LongitudeCoding.UNSIGNED, ByteOrder.BIG_ENDIAN, "ascat-hi"),
|
||||
EXASCT ( 42, 0, WindDirectionSense.OCEANOGRAPHIC, LongitudeCoding.UNSIGNED, ByteOrder.LITTLE_ENDIAN, "Exasct"),
|
||||
EXASCT_HI ( 82, 0, WindDirectionSense.OCEANOGRAPHIC, LongitudeCoding.UNSIGNED, ByteOrder.LITTLE_ENDIAN, "Exasct-hi"),
|
||||
OSCAT ( 36, 0, WindDirectionSense.METEOROLOGICAL, LongitudeCoding.UNSIGNED, ByteOrder.BIG_ENDIAN, "oscat"),
|
||||
OSCAT_HI ( 76, 0, WindDirectionSense.METEOROLOGICAL, LongitudeCoding.UNSIGNED, ByteOrder.LITTLE_ENDIAN, "oscat-hi"),
|
||||
WSCAT ( 79, 56, WindDirectionSense.METEOROLOGICAL, LongitudeCoding.SIGNED, ByteOrder.LITTLE_ENDIAN, "wscat"),
|
||||
UNKNOWN ( 76, 0, WindDirectionSense.METEOROLOGICAL, LongitudeCoding.UNSIGNED, ByteOrder.BIG_ENDIAN, "unknown");
|
||||
// @formatter:on
|
||||
|
||||
private int pointsPerRow; // number of Wind Vector Cell in each scan row
|
||||
// across satellite track
|
||||
|
||||
private WindDirectionSense windDirectionSense; // is the numeric wind
|
||||
// direction the "from"
|
||||
// (METEOROLOGICAL)
|
||||
// direction, or the "to"
|
||||
// (OCEANOGRAPHIC) direction?
|
||||
|
||||
private LongitudeCoding longitudeCoding; // is the two-byte value a SIGNED
|
||||
// (-18000 -- +18000) or UNSIGNED
|
||||
// (0 -- 36000) representation of
|
||||
// the (scaled by 100) longitude
|
||||
// east of Greenwich?
|
||||
|
||||
private ByteOrder byteOrder; // endianess of data in the byte stream
|
||||
|
||||
private String reportType; // string to use in reportType field of DB
|
||||
|
||||
private int valuesPerPoint = 9; // number of (short int) data values per
|
||||
// point
|
||||
|
||||
private int bytesPerValue = 2; // all are short int
|
||||
|
||||
private int fileHeaderLength; // length in bytes of per-file header field,
|
||||
// if any, in input file, before repeating
|
||||
// per-row data begins; of interest to decoder
|
||||
|
||||
private int rowHeaderLength = 8; // length in bytes of per-row header field
|
||||
// (2 bytes each for day, hour, min, sec)
|
||||
|
||||
private int bytesPerRow; // length in bytes of each row, comprising row
|
||||
// header and all data values for all points in
|
||||
// that row
|
||||
|
||||
public int getBytesPerRow() {
|
||||
return bytesPerRow;
|
||||
}
|
||||
|
||||
// Constructor
|
||||
NcscatMode(int pointsPerRow, int fileHeaderLength,
|
||||
WindDirectionSense windDirectionSense,
|
||||
LongitudeCoding longitudeCoding, ByteOrder byteOrder,
|
||||
String reportType) {
|
||||
this.pointsPerRow = pointsPerRow;
|
||||
this.fileHeaderLength = fileHeaderLength;
|
||||
this.windDirectionSense = windDirectionSense;
|
||||
this.longitudeCoding = longitudeCoding;
|
||||
this.byteOrder = byteOrder;
|
||||
this.reportType = reportType;
|
||||
|
||||
bytesPerRow = rowHeaderLength + pointsPerRow * valuesPerPoint
|
||||
* bytesPerValue;
|
||||
}
|
||||
|
||||
public String getReportType() {
|
||||
return reportType;
|
||||
}
|
||||
|
||||
public int getPointsPerRow() {
|
||||
return pointsPerRow;
|
||||
}
|
||||
|
||||
public int getFileHeaderLength() {
|
||||
return fileHeaderLength;
|
||||
}
|
||||
|
||||
public WindDirectionSense getWindDirectionSense() {
|
||||
return windDirectionSense;
|
||||
}
|
||||
|
||||
public LongitudeCoding getLongitudeCoding() {
|
||||
return longitudeCoding;
|
||||
}
|
||||
|
||||
public ByteOrder getByteOrder() {
|
||||
return byteOrder;
|
||||
}
|
||||
|
||||
public enum WindDirectionSense { // numeric direction value gives...
|
||||
METEOROLOGICAL, // degrees FROM which wind is blowing
|
||||
OCEANOGRAPHIC // degrees TO which wind is blowing
|
||||
}
|
||||
|
||||
public enum LongitudeCoding { // 2-byte wvc_lon (Wind Vector Cell -
|
||||
// longitude) field is (x0.01 deg)...
|
||||
SIGNED, // SIGNED short (-18000..+18000)
|
||||
UNSIGNED // UNSIGNED short (0..36000 east of Greenwich)
|
||||
}
|
||||
|
||||
public static NcscatMode stringToMode(String name) {
|
||||
// Given a string, return the corresponding enum
|
||||
NcscatMode returnValue = null;
|
||||
name = name.toUpperCase();
|
||||
name = name.replaceAll("-", "_");
|
||||
// TODO: Remove ambiguity number??
|
||||
try {
|
||||
returnValue = valueOf(name);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// TODO: Signal unrecognized Ncscat mode string
|
||||
returnValue = UNKNOWN;
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
public boolean consistentWith(ByteBuffer byteBuffer) {
|
||||
// Given a ByteBuffer containing ingested binary data of unknown
|
||||
// satellite type (mode), determine whether data are consistent
|
||||
// with "this" mode. We do this by seeing if date/hour fields
|
||||
// repeat where they would be expected to appear, and contain
|
||||
// reasonable values for those fields.
|
||||
|
||||
// TODO: Consider moving this to decoder...? (Kind of prefer
|
||||
// encapsulating it here, but also like enums to be rather
|
||||
// minimalistic...? -bh)
|
||||
|
||||
byteBuffer.order(byteOrder);
|
||||
int base = fileHeaderLength;
|
||||
for (int cycle = 0; cycle < 2; cycle++) {
|
||||
|
||||
// DAY (of year) candidate fields of consecutive rows out of
|
||||
// range...
|
||||
short thisCandidateDayOfYear = byteBuffer.getShort(base);
|
||||
short nextCandidateDayOfYear = byteBuffer.getShort(base
|
||||
+ bytesPerRow);
|
||||
if (thisCandidateDayOfYear < 1 || thisCandidateDayOfYear > 366
|
||||
|| nextCandidateDayOfYear < 1
|
||||
|| nextCandidateDayOfYear > 366)
|
||||
// ...means (right away) data can't be this type
|
||||
return false;
|
||||
// ...but if they don't match...
|
||||
if (thisCandidateDayOfYear != nextCandidateDayOfYear) {
|
||||
// ...can't rule it out (since first two rows could straddle a
|
||||
// day boundary)...but can skip checking hour and go to check
|
||||
// next pair of rows...
|
||||
break;
|
||||
}
|
||||
|
||||
// HOUR candidate fields (of consecutive rows) in range...?
|
||||
short thisCandidateHour = byteBuffer.getShort(base + 2);
|
||||
short nextCandidateHour = byteBuffer.getShort(base + 2
|
||||
+ bytesPerRow);
|
||||
if (thisCandidateHour < 0 || thisCandidateHour > 23
|
||||
|| nextCandidateHour < 0 || nextCandidateHour > 23)
|
||||
return false;
|
||||
// ...and if they do match (as well as day field above), then we
|
||||
// conclude consistency
|
||||
if (byteBuffer.getShort(base) == byteBuffer.getShort(base
|
||||
+ bytesPerRow)) {
|
||||
return true;
|
||||
}
|
||||
// ...but if they don't, again, first two rows could straddle an
|
||||
// hour boundary, so go to next pair of rows (cycle)...
|
||||
base += bytesPerRow;
|
||||
}
|
||||
// We've made it through 2 consecutive cycles, and neither (1st/2nd
|
||||
// nor 2nd/3rd) day+hour match, so conclude (assuming real consecutive
|
||||
// rows are not separated by an hour or more) data not consistent with
|
||||
// this type
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -2,7 +2,8 @@
|
|||
*
|
||||
* Ncscat Decoder
|
||||
*
|
||||
* This java class decodes Ascat quikscat (NESDIS File) raw data.
|
||||
* This Java class decodes ocean winds scatterometer/radiometer (NESDIS File) raw data.
|
||||
*
|
||||
* HISTORY
|
||||
*
|
||||
* Date Author Description
|
||||
|
@ -10,6 +11,7 @@
|
|||
* 11/2009 Uma Josyula Initial creation
|
||||
* 01/2011 B. Hebbard Handle ambiguity variants
|
||||
* 07/2012 B. Hebbard Handle OSCAT / OSCAT_HI
|
||||
* 10/2014 B. Hebbard Get reportType from NcscatMode, instead of if-then-else'ing over hardcode integer lengths
|
||||
*
|
||||
* This code has been developed by the SIB for use in the AWIPS2 system.
|
||||
*/
|
||||
|
@ -67,7 +69,7 @@ public class NcscatDecoder extends AbstractDecoder {
|
|||
NcscatProcessing sProcess = new NcscatProcessing();
|
||||
sProcess.setInputFileName(plugin);
|
||||
messageData = sProcess.separate(data);
|
||||
recLength = NcscatProcessing.getRecordLength();
|
||||
recLength = sProcess.getRecordLength();
|
||||
if (messageData != null) {
|
||||
|
||||
record = new NcscatRecord();
|
||||
|
@ -76,38 +78,7 @@ public class NcscatDecoder extends AbstractDecoder {
|
|||
record.setEndTime(sProcess.getEndTime());
|
||||
record.setRecordLength(recLength);
|
||||
record.setDataTime(new DataTime(sProcess.getStartTime()));
|
||||
|
||||
if (record.getRecordLength() == 688) {
|
||||
|
||||
if (plugin.equalsIgnoreCase("oscat")) {
|
||||
record.setReportType("oscat-hi");
|
||||
} else {
|
||||
record.setReportType("quikscat");
|
||||
}
|
||||
} else if (record.getRecordLength() == 1372) {
|
||||
record.setReportType("quikscat-hi");
|
||||
} else if (record.getRecordLength() == 382) {
|
||||
|
||||
if (plugin.equalsIgnoreCase("ascatx")) {
|
||||
|
||||
record.setReportType("Exasct");
|
||||
} else {
|
||||
|
||||
record.setReportType("ascat");
|
||||
}
|
||||
} else if (record.getRecordLength() == 742) {
|
||||
|
||||
if (plugin.equalsIgnoreCase("ascatx")) {
|
||||
|
||||
record.setReportType("Exasct-hi");
|
||||
} else {
|
||||
record.setReportType("ascat-hi");
|
||||
}
|
||||
} else if (record.getRecordLength() == 328) {
|
||||
record.setReportType("oscat");
|
||||
} else if (record.getRecordLength() == 715) {
|
||||
record.setReportType("wscat");
|
||||
}
|
||||
record.setReportType(sProcess.getNcscatMode().getReportType());
|
||||
|
||||
// If this is an (numbered) 'ambiguity' variant, add suffix to
|
||||
// reportType
|
||||
|
@ -178,20 +149,16 @@ public class NcscatDecoder extends AbstractDecoder {
|
|||
}
|
||||
// TODO: Review this temporary fix by BH to see if a broader
|
||||
// refactor might be better.
|
||||
|
||||
// Problem: Without the added 'else' below, non-local variable
|
||||
// "plugin" will
|
||||
// retain its previous value if the pattern matcher fails above;
|
||||
// this will happen
|
||||
// if the file suffix/extension (after the ".") is shorter than 5
|
||||
// characters.
|
||||
// Scenario: A file with suffix ".ascatx" is ingested, then later a
|
||||
// ".qsct" file.
|
||||
// "plugin" will retain its previous value if the pattern matcher
|
||||
// fails above; this will happen if the file suffix/extension (after
|
||||
// the ".") is shorter than 5 characters. Scenario: A file with
|
||||
// suffix ".ascatx" is ingested, then later a ".qsct" file.
|
||||
// Variable "plugin" will be set to "ascatx" by the first, but will
|
||||
// retain this
|
||||
// same value for the second; logic in NcscatProcessing.doSeparate()
|
||||
// will as a
|
||||
// result interpret the big-endian ".qsct" data as little endian
|
||||
// format.
|
||||
// retain this same value for the second; logic in
|
||||
// NcscatProcessing.doSeparate() will as a result interpret the
|
||||
// big-endian ".qsct" data as little endian format.
|
||||
// Alternate (better): Could make "plugin" local to this method
|
||||
else {
|
||||
plugin = "";
|
||||
|
@ -200,20 +167,14 @@ public class NcscatDecoder extends AbstractDecoder {
|
|||
// NcscatProcessing
|
||||
|
||||
// Handle ambiguity variants: In addition to files containing the
|
||||
// primary
|
||||
// (greatest likelihood) wind vector solutions, for some data types
|
||||
// we also
|
||||
// receive (typically 2 or 4) 'ambiguity' variants for the same
|
||||
// point locations,
|
||||
// but with (lesser likelihood) solutions. Since these cannot be
|
||||
// distinguished
|
||||
// from the primary files based on data format/content alone, we
|
||||
// look for a
|
||||
// (prearranged) telltale pattern somewhere in the file name. If
|
||||
// found, we
|
||||
// remember the indicated ambiguity number, for later tagging of the
|
||||
// database
|
||||
// record.
|
||||
// primary (greatest likelihood) wind vector solutions, for some
|
||||
// data types we also receive (typically 2 or 4) 'ambiguity'
|
||||
// variants for the same point locations, but with (lesser
|
||||
// likelihood) solutions. Since these cannot be distinguished from
|
||||
// the primary files based on data format/content alone, we
|
||||
// look for a (prearranged) telltale pattern somewhere in the file
|
||||
// name. If found, we remember the indicated ambiguity number, for
|
||||
// later tagging of the database record.
|
||||
pattern = Pattern.compile("ambig([1-9])");
|
||||
matcher = pattern.matcher(fileName);
|
||||
if (matcher.find()) {
|
||||
|
|
|
@ -7,14 +7,18 @@
|
|||
* <pre>
|
||||
* Uma Josyula 11/2009 Creation
|
||||
* B. Hebbard 07/2012 Handle OSCAT / OSCAT_HI
|
||||
* B. Hebbard R4865/TTR984 10/2014 Tighten code that infers satellite type
|
||||
* (from date/hour field recurrence) and
|
||||
* date handling to prevent garbage from being
|
||||
* interpreted as dates decades in the future.
|
||||
* </pre>
|
||||
*
|
||||
* This code has been developed by the SIB for use in the AWIPS system.
|
||||
*/
|
||||
|
||||
|
||||
package gov.noaa.nws.ncep.edex.plugin.ncscat.util;
|
||||
|
||||
import gov.noaa.nws.ncep.common.dataplugin.ncscat.NcscatMode;
|
||||
import gov.noaa.nws.ncep.common.dataplugin.ncscat.NcscatPoint;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
@ -24,369 +28,357 @@ import java.util.Calendar;
|
|||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.raytheon.uf.common.serialization.SerializationUtil;
|
||||
|
||||
|
||||
public class NcscatProcessing {
|
||||
|
||||
private final Logger log = Logger.getLogger(getClass().getName());
|
||||
|
||||
private final Log theLogger = LogFactory.getLog(getClass());
|
||||
|
||||
private final Logger log = Logger.getLogger(getClass().getName());
|
||||
private final Log theLogger = LogFactory.getLog(getClass());
|
||||
private List<NcscatPoint> item;
|
||||
List<Byte> newMessage=null;
|
||||
NcscatPoint sPointObj ;
|
||||
private Calendar endTime ;
|
||||
private static int scatNumber ;
|
||||
private Calendar startTime;
|
||||
private static int recordLength;
|
||||
private String inputFileName;
|
||||
private List<NcscatPoint> item;
|
||||
|
||||
List<Byte> newMessage = null;
|
||||
|
||||
public NcscatProcessing() {
|
||||
}
|
||||
NcscatPoint sPointObj;
|
||||
|
||||
public byte[] separate(byte[] data) {
|
||||
doSeparate(data);
|
||||
try {
|
||||
if(newMessage ==null){
|
||||
return (byte[])null;
|
||||
}
|
||||
else {
|
||||
byte[] tempBytes = listByteTobyteArray(newMessage);
|
||||
return tempBytes;
|
||||
}
|
||||
private Calendar endTime;
|
||||
|
||||
} catch (NoSuchElementException e) {
|
||||
return (byte[])null;
|
||||
}
|
||||
private int scatNumber;
|
||||
|
||||
}
|
||||
private Calendar startTime;
|
||||
|
||||
private int recordLength;
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* separate bulletins
|
||||
*/
|
||||
private void doSeparate(byte[] message) {
|
||||
int ji=0;
|
||||
int n = 0,doubleNcscat =0,scatXLen =0;
|
||||
ByteBuffer byteBuffer = null;
|
||||
byteBuffer = ByteBuffer.allocate(message.length);
|
||||
byteBuffer.put(message,0,message.length);
|
||||
int bitNum =0;
|
||||
int tempLength=message.length;
|
||||
int day,hour,min,sec;
|
||||
private String inputFileName;
|
||||
|
||||
startTime = Calendar.getInstance();
|
||||
endTime = Calendar.getInstance();
|
||||
private NcscatMode ncscatMode;
|
||||
|
||||
// Attempt to discriminate type of data by looking for 'period' of repeating date+hour fields.
|
||||
// TODO !! Guard against false negative which could occur if first 2 times straddle hour boundary,
|
||||
// !! possibly by checking for match EITHER 1st-&-2nd OR 2nd-&-3rd
|
||||
if ((byteBuffer.getShort(0) == byteBuffer.getShort(1484)) && (byteBuffer.getShort(2) == byteBuffer.getShort(1486))) {
|
||||
// ASCAT_HI or EXASCT_HI (...which are big and little endian, respectively)
|
||||
n=1476;
|
||||
scatNumber=82;
|
||||
recordLength=742;
|
||||
}
|
||||
else if((byteBuffer.getShort(0)== byteBuffer.getShort(764)) &&(byteBuffer.getShort(2)== byteBuffer.getShort(766))) {
|
||||
// ASCAT or EXASCT (...which are big and little endian, respectively)
|
||||
n=756;
|
||||
scatNumber=42;
|
||||
recordLength=382;
|
||||
}
|
||||
else if ((byteBuffer.getShort(0)== byteBuffer.getShort(1376)) &&(byteBuffer.getShort(2)== byteBuffer.getShort(1378))) {
|
||||
// QUIKSCAT -OR- OSCAT_HI (...which are big and little endian, respectively)
|
||||
n=1368;
|
||||
scatNumber = 76;
|
||||
recordLength =688;
|
||||
}
|
||||
else if ((byteBuffer.getShort(0) == byteBuffer.getShort(656)) && (byteBuffer.getShort(2) == byteBuffer.getShort(658))) {
|
||||
// OSCAT
|
||||
n=648;
|
||||
scatNumber = 36;
|
||||
recordLength = 328;
|
||||
}
|
||||
else if ((byteBuffer.getShort(0) == byteBuffer.getShort(2744)) && (byteBuffer.getShort(2) == byteBuffer.getShort(2746))) {
|
||||
// QUIKSCAT_HI
|
||||
n=2736;
|
||||
recordLength = 1372;
|
||||
scatNumber = 152;
|
||||
}
|
||||
else if((byteBuffer.getShort(56)== byteBuffer.getShort(1486)) &&(byteBuffer.getShort(58)== byteBuffer.getShort(1488))){
|
||||
// WSAT
|
||||
n=1422;
|
||||
scatNumber=79;
|
||||
recordLength=715;
|
||||
//TODO: Review this temporary fix by BH to see if a broader refactor might be better.
|
||||
// For WindSat -- which has a 56-byte header once per file, remove it from the
|
||||
// message array here, so we don't have to mess with it separately later.
|
||||
tempLength=message.length - 56;
|
||||
byte[] xmessage = new byte[tempLength];
|
||||
for (int i = 0; i<tempLength; i++) {
|
||||
xmessage[i] = message[i+56];
|
||||
public NcscatProcessing() {
|
||||
}
|
||||
|
||||
public byte[] separate(byte[] data) {
|
||||
doSeparate(data);
|
||||
try {
|
||||
if (newMessage == null) {
|
||||
return (byte[]) null;
|
||||
} else {
|
||||
byte[] tempBytes = listByteTobyteArray(newMessage);
|
||||
return tempBytes;
|
||||
}
|
||||
message = xmessage;
|
||||
byteBuffer = null;
|
||||
byteBuffer = ByteBuffer.allocate(tempLength);
|
||||
byteBuffer.put(message,0,tempLength);
|
||||
/* Original code as follows...
|
||||
byteBuffer = null;
|
||||
tempLength=message.length -56;
|
||||
byteBuffer = ByteBuffer.allocate(tempLength);
|
||||
byteBuffer.put(message,56,tempLength);
|
||||
*/
|
||||
//END of temporary fix by BH - Part 1 (compare Part 4)
|
||||
}
|
||||
|
||||
//TODO: Review this temporary fix by BH to see if a broader refactor might be better.
|
||||
// Endianess correction must be applied to the 4-short date/time field on each
|
||||
// line. Here we use set the ByteOrder of the byteBuffer, so that the 4
|
||||
// getShort(...) calls below will do the byte-flipping for us. We also
|
||||
// remember byteOrder for a bit later... (Part 3)
|
||||
//
|
||||
ByteOrder byteOrder;
|
||||
if ( (n == 1422) || // WSAT
|
||||
((n == 1368) && "oscat".equalsIgnoreCase(getInputFileName())) || // OSCAT_HI
|
||||
"ascatx".equalsIgnoreCase(getInputFileName()) ) { // EXASCT or EXASCT_HI
|
||||
byteOrder = ByteOrder.LITTLE_ENDIAN;
|
||||
}
|
||||
else {
|
||||
byteOrder = ByteOrder.BIG_ENDIAN;
|
||||
}
|
||||
|
||||
byteBuffer.order(byteOrder);
|
||||
//END of temporary fix by BH - Part 2 (new code added only)
|
||||
|
||||
try {
|
||||
if(message!=null){
|
||||
int dNcscatMult =0;
|
||||
doubleNcscat = scatNumber*2;
|
||||
scatXLen =doubleNcscat*9+8;
|
||||
while (ji < tempLength) {
|
||||
day = byteBuffer.getShort(ji) ;
|
||||
hour= byteBuffer.getShort(ji+2);
|
||||
min = byteBuffer.getShort(ji+4);
|
||||
sec = byteBuffer.getShort(ji+6);
|
||||
|
||||
if (day<0) break;
|
||||
|
||||
if(ji<8){
|
||||
//stTime = endTime;
|
||||
startTime.set(Calendar.DAY_OF_YEAR, day);
|
||||
startTime.set(Calendar.HOUR_OF_DAY, hour);
|
||||
startTime.set(Calendar.MINUTE, min);
|
||||
startTime.set(Calendar.SECOND, sec);
|
||||
}
|
||||
//else{
|
||||
endTime.set(Calendar.DAY_OF_YEAR, day);
|
||||
endTime.set(Calendar.HOUR_OF_DAY, hour);
|
||||
endTime.set(Calendar.MINUTE, min);
|
||||
endTime.set(Calendar.SECOND, sec);
|
||||
//}
|
||||
|
||||
ji=ji+scatXLen;
|
||||
|
||||
}//for while
|
||||
|
||||
newMessage= new ArrayList<Byte>(tempLength);
|
||||
|
||||
while(bitNum<tempLength){
|
||||
int consBitNum = bitNum;
|
||||
while (bitNum<consBitNum+8)
|
||||
{
|
||||
//TODO: Review this temporary fix by BH to see if a broader refactor might be better.
|
||||
// Here we again apply endianess correction to the 4-short date/time field on each
|
||||
// line. Above (via the ByteBuffer) was just for determining startTime and endTime
|
||||
// of the entire data set. Here we do it again as the 'message' array is moved to
|
||||
// newMessage (ArrayList) for later return and eventual writing to the HDF5 data
|
||||
// for each scan row. Note that the byte-swapping was already done below for the
|
||||
// data fields in each row following the leading date/time (in the process of
|
||||
// regrouping the data so data for each point is together); here we do it for the
|
||||
// date as well (where no other regrouping is required).
|
||||
//
|
||||
int offsetInDate = bitNum - consBitNum; // 0 thru 7
|
||||
if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
|
||||
// need to flip the 2 bytes of each short; map 0 1 2 3 4 5 6 7 to 1 0 3 2 5 4 7 6, respectively
|
||||
offsetInDate = offsetInDate/2*2+(1-offsetInDate%2);
|
||||
}
|
||||
newMessage.add((Byte)message[consBitNum+offsetInDate]);
|
||||
/* Original code as follows...
|
||||
newMessage.add((Byte)message[bitNum]);
|
||||
*/
|
||||
//END of temporary fix by BH - Part 3
|
||||
bitNum++;
|
||||
}//date field 8 bytes
|
||||
consBitNum = bitNum;
|
||||
while((scatXLen*dNcscatMult+7)<=bitNum && bitNum<(scatXLen*(dNcscatMult+1))){
|
||||
int calc=0;
|
||||
for (int qNoIndex =0; qNoIndex<doubleNcscat;qNoIndex++){
|
||||
for(int rou=0;rou<=8;rou++){
|
||||
|
||||
if(bitNum<tempLength){
|
||||
calc=consBitNum+doubleNcscat*rou+qNoIndex;
|
||||
//TODO: Review this temporary fix by BH to see if a broader refactor might be better.
|
||||
// Problem with the following is it applies the 56-byte bias (for WindSat) to the
|
||||
// address to copy from, but for the date transfer code to work above, bitNum
|
||||
// must already have had this bias applied (fix above moved it), and so consBitNum
|
||||
// -- the base address for this row of data, after the date field -- must also
|
||||
// have already reflected this correction. (Note that the 56-byte header is once
|
||||
// per file, rather than once per row.)
|
||||
/* Original code [removed] as follows...
|
||||
if(recordLength==715){
|
||||
calc=calc+56;
|
||||
}
|
||||
*/
|
||||
//END of temporary fix by BH - Part 4 (compare Part 1)
|
||||
if(byteOrder == ByteOrder.LITTLE_ENDIAN) {// swap the bytes
|
||||
newMessage.add(message[calc+1]);
|
||||
bitNum++;
|
||||
newMessage.add(message[calc]);//since 2 bytes form a short
|
||||
bitNum++;
|
||||
}
|
||||
else{
|
||||
newMessage.add(message[calc]);
|
||||
bitNum++;
|
||||
newMessage.add(message[calc+1]);//since 2 bytes form a short
|
||||
bitNum++;
|
||||
}
|
||||
|
||||
}//end of if
|
||||
|
||||
}//end of for
|
||||
qNoIndex++;
|
||||
}
|
||||
dNcscatMult++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}//if message is not null
|
||||
}// end of try block
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("No valid records found!");
|
||||
}
|
||||
theLogger.warn("No valid records found!");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} catch (NoSuchElementException e) {
|
||||
return (byte[]) null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* processHDF5Data -- SHOULD NOT BE USED IN PRESENT FORM
|
||||
* Please see NcscatResource.processHDF5Data(...)
|
||||
* @param message
|
||||
* separate bulletins
|
||||
*/
|
||||
private void doSeparate(byte[] message) {
|
||||
|
||||
ByteBuffer byteBuffer = ByteBuffer.allocate(message.length);
|
||||
byteBuffer.put(message, 0, message.length);
|
||||
|
||||
int tempLength = message.length;
|
||||
|
||||
startTime = Calendar.getInstance();
|
||||
startTime.setLenient(false); // guard against wild values
|
||||
startTime.set(Calendar.MILLISECOND, 0);
|
||||
endTime = Calendar.getInstance();
|
||||
endTime.setLenient(false); // guard against wild values
|
||||
endTime.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
// Determine type of data (that is, which satellite and resolution)
|
||||
// by examining it for unique consistency with known characteristics
|
||||
|
||||
NcscatMode matchedMode = NcscatMode.UNKNOWN;
|
||||
for (NcscatMode mode : NcscatMode.values()) {
|
||||
if (mode.consistentWith(byteBuffer)) {
|
||||
matchedMode = mode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchedMode == NcscatMode.UNKNOWN) {
|
||||
// TODO: Log error/warning -- and quit?
|
||||
}
|
||||
|
||||
ncscatMode = matchedMode;
|
||||
|
||||
// Set for historical compatibility...
|
||||
scatNumber = ncscatMode.getPointsPerRow();
|
||||
// assert ncscatMode.getBytesPerRow() % 2 == 0;
|
||||
recordLength = ncscatMode.getBytesPerRow() / 2;
|
||||
|
||||
if (ncscatMode.getFileHeaderLength() > 0) {
|
||||
// If there is a file header (separate from per-row headers), remove
|
||||
// it from the message array here, so we don't have to mess with it
|
||||
// separately later.
|
||||
tempLength = message.length - ncscatMode.getFileHeaderLength();
|
||||
byte[] xmessage = new byte[tempLength];
|
||||
for (int i = 0; i < tempLength; i++) {
|
||||
xmessage[i] = message[i + ncscatMode.getFileHeaderLength()];
|
||||
}
|
||||
message = xmessage;
|
||||
byteBuffer.clear();
|
||||
byteBuffer = null;
|
||||
byteBuffer = ByteBuffer.allocate(tempLength);
|
||||
byteBuffer.put(message, 0, tempLength);
|
||||
}
|
||||
|
||||
// Endianess correction must be applied to the 4-short date/time field
|
||||
// on each line. Here we set the ByteOrder of the byteBuffer, so
|
||||
// that the 4 getShort(...) calls below will do the byte-flipping for
|
||||
// us.
|
||||
//
|
||||
ByteOrder byteOrder = ncscatMode.getByteOrder();
|
||||
byteBuffer.order(byteOrder);
|
||||
|
||||
try {
|
||||
if (message != null) {
|
||||
int ji = 0;
|
||||
int dNcscatMult = 0;
|
||||
int doubleNcscat = scatNumber * 2;
|
||||
int scatXLen = doubleNcscat * 9 + 8;
|
||||
int byteNum = 0;
|
||||
|
||||
// Make a pass through all rows in file, just to determine
|
||||
// earliest and latest times
|
||||
int day, hour, min, sec;
|
||||
while (ji < tempLength) {
|
||||
day = byteBuffer.getShort(ji);
|
||||
hour = byteBuffer.getShort(ji + 2);
|
||||
min = byteBuffer.getShort(ji + 4);
|
||||
sec = byteBuffer.getShort(ji + 6);
|
||||
|
||||
if (day < 1 || day > 366 || hour < 0 || hour > 23
|
||||
|| min < 0 || min > 59 || sec < 0 || sec > 60) {
|
||||
// TODO log error?
|
||||
break;// TODO continue?
|
||||
}
|
||||
|
||||
if (ji < 8) { // first row
|
||||
startTime.set(Calendar.DAY_OF_YEAR, day);
|
||||
startTime.set(Calendar.HOUR_OF_DAY, hour);
|
||||
startTime.set(Calendar.MINUTE, min);
|
||||
startTime.set(Calendar.SECOND, sec);
|
||||
}
|
||||
|
||||
// Don't know ahead of time which row will be last
|
||||
// so set each time; last one will remain endTime
|
||||
endTime.set(Calendar.DAY_OF_YEAR, day);
|
||||
endTime.set(Calendar.HOUR_OF_DAY, hour);
|
||||
endTime.set(Calendar.MINUTE, min);
|
||||
endTime.set(Calendar.SECOND, sec);
|
||||
|
||||
ji = ji + scatXLen;
|
||||
|
||||
}// for while
|
||||
|
||||
// Time bounds scan done; now go back through the row data and
|
||||
// rearrange as needed.
|
||||
|
||||
newMessage = new ArrayList<Byte>(tempLength);
|
||||
|
||||
while (byteNum < tempLength) {
|
||||
int consByteNum = byteNum;
|
||||
while (byteNum < consByteNum + 8) {
|
||||
|
||||
// Here we again apply endianess correction to the
|
||||
// 4-short date/time field on each row. Above (via the
|
||||
// ByteBuffer) was just for determining startTime and
|
||||
// endTime of the entire data set. Here we do it again
|
||||
// as the 'message' array is moved to newMessage
|
||||
// (ArrayList) for later return and eventual writing to
|
||||
// the HDF5 data for each scan row. Note that the
|
||||
// byte-swapping is done below for the data fields in
|
||||
// each row following the leading date/time (in the
|
||||
// process of regrouping the data so data for each point
|
||||
// is together); here we do it for the date as well
|
||||
// (where no other regrouping is required).
|
||||
//
|
||||
int offsetInDate = byteNum - consByteNum; // 0 thru 7
|
||||
if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
|
||||
// need to flip the 2 bytes of each short; map 0 1 2
|
||||
// 3 4 5 6 7 to 1 0 3 2 5 4 7 6, respectively
|
||||
offsetInDate = offsetInDate / 2 * 2
|
||||
+ (1 - offsetInDate % 2);
|
||||
}
|
||||
newMessage.add((Byte) message[consByteNum
|
||||
+ offsetInDate]);
|
||||
byteNum++;
|
||||
}// date field 8 bytes
|
||||
|
||||
// Done with row header (date/time); now start on the data
|
||||
// for points in that row. (consByteNum is index of first
|
||||
// byte of such data .)
|
||||
|
||||
consByteNum = byteNum;
|
||||
|
||||
// In the incoming data for a row, all values for each
|
||||
// single parameter are grouped together (for all points in
|
||||
// the row). The following code "shuffles" things so that
|
||||
// all values for a single point are grouped together
|
||||
// (that is, all parameters for a given point). In the
|
||||
// process, proper endianess order is set for the two bytes
|
||||
// making up each data value.
|
||||
|
||||
while ((scatXLen * dNcscatMult + 7) <= byteNum
|
||||
&& byteNum < (scatXLen * (dNcscatMult + 1))) {
|
||||
int calc = 0;
|
||||
for (int qNoIndex = 0; qNoIndex < doubleNcscat; qNoIndex++) {
|
||||
for (int rou = 0; rou <= 8; rou++) {
|
||||
if (byteNum < tempLength) {
|
||||
calc = consByteNum + doubleNcscat * rou
|
||||
+ qNoIndex;
|
||||
if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
|
||||
// swap the two bytes making up the
|
||||
// short
|
||||
newMessage.add(message[calc + 1]);
|
||||
byteNum++;
|
||||
newMessage.add(message[calc]);
|
||||
byteNum++;
|
||||
} else { // ByteOrder.BIG_ENDIAN
|
||||
// preserve order of the two bytes
|
||||
// making up the short
|
||||
newMessage.add(message[calc]);
|
||||
byteNum++;
|
||||
newMessage.add(message[calc + 1]);
|
||||
byteNum++;
|
||||
}
|
||||
} // end of if
|
||||
} // end of for rou
|
||||
qNoIndex++;
|
||||
} // end of for qNoIndex
|
||||
dNcscatMult++;
|
||||
} // end of while
|
||||
|
||||
} // while (each row)
|
||||
|
||||
}// if message is not null
|
||||
}// end of try block
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("No valid records found!");
|
||||
}
|
||||
theLogger.warn("No valid records found!");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
public NcscatMode getNcscatMode() {
|
||||
return ncscatMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* processHDF5Data -- SHOULD NOT BE USED IN PRESENT FORM Please see
|
||||
* NcscatResource.processHDF5Data(...)
|
||||
*
|
||||
* @return List<NcscatPoint>
|
||||
*
|
||||
* @deprecated Please see NcscatResource.processHDF5Data(...)
|
||||
*/
|
||||
@Deprecated
|
||||
public List<NcscatPoint> processHDF5Data(byte[] hdf5Msg) {
|
||||
int ji = 0, bitNum = 0;
|
||||
int day, hour, min, sec;
|
||||
item = new ArrayList<NcscatPoint>();
|
||||
// TODO - Caution! Separate startTime Calendar object needs to be
|
||||
// allocated for each point row, since will be shared by all points
|
||||
// in that row. See below.
|
||||
startTime = Calendar.getInstance();
|
||||
ByteBuffer byteBuffer = null;
|
||||
byteBuffer = ByteBuffer.allocate(hdf5Msg.length);
|
||||
byteBuffer.put(hdf5Msg, 0, hdf5Msg.length);
|
||||
|
||||
while (ji < hdf5Msg.length) {
|
||||
|
||||
public List<NcscatPoint> processHDF5Data(byte[] hdf5Msg){
|
||||
int ji=0, bitNum=0;
|
||||
int day,hour,min,sec;
|
||||
item= new ArrayList<NcscatPoint>();
|
||||
// TODO - Caution! Separate startTime Calendar object needs to be allocated
|
||||
// for each point row, since will be shared by all points
|
||||
// in that row. See below.
|
||||
startTime = Calendar.getInstance();
|
||||
ByteBuffer byteBuffer = null;
|
||||
byteBuffer = ByteBuffer.allocate(hdf5Msg.length);
|
||||
byteBuffer.put(hdf5Msg,0,hdf5Msg.length);
|
||||
day = byteBuffer.getShort(bitNum);
|
||||
hour = byteBuffer.getShort(bitNum + 2);
|
||||
min = byteBuffer.getShort(bitNum + 4);
|
||||
sec = byteBuffer.getShort(bitNum + 6);
|
||||
ji = ji + 8;
|
||||
bitNum = bitNum + 8;
|
||||
// TODO - Caution! Need to allocate new startTime here...
|
||||
startTime.set(Calendar.DAY_OF_YEAR, day);
|
||||
startTime.set(Calendar.HOUR_OF_DAY, hour);
|
||||
startTime.set(Calendar.MINUTE, min);
|
||||
startTime.set(Calendar.SECOND, sec);
|
||||
for (int j = ji; j < ji + scatNumber * 18
|
||||
&& bitNum < hdf5Msg.length; j = j + 18) {
|
||||
sPointObj = new NcscatPoint();
|
||||
// TODO - continued - otherwise all points in all rows get same
|
||||
// time here
|
||||
sPointObj.setStTime(startTime);
|
||||
sPointObj.setLat(byteBuffer.getShort(j));
|
||||
sPointObj.setLon(byteBuffer.getShort(j + 2));
|
||||
sPointObj.setIql(byteBuffer.getShort(j + 4));
|
||||
sPointObj.setIsp(byteBuffer.getShort(j + 6));
|
||||
sPointObj.setIdr(byteBuffer.getShort(j + 8));
|
||||
sPointObj.setIrn(byteBuffer.getShort(j + 10));
|
||||
sPointObj.setIb1(byteBuffer.getShort(j + 12));
|
||||
sPointObj.setIb2(byteBuffer.getShort(j + 14));
|
||||
sPointObj.setIb3(byteBuffer.getShort(j + 16));
|
||||
bitNum = bitNum + 18;
|
||||
item.add(sPointObj);
|
||||
|
||||
while ( ji < hdf5Msg.length) {
|
||||
}// for
|
||||
|
||||
day = byteBuffer.getShort(bitNum) ;
|
||||
hour= byteBuffer.getShort(bitNum+2);
|
||||
min = byteBuffer.getShort(bitNum+4);
|
||||
sec = byteBuffer.getShort(bitNum+6);
|
||||
ji=ji+8;
|
||||
bitNum=bitNum+8;
|
||||
// TODO - Caution! Need to allocate new startTime here...
|
||||
startTime.set(Calendar.DAY_OF_YEAR, day);
|
||||
startTime.set(Calendar.HOUR_OF_DAY, hour);
|
||||
startTime.set(Calendar.MINUTE, min);
|
||||
startTime.set(Calendar.SECOND, sec);
|
||||
for(int j=ji;j<ji+scatNumber*18 && bitNum <hdf5Msg.length;j=j+18){
|
||||
sPointObj = new NcscatPoint();
|
||||
// TODO - continued - otherwise all points in all rows get same time here
|
||||
sPointObj.setStTime(startTime);
|
||||
sPointObj.setLat(byteBuffer.getShort(j));
|
||||
sPointObj.setLon(byteBuffer.getShort(j+2));
|
||||
sPointObj.setIql(byteBuffer.getShort(j+4));
|
||||
sPointObj.setIsp(byteBuffer.getShort(j+6));
|
||||
sPointObj.setIdr(byteBuffer.getShort(j+8));
|
||||
sPointObj.setIrn(byteBuffer.getShort(j+10));
|
||||
sPointObj.setIb1(byteBuffer.getShort(j+12));
|
||||
sPointObj.setIb2(byteBuffer.getShort(j+14));
|
||||
sPointObj.setIb3(byteBuffer.getShort(j+16));
|
||||
bitNum=bitNum+18;
|
||||
item.add(sPointObj);
|
||||
ji = bitNum;
|
||||
|
||||
}//for
|
||||
}// for while
|
||||
|
||||
ji=bitNum;
|
||||
return item;
|
||||
|
||||
}//for while
|
||||
}
|
||||
|
||||
return item;
|
||||
public Calendar getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
}
|
||||
public void setStartTime(Calendar startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public Calendar getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
public Calendar getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
|
||||
public void setEndTime(Calendar endTime) {
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
public void setStartTime(Calendar startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
private static byte[] listByteTobyteArray(List<Byte> temp) {
|
||||
byte[] byteArray = new byte[temp.size()];
|
||||
int jkl = 0;
|
||||
for (Byte current : temp) {
|
||||
byteArray[jkl] = current;
|
||||
jkl++;
|
||||
}
|
||||
|
||||
public Calendar getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
public void setEndTime(Calendar endTime) {
|
||||
this.endTime = endTime;
|
||||
}
|
||||
return byteArray;
|
||||
}
|
||||
|
||||
private static byte[] listByteTobyteArray(List<Byte> temp) {
|
||||
byte[] byteArray = new byte[temp.size()];
|
||||
int jkl=0;
|
||||
for(Byte current:temp){
|
||||
byteArray[jkl] =current;
|
||||
jkl++;
|
||||
}
|
||||
public int getRecordLength() {
|
||||
return recordLength;
|
||||
}
|
||||
|
||||
return byteArray;
|
||||
}
|
||||
public void setRecordLength(int recordLength) {
|
||||
this.recordLength = recordLength;
|
||||
}
|
||||
|
||||
public static int getRecordLength() {
|
||||
return recordLength;
|
||||
}
|
||||
public String getInputFileName() {
|
||||
return inputFileName;
|
||||
}
|
||||
|
||||
public static void setRecordLength(int recordLength) {
|
||||
NcscatProcessing.recordLength = recordLength;
|
||||
}
|
||||
public String getInputFileName() {
|
||||
return inputFileName;
|
||||
}
|
||||
|
||||
public void setInputFileName(String inputFileName) {
|
||||
this.inputFileName = inputFileName;
|
||||
}
|
||||
public void setInputFileName(String inputFileName) {
|
||||
this.inputFileName = inputFileName;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package gov.noaa.nws.ncep.viz.rsc.ncscat.rsc;
|
||||
|
||||
import gov.noaa.nws.ncep.common.dataplugin.ncscat.NcscatMode;
|
||||
import gov.noaa.nws.ncep.viz.common.ui.color.ColorButtonSelector;
|
||||
import gov.noaa.nws.ncep.viz.resources.INatlCntrsResourceData;
|
||||
import gov.noaa.nws.ncep.viz.resources.attributes.AbstractEditResourceAttrsDialog;
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package gov.noaa.nws.ncep.viz.rsc.ncscat.rsc;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* NcscatMode - Enum class to centralize and encapsulate all the things that
|
||||
* vary among different satellite and data feed types.
|
||||
*
|
||||
* //TODO: Consider moving this information entirely to the bundle and/or
|
||||
* preferences (.xml/.prm) files, so the Java code can be completely agnostic
|
||||
* about satellite data types; would allow extended 'configurability', at the
|
||||
* expense of slightly longer bundle/preference files...
|
||||
*
|
||||
* This code has been developed by the SIB for use in the AWIPS2 system.
|
||||
*
|
||||
* <pre>
|
||||
* SOFTWARE HISTORY
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* 02 Jun 2010 235B B. Hebbard Initial creation.
|
||||
* 03 Feb 2011 235E B. Hebbard Add support for ambiguity variants.
|
||||
* 16 Aug 2012 B. Hebbard Add OSCAT / OSCAT_HI
|
||||
* 11 Apr 2014 1128 B. Hebbard Add longitudeCoding field; change wind sense from boolean to enum.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bhebbard
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public enum NcscatMode {
|
||||
|
||||
// @formatter:off
|
||||
QUIKSCAT ( 76, WindDirectionSense.METEOROLOGICAL, LongitudeCoding.UNSIGNED, ByteOrder.BIG_ENDIAN ),
|
||||
QUIKSCAT_HI ( 152, WindDirectionSense.METEOROLOGICAL, LongitudeCoding.UNSIGNED, ByteOrder.BIG_ENDIAN ),
|
||||
ASCAT ( 42, WindDirectionSense.OCEANOGRAPHIC, LongitudeCoding.UNSIGNED, ByteOrder.BIG_ENDIAN ),
|
||||
ASCAT_HI ( 82, WindDirectionSense.OCEANOGRAPHIC, LongitudeCoding.UNSIGNED, ByteOrder.BIG_ENDIAN ),
|
||||
EXASCT ( 42, WindDirectionSense.OCEANOGRAPHIC, LongitudeCoding.UNSIGNED, ByteOrder.LITTLE_ENDIAN ),
|
||||
EXASCT_HI ( 82, WindDirectionSense.OCEANOGRAPHIC, LongitudeCoding.UNSIGNED, ByteOrder.LITTLE_ENDIAN ),
|
||||
OSCAT ( 36, WindDirectionSense.METEOROLOGICAL, LongitudeCoding.UNSIGNED, ByteOrder.BIG_ENDIAN ),
|
||||
OSCAT_HI ( 76, WindDirectionSense.METEOROLOGICAL, LongitudeCoding.UNSIGNED, ByteOrder.LITTLE_ENDIAN ),
|
||||
WSCAT ( 79, WindDirectionSense.METEOROLOGICAL, LongitudeCoding.SIGNED, ByteOrder.LITTLE_ENDIAN ),
|
||||
UNKNOWN ( 76, WindDirectionSense.METEOROLOGICAL, LongitudeCoding.UNSIGNED, ByteOrder.BIG_ENDIAN );
|
||||
// @formatter:on
|
||||
|
||||
private int pointsPerRow; // number of Wind Vector Cell in each scan row
|
||||
// across satellite track
|
||||
|
||||
private WindDirectionSense windDirectionSense; // is the numeric wind
|
||||
// direction the "from"
|
||||
// (METEOROLOGICAL)
|
||||
// direction, or the "to"
|
||||
// (OCEANOGRAPHIC) direction?
|
||||
|
||||
private LongitudeCoding longitudeCoding; // is the two-byte value a SIGNED
|
||||
// (-18000 -- +18000) or UNSIGNED
|
||||
// (0 -- 36000) representation of
|
||||
// the (scaled by 100) longitude
|
||||
// east of Greenwich?
|
||||
|
||||
private ByteOrder byteOrder; // endianess of data in the byte stream
|
||||
|
||||
// TODO: could add more here, to simplify (switch) code with more table
|
||||
// driven logic. But see above note about .xml/.prm...
|
||||
|
||||
// Constructor
|
||||
NcscatMode(int pointsPerRow, WindDirectionSense windDirectionSense,
|
||||
LongitudeCoding longitudeCoding, ByteOrder byteOrder) {
|
||||
this.pointsPerRow = pointsPerRow;
|
||||
this.windDirectionSense = windDirectionSense;
|
||||
this.longitudeCoding = longitudeCoding;
|
||||
this.byteOrder = byteOrder;
|
||||
}
|
||||
|
||||
public int getPointsPerRow() {
|
||||
return pointsPerRow;
|
||||
}
|
||||
|
||||
public WindDirectionSense getWindDirectionSense() {
|
||||
return windDirectionSense;
|
||||
}
|
||||
|
||||
public LongitudeCoding getLongitudeCoding() {
|
||||
return longitudeCoding;
|
||||
}
|
||||
|
||||
public ByteOrder getByteOrder() {
|
||||
return byteOrder;
|
||||
}
|
||||
|
||||
public static NcscatMode stringToMode(String name) {
|
||||
// Given a string, return the corresponding enum
|
||||
NcscatMode returnValue = null;
|
||||
name = name.toUpperCase();
|
||||
name = name.replaceAll("-", "_");
|
||||
// TODO: Remove ambiguity number??
|
||||
try {
|
||||
returnValue = valueOf(name);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// TODO: Signal unrecognized Ncscat mode string
|
||||
returnValue = UNKNOWN;
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
public enum WindDirectionSense { // numeric direction value gives...
|
||||
METEOROLOGICAL, // degrees FROM which wind is blowing
|
||||
OCEANOGRAPHIC // degrees TO which wind is blowing
|
||||
}
|
||||
|
||||
public enum LongitudeCoding { // 2-byte wvc_lon (Wind Vector Cell -
|
||||
// longitude) field is (x0.01 deg)...
|
||||
SIGNED, // SIGNED short (-18000..+18000)
|
||||
UNSIGNED // UNSIGNED short (0..36000 east of Greenwich)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,10 @@
|
|||
package gov.noaa.nws.ncep.viz.rsc.ncscat.rsc;
|
||||
|
||||
import gov.noaa.nws.ncep.common.dataplugin.ncscat.NcscatMode;
|
||||
import gov.noaa.nws.ncep.common.dataplugin.ncscat.NcscatPoint;
|
||||
import gov.noaa.nws.ncep.common.dataplugin.ncscat.NcscatRecord;
|
||||
import gov.noaa.nws.ncep.common.dataplugin.ncscat.NcscatMode.LongitudeCoding;
|
||||
import gov.noaa.nws.ncep.common.dataplugin.ncscat.NcscatMode.WindDirectionSense;
|
||||
import gov.noaa.nws.ncep.gempak.parameters.colorbar.ColorBarOrientation;
|
||||
import gov.noaa.nws.ncep.ui.pgen.display.DisplayElementFactory;
|
||||
import gov.noaa.nws.ncep.ui.pgen.display.IDisplayable;
|
||||
|
@ -13,8 +16,6 @@ import gov.noaa.nws.ncep.viz.resources.AbstractNatlCntrsResource;
|
|||
import gov.noaa.nws.ncep.viz.resources.INatlCntrsResource;
|
||||
import gov.noaa.nws.ncep.viz.resources.colorBar.ColorBarResource;
|
||||
import gov.noaa.nws.ncep.viz.resources.colorBar.ColorBarResourceData;
|
||||
import gov.noaa.nws.ncep.viz.rsc.ncscat.rsc.NcscatMode.LongitudeCoding;
|
||||
import gov.noaa.nws.ncep.viz.rsc.ncscat.rsc.NcscatMode.WindDirectionSense;
|
||||
import gov.noaa.nws.ncep.viz.ui.display.ColorBar;
|
||||
import gov.noaa.nws.ncep.viz.ui.display.NCMapDescriptor;
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import gov.noaa.nws.ncep.viz.resources.AbstractNatlCntrsRequestableResourceData;
|
|||
import gov.noaa.nws.ncep.viz.resources.INatlCntrsResourceData;
|
||||
import gov.noaa.nws.ncep.viz.resources.attributes.RGBColorAdapter;
|
||||
import gov.noaa.nws.ncep.viz.ui.display.ColorBar;
|
||||
import gov.noaa.nws.ncep.common.dataplugin.ncscat.NcscatMode;
|
||||
import gov.noaa.nws.ncep.ui.pgen.display.IVector.VectorType;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
|
|
Loading…
Add table
Reference in a new issue