changeset 8884:7a8c12706834

Work on SINFO-FlowDepth
author gernotbelger
date Tue, 13 Feb 2018 14:53:23 +0100
parents a536e1aacf0f
children e5f688820951
files artifacts/doc/conf/artifacts/sinfo.xml artifacts/doc/conf/generators/longitudinal-diagram-defaults.xml artifacts/doc/conf/themes.xml artifacts/doc/conf/themes/default.xml artifacts/doc/conf/themes/second.xml artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/AbstractSInfoProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/BedHeightInfo.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResult.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResults.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthExporter.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthFacet.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthFilterFacet.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthState.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/TkhProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/WstInfo.java artifacts/src/main/resources/messages.properties artifacts/src/main/resources/messages_de.properties artifacts/src/main/resources/messages_de_DE.properties artifacts/src/main/resources/messages_en.properties
diffstat 21 files changed, 435 insertions(+), 272 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/doc/conf/artifacts/sinfo.xml	Fri Feb 09 18:07:22 2018 +0100
+++ b/artifacts/doc/conf/artifacts/sinfo.xml	Tue Feb 13 14:53:23 2018 +0100
@@ -60,6 +60,9 @@
                     <facets>
                         <!-- REMARK: id's that ends with 'filtered' are handled differently ' -->
                         <facet name="sinfo_flow_depth.filtered" description="Facet for mean flow depth, filtered by current zoom state"/>
+                        <facet name="sinfo_flow_depth.tkh.filtered" description="Facet for mean flow depth including tkh, filtered by current zoom state"/>
+                        
+                        <facet name="sinfo_flow_depth.tkh" description="Facet for tkh"/>
 
                         <!-- 
                         <facet name="flow_velocity.totalchannel" description="A facet for total channels"/>
--- a/artifacts/doc/conf/generators/longitudinal-diagram-defaults.xml	Fri Feb 09 18:07:22 2018 +0100
+++ b/artifacts/doc/conf/generators/longitudinal-diagram-defaults.xml	Tue Feb 13 14:53:23 2018 +0100
@@ -14,7 +14,8 @@
     <axis name="Velocity"/>
     <axis name="Tau"/>
     <axis name="Q" include-zero="true"/>
-    <axis name="Flowdepth" />
+    <axis name="Flowdepth"/>
+    <axis name="tkhAxis" include-zero="true" />
     <domain-axis key="chart.longitudinal.section.xaxis.label" default="Fluss-Km" inverted="org.dive4elements.river.exports.IsKmUpEvaluator()">
         <arg expr="artifact.river"/>
     </domain-axis>
@@ -45,4 +46,5 @@
 
     <!-- S-INFO -->
     <processor class="org.dive4elements.river.artifacts.sinfo.flowdepth.FlowDepthProcessor" axis="Flowdepth"/>
+    <processor class="org.dive4elements.river.artifacts.sinfo.flowdepth.TkhProcessor" axis="tkhAxis"/>
 </longitudinal-defaults>
\ No newline at end of file
--- a/artifacts/doc/conf/themes.xml	Fri Feb 09 18:07:22 2018 +0100
+++ b/artifacts/doc/conf/themes.xml	Tue Feb 13 14:53:23 2018 +0100
@@ -407,5 +407,7 @@
 
         <!--  Mappings for S-INFO -->
         <mapping from="sinfo_flow_depth.filtered" to="SInfoFlowDepth" />
+        <mapping from="sinfo_flow_depth.tkh.filtered" to="SInfoFlowDepthTkh" />
+        <mapping from="sinfo_flow_depth.tkh" to="SInfoTkh" />
     </mappings>
 </themes>
\ No newline at end of file
--- a/artifacts/doc/conf/themes/default.xml	Fri Feb 09 18:07:22 2018 +0100
+++ b/artifacts/doc/conf/themes/default.xml	Tue Feb 13 14:53:23 2018 +0100
@@ -2883,5 +2883,22 @@
                 default="0, 0, 255" />
         </fields>
     </theme>
-    
+    <theme name="SInfoFlowDepthTkh">
+        <inherits>
+            <inherit from="LongitudinalSection" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 128" />
+        </fields>
+    </theme>
+    <theme name="SInfoTkh">
+        <inherits>
+            <inherit from="LongitudinalSection" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="128, 0, 128" />
+        </fields>
+    </theme>
 </themegroup>
--- a/artifacts/doc/conf/themes/second.xml	Fri Feb 09 18:07:22 2018 +0100
+++ b/artifacts/doc/conf/themes/second.xml	Tue Feb 13 14:53:23 2018 +0100
@@ -2880,4 +2880,22 @@
                 default="0, 0, 255" />
         </fields>
     </theme>
+    <theme name="SInfoFlowDepthTkh">
+        <inherits>
+            <inherit from="LongitudinalSection" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 128" />
+        </fields>
+    </theme>
+    <theme name="SInfoTkh">
+        <inherits>
+            <inherit from="LongitudinalSection" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="128, 0, 128" />
+        </fields>
+    </theme>    
 </themegroup>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/AbstractSInfoProcessor.java	Tue Feb 13 14:53:23 2018 +0100
@@ -0,0 +1,98 @@
+/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
+ *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
+ *
+ * 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.artifacts.sinfo.flowdepth;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.exports.DiagramGenerator;
+import org.dive4elements.river.exports.StyledSeriesBuilder;
+import org.dive4elements.river.exports.process.DefaultProcessor;
+import org.dive4elements.river.jfree.StyledXYSeries;
+import org.dive4elements.river.themes.ThemeDocument;
+
+/**
+ * Abstraction for some processor implementation within S-INFO. Probably this abstraction could also be used for other
+ * cases as well.
+ *
+ * @author Gernot Belger
+ *
+ */
+abstract class AbstractSInfoProcessor extends DefaultProcessor {
+
+    private final static Logger log = Logger.getLogger(AbstractSInfoProcessor.class);
+
+    private String yAxisLabel;
+
+    private final Set<String> handled_facet_types;
+
+    private final String i18n_axis_label;
+
+    public AbstractSInfoProcessor(final String i18n_axis_label, final Set<String> handled_facet_types) {
+        this.i18n_axis_label = i18n_axis_label;
+        this.handled_facet_types = handled_facet_types;
+    }
+
+    @Override
+    public final void doOut(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible) {
+
+        final CallContext context = generator.getCallContext();
+        final Map<String, String> metaData = bundle.getFacet().getMetaData();
+
+        final StyledXYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme);
+        series.putMetaData(metaData, bundle.getArtifact(), context);
+
+        this.yAxisLabel = metaData.get("Y");
+
+        final String facetName = bundle.getFacetName();
+        final FlowDepthCalculationResult data = (FlowDepthCalculationResult) bundle.getData(context);
+        if (data == null) {
+            // Check has been here before so we keep it for security reasons
+            // this should never happen though.
+            log.error("Data is null for facet: " + facetName);
+            return;
+        }
+
+        final double[][] points = generatePoints(data, facetName);
+
+        StyledSeriesBuilder.addPoints(series, points, true);
+        generator.addAxisSeries(series, this.axisName, visible);
+    }
+
+    /**
+     * Override to implement, call super as last line for default case.
+     */
+    protected double[][] generatePoints(@SuppressWarnings("unused") final FlowDepthCalculationResult data, final String facetName) {
+        final String error = String.format("Unknown facet name: %s", facetName);
+        log.error(error);
+        throw new UnsupportedOperationException(error);
+    }
+
+    @Override
+    public final boolean canHandle(final String facettype) {
+        return this.handled_facet_types.contains(facettype);
+    }
+
+    @Override
+    public final String getAxisLabel(final DiagramGenerator generator) {
+        if (this.yAxisLabel != null && !this.yAxisLabel.isEmpty()) {
+            // REMARK/UNINTENDED: yAxisLabel may also be a resolved message (side-effect of StyledXYSeries#putMetadata),
+            // and cannot be resolved, so we need to give the resolved value as default
+            // FIXME: In other implementations (i.e. FlowVelocityProcessor), an explicit (German) default label is given here,
+            // probably the English version will also show German (CHECK)
+            return generator.msg(this.yAxisLabel, this.yAxisLabel);
+        }
+        return generator.msg(this.i18n_axis_label, "MISSING");
+    }
+}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/BedHeightInfo.java	Fri Feb 09 18:07:22 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/BedHeightInfo.java	Tue Feb 13 14:53:23 2018 +0100
@@ -9,6 +9,8 @@
  */
 package org.dive4elements.river.artifacts.sinfo.flowdepth;
 
+import java.io.Serializable;
+
 import org.dive4elements.river.model.BedHeight;
 
 /**
@@ -16,7 +18,9 @@
  *
  * @author Gernot Belger
  */
-final class BedHeightInfo {
+final class BedHeightInfo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
 
     private final Integer year;
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java	Fri Feb 09 18:07:22 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java	Tue Feb 13 14:53:23 2018 +0100
@@ -75,8 +75,7 @@
 
         final String calcModeLabel = Resources.getMsg(this.context.getMeta(), sinfo.getCalculationMode().name());
 
-        final FlowDepthCalculationResults results = new FlowDepthCalculationResults(calcModeLabel, user, river, from,
-                to, useTkh);
+        final FlowDepthCalculationResults results = new FlowDepthCalculationResults(calcModeLabel, user, river, from, to, useTkh);
 
         for (final DifferencesPair diffPair : diffPairs) {
             final FlowDepthCalculationResult result = calculateResult(river, from, to, diffPair, problems, gaugeIndex);
@@ -87,8 +86,8 @@
         return new CalculationResult(results, problems);
     }
 
-    private FlowDepthCalculationResult calculateResult(final River river, final double from, final double to,
-            final DifferencesPair diffPair, final Calculation problems, final GaugeIndex gaugeIndex) {
+    private FlowDepthCalculationResult calculateResult(final River river, final double from, final double to, final DifferencesPair diffPair,
+            final Calculation problems, final GaugeIndex gaugeIndex) {
 
         /* access real input data from database */
         final String soundingId = diffPair.getSoundingId();
@@ -96,18 +95,15 @@
 
         final BedHeight bedHeight = loadBedHeight(soundingId, from, to);
         if (bedHeight == null) {
-            final String message = Resources.format(this.context.getMeta(), "Failed to access sounding with id '{0}'",
-                    soundingId);
+            final String message = Resources.format(this.context.getMeta(), "Failed to access sounding with id '{0}'", soundingId);
             problems.addProblem(message);
             return null;
         }
 
         /* REMARK: fetch ALL wst kms, because we want to determine the original reference gauge */
-        final WaterlevelData waterlevel = new WaterlevelFetcher().findWaterlevel(this.context, wstId, Double.NaN,
-                Double.NaN);
+        final WaterlevelData waterlevel = new WaterlevelFetcher().findWaterlevel(this.context, wstId, Double.NaN, Double.NaN);
         if (waterlevel == null) {
-            final String message = Resources.format(this.context.getMeta(), "Failed to access waterlevel with id '{0}'",
-                    wstId);
+            final String message = Resources.format(this.context.getMeta(), "Failed to access waterlevel with id '{0}'", wstId);
             problems.addProblem(message);
             return null;
         }
@@ -121,8 +117,7 @@
         checkWaterlevelDiscretisation(wstKms, problems);
 
         /* re-determine the reference gauge, in the same way as the WaterlevelArtifact would do it */
-        final String notinrange = Resources.getMsg(this.context.getMeta(), CSV_NOT_IN_GAUGE_RANGE,
-                CSV_NOT_IN_GAUGE_RANGE);
+        final String notinrange = Resources.getMsg(this.context.getMeta(), CSV_NOT_IN_GAUGE_RANGE, CSV_NOT_IN_GAUGE_RANGE);
 
         final Gauge refGauge = waterlevel.findReferenceGauge(river);
         final String refGaugeName = refGauge == null ? notinrange : refGauge.getName();
@@ -136,23 +131,23 @@
         // FIXME: nur prüfen/beschaffen wenn TKH Berechnung aktiv
         /* Abflusswerte vorhanden? */
         if (!(wstKms instanceof QKms)) {
-            final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ",
-                    null, label);
+            final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null, label);
             problems.addProblem(message);
             // TODO: keine Berechnung TKH
         }
 
+        // FIXME
         // - Sohlbeschaffenheit (D50 Korndurchmesser aus Seddb)
         // - Abhängig von Peiljahr
         // - kein D50 vorhanden --> Fehler
 
+        // FIXME
         // - Art der Gewässersohle (starr/mobil)
 
         final String bedHeightLabel = bedHeight.getDescription();
         final String wstLabel = wstKms.getName();
 
-        final UnivariateRealFunction wstInterpolator = DoubleUtil.getLinearInterpolator(wstKms.allKms(),
-                wstKms.allWs());
+        final UnivariateRealFunction wstInterpolator = DoubleUtil.getLinearInterpolator(wstKms.allKms(), wstKms.allWs());
 
         // FIXME: sort by station first, but in what direction?
         final List<BedHeightValue> values = bedHeight.getValues();
@@ -195,8 +190,7 @@
 
                 final String gaugeLabel = gauge == null ? notinrange : gauge.getName();
 
-                resultData.addRow(km, flowDepth, flowDepthTkh, tkh, wst, discharge, wstLabel, gaugeLabel, meanBedHeight,
-                        bedHeightLabel, location);
+                resultData.addRow(km, flowDepth, flowDepthTkh, tkh, wst, discharge, wstLabel, gaugeLabel, meanBedHeight, bedHeightLabel, location);
             }
             catch (final FunctionEvaluationException e) {
                 /* should only happen if out of range */
@@ -218,8 +212,7 @@
      * 1918 ≤ X < 1958 ± 12
      * X < 1918 ± 25
      */
-    private void checkYearDifference(final String label, final WaterlevelData waterlevel, final BedHeight sounding,
-            final Calculation problems) {
+    private void checkYearDifference(final String label, final WaterlevelData waterlevel, final BedHeight sounding, final Calculation problems) {
 
         final Integer soundingYear = sounding.getYear();
         if (soundingYear == null)
@@ -233,8 +226,7 @@
 
         final int difference = Math.abs(soundingYear - wstYear);
         if (difference > maxDifference) {
-            final String message = Resources.getMsg(this.context.getMeta(),
-                    "sinfo_calc_flow_depth.warning.year_difference", null, label, difference);
+            final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.year_difference", null, label, difference);
             problems.addProblem(message);
         }
     }
@@ -254,8 +246,7 @@
         return 3;
     }
 
-    private Gauge findGauge(final WaterlevelData waterlevel, final Gauge refGauge, final GaugeIndex gaugeIndex,
-            final double km) {
+    private Gauge findGauge(final WaterlevelData waterlevel, final Gauge refGauge, final GaugeIndex gaugeIndex, final double km) {
 
         // REMARK: using same logic as in WaterlevelExporter here
 
@@ -271,6 +262,7 @@
     }
 
     /* Checks if the discretisation of the waterlevel exceeds 1000m */
+    // FIXME: vermutlich sollten wir diesen check auf den gültigkeitsbereich einschränken
     private void checkWaterlevelDiscretisation(final WKms wstKms, final Calculation problems) {
         final int size = wstKms.size();
         for (int i = 0; i < size - 2; i++) {
@@ -280,8 +272,7 @@
             if (Math.abs(kmPrev - kmNext) > 1) {
                 final String label = wstKms.getName();
 
-                final String message = Resources.getMsg(this.context.getMeta(),
-                        "sinfo_calc_flow_depth.warning.waterlevel_discretisation", null, label);
+                final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.waterlevel_discretisation", null, label);
                 problems.addProblem(kmPrev, message);
             }
         }
@@ -314,4 +305,4 @@
 
         return BedHeight.getBedHeightById(bedheightId);
     }
-}
+}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResult.java	Fri Feb 09 18:07:22 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResult.java	Tue Feb 13 14:53:23 2018 +0100
@@ -72,4 +72,29 @@
 
         return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() };
     }
+
+    public double[][] getFlowDepthTkhPoints() {
+
+        final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size());
+        final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size());
+
+        for (final FlowDepthRow row : this.rows) {
+            xPoints.add(row.getStation());
+            yPoints.add(row.getFlowDepthWithTkh());
+        }
+
+        return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() };
+    }
+
+    public double[][] getTkhPoints() {
+        final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size());
+        final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size());
+
+        for (final FlowDepthRow row : this.rows) {
+            xPoints.add(row.getStation());
+            yPoints.add(row.getTkh());
+        }
+
+        return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() };
+    }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResults.java	Fri Feb 09 18:07:22 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResults.java	Tue Feb 13 14:53:23 2018 +0100
@@ -9,6 +9,7 @@
  */
 package org.dive4elements.river.artifacts.sinfo.flowdepth;
 
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -18,7 +19,9 @@
 /**
  * @author Gernot Belger
  */
-public final class FlowDepthCalculationResults {
+public final class FlowDepthCalculationResults implements Serializable {
+    private static final long serialVersionUID = 1L;
+
     private final List<FlowDepthCalculationResult> results = new ArrayList<>();
 
     private final River river;
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthExporter.java	Fri Feb 09 18:07:22 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthExporter.java	Tue Feb 13 14:53:23 2018 +0100
@@ -100,7 +100,6 @@
 
     private static final String CSV_META_HEADER_WATERLEVEL_NAME = "sinfo.export.flow_depth.csv.meta.header.waterlevel.name";
 
-
     private static final String CSV_META_HEADER_WATERLEVEL_GAUGE = "sinfo.export.flow_depth.csv.meta.header.waterlevel.gauge";
 
     private static final String CSV_META_HEADER_WATERLEVEL_YEAR = "sinfo.export.flow_depth.csv.meta.header.waterlevel.year";
@@ -163,8 +162,7 @@
         }
     }
 
-    private void writeCSVFlowDepthResult(final CSVWriter writer, final FlowDepthCalculationResult result,
-            final boolean useTkh) {
+    private void writeCSVFlowDepthResult(final CSVWriter writer, final FlowDepthCalculationResult result, final boolean useTkh) {
 
         /* first some specific metadata */
         final BedHeightInfo sounding = result.getSounding();
@@ -184,8 +182,7 @@
         // "# Höhensystem: "
         writeCSVMetaEntry(writer, CSV_META_HEADER_SOUNDING_ELEVATIOIN_MODEL, sounding.getCurElevationModelUnit());
         // "# ursprüngliches Höhensystem: "
-        writeCSVMetaEntry(writer, CSV_META_HEADER_SOUNDING_ELEVATIOIN_MODEL_ORIGINAL,
-                sounding.getOldElevationModelUnit());
+        writeCSVMetaEntry(writer, CSV_META_HEADER_SOUNDING_ELEVATIOIN_MODEL_ORIGINAL, sounding.getOldElevationModelUnit());
 
         // "##METADATEN WASSERSPIEGELLAGE"
         writeCSVMetaEntry(writer, CSV_META_HEADER_WATERLEVEL);
@@ -208,8 +205,7 @@
 
         final String calcModeLabel = results.getCalcModeLabel();
         final River river = results.getRiver();
-        writeCSVMetaEntry(writer, CSV_META_HEADER_RESULT, msg(CSV_META_HEADER_RESULT_LABEL), river.getName(),
-                calcModeLabel);
+        writeCSVMetaEntry(writer, CSV_META_HEADER_RESULT, msg(CSV_META_HEADER_RESULT_LABEL), river.getName(), calcModeLabel);
 
         // "# FLYS-Version: "
         writeCSVMetaEntry(writer, CSV_META_VERSION, msg(CSV_META_VERSION_LABEL), FLYS.VERSION);
@@ -302,10 +298,9 @@
 
         // Q [m³/s]
         final double discharge = row.getDischarge();
-        if( Double.isNaN(discharge))
+        if (Double.isNaN(discharge))
             lines.add(StringUtils.EMPTY);
-        else
-        {
+        else {
             final double roundedDischarge = RiverUtils.roundQ(discharge);
             lines.add(getQFormatter().format(roundedDischarge));
         }
@@ -402,8 +397,7 @@
         source.addMetaData("river_label", msg(CSV_META_RIVER_LABEL));
         source.addMetaData("river", river.getName());
 
-        final String rangeValue = String.format("%s - %s", getKmFormatter().format(results.getFrom()),
-                getKmFormatter().format(results.getTo()));
+        final String rangeValue = String.format("%s - %s", getKmFormatter().format(results.getFrom()), getKmFormatter().format(results.getTo()));
         source.addMetaData("range_label", msg(CSV_META_RANGE_LABEL));
         source.addMetaData("range", rangeValue);
 
@@ -422,8 +416,7 @@
         source.addMetaData("location_header", msg(CSV_LOCATION_HEADER));
     }
 
-    private void addJRTableData(final MetaAndTableJRDataSource source, final FlowDepthCalculationResult result,
-            final boolean useTkh) {
+    private void addJRTableData(final MetaAndTableJRDataSource source, final FlowDepthCalculationResult result, final boolean useTkh) {
 
         final Collection<FlowDepthRow> rows = result.getRows();
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthFacet.java	Tue Feb 13 14:53:23 2018 +0100
@@ -0,0 +1,93 @@
+/* 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.artifacts.sinfo.flowdepth;
+
+import org.apache.log4j.Logger;
+import org.dive4elements.artifactdatabase.state.Facet;
+import org.dive4elements.artifacts.Artifact;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.artifacts.D4EArtifact;
+import org.dive4elements.river.artifacts.model.CalculationResult;
+import org.dive4elements.river.artifacts.model.DataFacet;
+import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
+
+/**
+ * Facet of a FlowDepth curve.
+ */
+public class FlowDepthFacet extends DataFacet {
+
+    private static final long serialVersionUID = 1L;
+
+    private static Logger log = Logger.getLogger(FlowDepthFacet.class);
+
+    public FlowDepthFacet() {
+        // required for clone operation deepCopy()
+    }
+
+    public FlowDepthFacet(final int idx, final String name, final String description, final String yAxisLabelKey, final ComputeType type, final String stateId,
+            final String hash) {
+        super(idx, name, description, type, hash, stateId);
+        this.metaData.put("X", "sinfo.chart.flow_depth.xaxis.label");
+        this.metaData.put("Y", yAxisLabelKey);
+    }
+
+    @Override
+    public Object getData(final Artifact artifact, final CallContext context) {
+        log.debug("Get data for flow velocity at index: " + this.index);
+
+        final D4EArtifact flys = (D4EArtifact) artifact;
+
+        final CalculationResult res = (CalculationResult) flys.compute(context, this.hash, this.stateId, this.type, false);
+
+        final FlowDepthCalculationResults data = (FlowDepthCalculationResults) res.getData();
+
+        final FlowDepthCalculationResult result = data.getResults().get(this.index);
+
+        // FIXME: variable mean computation depending on current scale
+
+        // Double start = (Double)context.getContextValue("startkm");
+        // Double end = (Double)context.getContextValue("endkm");
+        // if(start != null && end != null) {
+        // RiverContext fc = (RiverContext)context.globalContext();
+        // ZoomScale scales = (ZoomScale)fc.get("zoomscale");
+        // RiverAccess access = new RiverAccess((D4EArtifact)artifact);
+        // String river = access.getRiverName();
+        //
+        // double radius = scales.getRadius(river, start, end);
+        // FlowVelocityData oldData = data[index];
+        // FlowVelocityData newData = new FlowVelocityData();
+        // double[][] q = oldData.getQPoints();
+        // double[][] totalV = MovingAverage.weighted(oldData.getTotalChannelPoints(), radius);
+        // double[][] mainV = MovingAverage.weighted(oldData.getMainChannelPoints(), radius);
+        // double[][] tau = MovingAverage.weighted(oldData.getTauPoints(), radius);
+        // for(int j = 0; j < q[0].length; j++) {
+        // newData.addKM(q[0][j]);
+        // newData.addQ(q[1][j]);
+        // newData.addTauMain(tau[1][j]);
+        // newData.addVMain(mainV[1][j]);
+        // newData.addVTotal(totalV[1][j]);
+        // }
+        // return newData;
+        // }
+
+        return result;
+    }
+
+    /** Copy deeply. */
+    @Override
+    public Facet deepCopy() {
+        final FlowDepthFacet copy = new FlowDepthFacet();
+        // FIXME: why does DataFacet does not override set? Bad access to variables of parent!
+        copy.set(this);
+        copy.type = this.type;
+        copy.hash = this.hash;
+        copy.stateId = this.stateId;
+        return copy;
+    }
+}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthFilterFacet.java	Fri Feb 09 18:07:22 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +0,0 @@
-/* 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.artifacts.sinfo.flowdepth;
-
-import org.apache.log4j.Logger;
-import org.dive4elements.artifactdatabase.state.Facet;
-import org.dive4elements.artifacts.Artifact;
-import org.dive4elements.artifacts.CallContext;
-import org.dive4elements.river.artifacts.D4EArtifact;
-import org.dive4elements.river.artifacts.model.CalculationResult;
-import org.dive4elements.river.artifacts.model.DataFacet;
-import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
-
-/**
- * Facet of a FlowDepth curve.
- */
-public class FlowDepthFilterFacet extends DataFacet {
-
-    private static Logger log = Logger.getLogger(FlowDepthFilterFacet.class);
-
-    public FlowDepthFilterFacet() {
-        // required for clone operation deepCopy()
-    }
-
-    public FlowDepthFilterFacet(
-        int         idx,
-        String      name,
-        String      description,
-        ComputeType type,
-        String      stateId,
-        String      hash
-    ) {
-        super(idx, name, description, type, hash, stateId);
-        this.metaData.put("X", "sinfo.chart.flow_depth.xaxis.label");
-        this.metaData.put("Y", "sinfo.chart.flow_depth.yaxis.label");
-    }
-
-    @Override
-    public Object getData(Artifact artifact, CallContext context) {
-        log.debug("Get data for flow velocity at index: " + index);
-
-        final D4EArtifact flys = (D4EArtifact) artifact;
-
-        final CalculationResult res = (CalculationResult)
-            flys.compute(context, hash, stateId, type, false);
-
-        final FlowDepthCalculationResults data = (FlowDepthCalculationResults) res.getData();
-        
-        final FlowDepthCalculationResult result = data.getResults().get(index);
-
-        // FIXME: variable mean computation depending on current scale
-//      Double start = (Double)context.getContextValue("startkm");
-//      Double end = (Double)context.getContextValue("endkm");
-//        if(start != null && end != null) {
-//            RiverContext fc = (RiverContext)context.globalContext();
-//            ZoomScale scales = (ZoomScale)fc.get("zoomscale");
-//            RiverAccess access = new RiverAccess((D4EArtifact)artifact);
-//            String river = access.getRiverName();
-//
-//            double radius = scales.getRadius(river, start, end);
-//            FlowVelocityData oldData = data[index];
-//            FlowVelocityData newData = new FlowVelocityData();
-//            double[][] q = oldData.getQPoints();
-//            double[][] totalV = MovingAverage.weighted(oldData.getTotalChannelPoints(), radius);
-//            double[][] mainV = MovingAverage.weighted(oldData.getMainChannelPoints(), radius);
-//            double[][] tau = MovingAverage.weighted(oldData.getTauPoints(), radius);
-//            for(int j = 0; j < q[0].length; j++) {
-//                newData.addKM(q[0][j]);
-//                newData.addQ(q[1][j]);
-//                newData.addTauMain(tau[1][j]);
-//                newData.addVMain(mainV[1][j]);
-//                newData.addVTotal(totalV[1][j]);
-//            }
-//            return newData;
-//        }
-
-      return result;
-    }
-
-
-    /** Copy deeply. */
-    @Override
-    public Facet deepCopy() {
-        FlowDepthFilterFacet copy = new FlowDepthFilterFacet();
-        // FIXME: why does DataFacet does not override set? Bad access to variables of parent!
-        copy.set(this);
-        copy.type    = type;
-        copy.hash    = hash;
-        copy.stateId = stateId;
-        return copy;
-    }
-}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthProcessor.java	Fri Feb 09 18:07:22 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthProcessor.java	Tue Feb 13 14:53:23 2018 +0100
@@ -1,6 +1,6 @@
 /* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
- * Software engineering by 
- *  Björnsen Beratende Ingenieure GmbH 
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
  *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
  *
  * This file is Free Software under the GNU AGPL (>=v3)
@@ -10,96 +10,41 @@
 
 package org.dive4elements.river.artifacts.sinfo.flowdepth;
 
-import java.util.Map;
+import java.util.HashSet;
+import java.util.Set;
 
-import org.apache.log4j.Logger;
-import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
-import org.dive4elements.artifacts.CallContext;
-import org.dive4elements.river.exports.DiagramGenerator;
-import org.dive4elements.river.exports.StyledSeriesBuilder;
-import org.dive4elements.river.exports.process.DefaultProcessor;
-import org.dive4elements.river.jfree.StyledXYSeries;
-import org.dive4elements.river.themes.ThemeDocument;
+public final class FlowDepthProcessor extends AbstractSInfoProcessor {
 
-public final class FlowDepthProcessor extends DefaultProcessor {
-
-	/* Theme name, usually defined in 'FacetTypes', but that is soooo bad dependencies... */
+    /* Theme name, usually defined in 'FacetTypes', but that is soooo bad dependencies... */
+    // REMARK: these mustend with 'filtered' so extra handling happens in chart: point are always recalculated, because data
+    // changes depending on zoom state
     static String FACET_FLOW_DEPTH_FILTERED = "sinfo_flow_depth.filtered";
 
-    private final static Logger log = Logger.getLogger(FlowDepthProcessor.class);
+    static String FACET_FLOW_DEPTH_TKH_FILTERED = "sinfo_flow_depth.tkh.filtered";
+
+    private static final Set<String> HANDLED_FACET_TYPES = new HashSet<>();
+
+    static {
+        HANDLED_FACET_TYPES.add(FACET_FLOW_DEPTH_FILTERED);
+        HANDLED_FACET_TYPES.add(FACET_FLOW_DEPTH_TKH_FILTERED);
+    }
 
     private static final String I18N_AXIS_LABEL = "sinfo.chart.flow_depth.section.yaxis.label";
-    private String yAxisLabel;
-
-    @Override
-    public void doOut(
-            final DiagramGenerator generator,
-            final ArtifactAndFacet bundle,
-            final ThemeDocument    theme,
-            final boolean          visible) {
-
-        final CallContext context = generator.getCallContext();
-        final Map<String, String> metaData = bundle.getFacet().getMetaData();
-        
-        final StyledXYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme);
-        series.putMetaData(metaData, bundle.getArtifact(), context);
 
-        yAxisLabel = metaData.get("Y");
-
-        final String facetName = bundle.getFacetName();
-        final FlowDepthCalculationResult data = (FlowDepthCalculationResult) bundle.getData(context);
-        if (data == null) {
-            // Check has been here before so we keep it for security reasons
-            // this should never happen though.
-            log.error("Data is null for facet: " + facetName);
-            return;
-        }
-        
-        final double [][] points = generatePoints(data);
-
-        StyledSeriesBuilder.addPoints(series, points, true);
-        generator.addAxisSeries(series, axisName, visible);
+    public FlowDepthProcessor() {
+        super(I18N_AXIS_LABEL, HANDLED_FACET_TYPES);
     }
 
-    private static double[][] generatePoints(final FlowDepthCalculationResult data) {
-
-    	// FIXME
-    	return data.getFlowDepthPoints();
+    // FIXME: do filtering
+    @Override
+    protected double[][] generatePoints(final FlowDepthCalculationResult data, final String facetName) {
 
-//        if (facetName.equals(FacetTypes.FLOW_VELOCITY_TOTALCHANNEL) ||
-//                facetName.equals(FacetTypes.FLOW_VELOCITY_TOTALCHANNEL_FILTERED)) {
-//            FlowVelocityData fData = (FlowVelocityData) data;
-//            points = fData.getTotalChannelPoints();
-//        } else if (facetName.equals(FacetTypes.FLOW_VELOCITY_MAINCHANNEL) ||
-//                facetName.equals(FacetTypes.FLOW_VELOCITY_MAINCHANNEL_FILTERED)) {
-//            FlowVelocityData fData = (FlowVelocityData) data;
-//            points = fData.getMainChannelPoints(); // I hate facets!
-//        } else if (facetName.equals(FacetTypes.FLOW_VELOCITY_MEASUREMENT)) {
-//            FastFlowVelocityMeasurementValue fData =
-//                (FastFlowVelocityMeasurementValue) data;
-//            points = new double[][] {{fData.getStation()},{fData.getV()}};
-//        } else {
-//            log.error("Unknown facet name: " + facetName);
-//            return;
-//        }
-	}
+        if (FACET_FLOW_DEPTH_FILTERED.contentEquals(facetName))
+            return data.getFlowDepthPoints();
 
-	@Override
-    public boolean canHandle(String facettype) {
-        return FACET_FLOW_DEPTH_FILTERED.equals(facettype);
-    }
+        if (FACET_FLOW_DEPTH_TKH_FILTERED.contentEquals(facetName))
+            return data.getFlowDepthTkhPoints();
 
-    @Override
-    public String getAxisLabel(DiagramGenerator generator) {
-        if (yAxisLabel != null && !yAxisLabel.isEmpty()) {
-        	// REMARK/UNINTENDED: yAxisLabel may also be a resolved message (side-effect of StyledXYSeries#putMetadata),
-        	// and cannot be resolved, so we need to give the resolved value as default
-        	// In other implementations (i.e. FlowVelocityProcessor), an explicit (German) default label is given here, probably
-        	// the English version will also show German (CHECK)
-            return generator.msg(yAxisLabel, yAxisLabel);
-        }
-        return generator.msg(
-                I18N_AXIS_LABEL,
-                "MISSING");
+        return super.generatePoints(data, facetName);
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthState.java	Fri Feb 09 18:07:22 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthState.java	Tue Feb 13 14:53:23 2018 +0100
@@ -25,9 +25,8 @@
 import org.dive4elements.river.artifacts.states.DefaultState;
 
 /** State in which a waterlevel has been calculated. */
-public class FlowDepthState
-extends      DefaultState
-{
+public class FlowDepthState extends DefaultState {
+
     /// ** The log that is used in this state. */
     // private static Logger log = Logger.getLogger(FlowDepthState.class);
 
@@ -35,6 +34,14 @@
 
     private static final String I18N_FACET_FLOW_DEPTH_FILTERED_DESCRIPTION = "sinfo.facet.flow_depth.filtered.description";
 
+    private static final String I18N_FACET_FLOW_DEPTH_TKH_FILTERED_DESCRIPTION = "sinfo.facet.flow_depth.tkh.filtered.description";
+
+    private static final String I18N_FACET_TKH_DESCRIPTION = "sinfo.facet.tkh.description";
+
+    private static final String SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL = "sinfo.chart.flow_depth.yaxis.label";
+
+    private static final String SINFO_CHART_TKX_YAXIS_LABEL = "sinfo.chart.tkh.yaxis.label";
+
     /**
      * From this state can only be continued trivially.
      */
@@ -44,13 +51,7 @@
     }
 
     @Override
-    public Object computeFeed(
-            final D4EArtifact artifact,
-            final String       hash,
-            final CallContext  context,
-            final List<Facet>  facets,
-            final Object       old
-            ) {
+    public Object computeFeed(final D4EArtifact artifact, final String hash, final CallContext context, final List<Facet> facets, final Object old) {
         // FIXME: why is this necessary?
         if (artifact instanceof ChartArtifact) {
             facets.add(new EmptyFacet());
@@ -61,13 +62,7 @@
     }
 
     @Override
-    public Object computeAdvance(
-            final D4EArtifact artifact,
-            final String       hash,
-            final CallContext  context,
-            final List<Facet>  facets,
-            final Object       old
-            ) {
+    public Object computeAdvance(final D4EArtifact artifact, final String hash, final CallContext context, final List<Facet> facets, final Object old) {
         if (artifact instanceof ChartArtifact) {
             facets.add(new EmptyFacet());
             return null;
@@ -77,15 +72,11 @@
 
     /**
      * Compute result or returned object from cache, create facets.
-     * @param old Object that was cached.
+     *
+     * @param old
+     *            Object that was cached.
      */
-    private Object compute(
-            final SINFOArtifact sinfo,
-            final CallContext   context,
-            final String        hash,
-            final List<Facet>   facets,
-            final Object        old
-            ) {
+    private Object compute(final SINFOArtifact sinfo, final CallContext context, final String hash, final List<Facet> facets, final Object old) {
 
         final CalculationResult res;
         if (old instanceof CalculationResult)
@@ -97,7 +88,7 @@
             return res;
         }
 
-        final FlowDepthCalculationResults results =  (FlowDepthCalculationResults) res.getData();
+        final FlowDepthCalculationResults results = (FlowDepthCalculationResults) res.getData();
 
         /* add themes for chart, for each result */
         final List<FlowDepthCalculationResult> resultList = results.getResults();
@@ -106,24 +97,36 @@
             final FlowDepthCalculationResult result = resultList.get(index);
 
             /* filtered (zoom dependent mean) flow depth */
-            final String facetFlowDepthFilteredDescription = Resources.getMsg( context.getMeta(), I18N_FACET_FLOW_DEPTH_FILTERED_DESCRIPTION, I18N_FACET_FLOW_DEPTH_FILTERED_DESCRIPTION, result.getLabel() );
-            facets.add(new FlowDepthFilterFacet(
-                    index,
-                    FlowDepthProcessor.FACET_FLOW_DEPTH_FILTERED,
-                    facetFlowDepthFilteredDescription,
-                    ComputeType.ADVANCE,
-                    this.id,
-                    hash
-                    ));
+            final String facetFlowDepthFilteredDescription = Resources.getMsg(context.getMeta(), I18N_FACET_FLOW_DEPTH_FILTERED_DESCRIPTION,
+                    I18N_FACET_FLOW_DEPTH_FILTERED_DESCRIPTION, result.getLabel());
+            facets.add(new FlowDepthFacet(index, FlowDepthProcessor.FACET_FLOW_DEPTH_FILTERED, facetFlowDepthFilteredDescription,
+                    SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, ComputeType.ADVANCE, this.id, hash));
 
-            // FIXME: add other themes
+            if (results.isUseTkh()) {
+                /* filtered (zoom dependent mean) flow depth including tkh */
+                final String facetFlowDepthTkhFilteredDescription = Resources.getMsg(context.getMeta(), I18N_FACET_FLOW_DEPTH_TKH_FILTERED_DESCRIPTION,
+                        I18N_FACET_FLOW_DEPTH_TKH_FILTERED_DESCRIPTION, result.getLabel());
+                facets.add(new FlowDepthFacet(index, FlowDepthProcessor.FACET_FLOW_DEPTH_TKH_FILTERED, facetFlowDepthTkhFilteredDescription,
+                        SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, ComputeType.ADVANCE, this.id, hash));
+
+                // FIXME: add other themes
+                // - Streckenfavoriten
+
+                // FIXME:
+                // - Gemittelte Linie der Fließtiefe mitsamt TKH
+                // - Transportkörperhöhen (oben/unten/schraffur)
+                final String facetTkhDescription = Resources.getMsg(context.getMeta(), I18N_FACET_TKH_DESCRIPTION, I18N_FACET_TKH_DESCRIPTION,
+                        result.getLabel());
+                facets.add(new FlowDepthFacet(index, TkhProcessor.FACET_TKH, facetTkhDescription, SINFO_CHART_TKX_YAXIS_LABEL, ComputeType.ADVANCE, this.id,
+                        hash));
+            }
+
+            // FIXME: Datenkorbkonfiguration
         }
 
-        if (!resultList.isEmpty() ) {
-            final Facet csv = new DataFacet(
-                    FacetTypes.CSV, "CSV data", ComputeType.ADVANCE, hash, this.id);
-            final Facet pdf = new DataFacet(
-                    FacetTypes.PDF, "PDF data", ComputeType.ADVANCE, hash, this.id);
+        if (!resultList.isEmpty()) {
+            final Facet csv = new DataFacet(FacetTypes.CSV, "CSV data", ComputeType.ADVANCE, hash, this.id);
+            final Facet pdf = new DataFacet(FacetTypes.PDF, "PDF data", ComputeType.ADVANCE, hash, this.id);
 
             facets.add(csv);
             facets.add(pdf);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/TkhProcessor.java	Tue Feb 13 14:53:23 2018 +0100
@@ -0,0 +1,39 @@
+/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
+ *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
+ *
+ * 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.artifacts.sinfo.flowdepth;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public final class TkhProcessor extends AbstractSInfoProcessor {
+
+    static String FACET_TKH = "sinfo_flow_depth.tkh";
+
+    private static final Set<String> HANDLED_FACET_TYPES = new HashSet<>();
+
+    static {
+        HANDLED_FACET_TYPES.add(FACET_TKH);
+    }
+
+    private static final String I18N_AXIS_LABEL = "sinfo.chart.tkh.section.yaxis.label";
+
+    public TkhProcessor() {
+        super(I18N_AXIS_LABEL, HANDLED_FACET_TYPES);
+    }
+
+    @Override
+    protected double[][] generatePoints(final FlowDepthCalculationResult data, final String facetName) {
+        if (FACET_TKH.contentEquals(facetName))
+            return data.getTkhPoints();
+
+        return super.generatePoints(data, facetName);
+    }
+}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/WstInfo.java	Fri Feb 09 18:07:22 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/WstInfo.java	Tue Feb 13 14:53:23 2018 +0100
@@ -9,13 +9,19 @@
  */
 package org.dive4elements.river.artifacts.sinfo.flowdepth;
 
+import java.io.Serializable;
+
 /**
  * @author Gernot Belger
  */
-final class WstInfo {
+final class WstInfo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
 
     private final String label;
+
     private final int year;
+
     private final String gauge;
 
     public WstInfo(final String label, final int year, final String gauge) {
--- a/artifacts/src/main/resources/messages.properties	Fri Feb 09 18:07:22 2018 +0100
+++ b/artifacts/src/main/resources/messages.properties	Tue Feb 13 14:53:23 2018 +0100
@@ -845,5 +845,9 @@
 sinfo.chart.flow_depth.yaxis.label = Flie\u00dftiefe [m]
 
 sinfo.chart.flow_depth.section.yaxis.label=Flie\u00dftiefe h [m]
-sinfo.facet.flow_depth.filtered.description = Flie\u00dftiefe ({0}) 
+sinfo.facet.flow_depth.filtered.description = Flie\u00dftiefe ({0})
+sinfo.facet.flow_depth.tkh.filtered.description = Flie\u00dftiefe mit TKH ({0})
 
+sinfo.facet.tkh.description = Transportk\u00f6rperh\u00f6hen ({0})
+sinfo.chart.tkh.section.yaxis.label = Transportk\u00f6rperh\u00f6hen [cm]
+sinfo.chart.tkh.yaxis.label = Transportk\u00f6rperh\u00f6hen [cm]
\ No newline at end of file
--- a/artifacts/src/main/resources/messages_de.properties	Fri Feb 09 18:07:22 2018 +0100
+++ b/artifacts/src/main/resources/messages_de.properties	Tue Feb 13 14:53:23 2018 +0100
@@ -852,5 +852,10 @@
 sinfo.chart.flow_depth.xaxis.label = {0}-km
 sinfo.chart.flow_depth.yaxis.label = Flie\u00dftiefe [m]
 
-sinfo.chart.flow_depth.section.yaxis.label=Flow Depth h [m]
-sinfo.facet.flow_depth.filtered.description = Flie\u00dftiefe ({0}) 
\ No newline at end of file
+sinfo.chart.flow_depth.section.yaxis.label=Flie\u00dftiefe h [m]
+sinfo.facet.flow_depth.filtered.description = Flie\u00dftiefe ({0})
+sinfo.facet.flow_depth.tkh.filtered.description = Flie\u00dftiefe mit TKH ({0})
+
+sinfo.facet.tkh.description = Transportk\u00f6rperh\u00f6hen ({0})
+sinfo.chart.tkh.section.yaxis.label = Transportk\u00f6rperh\u00f6hen [cm]
+sinfo.chart.tkh.yaxis.label = Transportk\u00f6rperh\u00f6hen [cm]
\ No newline at end of file
--- a/artifacts/src/main/resources/messages_de_DE.properties	Fri Feb 09 18:07:22 2018 +0100
+++ b/artifacts/src/main/resources/messages_de_DE.properties	Tue Feb 13 14:53:23 2018 +0100
@@ -846,5 +846,10 @@
 sinfo.chart.flow_depth.xaxis.label = {0}-km
 sinfo.chart.flow_depth.yaxis.label = Flie\u00dftiefe [m]
 
-sinfo.chart.flow_depth.section.yaxis.label=Flow Depth h [m]
-sinfo.facet.flow_depth.filtered.description = Flie\u00dftiefe ({0}) 
\ No newline at end of file
+sinfo.chart.flow_depth.section.yaxis.label=Flie\u00dftiefe h [m]
+sinfo.facet.flow_depth.filtered.description = Flie\u00dftiefe ({0})
+sinfo.facet.flow_depth.tkh.filtered.description = Flie\u00dftiefe mit TKH ({0})
+
+sinfo.facet.tkh.description = Transportk\u00f6rperh\u00f6hen ({0})
+sinfo.chart.tkh.section.yaxis.label = Transportk\u00f6rperh\u00f6hen [cm]
+sinfo.chart.tkh.yaxis.label = Transportk\u00f6rperh\u00f6hen [cm]
\ No newline at end of file
--- a/artifacts/src/main/resources/messages_en.properties	Fri Feb 09 18:07:22 2018 +0100
+++ b/artifacts/src/main/resources/messages_en.properties	Tue Feb 13 14:53:23 2018 +0100
@@ -846,4 +846,9 @@
 sinfo.chart.flow_depth.yaxis.label = Flie\u00dftiefe [m]
 
 sinfo.chart.flow_depth.section.yaxis.label=Flie\u00dftiefe h [m]
-sinfo.facet.flow_depth.filtered.description = Flie\u00dftiefe ({0}) 
\ No newline at end of file
+sinfo.facet.flow_depth.filtered.description = Flie\u00dftiefe ({0})
+sinfo.facet.flow_depth.tkh.filtered.description = Flie\u00dftiefe mit TKH ({0})
+
+sinfo.facet.tkh.description = Transportk\u00f6rperh\u00f6hen ({0})
+sinfo.chart.tkh.section.yaxis.label = Transportk\u00f6rperh\u00f6hen [cm]
+sinfo.chart.tkh.yaxis.label = Transportk\u00f6rperh\u00f6hen [cm]
\ No newline at end of file

http://dive4elements.wald.intevation.org