Mercurial > dive4elements > river
comparison backend/src/main/java/org/dive4elements/river/importer/parsers/WstParser.java @ 8976:e541938dd3ab
Range data handled consistently as BigDecimal to minimize the fractional part of a and b
author | mschaefer |
---|---|
date | Tue, 03 Apr 2018 10:43:53 +0200 |
parents | 5e38e2924c07 |
children | 5ff8ce9a2e06 |
comparison
equal
deleted
inserted
replaced
8975:a0a0a7f912ab | 8976:e541938dd3ab |
---|---|
6 * documentation coming with Dive4Elements River for details. | 6 * documentation coming with Dive4Elements River for details. |
7 */ | 7 */ |
8 | 8 |
9 package org.dive4elements.river.importer.parsers; | 9 package org.dive4elements.river.importer.parsers; |
10 | 10 |
11 import java.io.File; | |
12 import java.io.FileInputStream; | |
13 import java.io.IOException; | |
14 import java.io.InputStreamReader; | |
15 import java.io.LineNumberReader; | |
16 import java.math.BigDecimal; | |
17 import java.text.NumberFormat; | |
11 import java.util.ArrayList; | 18 import java.util.ArrayList; |
19 import java.util.Arrays; | |
12 import java.util.HashSet; | 20 import java.util.HashSet; |
13 import java.util.Arrays; | 21 import java.util.regex.Matcher; |
14 | 22 import java.util.regex.Pattern; |
15 import java.io.File; | |
16 import java.io.IOException; | |
17 import java.io.LineNumberReader; | |
18 import java.io.InputStreamReader; | |
19 import java.io.FileInputStream; | |
20 | |
21 import java.text.NumberFormat; | |
22 | 23 |
23 import org.apache.log4j.Logger; | 24 import org.apache.log4j.Logger; |
24 | 25 import org.dive4elements.river.backend.utils.DateGuesser; |
25 import org.dive4elements.river.backend.utils.StringUtil; | 26 import org.dive4elements.river.backend.utils.StringUtil; |
26 import org.dive4elements.river.backend.utils.DateGuesser; | 27 import org.dive4elements.river.importer.ImportRange; |
27 | |
28 import java.util.regex.Pattern; | |
29 import java.util.regex.Matcher; | |
30 | |
31 import java.math.BigDecimal; | |
32 | |
33 import org.dive4elements.river.importer.ImportWstQRange; | |
34 import org.dive4elements.river.importer.ImportWstColumn; | |
35 import org.dive4elements.river.importer.ImportTimeInterval; | 28 import org.dive4elements.river.importer.ImportTimeInterval; |
36 import org.dive4elements.river.importer.ImportRange; | |
37 import org.dive4elements.river.importer.ImportUnit; | 29 import org.dive4elements.river.importer.ImportUnit; |
38 import org.dive4elements.river.importer.ImportWst; | 30 import org.dive4elements.river.importer.ImportWst; |
31 import org.dive4elements.river.importer.ImportWstColumn; | |
32 import org.dive4elements.river.importer.ImportWstQRange; | |
39 | 33 |
40 public class WstParser | 34 public class WstParser |
41 { | 35 { |
42 private static Logger log = Logger.getLogger(WstParser.class); | 36 private static Logger log = Logger.getLogger(WstParser.class); |
43 | 37 |
45 public static final String COLUMN_BEZ_BREITE = "column-bez-breite"; | 39 public static final String COLUMN_BEZ_BREITE = "column-bez-breite"; |
46 public static final String COLUMN_QUELLE = "column-quelle"; | 40 public static final String COLUMN_QUELLE = "column-quelle"; |
47 public static final String COLUMN_DATUM = "column-datum"; | 41 public static final String COLUMN_DATUM = "column-datum"; |
48 | 42 |
49 public static final BigDecimal UNDEFINED_ZERO = | 43 public static final BigDecimal UNDEFINED_ZERO = |
50 new BigDecimal(0.0); | 44 new BigDecimal(0.0); |
51 public static final BigDecimal MIN_RANGE = | 45 public static final BigDecimal MIN_RANGE = |
52 new BigDecimal(-Double.MAX_VALUE); | 46 new BigDecimal(-Double.MAX_VALUE); |
53 public static final BigDecimal MAX_RANGE = | 47 public static final BigDecimal MAX_RANGE = |
54 new BigDecimal(Double.MAX_VALUE); | 48 new BigDecimal(Double.MAX_VALUE); |
55 | 49 |
56 public static final String ENCODING = "ISO-8859-1"; | 50 public static final String ENCODING = "ISO-8859-1"; |
57 | 51 |
58 public static final Pattern UNIT_COMMENT = | 52 public static final Pattern UNIT_COMMENT = |
59 Pattern.compile("\\*\\s*[kK][mM]\\s+(.+)"); | 53 Pattern.compile("\\*\\s*[kK][mM]\\s+(.+)"); |
60 | 54 |
61 public static final Pattern UNIT = | 55 public static final Pattern UNIT = |
62 Pattern.compile("[^\\[]*\\[([^]]+)\\].*"); | 56 Pattern.compile("[^\\[]*\\[([^]]+)\\].*"); |
63 | 57 |
64 public static final Pattern YEAR_INTERVAL = | 58 public static final Pattern YEAR_INTERVAL = |
65 Pattern.compile("(\\d{4})\\s*[-/]\\s*(\\d{4})"); | 59 Pattern.compile("(\\d{4})\\s*[-/]\\s*(\\d{4})"); |
66 | 60 |
67 public static final double INTERVAL_GAP = 0.00001d; | 61 public static final BigDecimal INTERVAL_GAP = new BigDecimal("0.00001"); |
68 | 62 |
69 protected ImportWst wst; | 63 protected ImportWst wst; |
70 | 64 |
71 protected ImportRange lastRange; | 65 protected ImportRange lastRange; |
72 protected Double lastA; | |
73 protected Double lastB; | |
74 | 66 |
75 public WstParser() { | 67 public WstParser() { |
76 } | 68 } |
77 | 69 |
78 public WstParser(ImportWst wst) { | 70 public WstParser(final ImportWst wst) { |
79 this.wst = wst; | 71 this.wst = wst; |
80 } | 72 } |
81 | 73 |
82 public ImportWst getWst() { | 74 public ImportWst getWst() { |
83 return wst; | 75 return this.wst; |
84 } | 76 } |
85 | 77 |
86 public void setWst(ImportWst wst) { | 78 public void setWst(final ImportWst wst) { |
87 this.wst = wst; | 79 this.wst = wst; |
88 } | 80 } |
89 | 81 |
90 public static final class ParseException extends Exception { | 82 public static final class ParseException extends Exception { |
91 public ParseException() { | 83 public ParseException() { |
92 } | 84 } |
93 | 85 |
94 public ParseException(String msg) { | 86 public ParseException(final String msg) { |
95 super(msg); | 87 super(msg); |
96 } | 88 } |
97 } // class ParseException | 89 } // class ParseException |
98 | 90 |
99 /** Returns a new ImportTimeInterval with a date guessed from string. */ | 91 /** Returns a new ImportTimeInterval with a date guessed from string. */ |
100 public static ImportTimeInterval guessDate(String string) { | 92 public static ImportTimeInterval guessDate(final String string) { |
101 try { | 93 try { |
102 Matcher m = YEAR_INTERVAL.matcher(string); | 94 final Matcher m = YEAR_INTERVAL.matcher(string); |
103 if (m.matches()) { | 95 if (m.matches()) { |
104 return new ImportTimeInterval( | 96 return new ImportTimeInterval( |
105 DateGuesser.guessDate(m.group(1)), | 97 DateGuesser.guessDate(m.group(1)), |
106 DateGuesser.guessDate(m.group(2))); | 98 DateGuesser.guessDate(m.group(2))); |
107 } | 99 } |
108 | 100 |
109 return new ImportTimeInterval( | 101 return new ImportTimeInterval( |
110 DateGuesser.guessDate(string)); | 102 DateGuesser.guessDate(string)); |
111 } | 103 } |
112 catch (IllegalArgumentException iae) { | 104 catch (final IllegalArgumentException iae) { |
113 log.warn("WST: String '" + string + | 105 log.warn("WST: String '" + string + |
114 "' could not be interpreted as valid timestamp"); | 106 "' could not be interpreted as valid timestamp"); |
115 } | 107 } |
116 return null; | 108 return null; |
117 } | 109 } |
118 | 110 |
119 public void parse(File file) throws IOException, ParseException { | 111 public void parse(final File file) throws IOException, ParseException { |
120 | 112 |
121 log.info("Parsing WST file '" + file + "'"); | 113 log.info("Parsing WST file '" + file + "'"); |
122 | 114 |
123 if (wst == null) { | 115 if (this.wst == null) { |
124 wst = new ImportWst(file.getName()); | 116 this.wst = new ImportWst(file.getName()); |
125 } | 117 } |
126 else { | 118 else { |
127 wst.setDescription(file.getName()); | 119 this.wst.setDescription(file.getName()); |
128 } | 120 } |
129 | 121 |
130 LineNumberReader in = | 122 final LineNumberReader in = |
131 new LineNumberReader( | 123 new LineNumberReader( |
132 new InputStreamReader( | 124 new InputStreamReader( |
133 new FileInputStream(file), ENCODING)); | 125 new FileInputStream(file), ENCODING)); |
134 try { | 126 try { |
135 String input; | 127 String input; |
136 boolean first = true; | 128 boolean first = true; |
137 int columnCount = 0; | 129 int columnCount = 0; |
138 | 130 |
156 * if none is found in WST-file. | 148 * if none is found in WST-file. |
157 * Use in case no unit comment is found in file */ | 149 * Use in case no unit comment is found in file */ |
158 String einheit = "m ü. unbekannte Referenz"; | 150 String einheit = "m ü. unbekannte Referenz"; |
159 boolean unitFound = false; | 151 boolean unitFound = false; |
160 | 152 |
161 HashSet<BigDecimal> kms = new HashSet<BigDecimal>(); | 153 final HashSet<BigDecimal> kms = new HashSet<>(); |
162 | 154 |
163 while ((input = in.readLine()) != null) { | 155 while ((input = in.readLine()) != null) { |
164 String line = input; | 156 String line = input; |
165 if (first) { // fetch number of columns | 157 if (first) { // fetch number of columns |
166 if ((line = line.trim()).length() == 0) { | 158 if ((line = line.trim()).length() == 0) { |
168 } | 160 } |
169 try { | 161 try { |
170 columnCount = Integer.parseInt(line); | 162 columnCount = Integer.parseInt(line); |
171 if (columnCount <= 0) { | 163 if (columnCount <= 0) { |
172 throw new NumberFormatException( | 164 throw new NumberFormatException( |
173 "number of columns <= 0"); | 165 "number of columns <= 0"); |
174 } | 166 } |
175 log.debug("Number of columns: " + columnCount); | 167 log.debug("Number of columns: " + columnCount); |
176 wst.setNumberColumns(columnCount); | 168 this.wst.setNumberColumns(columnCount); |
177 lsBezeichner = new String[columnCount]; | 169 lsBezeichner = new String[columnCount]; |
178 } | 170 } |
179 catch (NumberFormatException nfe) { | 171 catch (final NumberFormatException nfe) { |
180 log.warn("WST: invalid number.", nfe); | 172 log.warn("WST: invalid number.", nfe); |
181 continue; | 173 continue; |
182 } | 174 } |
183 first = false; | 175 first = false; |
184 continue; | 176 continue; |
186 | 178 |
187 line = line.replace(',', '.'); | 179 line = line.replace(',', '.'); |
188 | 180 |
189 // handle Q-lines | 181 // handle Q-lines |
190 if (line.startsWith("*\u001f")) { | 182 if (line.startsWith("*\u001f")) { |
191 BigDecimal [] data = parseLineAsDouble( | 183 final BigDecimal [] data = parseLineAsDouble( |
192 line, columnCount, false, true); | 184 line, columnCount, false, true); |
193 | 185 |
194 if (aktAbfluesse != null) { | 186 if (aktAbfluesse != null) { |
195 // add Q-ranges obtained from previous lines | 187 // add Q-ranges obtained from previous lines |
196 if (kmHist1 != null && kmHist2 != null | 188 if (kmHist1 != null && kmHist2 != null |
197 && kmHist1.compareTo(kmHist2) < 0) { | 189 && kmHist1.compareTo(kmHist2) < 0) { |
198 // stations descending in file | 190 // stations descending in file |
199 BigDecimal t = minKm; minKm = maxKm; maxKm = t; | 191 final BigDecimal t = minKm; minKm = maxKm; maxKm = t; |
200 } | 192 } |
201 addInterval(minKm, maxKm, aktAbfluesse); | 193 addInterval(minKm, maxKm, aktAbfluesse); |
202 minKm = MAX_RANGE; | 194 minKm = MAX_RANGE; |
203 maxKm = MIN_RANGE; | 195 maxKm = MIN_RANGE; |
204 } | 196 } |
214 } | 206 } |
215 | 207 |
216 // remember Q-values from first Q-line | 208 // remember Q-values from first Q-line |
217 // for header generation | 209 // for header generation |
218 if (firstAbfluesse == null) { | 210 if (firstAbfluesse == null) { |
219 firstAbfluesse = (BigDecimal [])aktAbfluesse.clone(); | 211 firstAbfluesse = aktAbfluesse.clone(); |
220 } | 212 } |
221 continue; | 213 continue; |
222 } | 214 } |
223 | 215 |
224 // handle special column identifiers | 216 // handle special column identifiers |
229 continue; | 221 continue; |
230 } | 222 } |
231 | 223 |
232 if (spezial.startsWith(COLUMN_BEZ_TEXT)) { | 224 if (spezial.startsWith(COLUMN_BEZ_TEXT)) { |
233 spezial = spezial.substring( | 225 spezial = spezial.substring( |
234 COLUMN_BEZ_TEXT.length()).trim(); | 226 COLUMN_BEZ_TEXT.length()).trim(); |
235 if (spezial.length() == 0) { | 227 if (spezial.length() == 0) { |
236 continue; | 228 continue; |
237 } | 229 } |
238 langBezeichner = StringUtil.splitQuoted(spezial, '"'); | 230 langBezeichner = StringUtil.splitQuoted(spezial, '"'); |
239 } | 231 } |
240 else if (spezial.startsWith(COLUMN_BEZ_BREITE)) { | 232 else if (spezial.startsWith(COLUMN_BEZ_BREITE)) { |
241 spezial = spezial.substring( | 233 spezial = spezial.substring( |
242 COLUMN_BEZ_BREITE.length()).trim(); | 234 COLUMN_BEZ_BREITE.length()).trim(); |
243 | 235 |
244 if (spezial.length() == 0) { | 236 if (spezial.length() == 0) { |
245 continue; | 237 continue; |
246 } | 238 } |
247 | 239 |
248 String[] split = spezial.split("\\s+"); | 240 final String[] split = spezial.split("\\s+"); |
249 | 241 |
250 colNaWidths = new int[split.length]; | 242 colNaWidths = new int[split.length]; |
251 for (int i=0; i < split.length; i++) { | 243 for (int i=0; i < split.length; i++) { |
252 colNaWidths[i] = Integer.parseInt(split[i]); | 244 colNaWidths[i] = Integer.parseInt(split[i]); |
253 } | 245 } |
254 } | 246 } |
255 else if (spezial.startsWith(COLUMN_QUELLE)) { | 247 else if (spezial.startsWith(COLUMN_QUELLE)) { |
256 spezial = spezial.substring( | 248 spezial = spezial.substring( |
257 COLUMN_QUELLE.length()).trim(); | 249 COLUMN_QUELLE.length()).trim(); |
258 if (spezial.length() == 0) { | 250 if (spezial.length() == 0) { |
259 continue; | 251 continue; |
260 } | 252 } |
261 quellen = StringUtil.splitQuoted(spezial, '"'); | 253 quellen = StringUtil.splitQuoted(spezial, '"'); |
262 log.debug("sources: " + Arrays.toString(quellen)); | 254 log.debug("sources: " + Arrays.toString(quellen)); |
263 } | 255 } |
264 else if (spezial.startsWith(COLUMN_DATUM)) { | 256 else if (spezial.startsWith(COLUMN_DATUM)) { |
265 spezial = spezial.substring( | 257 spezial = spezial.substring( |
266 COLUMN_DATUM.length()).trim(); | 258 COLUMN_DATUM.length()).trim(); |
267 if (spezial.length() == 0) { | 259 if (spezial.length() == 0) { |
268 continue; | 260 continue; |
269 } | 261 } |
270 daten = StringUtil.splitQuoted(spezial, '"'); | 262 daten = StringUtil.splitQuoted(spezial, '"'); |
271 } | 263 } |
281 Matcher m = UNIT_COMMENT.matcher(line); | 273 Matcher m = UNIT_COMMENT.matcher(line); |
282 if (m.matches()) { | 274 if (m.matches()) { |
283 log.debug("unit comment found"); | 275 log.debug("unit comment found"); |
284 // XXX: This hack is needed because desktop | 276 // XXX: This hack is needed because desktop |
285 // FLYS is broken figuring out the unit | 277 // FLYS is broken figuring out the unit |
286 String [] units = m.group(1).split("\\s{2,}"); | 278 final String [] units = m.group(1).split("\\s{2,}"); |
287 m = UNIT.matcher(units[0]); | 279 m = UNIT.matcher(units[0]); |
288 einheit = m.matches() ? m.group(1) : units[0]; | 280 einheit = m.matches() ? m.group(1) : units[0]; |
289 log.debug("unit: " + einheit); | 281 log.debug("unit: " + einheit); |
290 unitFound = true; | 282 unitFound = true; |
291 } | 283 } |
294 } | 286 } |
295 | 287 |
296 if (firstAbfluesse != null) { | 288 if (firstAbfluesse != null) { |
297 if (!columnHeaderChecked) { | 289 if (!columnHeaderChecked) { |
298 int unknownCount = 0; | 290 int unknownCount = 0; |
299 HashSet<String> uniqueColumnNames = | 291 final HashSet<String> uniqueColumnNames = |
300 new HashSet<String>(); | 292 new HashSet<>(); |
301 if (langBezeichner != null) { | 293 if (langBezeichner != null) { |
302 // use column name from '*!column-bez-text'-line | 294 // use column name from '*!column-bez-text'-line |
303 lsBezeichner = StringUtil.fitArray( | 295 lsBezeichner = StringUtil.fitArray( |
304 langBezeichner, lsBezeichner); | 296 langBezeichner, lsBezeichner); |
305 } | 297 } |
306 for (int i = 0; i < lsBezeichner.length; ++i) { | 298 for (int i = 0; i < lsBezeichner.length; ++i) { |
307 if (lsBezeichner[i] == null | 299 if (lsBezeichner[i] == null |
308 || lsBezeichner[i].length() == 0) { | 300 || lsBezeichner[i].length() == 0) { |
309 // generate alternative column names | 301 // generate alternative column names |
310 double q = firstAbfluesse.length > i ? | 302 final double q = firstAbfluesse.length > i ? |
311 firstAbfluesse[i].doubleValue() : 0d; | 303 firstAbfluesse[i].doubleValue() : 0d; |
312 if (q < 0.001) { | 304 if (q < 0.001) { |
313 lsBezeichner[i] = | 305 lsBezeichner[i] = |
314 "<unbekannt #" + unknownCount + ">"; | 306 "<unbekannt #" + unknownCount + ">"; |
315 ++unknownCount; | 307 ++unknownCount; |
316 } | 308 } |
317 else { | 309 else { |
318 lsBezeichner[i] = "Q="+format(q); | 310 lsBezeichner[i] = "Q="+format(q); |
319 } | 311 } |
320 } | 312 } |
321 String candidate = lsBezeichner[i]; | 313 String candidate = lsBezeichner[i]; |
322 int collision = 1; | 314 int collision = 1; |
323 while (!uniqueColumnNames.add(candidate)) { | 315 while (!uniqueColumnNames.add(candidate)) { |
324 candidate = lsBezeichner[i] + | 316 candidate = lsBezeichner[i] + |
325 " (" + collision + ")"; | 317 " (" + collision + ")"; |
326 ++collision; | 318 ++collision; |
327 } | 319 } |
328 ImportWstColumn iwc = wst.getColumn(i); | 320 final ImportWstColumn iwc = this.wst.getColumn(i); |
329 iwc.setName(candidate); | 321 iwc.setName(candidate); |
330 if (quellen != null && i < quellen.length) { | 322 if (quellen != null && i < quellen.length) { |
331 iwc.setSource(quellen[i]); | 323 iwc.setSource(quellen[i]); |
332 } | 324 } |
333 String potentialDate = | 325 final String potentialDate = |
334 daten != null && i < daten.length | 326 daten != null && i < daten.length |
335 ? daten[i] | 327 ? daten[i] |
336 : candidate; | 328 : candidate; |
337 iwc.setTimeInterval(guessDate(potentialDate)); | 329 iwc.setTimeInterval(guessDate(potentialDate)); |
338 } | 330 } |
339 columnHeaderChecked = true; | 331 columnHeaderChecked = true; |
340 } | 332 } |
341 | 333 |
342 BigDecimal [] data = parseLineAsDouble( | 334 final BigDecimal [] data = parseLineAsDouble( |
343 line, columnCount, true, false); | 335 line, columnCount, true, false); |
344 | 336 |
345 BigDecimal kaem = data[0]; | 337 final BigDecimal kaem = data[0]; |
346 | 338 |
347 if (!kms.add(kaem)) { | 339 if (!kms.add(kaem)) { |
348 log.warn( | 340 log.warn( |
349 "WST: km " + kaem + | 341 "WST: km " + kaem + |
350 " (line " + in.getLineNumber() + | 342 " (line " + in.getLineNumber() + |
351 ") found more than once. -> ignored"); | 343 ") found more than once. -> ignored"); |
352 continue; | 344 continue; |
353 } | 345 } |
354 | 346 |
355 // check consistence of station ordering in file | 347 // check consistence of station ordering in file |
356 if (kmHist2 != null && | 348 if (kmHist2 != null && |
357 kmHist2.compareTo(kmHist1) != kmHist1.compareTo(kaem) | 349 kmHist2.compareTo(kmHist1) != kmHist1.compareTo(kaem) |
358 ) { | 350 ) { |
359 throw new ParseException("WST: Stations in " + file + | 351 throw new ParseException("WST: Stations in " + file + |
360 " near line " + in.getLineNumber() + | 352 " near line " + in.getLineNumber() + |
361 " not ordered. File rejected."); | 353 " not ordered. File rejected."); |
362 } | 354 } |
363 | 355 |
364 // remember stations in two previous lines | 356 // remember stations in two previous lines |
365 kmHist2 = kmHist1; | 357 kmHist2 = kmHist1; |
366 kmHist1 = kaem; | 358 kmHist1 = kaem; |
383 if (langBezeichner != null) { | 375 if (langBezeichner != null) { |
384 // nothing to do | 376 // nothing to do |
385 } | 377 } |
386 else if (colNaWidths != null) { | 378 else if (colNaWidths != null) { |
387 for (int j = 0, i = 0, N = input.length(); | 379 for (int j = 0, i = 0, N = input.length(); |
388 j < colNaWidths.length && i < N; | 380 j < colNaWidths.length && i < N; |
389 i += colNaWidths[j++] | 381 i += colNaWidths[j++] |
390 ) { | 382 ) { |
391 lsBezeichner[j] = input.substring( | 383 lsBezeichner[j] = input.substring( |
392 i, i+colNaWidths[j]).trim(); | 384 i, i+colNaWidths[j]).trim(); |
393 } | 385 } |
394 } | 386 } |
395 else { // fetch column names from non-comment header line | 387 else { // fetch column names from non-comment header line |
396 // (above first Qs) | 388 // (above first Qs) |
397 // first column begins at position 8 in line | 389 // first column begins at position 8 in line |
398 for (int i = 8, col = 0; i < input.length(); i += 9) { | 390 for (int i = 8, col = 0; i < input.length(); i += 9) { |
399 // one column header is 9 chars wide | 391 // one column header is 9 chars wide |
400 // but the last one may be shorter | 392 // but the last one may be shorter |
401 if (col < lsBezeichner.length) { | 393 if (col < lsBezeichner.length) { |
402 lsBezeichner[col++] = | 394 lsBezeichner[col++] = |
403 input.substring( | 395 input.substring( |
404 i, | 396 i, |
405 Math.min(i + 9, input.length()) | 397 Math.min(i + 9, input.length()) |
406 ).trim(); | 398 ).trim(); |
407 } | 399 } |
408 if (col == lsBezeichner.length) { | 400 if (col == lsBezeichner.length) { |
409 break; | 401 break; |
410 } | 402 } |
411 } | 403 } |
415 } // for all lines in WST file | 407 } // for all lines in WST file |
416 | 408 |
417 if (!unitFound) { | 409 if (!unitFound) { |
418 log.warn("no unit and height reference found. Using default."); | 410 log.warn("no unit and height reference found. Using default."); |
419 } | 411 } |
420 wst.setUnit(new ImportUnit(einheit)); | 412 this.wst.setUnit(new ImportUnit(einheit)); |
421 | 413 |
422 // add Q-ranges obtained from previous lines | 414 // add Q-ranges obtained from previous lines |
423 // in case there was no further Q-line | 415 // in case there was no further Q-line |
424 // but only if there were values following the last Q-line | 416 // but only if there were values following the last Q-line |
425 if (minKm != MAX_RANGE && maxKm != MIN_RANGE) { | 417 if (minKm != MAX_RANGE && maxKm != MIN_RANGE) { |
426 if (kmHist1 != null && kmHist2 != null | 418 if (kmHist1 != null && kmHist2 != null |
427 && kmHist1.compareTo(kmHist2) < 0) { | 419 && kmHist1.compareTo(kmHist2) < 0) { |
428 // stations descending in file | 420 // stations descending in file |
429 BigDecimal t = minKm; minKm = maxKm; maxKm = t; | 421 final BigDecimal t = minKm; minKm = maxKm; maxKm = t; |
430 } | 422 } |
431 addInterval(minKm, maxKm, aktAbfluesse); | 423 addInterval(minKm, maxKm, aktAbfluesse); |
432 } | 424 } |
433 } | 425 } |
434 finally { | 426 finally { |
435 in.close(); | 427 in.close(); |
436 } | 428 } |
437 } | 429 } |
438 | 430 |
439 protected void addValue(BigDecimal km, BigDecimal w, int index) { | 431 protected void addValue(final BigDecimal km, final BigDecimal w, final int index) { |
440 if (w != null) { | 432 if (w != null) { |
441 ImportWstColumn column = wst.getColumn(index); | 433 final ImportWstColumn column = this.wst.getColumn(index); |
442 column.addColumnValue(km, w); | 434 column.addColumnValue(km, w); |
443 } | 435 } |
444 } | 436 } |
445 | 437 |
446 private static final NumberFormat NF = getNumberFormat(); | 438 private static final NumberFormat NF = getNumberFormat(); |
447 | 439 |
448 private static final NumberFormat getNumberFormat() { | 440 private static final NumberFormat getNumberFormat() { |
449 NumberFormat nf = NumberFormat.getInstance(); | 441 final NumberFormat nf = NumberFormat.getInstance(); |
450 nf.setMinimumFractionDigits(2); | 442 nf.setMinimumFractionDigits(2); |
451 nf.setMaximumFractionDigits(2); | 443 nf.setMaximumFractionDigits(2); |
452 return nf; | 444 return nf; |
453 } | 445 } |
454 | 446 |
455 protected static String format(double value) { | 447 protected static String format(final double value) { |
456 return NF.format(value); | 448 return NF.format(value); |
457 } | 449 } |
458 | 450 |
459 protected void addInterval( | 451 protected void addInterval( |
460 BigDecimal from, | 452 final BigDecimal from, |
461 BigDecimal to, | 453 final BigDecimal to, |
462 BigDecimal [] values | 454 final BigDecimal[] values |
463 ) { | 455 ) { |
464 log.debug("addInterval: " + from + " " + to); | 456 log.debug("addInterval: " + from + " " + to); |
465 | 457 |
466 if (values == null || from == MAX_RANGE || from == MIN_RANGE) { | 458 if (values == null || from == MAX_RANGE || from == MIN_RANGE) { |
467 return; | 459 return; |
468 } | 460 } |
469 | 461 |
470 // expand single-line i.e. 0-lenght Q-range to minimal length | 462 // expand single-line i.e. 0-lenght Q-range to minimal length |
463 final ImportRange range = new ImportRange(from, to); | |
471 if (from == to) { | 464 if (from == to) { |
472 if (lastRange != null && lastA > lastB) { | 465 if ((this.lastRange != null) && (this.lastRange.difference() < 0.0)) |
473 to = new BigDecimal(from.doubleValue() - INTERVAL_GAP); | 466 range.setB(from.subtract(INTERVAL_GAP)); |
474 } | 467 else |
475 else { | 468 range.setB(from.add(INTERVAL_GAP)); |
476 to = new BigDecimal(from.doubleValue() + INTERVAL_GAP); | 469 } |
477 } | |
478 } | |
479 | |
480 ImportRange range = new ImportRange(from, to); | |
481 | 470 |
482 // little workaround to make the q ranges tightly fit. | 471 // little workaround to make the q ranges tightly fit. |
483 // Leave a very small gap to ensure that the range queries | 472 // Leave a very small gap to ensure that the range queries |
484 // still work. | 473 // still work. |
485 | 474 |
486 if (lastRange != null) { | 475 if (this.lastRange != null) { |
487 double a2 = range.getA().doubleValue(); | 476 if (this.lastRange.difference() > 0.0) |
488 double b2 = range.getB().doubleValue(); | 477 this.lastRange.setB(range.getA().subtract(INTERVAL_GAP)); |
489 | 478 else // lastA >= lastB |
490 if (lastA < lastB) { | 479 this.lastRange.setA(range.getB().add(INTERVAL_GAP)); |
491 lastRange.setB(new BigDecimal(a2 - INTERVAL_GAP)); | 480 } |
492 } | 481 |
493 else { // lastA >= lastB | 482 for (int i = 0; i < values.length; ++i) |
494 lastRange.setA(new BigDecimal(b2 + INTERVAL_GAP)); | 483 this.wst.getColumn(i).addColumnQRange(new ImportWstQRange(range, values[i])); |
495 } | 484 |
496 } | 485 this.lastRange = range; |
497 | |
498 for (int i = 0; i < values.length; ++i) { | |
499 ImportWstColumn column = wst.getColumn(i); | |
500 ImportWstQRange wstQRange = new ImportWstQRange(range, values[i]); | |
501 column.addColumnQRange(wstQRange); | |
502 } | |
503 | |
504 lastA = from.doubleValue(); | |
505 lastB = to.doubleValue(); | |
506 lastRange = range; | |
507 } | 486 } |
508 | 487 |
509 private static final BigDecimal [] parseLineAsDouble( | 488 private static final BigDecimal [] parseLineAsDouble( |
510 String line, | 489 final String line, |
511 int count, | 490 final int count, |
512 boolean bStation, | 491 final boolean bStation, |
513 boolean bParseEmptyAsZero | 492 final boolean bParseEmptyAsZero |
514 ) throws ParseException { | 493 ) throws ParseException { |
515 String [] tokens = parseLine(line, count, bStation); | 494 final String [] tokens = parseLine(line, count, bStation); |
516 | 495 |
517 BigDecimal [] doubles = new BigDecimal[tokens.length]; | 496 final BigDecimal [] doubles = new BigDecimal[tokens.length]; |
518 | 497 |
519 for (int i = 0; i < doubles.length; ++i) { | 498 for (int i = 0; i < doubles.length; ++i) { |
520 String token = tokens[i].trim(); | 499 final String token = tokens[i].trim(); |
521 if (token.length() != 0) { | 500 if (token.length() != 0) { |
522 doubles[i] = new BigDecimal(token); | 501 doubles[i] = new BigDecimal(token); |
523 } | 502 } |
524 else if (bParseEmptyAsZero) { | 503 else if (bParseEmptyAsZero) { |
525 doubles[i] = UNDEFINED_ZERO; | 504 doubles[i] = UNDEFINED_ZERO; |
528 | 507 |
529 return doubles; | 508 return doubles; |
530 } | 509 } |
531 | 510 |
532 private static String [] parseLine( | 511 private static String [] parseLine( |
533 String line, | 512 final String line, |
534 int tokenCount, | 513 final int tokenCount, |
535 boolean bParseStation | 514 final boolean bParseStation |
536 ) throws ParseException { | 515 ) throws ParseException { |
537 ArrayList<String> strings = new ArrayList<String>(); | 516 final ArrayList<String> strings = new ArrayList<>(); |
538 | 517 |
539 if (bParseStation) { | 518 if (bParseStation) { |
540 if (line.length() < 8) { | 519 if (line.length() < 8) { |
541 throw new IllegalArgumentException("station too short"); | 520 throw new IllegalArgumentException("station too short"); |
542 } | 521 } |
548 pos += 9; | 527 pos += 9; |
549 if (pos >= line.length()) { | 528 if (pos >= line.length()) { |
550 break; | 529 break; |
551 } | 530 } |
552 strings.add(line.substring(pos, | 531 strings.add(line.substring(pos, |
553 Math.min(pos + 8, line.length()))); | 532 Math.min(pos + 8, line.length()))); |
554 } | 533 } |
555 | 534 |
556 return strings.toArray(new String[strings.size()]); | 535 return strings.toArray(new String[strings.size()]); |
557 } | 536 } |
558 } | 537 } |