Mercurial > dive4elements > river
comparison artifacts/src/main/java/org/dive4elements/river/exports/FixWaterlevelExporter.java @ 9457:65f28328c9a3
ausgelagerte Wasserspiegellage AWSPL neue Spalte
author | gernotbelger |
---|---|
date | Tue, 28 Aug 2018 14:02:23 +0200 |
parents | |
children | f06e3766997f |
comparison
equal
deleted
inserted
replaced
9456:c96f6c8a6b03 | 9457:65f28328c9a3 |
---|---|
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.exports; | |
10 | |
11 import java.io.OutputStream; | |
12 import java.text.NumberFormat; | |
13 import java.util.ArrayList; | |
14 import java.util.HashMap; | |
15 import java.util.List; | |
16 import java.util.Map; | |
17 | |
18 import org.apache.log4j.Logger; | |
19 import org.dive4elements.river.artifacts.D4EArtifact; | |
20 import org.dive4elements.river.artifacts.access.RangeAccess; | |
21 import org.dive4elements.river.artifacts.common.DefaultCalculationResults; | |
22 import org.dive4elements.river.artifacts.common.ExportContextPDF; | |
23 import org.dive4elements.river.artifacts.common.GeneralResultType; | |
24 import org.dive4elements.river.artifacts.common.JasperReporter; | |
25 import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource; | |
26 import org.dive4elements.river.artifacts.model.ConstantWQKms; | |
27 import org.dive4elements.river.artifacts.model.DischargeTables; | |
28 import org.dive4elements.river.artifacts.model.WQKms; | |
29 import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils; | |
30 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; | |
31 import org.dive4elements.river.model.Gauge; | |
32 import org.dive4elements.river.utils.Formatter; | |
33 import org.dive4elements.river.utils.RiverUtils; | |
34 import org.dive4elements.river.utils.RiverUtils.WQ_MODE; | |
35 | |
36 import au.com.bytecode.opencsv.CSVWriter; | |
37 import net.sf.jasperreports.engine.JRException; | |
38 | |
39 /** | |
40 * Generates different output formats (wst, csv, pdf) of data that resulted from | |
41 * a waterlevel computation. | |
42 * | |
43 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> | |
44 */ | |
45 public class FixWaterlevelExporter extends WaterlevelExporter { | |
46 | |
47 /** The log used in this exporter. */ | |
48 private static Logger log = Logger.getLogger(FixWaterlevelExporter.class); | |
49 | |
50 private final Map<String, Double> gaugeQ_W_Map = new HashMap<>(); | |
51 | |
52 @Override | |
53 protected void writeRow4(final CSVWriter writer, final double wqkm[], final D4EArtifact flys, final Gauge gauge) { | |
54 final NumberFormat kmf = getKmFormatter(); | |
55 final NumberFormat wf = getWFormatter(); | |
56 final NumberFormat qf = getQFormatter(); | |
57 | |
58 final String waterlevel = getWaterlevel(wqkm[1], gauge); | |
59 | |
60 writer.writeNext(new String[] { kmf.format(wqkm[2]), wf.format(wqkm[0]), waterlevel, qf.format(RiverUtils.roundQ(wqkm[1])), | |
61 RiverUtils.getLocationDescription(flys, wqkm[2]) }); | |
62 } | |
63 | |
64 /** Write an csv-row at gauge location. */ | |
65 @Override | |
66 protected void writeRow6(final CSVWriter writer, final double wqkm[], final String wOrQDesc, final D4EArtifact flys, final Gauge gauge) { | |
67 final NumberFormat kmf = getKmFormatter(); | |
68 final NumberFormat wf = getWFormatter(); | |
69 final NumberFormat qf = getQFormatter(); | |
70 | |
71 final String waterlevel = getWaterlevel(wqkm[1], gauge); | |
72 | |
73 writer.writeNext(new String[] { kmf.format(wqkm[2]), wf.format(wqkm[0]), waterlevel, qf.format(RiverUtils.roundQ(wqkm[1])), wOrQDesc, | |
74 RiverUtils.getLocationDescription(flys, wqkm[2]), gauge.getName() }); | |
75 } | |
76 | |
77 private String getWaterlevel(final double discharge, final Gauge gauge) { | |
78 final NumberFormat formatter = Formatter.getWaterlevelW(this.context); | |
79 final Double waterlevel = this.getWforGaugeAndQ(gauge, discharge); | |
80 return formatter.format(waterlevel); | |
81 } | |
82 | |
83 private Double getWforGaugeAndQ(final Gauge gauge, final double q) { | |
84 | |
85 final String key = gauge.getName() + String.valueOf(q); | |
86 if (!this.gaugeQ_W_Map.containsKey(key)) { | |
87 | |
88 final DischargeTables dct = new DischargeTables(gauge.getRiver().getName(), gauge.getName()); | |
89 final double[] qs = DischargeTables.getWsForQ(dct.getFirstTable(), q); // TODO: KLÄREN, welche Abflusstabelle genommen werden soll! | |
90 if (qs != null && qs.length > 0) { | |
91 this.gaugeQ_W_Map.put(key, qs[0]); | |
92 } | |
93 } | |
94 return this.gaugeQ_W_Map.get(key); | |
95 } | |
96 | |
97 /** | |
98 * Write the header, with different headings depending on whether at a | |
99 * gauge or at a location. | |
100 */ | |
101 | |
102 @Override | |
103 protected void writeCSVHeader(final CSVWriter writer, final boolean atGauge, final boolean isQ) { | |
104 log.info("WaterlevelExporter.writeCSVHeader"); | |
105 | |
106 final String unit = RiverUtils.getRiver((D4EArtifact) this.master).getWstUnit().getName(); | |
107 | |
108 final String headerWamPegelNeu = msg("fix.export.csv.w_at_gauge"); | |
109 | |
110 if (atGauge) { | |
111 writer.writeNext(new String[] { msg(CSV_KM_HEADER, DEFAULT_CSV_KM_HEADER), msg(CSV_W_HEADER, DEFAULT_CSV_W_HEADER, new Object[] { unit }), | |
112 headerWamPegelNeu, msg(CSV_Q_HEADER, DEFAULT_CSV_Q_HEADER), | |
113 | |
114 // FIXME: use WaterlevelDescriptionBuilder instead and also remove all this duplicate code. | |
115 (isQ ? msg(CSV_Q_DESC_HEADER, DEFAULT_CSV_Q_DESC_HEADER) : msg(CSV_W_DESC_HEADER, DEFAULT_CSV_W_DESC_HEADER)), | |
116 msg(CSV_LOCATION_HEADER, DEFAULT_CSV_LOCATION_HEADER), msg(CSV_GAUGE_HEADER, DEFAULT_CSV_GAUGE_HEADER) }); | |
117 } else { | |
118 writer.writeNext(new String[] { msg(CSV_KM_HEADER, DEFAULT_CSV_KM_HEADER), msg(CSV_W_HEADER, DEFAULT_CSV_W_HEADER, new Object[] { unit }), | |
119 headerWamPegelNeu, msg(CSV_Q_HEADER, DEFAULT_CSV_Q_HEADER), msg(CSV_LOCATION_HEADER, DEFAULT_CSV_LOCATION_HEADER) }); | |
120 } | |
121 } | |
122 | |
123 @Override | |
124 protected void writePDF(final OutputStream out) { | |
125 | |
126 log.debug("write PDF"); | |
127 | |
128 final MetaAndTableJRDataSource source = new MetaAndTableJRDataSource(); | |
129 final String jasperFile = "/jasper/templates/fix_waterlevel.jrxml"; // "/jasper/fix_waterlevel_en.jasper"); | |
130 | |
131 addMetaData(source); | |
132 try { | |
133 final List<String[]> sorted = getRows(); // Custom Result could be nice, too... | |
134 for (final String[] list : sorted) { | |
135 source.addData(list); | |
136 } | |
137 | |
138 final JasperReporter reporter = new JasperReporter(); | |
139 reporter.addReport(jasperFile, source); | |
140 reporter.exportPDF(out); | |
141 } | |
142 catch (final JRException je) { | |
143 log.warn("Error generating PDF Report!", je); | |
144 } | |
145 } | |
146 | |
147 private void addMetaData(final MetaAndTableJRDataSource source) { | |
148 final D4EArtifact flys = (D4EArtifact) this.master; | |
149 final String user = CalculationUtils.findArtifactUser(this.context, flys); | |
150 final RangeAccess ra = new RangeAccess(flys); | |
151 final RiverInfo ri = new RiverInfo(ra.getRiver()); | |
152 | |
153 final DefaultCalculationResults results = new DefaultCalculationResults(msg("calculation.analysis"), user, ri, ra.getRange()); | |
154 final ExportContextPDF contextPdf = new ExportContextPDF(this.context, results); | |
155 contextPdf.addJRMetaDataDefaults(source); | |
156 contextPdf.addJRMetaDataForModules(source); | |
157 | |
158 /* column headings */ | |
159 contextPdf.addJRMetadata(source, "station_header", GeneralResultType.station); | |
160 contextPdf.addJRMetadata(source, "fix_w", msg(CSV_W_HEADER, DEFAULT_CSV_W_HEADER, new Object[] { ri.getWstUnit() })); | |
161 contextPdf.addJRMetadata(source, "w_at_gauge_header", msg("fix.export.csv.w_at_gauge")); | |
162 contextPdf.addJRMetadata(source, "fix_q", msg(CSV_Q_HEADER)); | |
163 contextPdf.addJRMetadata(source, "waterlevel_name_header", msg("common.export.csv.header.mainvalue_label")); | |
164 contextPdf.addJRMetadata(source, "location_header", msg("common.export.csv.header.location")); | |
165 contextPdf.addJRMetadata(source, "gauge_header", msg("common.export.csv.header.gauge")); | |
166 | |
167 } | |
168 | |
169 private List<String[]> getRows() { | |
170 final List<String[]> list = new ArrayList<>(); | |
171 final WQ_MODE mode = RiverUtils.getWQMode((D4EArtifact) this.master); | |
172 final boolean atGauge = mode == WQ_MODE.QGAUGE || mode == WQ_MODE.WGAUGE; | |
173 final boolean isQ = mode == WQ_MODE.QGAUGE || mode == WQ_MODE.QFREE; | |
174 | |
175 Double first = Double.NaN; | |
176 Double last = Double.NaN; | |
177 | |
178 for (final WQKms[] tmp : this.data) { | |
179 for (final WQKms wqkms : tmp) { | |
180 list.addAll(getRows2(wqkms, atGauge, isQ)); | |
181 final double[] firstLast = wqkms.getFirstLastKM(); | |
182 if (first.isNaN()) { | |
183 /* Initialize */ | |
184 first = firstLast[0]; | |
185 last = firstLast[1]; | |
186 } | |
187 if (firstLast[0] > firstLast[1]) { | |
188 /* | |
189 * Calculating upstream we assert that it is | |
190 * impossible that the direction changes during this | |
191 * loop | |
192 */ | |
193 first = Math.max(first, firstLast[0]); | |
194 last = Math.min(last, firstLast[1]); | |
195 } else if (firstLast[0] < firstLast[1]) { | |
196 first = Math.min(first, firstLast[0]); | |
197 last = Math.max(last, firstLast[1]); | |
198 } else { | |
199 first = last = firstLast[0]; | |
200 } | |
201 } | |
202 } | |
203 | |
204 /* Append the official fixing at the bottom */ | |
205 for (final WQKms wqkms : this.officalFixings) { | |
206 list.addAll(getRows2(filterWQKms(wqkms, first, last), atGauge, isQ)); | |
207 } | |
208 return list; | |
209 } | |
210 | |
211 protected List<String[]> getRows2(final WQKms wqkms, final boolean atGauge, final boolean isQ) { | |
212 log.debug("WaterlevelExporter.addWKmsData"); // OLD CODE :-/ | |
213 | |
214 final List<String[]> list = new ArrayList<>(); | |
215 // Skip constant data. | |
216 if (wqkms instanceof ConstantWQKms) { | |
217 return null; | |
218 } | |
219 | |
220 final NumberFormat kmf = getKmFormatter(); | |
221 final NumberFormat wf = getWFormatter(); | |
222 final NumberFormat qf = getQFormatter(); | |
223 | |
224 final int size = wqkms.size(); | |
225 double[] result = new double[3]; | |
226 | |
227 final D4EArtifact flys = (D4EArtifact) this.master; | |
228 final RangeAccess rangeAccess = new RangeAccess(flys); | |
229 | |
230 final Gauge gauge = rangeAccess.getRiver().determineRefGauge(rangeAccess.getKmRange(), rangeAccess.isRange()); | |
231 | |
232 final String gaugeName = gauge.getName(); | |
233 String desc = ""; | |
234 final String notinrange = msg(CSV_NOT_IN_GAUGE_RANGE, DEFAULT_CSV_NOT_IN_GAUGE_RANGE); | |
235 | |
236 final double a = gauge.getRange().getA().doubleValue(); | |
237 final double b = gauge.getRange().getB().doubleValue(); | |
238 | |
239 desc = getDesc(wqkms, isQ); | |
240 final long startTime = System.currentTimeMillis(); | |
241 | |
242 for (int i = 0; i < size; i++) { | |
243 result = wqkms.get(i, result); | |
244 final double q = result[1]; | |
245 final String waterlevel = this.getWaterlevel(q, gauge); // THIS IS NEW (and makes common super method | |
246 // difficult) | |
247 if (atGauge) { | |
248 list.add(new String[] { kmf.format(result[2]), wf.format(result[0]), waterlevel, qf.format(RiverUtils.roundQ(result[1])), desc, | |
249 RiverUtils.getLocationDescription(flys, result[2]), result[2] >= a && result[2] <= b ? gaugeName : notinrange }); | |
250 } else { | |
251 list.add(new String[] { kmf.format(result[2]), wf.format(result[0]), waterlevel, qf.format(RiverUtils.roundQ(result[1])), desc, | |
252 RiverUtils.getLocationDescription(flys, result[2]), result[2] >= a && result[2] <= b ? gaugeName : notinrange }); | |
253 } | |
254 | |
255 } | |
256 | |
257 return list; | |
258 } | |
259 } |