Mercurial > dive4elements > river
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 : |