All Downloads are FREE. Search and download functionalities are using the official Maven repository.

decodes.decoder.LatLonFunction Maven / Gradle / Ivy

Go to download

A collection of software for aggregatting and processing environmental data such as from NOAA GOES satellites.

The newest version!
package decodes.decoder;

import ilex.util.Logger;
import ilex.util.TextUtil;
import ilex.var.Variable;

import java.io.File;
import java.io.FileReader;
import java.io.LineNumberReader;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import decodes.datasource.RawMessage;
import decodes.db.Constants;
import decodes.db.DataType;
import decodes.db.DecodesScript;
import decodes.util.DecodesSettings;

/**
 * This function parses ASCII latitude and longitude that are frequently
 * included at the end of messages, in the following format:
 * 
N35o48'31.80"W83o55'36.30"
* This function uses Java regular expressions to parse the data. * The only additional information it needs is how to map the labels that * occur in the message to sensor data types. *

* This is done in the first of the following ways that succeeds: *

    *
  • Look for an argument of the form
  • *
  • Look for a sensor with data type standard="label" and code that matches * the label in the message
  • *
  • Go through each sensor and try to find a data type equivalent to the * label that matches a data time assigned to the sensor
  • *
* After executing, the cursor is left after the last sensor block that was * successfully parsed. */ public class LatLonFunction extends DecodesFunction { public static final String module = "LatLon"; /** Pattern for a degrees minutes seconds, all inside capture groups */ public static final String degMinSec = "(\\d{1,3})o(\\d{1,2})'(\\d{1,2}\\.?\\d*)\""; /** * Pattern for a entire lat/lon. Capture groups are: *
    *
  • 0: entire block
  • *
  • 1: N or S
  • *
  • 2: latitude degrees
  • *
  • 3: latitude minutes
  • *
  • 4: latitude seconds
  • *
  • 5: E or W
  • *
  • 6: longitude degrees
  • *
  • 7: longitude minutes
  • *
  • 8: longitude seconds
  • *
*/ public static final String latLon = "^\\s*([NnSs])" + degMinSec + "([EeWw])" + degMinSec; private Pattern latLonPat = Pattern.compile(latLon); private boolean testMode = false; private int lineNumber = 1; // line number where first block starts int latSensorNum = -1; int lonSensorNum = -1; boolean storeInSite = false; public LatLonFunction() { } /** * Parse the passed message. * @param msg the message in a single string * @return the index after the final character that was parsed. */ public int parse(String msgData, DecodedMessage decmsg) { Matcher blockMatcher = latLonPat.matcher(msgData); boolean foundBlock = false; int endProcessingIdx = 0; if (blockMatcher.find()) { // Get the label, minute offset, minute index and sensor data foundBlock = true; trace("Sensor Block at (" + blockMatcher.start() + "," + blockMatcher.end() + "): " + "'" + blockMatcher.group(0) + "'"); endProcessingIdx = blockMatcher.end(); char ns = blockMatcher.group(1).charAt(0); int sign = (ns == 'S' || ns == 's') ? -1 : 1; double latitude = 0.0; int deg, min; double sec; try { deg = Integer.parseInt(blockMatcher.group(2)); min = Integer.parseInt(blockMatcher.group(3)); sec = Double.parseDouble(blockMatcher.group(4)); latitude = sign * (deg + (min/60.) + (sec/3600.)); } catch(NumberFormatException ex) { // shouldn't happen warning("Bad latitude '" + blockMatcher.group(0) + "': " + ex); } char ew = blockMatcher.group(5).charAt(0); sign = (ew == 'W' || ns == 'w') ? -1 : 1; double longitude = 0.0; try { deg = Integer.parseInt(blockMatcher.group(6)); min = Integer.parseInt(blockMatcher.group(7)); sec = Double.parseDouble(blockMatcher.group(8)); longitude = sign * (deg + (min/60.) + (sec/3600.)); } catch(NumberFormatException ex) { // shouldn't happen warning("Bad latitude '" + blockMatcher.group(0) + "': " + ex); } if (storeInSite) { } else if (decmsg != null && latSensorNum >= 0 && lonSensorNum >= 0) { decmsg.addSample(latSensorNum, new Variable(latitude), lineNumber); decmsg.addSample(lonSensorNum, new Variable(longitude), lineNumber); } else info("parsed '" + blockMatcher.group(0) + "' latitude=" + latitude + ", longitude=" + longitude); } // Finally eat any whitespace at the end. while(endProcessingIdx < msgData.length() && Character.isWhitespace(msgData.charAt(endProcessingIdx))) endProcessingIdx++; if(!foundBlock) { trace("No match found."); } return endProcessingIdx; } @Override public DecodesFunction makeCopy() { return new LatLonFunction(); } @Override public String getFuncName() { return module; } @Override public void execute(DataOperations dd, DecodedMessage decmsg) throws DecoderException { // Get from here to end of message into a String int startPos = dd.getBytePos(); lineNumber = dd.getCurrentLine(); StringBuilder sb = new StringBuilder(); while(dd.moreChars()) { sb.append((char)dd.curByte()); dd.forwardspace(); } String toParse = sb.toString(); trace("Processing '" + toParse + "'"); int finishIdx = parse(toParse, decmsg); dd.setBytePos(startPos + finishIdx); } private void trace(String s) { if (testMode) System.out.println(module + " " + s); else Logger.instance().debug3(module + " " + s); } private void info(String s) { if (testMode) System.out.println(module + " " + s); else Logger.instance().info(module + " " + s); } private void warning(String s) { if (testMode) System.out.println(module + " " + s); else Logger.instance().warning(module + " " + s); } /** * The argument contains a map of message sensor labels to DECODES sensor * numbers, separated by comma. *

* label=number [, label=number]* *

* where label is the label as it appears in the message and number is an integer * matching a DECODES sensor number. *

* The following additional arguments are processed: *

    *
  • processMOFF=true|false - use this to override the decodes.properties setting
  • *
*/ @Override public void setArguments(String argString, DecodesScript script) throws ScriptFormatException { argString = argString.trim(); if (argString.equalsIgnoreCase("site")) storeInSite = true; else if (argString.length() > 0) { int comma = argString.indexOf(','); if (comma == -1) throw new ScriptFormatException(module + " Bad argument '" + argString + "'. Expected the word 'site' or lat,lon sensor numbers."); try { latSensorNum = Integer.parseInt(argString.substring(0,comma)); lonSensorNum = Integer.parseInt(argString.substring(comma+1)); } catch(Exception ex) { throw new ScriptFormatException(module + " Bad argument '" + argString + "'. Expected lat and lon integers, separated by comma."); } } } public void setTestMode(boolean testMode) { this.testMode = testMode; } /** * Main method for test. Pass name of a file containing ascii self-describing * messages, one per line. * @param args single argument filename * @throws Exception */ public static void main(String[] args) throws Exception { File file = new File(args[0]); LineNumberReader lnr = new LineNumberReader( new FileReader(file)); String line; AsciiSelfDescFunction asdf = new AsciiSelfDescFunction(); LatLonFunction llf = new LatLonFunction(); asdf.setTestMode(true); llf.setTestMode(true); while((line = lnr.readLine()) != null) { System.out.println("============="); System.out.println(line); System.out.println(); RawMessage rawMsg = new RawMessage(line.getBytes()); rawMsg.setHeaderLength(37); DataOperations dataOps = new DataOperations(rawMsg); // If the high-data rate status byte is present, skip it. if ((char)dataOps.curByte() != ':') dataOps.forwardspace(); asdf.execute(dataOps, null); llf.execute(dataOps, null); System.out.println("Processed " + (dataOps.getBytePos()+rawMsg.getHeaderLength()) + " characters out of " + line.length() + "."); // int len = asdp.parse(line.substring(37), null); // System.out.println("Processed " + (len+37) + " characters out of " + line.length() + "."); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy