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