felix@4728: package de.intevation.flys.importer.parsers; felix@4728: teichmann@4735: import de.intevation.artifacts.common.utils.FileTools; teichmann@4735: teichmann@4735: import de.intevation.flys.importer.XY; teichmann@4735: felix@4747: import de.intevation.flys.importer.parsers.tim.Coordinate; teichmann@4735: felix@4762: import de.intevation.flys.utils.DateGuesser; teichmann@4768: import de.intevation.flys.utils.EpsilonComparator; felix@4762: teichmann@4735: import java.io.File; teichmann@4735: import java.io.IOException; teichmann@4735: felix@4728: import java.util.ArrayList; felix@4761: import java.util.Calendar; felix@4761: import java.util.Date; teichmann@4735: import java.util.List; felix@4728: import java.util.Map; felix@4728: import java.util.TreeMap; felix@4728: felix@4728: import org.apache.log4j.Logger; felix@4728: felix@4728: felix@4728: /** felix@4728: * To create cross-sections, generate: Map> from files felix@4755: * in w80 format. felix@4728: */ felix@4728: public class W80Parser extends LineParser implements CrossSectionParser felix@4728: { felix@4728: /** Private logger. */ felix@4728: private static Logger logger = Logger.getLogger(W80Parser.class); felix@4728: felix@4728: felix@4728: /** The current line to which add points. */ felix@4728: private List currentLine; felix@4728: felix@4728: felix@4728: /** Data collected so far, last element will be currentLine. */ felix@4728: protected Map> data; felix@4728: felix@4728: felix@4747: /** Anchor to project to. */ teichmann@4768: private static class Anchor extends Coordinate { teichmann@4768: teichmann@4768: private static final double EPSILON = 1e-5; teichmann@4768: felix@4747: private double station; teichmann@4768: teichmann@4768: public Anchor(double x, double y, double z, double station) { teichmann@4768: super(x, y, z); felix@4747: this.station = station; felix@4747: } teichmann@4768: teichmann@4768: public boolean sameStation(double station) { teichmann@4768: return Math.abs(this.station - station) < EPSILON; felix@4747: } felix@4747: } felix@4747: felix@4747: felix@4760: /** Reference point for simple projection. */ felix@4747: private Anchor anchor; felix@4747: felix@4747: felix@4804: /** felix@4804: * Reference point for distance calculations, introduced to felix@4804: * deal with bends in the lines. felix@4804: * Array has two entrys: first is GK-Right, second GK-High. felix@4804: */ felix@4804: private double[] lastPointGK; felix@4804: felix@4804: felix@4761: /** Measurement date of anchor as listed in w80 file. */ felix@4761: private Date anchorDate; felix@4761: felix@4761: felix@4804: private double distanceToLastPoint(double gkr, double gkh) { felix@4804: double dx = gkr - lastPointGK[0]; felix@4804: double dy = gkh - lastPointGK[1]; felix@4804: double d = dx*dx + dy*dy; felix@4804: felix@4804: return Math.sqrt(d); felix@4804: } felix@4804: felix@4804: felix@4728: /** Trivial constructor. */ felix@4728: public W80Parser() { teichmann@4735: data = new TreeMap>(EpsilonComparator.CMP); felix@4728: } felix@4728: felix@4728: felix@4728: /** Get the description of the cross section parsed. */ felix@4728: @Override felix@4728: public String getDescription() { felix@4729: return FileTools.removeExtension(getFileName()); felix@4728: } felix@4728: felix@4728: felix@4728: /** Get the year of this cross sections measurement. */ felix@4728: @Override felix@4728: public Integer getYear() { teichmann@4769: if (anchorDate == null) { felix@4777: return null; teichmann@4769: } felix@4762: Calendar dateCalendar = Calendar.getInstance(); felix@4762: dateCalendar.setTime(anchorDate); felix@4762: return dateCalendar.get(Calendar.YEAR); felix@4728: } felix@4728: felix@4728: felix@4728: /** felix@4728: * Return the data parsed. felix@4728: * @return map of stations (km) to list of points. felix@4728: */ felix@4728: @Override felix@4728: public Map> getData() { felix@4728: return data; felix@4728: } felix@4728: felix@4728: felix@4728: public void parseW80s(File root, final Callback callback) { felix@4728: felix@4728: FileTools.walkTree(root, new FileTools.FileVisitor() { felix@4728: @Override felix@4728: public boolean visit(File file) { felix@4728: if (file.isFile() && file.canRead() felix@4728: && file.getName().toLowerCase().endsWith(".w80") felix@4728: && (callback == null || callback.accept(file))) { felix@4728: reset(); felix@4728: try { felix@4728: parse(file); felix@4728: logger.info("parsing done"); felix@4728: if (callback != null) { felix@4728: callback.parsed(W80Parser.this); felix@4728: } felix@4728: } felix@4728: catch (IOException ioe) { felix@4728: logger.error("IOException while parsing file"); felix@4728: return false; felix@4728: } felix@4728: } felix@4728: return true; felix@4728: } felix@4728: }); felix@4728: } felix@4728: felix@4728: felix@4728: /** Called before consuming first line of file. */ felix@4728: public void reset() { felix@4728: data.clear(); felix@4728: currentLine = new ArrayList(); felix@4749: anchor = null; felix@4761: anchorDate = null; felix@4804: lastPointGK = new double[] {0d,0d}; felix@4749: } felix@4749: felix@4749: felix@4749: /** felix@4749: * Get the Index of the last cross-section lines point. felix@4749: * @return last points index, -1 if not available. felix@4749: */ felix@4803: private int getLastPointIdx() { felix@4749: if (currentLine == null || currentLine.isEmpty()) { felix@4749: return -1; felix@4749: } felix@4749: XY lastPoint = this.currentLine.get(currentLine.size()-1); felix@4749: return lastPoint.getIndex(); felix@4749: } felix@4749: felix@4757: felix@4804: private double getLastPointX() { felix@4804: if (currentLine == null || currentLine.isEmpty()) { felix@4804: return 0d; felix@4804: } felix@4804: XY lastPoint = this.currentLine.get(currentLine.size()-1); felix@4804: return lastPoint.getX(); felix@4804: } felix@4804: felix@4804: felix@4749: /** felix@4749: * Add a Point (YZ,Index) to the current cross section line. felix@4749: * @param y The y coordinate of new point. felix@4749: * @param z The z coordinate of new point. felix@4749: * @param idx Ignored, the parameter of new point. felix@4749: * @return true if point could been added, false otherwise (e.g. not felix@4749: * parsable y or z values. felix@4749: */ felix@4749: private boolean addPoint(double gkr, double gkh, double height, String idx) { felix@4804: // Calculate distance between this and lst point (add distances). felix@4804: double d = distanceToLastPoint(gkr, gkh); felix@4804: double totalX = getLastPointX() + d; felix@4751: felix@4749: // We ignore idx, and increment instead. felix@4749: int index; felix@4803: int lastPointIdx = getLastPointIdx(); felix@4749: if (lastPointIdx <= 0) { felix@4749: index = 1; felix@4749: } else { felix@4749: index = lastPointIdx + 1; felix@4749: } felix@4749: felix@4804: this.lastPointGK[0] = gkr; felix@4804: this.lastPointGK[1] = gkh; felix@4804: currentLine.add(new XY(totalX, height/1000d, index)); felix@4749: return true; felix@4728: } felix@4728: felix@4728: felix@4728: /** felix@4755: * Called for each line. Try to extract info from a w80 line. felix@4728: */ felix@4728: @Override felix@4728: protected void handleLine(int lineNum, String line) { felix@4757: // The 'shore' field shows which side of the river the shore is measured. felix@4757: // Therefore, the points have to be added in the correct order (also felix@4757: // because later distances are calculated which cannot be felix@4757: // negative. felix@4728: String pointId = line.substring(0,20); felix@4758: String station = line.substring(9,15); felix@4804: String shore = line.substring(15,16); felix@4751: // TODO: There is 'station' and a 'shore'-code behind. felix@4751: // 1 = left, 2 = right. none = middle felix@4804: String pointIndex = line.substring(16,21); felix@4750: // For GK, first seven digits are of interest. felix@4728: String gkRight = line.substring(20,30); felix@4728: String gkHigh = line.substring(30,40); felix@4728: String date = line.substring(40,46); felix@4759: /* Fields not (yet?) of interest for FLYS felix@4728: String locType = line.substring(46,47); felix@4759: */ felix@4728: String height = line.substring(47,54); felix@4728: String dateH = line.substring(54,60); felix@4759: /* Fields not (yet?) of interest for FLYS felix@4728: String typeH = line.substring(60,61); felix@4728: String kindH = line.substring(61,64); felix@4759: */ felix@4728: String dateDec = line.substring(64,70); felix@4759: /* Fields not (yet?) of interest for FLYS felix@4728: String note = line.substring(70,78); felix@4728: String actual = line.substring(78); felix@4759: */ felix@4759: felix@4750: double stationKm = Double.parseDouble(station) / 1000d; felix@4750: double gkRightKm = Double.parseDouble(gkRight.substring(0,7)); felix@4750: double gkHighKm = Double.parseDouble(gkHigh.substring(0,7)); felix@4750: double heightM = Double.parseDouble(height); felix@4750: felix@4750: // New (or first) line. teichmann@4768: if (anchor == null || !anchor.sameStation(stationKm)) { teichmann@4768: anchor = new Anchor(gkRightKm, gkHighKm, heightM, stationKm); felix@4804: lastPointGK[0] = gkRightKm; felix@4804: lastPointGK[1] = gkHighKm; felix@4750: currentLine = new ArrayList(); felix@4750: data.put(stationKm, currentLine); felix@4802: currentLine.add(new XY(0d, heightM, 0)); teichmann@4769: try { teichmann@4769: anchorDate = DateGuesser.guessDate(date); teichmann@4769: } teichmann@4769: catch (IllegalArgumentException iae) { teichmann@4769: logger.warn("W80: Invalid date '" + date + "'."); teichmann@4769: } felix@4750: } felix@4750: else { felix@4750: addPoint(gkRightKm, gkHighKm, heightM, pointIndex); felix@4750: } felix@4728: } felix@4728: felix@4728: felix@4728: /** Called when file is fully consumed. */ felix@4728: @Override felix@4728: protected void finish() { felix@4728: logger.info("Parsed " + data.size() + " lines"); felix@4728: } felix@4728: felix@4728: felix@4728: /** Parses files given as arguments. */ felix@4728: public static void main(String [] args) { felix@4728: felix@4728: W80Parser parser = new W80Parser(); felix@4728: felix@4728: logger.warn("Start parsing files."); felix@4728: for (String arg: args) { felix@4802: logger.warn("Parsing a file."); felix@4728: parser.parseW80s(new File(arg), null); felix@4728: } felix@4728: logger.error("Finished parsing files."); felix@4728: } felix@4728: } felix@4728: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :