comparison backend/src/main/java/org/dive4elements/river/importer/parsers/W80Parser.java @ 7730:e1b831fe435a slt-simplify-cross-sections

Merged default into slt-simplify-cross-sections branch and updated package and class names.
author Tom Gottfried <tom@intevation.de>
date Mon, 20 Jan 2014 14:04:20 +0100
parents 4c3ccf2b0304
children 3bb1c62ad732
comparison
equal deleted inserted replaced
5084:ca45dd039b54 7730:e1b831fe435a
1 /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
2 * Software engineering by Intevation GmbH
3 *
4 * This file is Free Software under the GNU AGPL (>=v3)
5 * and comes with ABSOLUTELY NO WARRANTY! Check out the
6 * documentation coming with Dive4Elements River for details.
7 */
8
9 package org.dive4elements.river.importer.parsers;
10
11 import org.dive4elements.artifacts.common.utils.FileTools;
12
13 import org.dive4elements.river.importer.XY;
14
15 import org.dive4elements.river.importer.parsers.tim.Coordinate;
16
17 import org.dive4elements.river.utils.DateGuesser;
18 import org.dive4elements.river.utils.EpsilonComparator;
19
20 import java.io.File;
21 import java.io.IOException;
22
23 import java.util.ArrayList;
24 import java.util.Calendar;
25 import java.util.Date;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.TreeMap;
29
30 import org.apache.log4j.Logger;
31
32
33 /**
34 * To create cross-sections, generate: Map<double,list<xy>> from files
35 * in w80 format.
36 */
37 public class W80Parser extends LineParser implements CrossSectionParser
38 {
39 /** Private logger. */
40 private static Logger logger = Logger.getLogger(W80Parser.class);
41
42
43 /** The current line to which add points. */
44 private List<XY> currentLine;
45
46
47 /** Data collected so far, last element will be currentLine. */
48 protected Map<Double, List<XY>> data;
49
50
51 /** Anchor to project to. */
52 private static class Anchor extends Coordinate {
53
54 private static final double EPSILON = 1e-5;
55
56 private double station;
57
58 public Anchor(double x, double y, double z, double station) {
59 super(x, y, z);
60 this.station = station;
61 }
62
63 public boolean sameStation(double station) {
64 return Math.abs(this.station - station) < EPSILON;
65 }
66 }
67
68
69 /** Reference point for simple projection. */
70 private Anchor anchor;
71
72
73 /**
74 * Reference point for distance calculations, introduced to
75 * deal with bends in the lines.
76 * Array has two entrys: first is GK-Right, second GK-High.
77 */
78 private double[] lastPointGK;
79
80
81 /** Measurement date of anchor as listed in w80 file. */
82 private Date anchorDate;
83
84
85 private double distanceToLastPoint(double gkr, double gkh) {
86 double dx = gkr - lastPointGK[0];
87 double dy = gkh - lastPointGK[1];
88 double d = dx*dx + dy*dy;
89
90 return Math.sqrt(d);
91 }
92
93
94 /** Trivial constructor. */
95 public W80Parser() {
96 data = new TreeMap<Double, List<XY>>(EpsilonComparator.CMP);
97 }
98
99
100 /** Get the description of the cross section parsed. */
101 @Override
102 public String getDescription() {
103 return FileTools.removeExtension(getFileName());
104 }
105
106
107 /** Get the year of this cross sections measurement. */
108 @Override
109 public Integer getYear() {
110 if (anchorDate == null) {
111 return null;
112 }
113 Calendar dateCalendar = Calendar.getInstance();
114 dateCalendar.setTime(anchorDate);
115 return dateCalendar.get(Calendar.YEAR);
116 }
117
118
119 /**
120 * Return the data parsed.
121 * @return map of stations (km) to list of points.
122 */
123 @Override
124 public Map<Double, List<XY>> getData() {
125 return data;
126 }
127
128
129 public void parseW80s(File root, final Callback callback) {
130
131 FileTools.walkTree(root, new FileTools.FileVisitor() {
132 @Override
133 public boolean visit(File file) {
134 if (file.isFile() && file.canRead()
135 && file.getName().toLowerCase().endsWith(".w80")
136 && (callback == null || callback.accept(file))) {
137 reset();
138 try {
139 parse(file);
140 logger.info("parsing done");
141 if (callback != null) {
142 callback.parsed(W80Parser.this);
143 }
144 }
145 catch (IOException ioe) {
146 logger.error("IOException while parsing file");
147 return false;
148 }
149 }
150 return true;
151 }
152 });
153 }
154
155
156 /** Called before consuming first line of file. */
157 public void reset() {
158 data.clear();
159 currentLine = new ArrayList<XY>();
160 anchor = null;
161 anchorDate = null;
162 lastPointGK = new double[] {0d,0d};
163 }
164
165
166 /**
167 * Get the Index of the last cross-section lines point.
168 * @return last points index, -1 if not available.
169 */
170 private int getLastPointIdx() {
171 if (currentLine == null || currentLine.isEmpty()) {
172 return -1;
173 }
174 XY lastPoint = this.currentLine.get(currentLine.size()-1);
175 return lastPoint.getIndex();
176 }
177
178
179 private double getLastPointX() {
180 if (currentLine == null || currentLine.isEmpty()) {
181 return 0d;
182 }
183 XY lastPoint = this.currentLine.get(currentLine.size()-1);
184 return lastPoint.getX();
185 }
186
187
188 /**
189 * Add a Point (YZ,Index) to the current cross section line.
190 * @param y The y coordinate of new point.
191 * @param z The z coordinate of new point.
192 * @param idx Ignored, the parameter of new point.
193 * @return true if point could been added, false otherwise (e.g. not
194 * parsable y or z values.
195 */
196 private boolean addPoint(double gkr, double gkh, double height, String idx) {
197 // Calculate distance between this and lst point (add distances).
198 double d = distanceToLastPoint(gkr, gkh);
199 double totalX = getLastPointX() + d;
200
201 // We ignore idx, and increment instead.
202 int index;
203 int lastPointIdx = getLastPointIdx();
204 if (lastPointIdx <= 0) {
205 index = 1;
206 } else {
207 index = lastPointIdx + 1;
208 }
209
210 this.lastPointGK[0] = gkr;
211 this.lastPointGK[1] = gkh;
212 currentLine.add(new XY(totalX, height/1000d, index));
213 return true;
214 }
215
216
217 /**
218 * Called for each line. Try to extract info from a w80 line.
219 */
220 @Override
221 protected void handleLine(int lineNum, String line) {
222 // The 'shore' field shows which side of the river the shore is measured.
223 // Therefore, the points have to be added in the correct order (also
224 // because later distances are calculated which cannot be
225 // negative.
226 String pointId = line.substring(0,20);
227 String station = line.substring(9,15);
228 String shore = line.substring(15,16);
229 // TODO: There is 'station' and a 'shore'-code behind.
230 // 1 = left, 2 = right. none = middle
231 String pointIndex = line.substring(16,21);
232 // For GK, first seven digits are of interest.
233 String gkRight = line.substring(20,30);
234 String gkHigh = line.substring(30,40);
235 String date = line.substring(40,46);
236 /* Fields not (yet?) of interest for FLYS
237 String locType = line.substring(46,47);
238 */
239 String height = line.substring(47,54);
240 String dateH = line.substring(54,60);
241 /* Fields not (yet?) of interest for FLYS
242 String typeH = line.substring(60,61);
243 String kindH = line.substring(61,64);
244 */
245 String dateDec = line.substring(64,70);
246 /* Fields not (yet?) of interest for FLYS
247 String note = line.substring(70,78);
248 String actual = line.substring(78);
249 */
250
251 double stationKm = Double.parseDouble(station) / 1000d;
252 double gkRightKm = Double.parseDouble(gkRight.substring(0,7));
253 double gkHighKm = Double.parseDouble(gkHigh.substring(0,7));
254 double heightM = Double.parseDouble(height);
255
256 // New (or first) line.
257 if (anchor == null || !anchor.sameStation(stationKm)) {
258 anchor = new Anchor(gkRightKm, gkHighKm, heightM, stationKm);
259 lastPointGK[0] = gkRightKm;
260 lastPointGK[1] = gkHighKm;
261 currentLine = new ArrayList<XY>();
262 data.put(stationKm, currentLine);
263 currentLine.add(new XY(0d, heightM, 0));
264 try {
265 anchorDate = DateGuesser.guessDate(date);
266 }
267 catch (IllegalArgumentException iae) {
268 logger.warn("W80: Invalid date '" + date + "'.");
269 }
270 }
271 else {
272 addPoint(gkRightKm, gkHighKm, heightM, pointIndex);
273 }
274 }
275
276
277 /** Called when file is fully consumed. */
278 @Override
279 protected void finish() {
280 logger.info("Parsed " + data.size() + " lines");
281 }
282
283
284 /** Parses files given as arguments. */
285 public static void main(String [] args) {
286
287 W80Parser parser = new W80Parser();
288
289 logger.warn("Start parsing files.");
290 for (String arg: args) {
291 logger.warn("Parsing a file.");
292 parser.parseW80s(new File(arg), null);
293 }
294 logger.error("Finished parsing files.");
295 }
296 }
297 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org