Mercurial > dive4elements > river
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/FixWaterlevelExporter.java Tue Aug 28 14:02:23 2018 +0200 @@ -0,0 +1,259 @@ +/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ + +package org.dive4elements.river.exports; + +import java.io.OutputStream; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.dive4elements.river.artifacts.D4EArtifact; +import org.dive4elements.river.artifacts.access.RangeAccess; +import org.dive4elements.river.artifacts.common.DefaultCalculationResults; +import org.dive4elements.river.artifacts.common.ExportContextPDF; +import org.dive4elements.river.artifacts.common.GeneralResultType; +import org.dive4elements.river.artifacts.common.JasperReporter; +import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource; +import org.dive4elements.river.artifacts.model.ConstantWQKms; +import org.dive4elements.river.artifacts.model.DischargeTables; +import org.dive4elements.river.artifacts.model.WQKms; +import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils; +import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; +import org.dive4elements.river.model.Gauge; +import org.dive4elements.river.utils.Formatter; +import org.dive4elements.river.utils.RiverUtils; +import org.dive4elements.river.utils.RiverUtils.WQ_MODE; + +import au.com.bytecode.opencsv.CSVWriter; +import net.sf.jasperreports.engine.JRException; + +/** + * Generates different output formats (wst, csv, pdf) of data that resulted from + * a waterlevel computation. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class FixWaterlevelExporter extends WaterlevelExporter { + + /** The log used in this exporter. */ + private static Logger log = Logger.getLogger(FixWaterlevelExporter.class); + + private final Map<String, Double> gaugeQ_W_Map = new HashMap<>(); + + @Override + protected void writeRow4(final CSVWriter writer, final double wqkm[], final D4EArtifact flys, final Gauge gauge) { + final NumberFormat kmf = getKmFormatter(); + final NumberFormat wf = getWFormatter(); + final NumberFormat qf = getQFormatter(); + + final String waterlevel = getWaterlevel(wqkm[1], gauge); + + writer.writeNext(new String[] { kmf.format(wqkm[2]), wf.format(wqkm[0]), waterlevel, qf.format(RiverUtils.roundQ(wqkm[1])), + RiverUtils.getLocationDescription(flys, wqkm[2]) }); + } + + /** Write an csv-row at gauge location. */ + @Override + protected void writeRow6(final CSVWriter writer, final double wqkm[], final String wOrQDesc, final D4EArtifact flys, final Gauge gauge) { + final NumberFormat kmf = getKmFormatter(); + final NumberFormat wf = getWFormatter(); + final NumberFormat qf = getQFormatter(); + + final String waterlevel = getWaterlevel(wqkm[1], gauge); + + writer.writeNext(new String[] { kmf.format(wqkm[2]), wf.format(wqkm[0]), waterlevel, qf.format(RiverUtils.roundQ(wqkm[1])), wOrQDesc, + RiverUtils.getLocationDescription(flys, wqkm[2]), gauge.getName() }); + } + + private String getWaterlevel(final double discharge, final Gauge gauge) { + final NumberFormat formatter = Formatter.getWaterlevelW(this.context); + final Double waterlevel = this.getWforGaugeAndQ(gauge, discharge); + return formatter.format(waterlevel); + } + + private Double getWforGaugeAndQ(final Gauge gauge, final double q) { + + final String key = gauge.getName() + String.valueOf(q); + if (!this.gaugeQ_W_Map.containsKey(key)) { + + final DischargeTables dct = new DischargeTables(gauge.getRiver().getName(), gauge.getName()); + final double[] qs = DischargeTables.getWsForQ(dct.getFirstTable(), q); // TODO: KLÄREN, welche Abflusstabelle genommen werden soll! + if (qs != null && qs.length > 0) { + this.gaugeQ_W_Map.put(key, qs[0]); + } + } + return this.gaugeQ_W_Map.get(key); + } + + /** + * Write the header, with different headings depending on whether at a + * gauge or at a location. + */ + + @Override + protected void writeCSVHeader(final CSVWriter writer, final boolean atGauge, final boolean isQ) { + log.info("WaterlevelExporter.writeCSVHeader"); + + final String unit = RiverUtils.getRiver((D4EArtifact) this.master).getWstUnit().getName(); + + final String headerWamPegelNeu = msg("fix.export.csv.w_at_gauge"); + + if (atGauge) { + writer.writeNext(new String[] { msg(CSV_KM_HEADER, DEFAULT_CSV_KM_HEADER), msg(CSV_W_HEADER, DEFAULT_CSV_W_HEADER, new Object[] { unit }), + headerWamPegelNeu, msg(CSV_Q_HEADER, DEFAULT_CSV_Q_HEADER), + + // FIXME: use WaterlevelDescriptionBuilder instead and also remove all this duplicate code. + (isQ ? msg(CSV_Q_DESC_HEADER, DEFAULT_CSV_Q_DESC_HEADER) : msg(CSV_W_DESC_HEADER, DEFAULT_CSV_W_DESC_HEADER)), + msg(CSV_LOCATION_HEADER, DEFAULT_CSV_LOCATION_HEADER), msg(CSV_GAUGE_HEADER, DEFAULT_CSV_GAUGE_HEADER) }); + } else { + writer.writeNext(new String[] { msg(CSV_KM_HEADER, DEFAULT_CSV_KM_HEADER), msg(CSV_W_HEADER, DEFAULT_CSV_W_HEADER, new Object[] { unit }), + headerWamPegelNeu, msg(CSV_Q_HEADER, DEFAULT_CSV_Q_HEADER), msg(CSV_LOCATION_HEADER, DEFAULT_CSV_LOCATION_HEADER) }); + } + } + + @Override + protected void writePDF(final OutputStream out) { + + log.debug("write PDF"); + + final MetaAndTableJRDataSource source = new MetaAndTableJRDataSource(); + final String jasperFile = "/jasper/templates/fix_waterlevel.jrxml"; // "/jasper/fix_waterlevel_en.jasper"); + + addMetaData(source); + try { + final List<String[]> sorted = getRows(); // Custom Result could be nice, too... + for (final String[] list : sorted) { + source.addData(list); + } + + final JasperReporter reporter = new JasperReporter(); + reporter.addReport(jasperFile, source); + reporter.exportPDF(out); + } + catch (final JRException je) { + log.warn("Error generating PDF Report!", je); + } + } + + private void addMetaData(final MetaAndTableJRDataSource source) { + final D4EArtifact flys = (D4EArtifact) this.master; + final String user = CalculationUtils.findArtifactUser(this.context, flys); + final RangeAccess ra = new RangeAccess(flys); + final RiverInfo ri = new RiverInfo(ra.getRiver()); + + final DefaultCalculationResults results = new DefaultCalculationResults(msg("calculation.analysis"), user, ri, ra.getRange()); + final ExportContextPDF contextPdf = new ExportContextPDF(this.context, results); + contextPdf.addJRMetaDataDefaults(source); + contextPdf.addJRMetaDataForModules(source); + + /* column headings */ + contextPdf.addJRMetadata(source, "station_header", GeneralResultType.station); + contextPdf.addJRMetadata(source, "fix_w", msg(CSV_W_HEADER, DEFAULT_CSV_W_HEADER, new Object[] { ri.getWstUnit() })); + contextPdf.addJRMetadata(source, "w_at_gauge_header", msg("fix.export.csv.w_at_gauge")); + contextPdf.addJRMetadata(source, "fix_q", msg(CSV_Q_HEADER)); + contextPdf.addJRMetadata(source, "waterlevel_name_header", msg("common.export.csv.header.mainvalue_label")); + contextPdf.addJRMetadata(source, "location_header", msg("common.export.csv.header.location")); + contextPdf.addJRMetadata(source, "gauge_header", msg("common.export.csv.header.gauge")); + + } + + private List<String[]> getRows() { + final List<String[]> list = new ArrayList<>(); + final WQ_MODE mode = RiverUtils.getWQMode((D4EArtifact) this.master); + final boolean atGauge = mode == WQ_MODE.QGAUGE || mode == WQ_MODE.WGAUGE; + final boolean isQ = mode == WQ_MODE.QGAUGE || mode == WQ_MODE.QFREE; + + Double first = Double.NaN; + Double last = Double.NaN; + + for (final WQKms[] tmp : this.data) { + for (final WQKms wqkms : tmp) { + list.addAll(getRows2(wqkms, atGauge, isQ)); + final double[] firstLast = wqkms.getFirstLastKM(); + if (first.isNaN()) { + /* Initialize */ + first = firstLast[0]; + last = firstLast[1]; + } + if (firstLast[0] > firstLast[1]) { + /* + * Calculating upstream we assert that it is + * impossible that the direction changes during this + * loop + */ + first = Math.max(first, firstLast[0]); + last = Math.min(last, firstLast[1]); + } else if (firstLast[0] < firstLast[1]) { + first = Math.min(first, firstLast[0]); + last = Math.max(last, firstLast[1]); + } else { + first = last = firstLast[0]; + } + } + } + + /* Append the official fixing at the bottom */ + for (final WQKms wqkms : this.officalFixings) { + list.addAll(getRows2(filterWQKms(wqkms, first, last), atGauge, isQ)); + } + return list; + } + + protected List<String[]> getRows2(final WQKms wqkms, final boolean atGauge, final boolean isQ) { + log.debug("WaterlevelExporter.addWKmsData"); // OLD CODE :-/ + + final List<String[]> list = new ArrayList<>(); + // Skip constant data. + if (wqkms instanceof ConstantWQKms) { + return null; + } + + final NumberFormat kmf = getKmFormatter(); + final NumberFormat wf = getWFormatter(); + final NumberFormat qf = getQFormatter(); + + final int size = wqkms.size(); + double[] result = new double[3]; + + final D4EArtifact flys = (D4EArtifact) this.master; + final RangeAccess rangeAccess = new RangeAccess(flys); + + final Gauge gauge = rangeAccess.getRiver().determineRefGauge(rangeAccess.getKmRange(), rangeAccess.isRange()); + + final String gaugeName = gauge.getName(); + String desc = ""; + final String notinrange = msg(CSV_NOT_IN_GAUGE_RANGE, DEFAULT_CSV_NOT_IN_GAUGE_RANGE); + + final double a = gauge.getRange().getA().doubleValue(); + final double b = gauge.getRange().getB().doubleValue(); + + desc = getDesc(wqkms, isQ); + final long startTime = System.currentTimeMillis(); + + for (int i = 0; i < size; i++) { + result = wqkms.get(i, result); + final double q = result[1]; + final String waterlevel = this.getWaterlevel(q, gauge); // THIS IS NEW (and makes common super method + // difficult) + if (atGauge) { + list.add(new String[] { kmf.format(result[2]), wf.format(result[0]), waterlevel, qf.format(RiverUtils.roundQ(result[1])), desc, + RiverUtils.getLocationDescription(flys, result[2]), result[2] >= a && result[2] <= b ? gaugeName : notinrange }); + } else { + list.add(new String[] { kmf.format(result[2]), wf.format(result[0]), waterlevel, qf.format(RiverUtils.roundQ(result[1])), desc, + RiverUtils.getLocationDescription(flys, result[2]), result[2] >= a && result[2] <= b ? gaugeName : notinrange }); + } + + } + + return list; + } +} \ No newline at end of file