//
// TextAdapter.java
//
/*
VisAD system for interactive analysis and visualization of numerical
data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
package visad.data.text;
import java.io.IOException;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import visad.Set;
import java.net.URL;
import visad.*;
import visad.VisADException;
import visad.data.in.ArithProg;
import visad.util.DataUtility;
import java.util.regex.*;
/** this is an VisAD file adapter for comma-, tab- and blank-separated
* ASCII text file data. It will attempt to create a FlatField from
* the data and descriptions given in the file and/or the constructor.
*
* The text files contained delimited data. The delimiter is
* determined as follows: if the file has a well-known extension
* (.csv, .tsv, .bsv) then the delimiter is implied by the extension.
* In all other cases, the delimiter for the data (and for the
* "column labels") is determined by reading the first line and
* looking, in order, for a tab, comma, or blank. Which ever one
* is found first is taken as the delimiter.
*
* Two extra pieces of information are needed: the VisAD "MathType"
* which is specified as a string (e.g., (x,y)->(temperature))
* and may either be the first line of the file or passed in through
* one of the constructors.
*
* The second item are the "column labels" which contain the names
* of each field in the data. The names of all range components
* specified in the "MathType" must appear. The names of domain
* components are optional. The values in this string are separated
* by the delimiter, as defined above.
*
* See visad.data.text.README.text for more details.
*
* @author Tom Whittaker
*
*/
public class TextAdapter {
private static final String ATTR_COLSPAN = "colspan";
private static final String ATTR_VALUE = "value";
private static final String ATTR_OFFSET = "off";
private static final String ATTR_ERROR = "err";
private static final String ATTR_SCALE = "sca";
private static final String ATTR_POSITION ="pos";
private static final String ATTR_FORMAT = "fmt";
private static final String ATTR_TIMEZONE = "tz";
private static final String ATTR_UNIT= "unit";
private static final String ATTR_MISSING = "mis";
private static final String ATTR_INTERVAL = "int";
private static final String COMMA = ",";
private static final String SEMICOLON = ";";
private static final String TAB = "\t";
private static final String BLANK = " ";
private static final String BLANK_DELIM = "\\s+";
private FlatField ff = null;
private Field field = null;
private boolean debug = false;
private String DELIM;
private boolean DOQUOTE = true;
private boolean GOTTIME = false;
HeaderInfo []infos;
double[] rangeErrorEstimates;
Unit[] rangeUnits;
Set[] rangeSets;
double[] domainErrorEstimates;
Unit[] domainUnits;
int[][] hdrColumns;
int[][] values_to_index;
private Hashtable properties;
private boolean onlyReadOneLine = false;
private Pattern skipPattern;
/**If this is defined then when processing each tuple pass the processor the tuple
and do not try to create the field */
private StreamProcessor streamProcessor;
/** Create a VisAD FlatField from a local Text (comma-, tab- or
* blank-separated values) ASCII file
* @param filename name of local file.
* @exception IOException if there was a problem reading the file.
* @exception VisADException if an unexpected problem occurs.
*/
public TextAdapter(String filename) throws IOException, VisADException {
this(filename, null, null);
}
/** Create a VisAD FlatField from a local Text (comma-, tab- or
* blank-separated values) ASCII file
* @param filename name of local file.
* @param map the VisAD "MathType" as a string defining the FlatField
* @param params the list of parameters used to define what columns
* of the text file correspond to what MathType parameters.
* @exception IOException if there was a problem reading the file.
* @exception VisADException if an unexpected problem occurs.
*/
public TextAdapter(String filename, String map, String params)
throws IOException, VisADException {
InputStream is = new FileInputStream(filename);
DELIM = getDelimiter(filename);
readit(is, map, params);
}
/** Create a VisAD FlatField from a remote Text (comma-, tab- or
* blank-separated values) ASCII file
*
* @param url File URL.
* @exception IOException if there was a problem reading the file.
* @exception VisADException if an unexpected problem occurs.
*/
public TextAdapter(URL url) throws IOException, VisADException {
this(url, null, null);
}
/** Create a VisAD FlatField from a local Text (comma-, tab- or
* blank-separated values) ASCII file
* @param url File URL.
* @param map the VisAD "MathType" as a string defining the FlatField
* @param params the list of parameters used to define what columns
* of the text file correspond to what MathType parameters.
* @exception IOException if there was a problem reading the file.
* @exception VisADException if an unexpected problem occurs.
*/
public TextAdapter(URL url, String map, String params)
throws IOException, VisADException {
DELIM = getDelimiter(url.getFile());
InputStream is = url.openStream();
readit(is, map, params);
}
/** Create a VisAD FlatField from a local Text (comma-, tab- or
* blank-separated values) ASCII file
* @param inputStream The input stream to read from
* @param delimiter the delimiter
* @param map the VisAD "MathType" as a string defining the FlatField
* @param params the list of parameters used to define what columns
* of the text file correspond to what MathType parameters.
* @exception IOException if there was a problem reading the file.
* @exception VisADException if an unexpected problem occurs.
*/
public TextAdapter(InputStream inputStream, String delimiter, String map, String params)
throws IOException, VisADException {
this(inputStream, delimiter, map,params,false);
}
/** Create a VisAD FlatField from a local Text (comma-, tab- or
* blank-separated values) ASCII file
* @param inputStream The input stream to read from
* @param delimiter the delimiter
* @param map the VisAD "MathType" as a string defining the FlatField
* @param params the list of parameters used to define what columns
* of the text file correspond to what MathType parameters.
* @param onlyReadOneLine If true then only read one line of data. This is used so client code can
* read the meta data.
* @exception IOException if there was a problem reading the file.
* @exception VisADException if an unexpected problem occurs.
*/
public TextAdapter(InputStream inputStream, String delimiter, String map, String params,boolean onlyReadOneLine)
throws IOException, VisADException {
this(inputStream, delimiter, map, params, null, onlyReadOneLine);
}
/** Create a VisAD FlatField from a local Text (comma-, tab- or
* blank-separated values) ASCII file
* @param inputStream The input stream to read from
* @param delimiter the delimiter
* @param map the VisAD "MathType" as a string defining the FlatField
* @param params the list of parameters used to define what columns
* of the text file correspond to what MathType parameters.
* @param properties properties
* @param onlyReadOneLine If true then only read one line of data. This is used so client code can
* read the meta data.
* @exception IOException if there was a problem reading the file.
* @exception VisADException if an unexpected problem occurs.
*/
public TextAdapter(InputStream inputStream, String delimiter, String map, String params,Hashtable properties, boolean onlyReadOneLine)
throws IOException, VisADException {
this(inputStream, delimiter, map, params, properties, onlyReadOneLine, null);
}
/** Create a VisAD FlatField from a local Text (comma-, tab- or
* blank-separated values) ASCII file
* @param inputStream The input stream to read from
* @param delimiter the delimiter
* @param map the VisAD "MathType" as a string defining the FlatField
* @param params the list of parameters used to define what columns
* of the text file correspond to what MathType parameters.
* @param properties properties
* @param onlyReadOneLine If true then only read one line of data. This is used so client code can
* read the meta data.
* @param skipPatternString if non-null then skip any line that matches this pattern
* @exception IOException if there was a problem reading the file.
* @exception VisADException if an unexpected problem occurs.
*/
public TextAdapter(InputStream inputStream, String delimiter, String map, String params,Hashtable properties, boolean onlyReadOneLine,String skipPatternString)
throws IOException, VisADException {
this(inputStream, delimiter, map, params, properties, onlyReadOneLine, skipPatternString,null);
}
/** Create a VisAD FlatField from a local Text (comma-, tab- or
* blank-separated values) ASCII file
* @param inputStream The input stream to read from
* @param delimiter the delimiter
* @param map the VisAD "MathType" as a string defining the FlatField
* @param params the list of parameters used to define what columns
* of the text file correspond to what MathType parameters.
* @param properties properties
* @param onlyReadOneLine If true then only read one line of data. This is used so client code can
* read the meta data.
* @param skipPatternString if non-null then skip any line that matches this pattern
* @param streamProcessor Optional processor of the Tuple stream for point obs
* @exception IOException if there was a problem reading the file.
* @exception VisADException if an unexpected problem occurs.
*/
public TextAdapter(InputStream inputStream, String delimiter, String map, String params,Hashtable properties, boolean onlyReadOneLine,String skipPatternString,StreamProcessor streamProcessor)
throws IOException, VisADException {
this.onlyReadOneLine = onlyReadOneLine;
this.streamProcessor = streamProcessor;
DELIM = delimiter;
this.properties = properties;
if(skipPatternString!=null && skipPatternString.length()>0) {
skipPattern = Pattern.compile(skipPatternString);
}
readit(inputStream, map, params);
}
public static String getDelimiter(String filename) {
if(filename == null) return null;
filename = filename.trim().toLowerCase();
if (filename.endsWith(".csv")) return COMMA;
if (filename.endsWith(".tsv")) return TAB;
if (filename.endsWith(".bsv")) return BLANK;
return null;
}
/**
* Is the given text line a comment
*
* @return is it a comment line
*/
public static boolean isComment(String line) {
return (line.startsWith("#") ||
line.startsWith("!") ||
line.startsWith("%") ||
line.length() < 1);
}
public static String readLine(BufferedReader bis)
throws IOException {
while (true) {
String line = bis.readLine();
if (line == null) return null;
if (!isText(line)) return null;
if (isComment(line)) continue;
return line.trim();
}
}
void readit(InputStream is, String map, String params)
throws IOException, VisADException {
// read the ASCII file, using commas as field separators
// first line is a header line
List realTypes = new ArrayList();
ff = null;
field = null;
if (debug) System.out.println("#### Text Adapter v2.x running");
BufferedReader bis = new BufferedReader(new InputStreamReader(is));
// mapping defines how the names are mapped
// for example: (x,y) => (one, two, three)
String maps = null;
if (map == null) {
maps = readLine(bis);
if(maps != null) {
maps = maps.trim();
}
} else {
maps = map;
}
if (maps != null) {
maps = makeMT(maps);
}
if (maps == null) {
throw new visad.data.BadFormException(
"TextAdapter: Invalid or missing MathType");
}
ListnameChanges = new ArrayList();
if (debug) System.out.println("Specified MathType = "+maps);
// but first, we need to get the column headers because they
// may have [units] associated with them. The column headers
// primarily define where the data are.
String hdr = null;
if (params == null) {
hdr = readLine(bis);
} else {
hdr = params;
}
String hdrDelim = DELIM;
if (DELIM == null) {
if (hdr.indexOf(BLANK) != -1) hdrDelim = BLANK_DELIM;
if (hdr.indexOf(COMMA) != -1) hdrDelim = COMMA;
if (hdr.indexOf(SEMICOLON) != -1) hdrDelim = SEMICOLON;
if (hdr.indexOf(TAB) != -1) hdrDelim = TAB;
if (debug) System.out.println("Using header delimiter = "+ hdrDelim + "("+
(hdrDelim.getBytes())[0] + ")");
}
// squeeze out extra blank spaces
if (hdrDelim.equals(BLANK) || hdrDelim.equals(BLANK_DELIM)) {
//System.out.println("line before squeeze: " + line);
hdr = hdr.replaceAll("\\s++", " ").trim();
//System.out.println("line after squeeze: " + line);
}
String[] sthdr = hdr.split(hdrDelim);
// since blanks separate the metadata, if we have a blank
// delimiter, we run into problems. Loop through the header and
// put humpty dumpty back together again
if (hdrDelim.equals(BLANK_DELIM) || hdrDelim.equals(BLANK)) {
List chunks = new ArrayList();
for (int i = 0; i < sthdr.length; i++) {
String subchunk = sthdr[i].trim();
int m = subchunk.indexOf("[");
if (m == -1) {
chunks.add(subchunk);
continue;
}
// have "[", find "]"
int m2 = subchunk.indexOf("]");
while (m2 < 0 && i < sthdr.length) {
i++;
subchunk += " " +sthdr[i].trim();
m2 = subchunk.indexOf("]");
}
chunks.add(subchunk);
}
sthdr = (String[]) chunks.toArray(new String[chunks.size()]);
}
int nhdr = sthdr.length;
infos = new HeaderInfo[nhdr];
for(int i=0;i= name.length()) {
infos[i].name = name.substring(0,m).trim();
} else {
infos[i].name = (name.substring(0,m)+name.substring(m2+1)).trim();
}
// 0. Remove any spaces around the "=" signs
String cl = name.substring(m+1,m2).trim();
cl = cl.replaceAll(" +=","=");
cl = cl.replaceAll("= +","=");
String[] stcl = cl.split(BLANK_DELIM);
int ncl = stcl.length;
if (ncl == 1 && cl.indexOf("=") == -1) {
hdrUnitString = cl; // backward compatible...
} else {
for (int l = 0; l < ncl; l++) {
String s = stcl[l];
String[] sts = s.split("=");
if (sts.length != 2) {
throw new VisADException("TextAdapter: Invalid clause in: "+s);
}
String tok = sts[0];
String val = sts[1];
// check for quoted strings
if (val.startsWith("\"")) {
// see if ending quote also fetched
if (val.endsWith("\"")) {
String v2 = val.substring(1,val.length()-1);
val = v2;
} else {
// if not, then reparse stcl to suck up spaces...
try {
String v2="";
for (int q=l+1; q < ncl; q++) {
String vTmp = stcl[q];
// find next token that has a " in it
int pos = vTmp.indexOf("\"");
l++;
if (pos < 0) { // no "
v2 = v2+" "+vTmp;
} else {
v2 = v2+" "+vTmp.substring(0,pos);
break;
}
}
String v3 = val.substring(1)+v2;
val = v3;
//} catch (NoSuchElementException nse2) {
} catch (ArrayIndexOutOfBoundsException nse2) {
val="";
}
}
}
if (debug) System.out.println("#### tok = "+tok+ " val = '"+val+"'");
if (tok.toLowerCase().startsWith(ATTR_UNIT)) {
hdrUnitString = val;
} else if (tok.toLowerCase().startsWith(ATTR_MISSING)) {
infos[i].missingString = val.trim();
try {
infos[i].missingValue = Double.parseDouble(val);
} catch (java.lang.NumberFormatException me) {
infos[i].missingValue = Double.NaN;
}
} else if (tok.toLowerCase().startsWith(ATTR_INTERVAL)) {
infos[i].isInterval = -1;
if (val.toLowerCase().startsWith("t")) infos[i].isInterval = 1;
if (val.toLowerCase().startsWith("f")) infos[i].isInterval = 0;
if (infos[i].isInterval == -1) {
throw new VisADException("TextAdapter: Value of \'interval\' must be \'true\' or \'false\'");
}
} else if (tok.toLowerCase().startsWith(ATTR_ERROR)) {
infos[i].errorEstimate = Double.parseDouble(val);
} else if (tok.toLowerCase().startsWith(ATTR_SCALE)) {
infos[i].scale = Double.parseDouble(val);
} else if (tok.toLowerCase().startsWith(ATTR_OFFSET)) {
infos[i].offset = Double.parseDouble(val);
} else if (tok.toLowerCase().startsWith(ATTR_VALUE)) {
infos[i].fixedValue = val.trim();
numHdrValues++;
} else if (tok.toLowerCase().startsWith(ATTR_COLSPAN)) {
infos[i].colspan = (int)Double.parseDouble(val.trim());
} else if (tok.toLowerCase().startsWith(ATTR_POSITION)) {
String[] stp = val.split(":");
if (stp.length != 2) {
throw new VisADException("TextAdapter: invalid Position parameter in:"+s);
}
hdrColumns[0][i] = Integer.parseInt(stp[0].trim());
hdrColumns[1][i] = Integer.parseInt(stp[1].trim());
} else if (tok.toLowerCase().startsWith(ATTR_FORMAT)) {
infos[i].formatString = val.trim();
} else if (tok.toLowerCase().startsWith(ATTR_TIMEZONE)) {
infos[i].tzString = val.trim();
} else {
throw new VisADException("TextAdapter: invalid token name: "+s);
}
}
}
}
if(properties!=null) {
for(int headerIdx=0;headerIdx -1) { // if no list, get from file
values_to_index[0][countValues] = k;
values_to_index[2][countValues] = i;
}
break;
}
}
if (gotName) continue;
// or see if its a range name...
for (int k=0; k=0) { // fixed value
String name = line.substring(0,index).trim();
String value = line.substring(index+1).trim();
boolean foundIt = false;
for(int paramIdx=0;paramIdx= nhdr) { // are we past where domain would be found?
if (!gotFirst) {
throw new VisADException(
"TextAdapter: Cannot find first raster value");
}
rvaluePointer ++;
rValues[rvaluePointer] = getVal(sa, irange);
} else { // or are we still looking for domain?
if (values_to_index[0][i] != -1) {
dValues[values_to_index[0][i]] = getVal(sa, i);
}
if (gotFirst) { // already gathering data
rvaluePointer ++;
rValues[rvaluePointer] = getVal(sa, irange);
} else {
if (values_to_index[1][i] != -1) {
// cannot dimension the array until we have found
// the first set of range values!!
rValues = new double[n - i];
irange = i;
rValues[rvaluePointer] = getVal(sa, irange);
gotFirst = true;
}
}
}
}
} else { // is probably NOT a raster
dataArray = new Data[numRng];
if (debug) System.out.println("probably not a raster...");
if (streamProcessor==null) {
rValues = new double[numRng];
}
MathType thisMT;
if (n > nhdr) n = nhdr; // in case the # tokens > # parameters
n +=numHdrValues;
int tokenIdx = 0; // token counter
for (int i=0; i= tokens.length) { // more params than tokens
sa = ""; // need to have a missing value
} else {
sa = tokens[tokenIdx++].trim();
int moreColumns = infos[i].colspan-1;
while (moreColumns>0) {
sa = sa + " " + tokens[tokenIdx++].trim();
moreColumns--;
}
}
String sThisText;
if (values_to_index[0][i] != -1) {
if(dValues!=null)
dValues[values_to_index[0][i]] = getVal(sa, i);
} else if (values_to_index[1][i] != -1) {
int tupleIndex = values_to_index[1][i];
int infosIndex = values_to_index[2][i];
thisMT = rangeType.getComponent(tupleIndex);
if (thisMT instanceof TextType) {
// if Text, then check for quoted string
if (sa.startsWith("\"")) {
if (sa.endsWith("\"")) { // if single token ends with quote
String sa2 = sa.substring(1,sa.length()-1);
sThisText = sa2;
} else {
// TODO: work on this
try {
String delim =
dataDelim.equals(BLANK_DELIM) ? BLANK : dataDelim;
String sa2="";
for (int q=tokenIdx; q < tokens.length; q++) {
String saTmp = tokens[q];
// find next token that has a " in it
int pos = saTmp.indexOf("\"");
tokenIdx++;
if (pos < 0) { // no dataDelim
sa2 = sa2+delim+saTmp;
} else {
sa2 = sa2+saTmp.substring(0,pos);
//tokens[tokenIdx] = saTmp.substring(pos+1);
break;
}
}
//sThisText = sa.substring(1)+sa2;
sThisText = sa.substring(1)+delim+sa2;
//} catch (NoSuchElementException nse) {
} catch (ArrayIndexOutOfBoundsException nse) {
sThisText = "";
}
}
if (debug) System.out.println("#### Text value='"+sThisText+"'");
// if not quoted, then take "as is"
} else {
sThisText = sa;
}
// now make the VisAD Data
try {
dataArray[tupleIndex] =
new Text((TextType)thisMT, sThisText);
if (debug) System.out.println("dataArray[" +
tupleIndex + "] = " +
dataArray[tupleIndex]);
} catch (Exception e) {
System.out.println(" Exception converting " +
thisMT + " to TextType " + e);
}
// if not Text, then treat as numeric
} else {
// if(true) continue;
double value = getVal(sa,i);
if(rValues!=null)
rValues[tupleIndex] = value;
try {
if(prototypeReals[i]==null) {
prototypeReals[i] = new Real((RealType) thisMT, value, infos[infosIndex].unit);
}
dataArray[tupleIndex] =
prototypeReals[i].cloneButValue(value);
if(debug)System.out.println("dataArray[" +
tupleIndex + "] = " +
dataArray[tupleIndex]);
} catch (Exception e) {
System.out.println(" Exception converting " + thisMT + " " + e);
e.printStackTrace();
}
}
}
}
}
if(tryToMakeTuple) {
try {
if (dataArray != null) {
if (streamProcessor!=null) {
streamProcessor.processValues(dataArray);
} else {
if(tupleType == null) {
tuple = new Tuple(dataArray);
tupleType = (TupleType)tuple.getType();
} else {
tuple = new Tuple(tupleType, dataArray, false, false);
}
}
}
} catch (visad.TypeException te) {
// do nothing: it means they are all reals
// tuple = new RealTuple(dataArray);
tuple = null;
tryToMakeTuple = false;
} catch(NullPointerException npe) {
for(int i=0;i 1) numVal = numElements;
if (numDom > 2 && numRng == 1 && numElements == 1) {
numVal = numSamples / (2 * numDom);
keepConstant = true;
}
for (int i=0; i");
if (k < 0) {
// System.out.println("TextAdapter: invalid MathType form; -> required");
return null;
}
StringBuffer sb = new StringBuffer("");
for (int i=0; i");
if (t.charAt(k-1) != ')' ) {
if (t.charAt(k+2) != '(' ) {
String t2 = "("+t.substring(0,k) + ")->("+t.substring(k+2)+")";
t = t2;
} else {
String t2 = "("+t.substring(0,k) + ")"+t.substring(k);
t = t2;
}
} else if (t.charAt(k+2) != '(' ) {
String t2 = t.substring(0,k+2)+"("+t.substring(k+2)+")";
t = t2;
}
if (!t.startsWith("((") ) {
String t2= "("+t+")";
t = t2;
}
return t;
}
private static final boolean isText(String s)
{
final int len = (s == null ? -1 : s.length());
if (len <= 0) {
// well, it's not really *binary*, so pretend it's text
return true;
}
for (int i = 0; i < len; i++) {
final char ch = s.charAt(i);
if (Character.isISOControl(ch) && !Character.isWhitespace(ch)) {
// we might want to special-case formfeed/linefeed/newline here...
return false;
}
}
return true;
}
/**
* generate a DateTime from a string
* @param string - Formatted date/time string
*
* @return - the equivalent VisAD DateTime for the string
*
* (lifted from au.gov.bom.aifs.common.ada.VisADXMLAdapter.java)
*/
private static visad.DateTime makeDateTimeFromString(String string,
String format, String tz)
throws java.text.ParseException
{
visad.DateTime dt = null;
// try to parse the string using the supplied DateTime format
try {
if(dateParsers!=null) {
for(int i=0;i values[0][0];
if (ascending) {
for (int i=1; i values[0][i - 1]) {
ordered = false;
break;
}
}
}
Set set = null;
if (ordered) {
ArithProg arithProg = new ArithProg();
if (arithProg.accumulate(values[0])) {
// The domain values form an arithmetic progression (ordered and
// equally spaced) so use a linear set.
set = new Linear1DSet(type, values[0][0], values[0][numSamples - 1],
numSamples);
} else {
// The samples are ordered, so use a gridded set.
set = new Gridded1DDoubleSet(type, values, numSamples);
}
} else {
set = new Irregular1DSet(type, Set.doubleToFloat(values));
}
return set;
}
private static class HeaderInfo {
String name;
Unit unit;
double missingValue = Double.NaN;
String missingString;
String formatString;
String tzString = "GMT";
int isInterval = 0;
double errorEstimate=0;
double scale=1.0;
double offset=0.0;
String fixedValue;
int colspan = 1;
boolean isText = false;
public boolean isParam(String param) {
return name.equals(param) || name.equals(param+"(Text)");
}
public String toString() {
return name;
}
}
/**
* Read in the given file and return the processed data
*
* @param file The file to read in
* @return the data
*/
public static Data processFile(String file) throws Exception {
TextAdapter ta = new TextAdapter(file);
System.out.println(ta.getData().getType());
return ta.getData();
}
// uncomment to test
public static void main(String[] args) throws Exception {
if (args.length == 0) {
System.out.println("Must supply a filename");
System.exit(1);
}
TextAdapter ta = new TextAdapter(args[0]);
System.out.println(ta.getData().getType());
new visad.jmet.DumpType().dumpMathType(ta.getData().getType(),System.out);
new visad.jmet.DumpType().dumpDataType(ta.getData(),System.out);
System.out.println("#### Data = "+ta.getData());
System.out.println("EOF... ");
}
/**
* A cut-and-paste from the IDV Misc method
* Decodes a string representation of a latitude or longitude and
* returns a double version (in degrees). Acceptible formats are:
*
* +/- ddd:mm, ddd:mm:, ddd:mm:ss, ddd::ss, ddd.fffff ===> [+/-] ddd.fffff
* +/- ddd, ddd:, ddd:: ===> [+/-] ddd
* +/- :mm, :mm:, :mm:ss, ::ss, .fffff ===> [+/-] .fffff
* +/- :, :: ===> 0.0
* Any of the above with N,S,E,W appended
*
*
* @param latlon string representation of lat or lon
* @return the decoded value in degrees
*/
public static double decodeLatLon(String latlon) {
// first check to see if there is a N,S,E,or W on this
latlon = latlon.trim();
int dirIndex = -1;
int southOrWest = 1;
double value = Double.NaN;
if (latlon.indexOf("S") > 0) {
southOrWest = -1;
dirIndex = latlon.indexOf("S");
} else if (latlon.indexOf("W") > 0) {
southOrWest = -1;
dirIndex = latlon.indexOf("W");
} else if (latlon.indexOf("N") > 0) {
dirIndex = latlon.indexOf("N");
} else if (latlon.indexOf("E") > 0) {
dirIndex = latlon.indexOf("E");
}
if (dirIndex > 0) {
latlon = latlon.substring(0, dirIndex).trim();
}
// now see if this is a negative value
if (latlon.indexOf("-") == 0) {
southOrWest *= -1;
latlon = latlon.substring(latlon.indexOf("-") + 1).trim();
}
if (latlon.indexOf(":") >= 0) { //have something like DD:MM:SS, DD::, DD:MM:, etc
int firstIdx = latlon.indexOf(":");
String hours = latlon.substring(0, firstIdx);
String minutes = latlon.substring(firstIdx + 1);
String seconds = "";
if (minutes.indexOf(":") >= 0) {
firstIdx = minutes.indexOf(":");
String temp = minutes.substring(0, firstIdx);
seconds = minutes.substring(firstIdx + 1);
minutes = temp;
}
try {
value = (hours.equals("") == true)
? 0
: Double.parseDouble(hours);
if ( !minutes.equals("")) {
value += Double.parseDouble(minutes) / 60.;
}
if ( !seconds.equals("")) {
value += Double.parseDouble(seconds) / 3600.;
}
} catch (NumberFormatException nfe) {
value = Double.NaN;
}
} else { //have something like DD.ddd
try {
value = Double.parseDouble(latlon);
} catch (NumberFormatException nfe) {
value = Double.NaN;
}
}
return value * southOrWest;
}
public interface StreamProcessor {
public void processValues(Data[] tuple) throws VisADException ;
}
}
Ads help maintain this website.