changeset 9259:66b003701546

Added infrastructure height and Q annotation to S-Info flood duration curve chart
author mschaefer
date Mon, 16 Jul 2018 08:43:07 +0200
parents d950c6055102
children b570b6fcc052
files artifacts/doc/conf/artifacts/sinfo.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/flood_duration/FloodDurationCalculationResults.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculator.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCurveGenerator.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCurveProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationInfrastructureFacet.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationMainValuesQFacet.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationMainValuesWFacet.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationState.java artifacts/src/main/resources/messages.properties artifacts/src/main/resources/messages_de.properties
diffstat 14 files changed, 297 insertions(+), 98 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/doc/conf/artifacts/sinfo.xml	Mon Jul 16 08:41:51 2018 +0200
+++ b/artifacts/doc/conf/artifacts/sinfo.xml	Mon Jul 16 08:43:07 2018 +0200
@@ -370,10 +370,9 @@
           <facets>
             <facet name="duration_curve.w" description="facet.duration_curve.w"/>
             <facet name="duration_curve.q" description="facet.duration_curve.q"/>
-            <facet name="infrastructure.w" description="geodetic height of the infrastructure"/>
-            <facet name="mainvalues.w" description="W Main Values"/>
-            <facet name="mainvalues.q" description="Q Main Values at optional second axis"/>
-            <facet name="infrastructure.q" description="discharge of the infrastructure height"/>
+            <facet name="infrastructure.wq" description="w and q of the infrastructure"/>
+            <facet name="sinfo.mainvalues.w" description="W Main Values"/>
+            <facet name="sinfo.mainvalues.q" description="Q Main Values at optional second axis"/>
             <facet name="duration_curve.manualpoints" description="Manuelle Punkte"/>
           </facets>
         </outputmode>
--- a/artifacts/doc/conf/themes.xml	Mon Jul 16 08:41:51 2018 +0200
+++ b/artifacts/doc/conf/themes.xml	Mon Jul 16 08:43:07 2018 +0200
@@ -451,6 +451,9 @@
         <mapping from="sinfo_facet_flood_height.left" to="SInfoInfrastructureHeightLeft" />
         <mapping from="sinfo_facet_flood_height.right" to="SInfoInfrastructureHeightRight" />
         <mapping from="mainvalue.w" to="SInfoMainValues" />
+        <mapping from="sinfo.mainvalues.q" to="SInfoMainValuesQ" />
+        <mapping from="sinfo.mainvalues.w" to="SInfoMainValuesW" />
+        <mapping from="infrastructure.wq" to="InfrastructureWQ" />
         
         <mapping from="sinfo_facet_predefined_channel_width" to="SInfoPredefinedChannelWidth" />
         <mapping from="sinfo_facet_predefined_channel_depth" to="SInfoPredefinedChannelDepth" />
--- a/artifacts/doc/conf/themes/default.xml	Mon Jul 16 08:41:51 2018 +0200
+++ b/artifacts/doc/conf/themes/default.xml	Mon Jul 16 08:43:07 2018 +0200
@@ -2883,4 +2883,34 @@
       <field name="linecolor" type="Color" display="Farbe" default="0, 96, 192" />
     </fields>
   </theme>
+  <theme name="SInfoMainValuesQ">
+    <inherits>
+      <inherit from="Lines" />
+    </inherits>
+    <fields>
+      <field name="linecolor" type="Color" display="Farbe" default="51, 204, 0" />
+      <field name="textorientation" type="boolean" display="Textausrichtung" default="true" />
+      <field name="showlinelabel" type="boolean" display="Linienbeschriftung anzeigen" default="true" hints="hidden" />
+    </fields>
+  </theme>
+  <theme name="SInfoMainValuesW">
+    <inherits>
+      <inherit from="Lines" />
+    </inherits>
+    <fields>
+      <field name="linecolor" type="Color" display="Farbe" default="0, 102, 204" />
+      <field name="textorientation" type="boolean" display="Textausrichtung" default="true" />
+      <field name="showlinelabel" type="boolean" display="Linienbeschriftung anzeigen" default="true" hints="hidden" />
+    </fields>
+  </theme>
+  <theme name="InfrastructureWQ">
+    <inherits>
+      <inherit from="Lines" />
+    </inherits>
+    <fields>
+      <field name="linecolor" type="Color" display="Farbe" default="144, 48, 96" />
+      <field name="textorientation" type="boolean" display="Textausrichtung" default="true" />
+      <field name="showlinelabel" type="boolean" display="Linienbeschriftung anzeigen" default="true" hints="hidden" />
+    </fields>
+  </theme>
 </themegroup>
\ No newline at end of file
--- a/artifacts/doc/conf/themes/second.xml	Mon Jul 16 08:41:51 2018 +0200
+++ b/artifacts/doc/conf/themes/second.xml	Mon Jul 16 08:43:07 2018 +0200
@@ -2871,4 +2871,34 @@
       <field name="linecolor" type="Color" display="Farbe" default="0, 96, 192" />
     </fields>
   </theme>
+  <theme name="SInfoMainValuesQ">
+    <inherits>
+      <inherit from="Lines" />
+    </inherits>
+    <fields>
+      <field name="linecolor" type="Color" display="Farbe" default="51, 204, 0" />
+      <field name="textorientation" type="boolean" display="Textausrichtung" default="true" />
+      <field name="showlinelabel" type="boolean" display="Linienbeschriftung anzeigen" default="true" hints="hidden" />
+    </fields>
+  </theme>
+  <theme name="SInfoMainValuesW">
+    <inherits>
+      <inherit from="Lines" />
+    </inherits>
+    <fields>
+      <field name="linecolor" type="Color" display="Farbe" default="0, 102, 204" />
+      <field name="textorientation" type="boolean" display="Textausrichtung" default="true" />
+      <field name="showlinelabel" type="boolean" display="Linienbeschriftung anzeigen" default="true" hints="hidden" />
+    </fields>
+  </theme>
+  <theme name="InfrastructureWQ">
+    <inherits>
+      <inherit from="Lines" />
+    </inherits>
+    <fields>
+      <field name="linecolor" type="Color" display="Farbe" default="144, 48, 96" />
+      <field name="textorientation" type="boolean" display="Textausrichtung" default="true" />
+      <field name="showlinelabel" type="boolean" display="Linienbeschriftung anzeigen" default="true" hints="hidden" />
+    </fields>
+  </theme>
 </themegroup>
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResults.java	Mon Jul 16 08:41:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResults.java	Mon Jul 16 08:43:07 2018 +0200
@@ -9,11 +9,14 @@
  */
 package org.dive4elements.river.artifacts.sinfo.flood_duration;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.apache.commons.lang.math.DoubleRange;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResults;
 import org.dive4elements.river.artifacts.model.CalculationResult;
 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
-import org.dive4elements.river.jfree.RiverAnnotation;
+import org.dive4elements.river.jfree.StickyAxisAnnotation;
 
 /**
  * @author Gernot Belger
@@ -24,6 +27,8 @@
 
     public FloodDurationCalculationResults(final String calcModeLabel, final String user, final RiverInfo river, final DoubleRange calcRange) {
         super(calcModeLabel, user, river, calcRange);
+        this.mainValueWAnnotations = new ArrayList<>();
+        this.mainValueQAnnotations = new ArrayList<>();
     }
 
     private CalculationResult durationCurve;
@@ -36,23 +41,35 @@
         this.durationCurve = durationCurve;
     }
 
-    private RiverAnnotation mainValueWAnnotation;
+    private final List<StickyAxisAnnotation> mainValueWAnnotations;
 
-    public RiverAnnotation getMainValueWAnnotation() {
-        return this.mainValueWAnnotation;
-    }
-
-    public void setMainValueWAnnotation(final RiverAnnotation mainValueAnnotation) {
-        this.mainValueWAnnotation = mainValueAnnotation;
+    public List<StickyAxisAnnotation> getMainValueWAnnotations() {
+        return this.mainValueWAnnotations;
     }
 
-    private RiverAnnotation mainValueQAnnotation;
+    private final List<StickyAxisAnnotation> mainValueQAnnotations;
 
-    public RiverAnnotation getMainValueQAnnotation() {
-        return this.mainValueQAnnotation;
+    public List<StickyAxisAnnotation> getMainValueQAnnotations() {
+        return this.mainValueQAnnotations;
     }
 
-    public void setMainValueQAnnotation(final RiverAnnotation mainValueAnnotation) {
-        this.mainValueQAnnotation = mainValueAnnotation;
+    private StickyAxisAnnotation infrastructureWAnnotation;
+
+    public StickyAxisAnnotation getInfrastructureWAnnotation() {
+        return this.infrastructureWAnnotation;
+    }
+
+    public void setInfrastructureWAnnotation(final StickyAxisAnnotation infrastructureWAnnotation) {
+        this.infrastructureWAnnotation = infrastructureWAnnotation;
+    }
+
+    private StickyAxisAnnotation infrastructureQAnnotation;
+
+    public StickyAxisAnnotation getInfrastructureQAnnotation() {
+        return this.infrastructureQAnnotation;
+    }
+
+    public void setInfrastructureQAnnotation(final StickyAxisAnnotation infrastructureQAnnotation) {
+        this.infrastructureQAnnotation = infrastructureQAnnotation;
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculator.java	Mon Jul 16 08:41:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculator.java	Mon Jul 16 08:43:07 2018 +0200
@@ -10,7 +10,6 @@
 package org.dive4elements.river.artifacts.sinfo.flood_duration;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -27,13 +26,13 @@
 import org.dive4elements.river.artifacts.model.CalculationResult;
 import org.dive4elements.river.artifacts.model.WQDay;
 import org.dive4elements.river.artifacts.model.WQKms;
+import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.sinfo.common.GaugeDurationValuesFinder;
 import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider;
 import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType;
 import org.dive4elements.river.artifacts.sinfo.common.WQBaseTableFinder;
 import org.dive4elements.river.artifacts.sinfo.flood_duration.RiversideRadioChoice.RiversideChoiceKey;
 import org.dive4elements.river.exports.WaterlevelDescriptionBuilder;
-import org.dive4elements.river.jfree.RiverAnnotation;
 import org.dive4elements.river.jfree.StickyAxisAnnotation;
 import org.dive4elements.river.jfree.StickyAxisAnnotation.SimpleAxis;
 import org.dive4elements.river.model.Attribute.AttributeKey;
@@ -50,7 +49,7 @@
  */
 final class FloodDurationCalculator {
 
-    private final Collection<ResultRow> rows = new ArrayList<>();
+    private final List<ResultRow> rows = new ArrayList<>();
 
     private final RiverInfoProvider riverInfoProvider;
 
@@ -95,19 +94,16 @@
         final WQKms[] wqkmsArray = calculateWaterlevels(winfo, stationsSorted, problems);
 
         // Determine discharge state labels of the main values
-        final WaterlevelDescriptionBuilder wdescBuilder = new WaterlevelDescriptionBuilder(winfo, this.context);
-        final String[] mainValueLabels = findMainValueLabels(wqkmsArray, winfo.getQs(), wdescBuilder, problems);
+        updateMainValueLabels(wqkmsArray, winfo, problems);
 
         // Create a finder for Q in the {river}.wst km-w-q table
         final WQBaseTableFinder wqFinder = WQBaseTableFinder.loadValues(this.riverInfoProvider.getRiver(), calcRange.getMinimumDouble(),
                 calcRange.getMaximumDouble(), problems);
 
-        final WaterlevelDescriptionBuilder descBuilder = new WaterlevelDescriptionBuilder(winfo, this.context);
-
         // Calculate the durations and create the result rows
         for (int i = 0; i <= stationsSorted.length - 1; i++) {
             final Gauge gauge = this.riverInfoProvider.getGauge(stationsSorted[i], true);
-            final ResultRow row = createRow(descBuilder, stationsSorted[i], gauge, firstGauge, wqkmsArray, durFinders.get(gauge), i);
+            final ResultRow row = createRow(stationsSorted[i], gauge, firstGauge, wqkmsArray, durFinders.get(gauge), i);
             if (allStations.containsKey(stationsSorted[i]) && (allStations.get(stationsSorted[i]) != null))
                 calculateInfrastructure(row, gauge, allStations.get(stationsSorted[i]), wqFinder, durFinders);
             this.rows.add(row);
@@ -117,10 +113,16 @@
                 this.rows.add(row2);
             }
         }
+        final String[] mainValueLabels = new String[wqkmsArray.length];
+        for (int i = 0; i <= wqkmsArray.length - 1; i++)
+            mainValueLabels[i] = wqkmsArray[i].getName();
         results.addResult(new FloodDurationCalculationResult(label, mainValueLabels, this.rows), problems);
+
         calcWQDays(problems, stationsSorted[0], AttributeKey.LEFT, winfo, results);
-        calcMainValueAnnotations(label, problems, 0, AttributeKey.LEFT, wqkmsArray, mainValueLabels, results);
-        // TODO Infrastrukturhoehe
+
+        calcMainValueAnnotations(problems, 0, AttributeKey.LEFT, wqkmsArray, results);
+
+        calcInfrastructureAnnotations(problems, this.rows.get(0), wqkmsArray, results);
     }
 
     /**
@@ -149,42 +151,56 @@
     /**
      * Calculate the data for the W and Q main value lines in the duration curve chart and add to result collection
      */
-    private void calcMainValueAnnotations(final String label, final Calculation problems, final int stationIndex, final AttributeKey riverside,
-            final WQKms[] wqkmsArray, final String[] mainValueLabels, final FloodDurationCalculationResults results) {
+    private void calcMainValueAnnotations(final Calculation problems, final int stationIndex, final AttributeKey riverside,
+            final WQKms[] wqkmsArray, final FloodDurationCalculationResults results) {
 
-        // Same way as in MainValueWFacet and ..QFacet
+        // Same way as in MainValueWFacet and ..QFacet, but special label handling
         final List<StickyAxisAnnotation> ws = new ArrayList<>();
         final List<StickyAxisAnnotation> qs = new ArrayList<>();
         for (int i = 0; i <= wqkmsArray.length - 1; i++) {
-            final StickyAxisAnnotation qAnnotation = new StickyAxisAnnotation(mainValueLabels[i], (float) wqkmsArray[i].getQ(stationIndex), SimpleAxis.Y_AXIS,
+            final String qLabel = wqkmsArray[i].getName().startsWith("W=") ? "Q(" + wqkmsArray[i].getName() + ")" : wqkmsArray[i].getName();
+            final StickyAxisAnnotation qAnnotation = new StickyAxisAnnotation(qLabel, (float) wqkmsArray[i].getQ(stationIndex), SimpleAxis.Y_AXIS,
                     FloodDurationCurveGenerator.YAXIS.Q.idx);
             qs.add(qAnnotation);
-            setHitPoint((WQDay) results.getDurationCurve().getData(), qAnnotation);
-            final StickyAxisAnnotation wAnnotation = new StickyAxisAnnotation(mainValueLabels[i], (float) wqkmsArray[i].getW(stationIndex), SimpleAxis.Y_AXIS,
+            FloodDurationMainValuesQFacet.setHitPoint((WQDay) results.getDurationCurve().getData(), qAnnotation);
+            final String wLabel = !wqkmsArray[i].getName().startsWith("W=") ? "W(" + wqkmsArray[i].getName() + ")" : wqkmsArray[i].getName();
+            final StickyAxisAnnotation wAnnotation = new StickyAxisAnnotation(wLabel, (float) wqkmsArray[i].getW(stationIndex), SimpleAxis.Y_AXIS,
                     FloodDurationCurveGenerator.YAXIS.W.idx);
             ws.add(wAnnotation);
-            setHitPoint((WQDay) results.getDurationCurve().getData(), wAnnotation);
+            FloodDurationMainValuesWFacet.setHitPoint((WQDay) results.getDurationCurve().getData(), wAnnotation);
         }
-        // TODO RiverAnnotation ersetzen weil das eine NotSerializableException erzeugt
-        results.setMainValueQAnnotation(new RiverAnnotation(label, qs));
-        results.setMainValueWAnnotation(new RiverAnnotation(label, ws));
+        results.getMainValueQAnnotations().clear();
+        results.getMainValueQAnnotations().addAll(qs);
+        results.getMainValueWAnnotations().clear();
+        results.getMainValueWAnnotations().addAll(ws);
     }
 
     /**
-     * Set the hit-point in Q where a line drawn from the axis would hit the
-     * curve in WQDay (if hit).
-     * Employ linear interpolation.
+     * Calculate the data for the W and Q lines in the duration curve chart for the infrastructure height and add to result
+     * collection
      */
-    private static void setHitPoint(final WQDay wqday, final StickyAxisAnnotation annotation) {
+    private void calcInfrastructureAnnotations(final Calculation problems, final ResultRow row, final WQKms[] wqkmsArray,
+            final FloodDurationCalculationResults results) {
 
-        final float q = annotation.getPos();
-        final Double day = wqday.interpolateDayByQ(q);
-        if (day != null) {
-            annotation.setHitPoint(day.floatValue());
+        if (row.getValue(SInfoResultType.infrastructuretype) == null) {
+            results.setInfrastructureWAnnotation(null);
+            results.setInfrastructureQAnnotation(null);
+            return;
         }
-        // else if (log.isDebugEnabled()) {
-        // log.debug("StickyAnnotation does not hit wqday curve: " + q);
-        // }
+        // Same way as in MainValueWFacet and ..QFacet
+        final String label = Resources.getMsg(this.context.getMeta(), "sinfo.chart.flood_duration.curve.infrastructure",
+                "sinfo.chart.flood_duration.curve.infrastructure",
+                SInfoResultType.infrastructuretype.exportValue(this.context, row.getValue(SInfoResultType.infrastructuretype))
+                + ", " + SInfoResultType.riverside.exportValue(this.context, row.getValue(SInfoResultType.riverside)));
+        final StickyAxisAnnotation qAnnotation = new StickyAxisAnnotation(label, (float) row.getDoubleValue(SInfoResultType.floodDischarge),
+                SimpleAxis.Y_AXIS, FloodDurationCurveGenerator.YAXIS.Q.idx);
+        FloodDurationMainValuesQFacet.setHitPoint((WQDay) results.getDurationCurve().getData(), qAnnotation);
+        final StickyAxisAnnotation wAnnotation = new StickyAxisAnnotation(label, (float) row.getDoubleValue(SInfoResultType.infrastructureHeight),
+                SimpleAxis.Y_AXIS, FloodDurationCurveGenerator.YAXIS.W.idx);
+        FloodDurationMainValuesWFacet.setHitPoint((WQDay) results.getDurationCurve().getData(), wAnnotation);
+
+        results.setInfrastructureQAnnotation(qAnnotation);
+        results.setInfrastructureWAnnotation(wAnnotation);
     }
 
     /**
@@ -262,24 +278,38 @@
     }
 
     /**
-     * Determines the waterlevel/discharge state labels for the selected Q or W values
+     * Determines the waterlevel/discharge state labels for the selected Q or W values and sets them in the WQKms array
      */
-    private String[] findMainValueLabels(final WQKms[] wqkmsArray, final double[] qs, final WaterlevelDescriptionBuilder descBuilder,
-            final Calculation problems) {
+    private void updateMainValueLabels(final WQKms[] wqkmsArray, final WINFOArtifact winfo, final Calculation problems) {
 
-        final String[] mainValueLabels = new String[wqkmsArray.length];
         for (int i = 0; i <= wqkmsArray.length - 1; i++)
-            mainValueLabels[i] = descBuilder.getDesc(wqkmsArray[i]);
-        return mainValueLabels;
+            wqkmsArray[i].setName(buildWQDescription(wqkmsArray[i], winfo));
+    }
+
+    /**
+     *
+     * @param wqkms
+     * @param descBuilder
+     * @return
+     */
+    private String buildWQDescription(final WQKms wqkms, final WINFOArtifact winfo) {
+        final WaterlevelDescriptionBuilder descBuilder = new WaterlevelDescriptionBuilder(winfo, this.context);
+        final String description = descBuilder.getDesc(wqkms);
+        if (!description.isEmpty() && Character.isDigit(description.charAt(0))) {
+            if (winfo.isQ())
+                return "Q=" + description;
+            else
+                return "W=" + description;
+        }
+        else
+            return description;
     }
 
     /**
      * Create a result row for a station and its gauge, and add w-q-values as selected
-     *
-     * @param descBuilder
      */
-    private ResultRow createRow(final WaterlevelDescriptionBuilder descBuilder, final Double station, final Gauge gauge, final Gauge firstGauge,
-            final WQKms[] wqkmsArray, final GaugeDurationValuesFinder durationFinder, final int kmIndex) {
+    private ResultRow createRow(final Double station, final Gauge gauge, final Gauge firstGauge, final WQKms[] wqkmsArray,
+            final GaugeDurationValuesFinder durationFinder, final int kmIndex) {
 
         final ResultRow row = ResultRow.create();
         row.putValue(GeneralResultType.station, station);
@@ -294,14 +324,12 @@
 
         final List<DurationWaterlevel> waterlevels = new ArrayList<>(wqkmsArray.length);
 
-        for (final WQKms wqKm : wqkmsArray) {
-            assert (wqKm.getKm(kmIndex) == station.doubleValue());
+        for (final WQKms wqKms : wqkmsArray) {
+            assert (wqKms.getKm(kmIndex) == station.doubleValue());
 
-            final int overflowDays = (int) Math.round(underflowDaysToOverflowDays(durationFinder.getDuration(wqKm.getQ(kmIndex))));
+            final int overflowDays = (int) Math.round(underflowDaysToOverflowDays(durationFinder.getDuration(wqKms.getQ(kmIndex))));
 
-            final String waterlevelLabel = descBuilder.getDesc(wqKm);
-
-            final DurationWaterlevel dw = new DurationWaterlevel(wqKm.getW(kmIndex), overflowDays, wqKm.getQ(kmIndex), waterlevelLabel);
+            final DurationWaterlevel dw = new DurationWaterlevel(wqKms.getW(kmIndex), overflowDays, wqKms.getQ(kmIndex), wqKms.getName());
             waterlevels.add(dw);
         }
         row.putValue(SInfoResultType.customMultiRowColWaterlevel, waterlevels);
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCurveGenerator.java	Mon Jul 16 08:41:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCurveGenerator.java	Mon Jul 16 08:43:07 2018 +0200
@@ -173,12 +173,16 @@
         else if (name.equals(DURATION_Q)) {
             doQOut((WQDay) ((CalculationResult) artifactFacet.getData(context)).getData(), artifactFacet, attr, visible);
         }
-        else if (name.equals(MAINVALUES_Q) || name.equals(MAINVALUES_W)) {
+        else if (name.equals(FloodDurationCurveProcessor.FACET_FLOOD_DURATION_MAINVALUES_Q)
+                || name.equals(FloodDurationCurveProcessor.FACET_FLOOD_DURATION_MAINVALUES_W)) {
             doAnnotations((RiverAnnotation) artifactFacet.getData(context), artifactFacet, attr, visible);
         }
-        else if (name.equals(RELATIVE_POINT)) {
-            doPointOut((Point2D) artifactFacet.getData(context), artifactFacet, attr, visible);
+        else if (name.equals(FloodDurationCurveProcessor.FACET_FLOOD_DURATION_INFRASTRUCTURE) && (artifactFacet.getData(context) != null)) {
+            doAnnotations((RiverAnnotation) artifactFacet.getData(context), artifactFacet, attr, visible);
         }
+        // else if (name.equals(RELATIVE_POINT)) {
+        // doPointOut((Point2D) artifactFacet.getData(context), artifactFacet, attr, visible);
+        // }
         else if (FacetTypes.IS.MANUALPOINTS(name)) {
             doPoints(artifactFacet.getData(context), artifactFacet, attr, visible, YAXIS.W.idx);
         }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCurveProcessor.java	Mon Jul 16 08:41:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCurveProcessor.java	Mon Jul 16 08:43:07 2018 +0200
@@ -13,15 +13,13 @@
 import java.util.HashSet;
 import java.util.Set;
 
-import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
 import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
+import org.dive4elements.river.artifacts.model.FacetTypes;
 import org.dive4elements.river.exports.DiagramGenerator;
 import org.dive4elements.river.exports.DurationCurveGenerator;
-import org.dive4elements.river.exports.XYChartGenerator;
 import org.dive4elements.river.exports.process.DefaultProcessor;
-import org.dive4elements.river.themes.ThemeDocument;
 
 /**
  * Processor to generate the facet and data series of a flood duration curve
@@ -31,13 +29,15 @@
  */
 public final class FloodDurationCurveProcessor extends DefaultProcessor {
 
-    private static final String FACET_FLOOD_DURATION_W = "duration_curve.w";
+    private static final String FACET_FLOOD_DURATION_W = FacetTypes.DURATION_W; // "duration_curve.w";
 
-    private static final String FACET_FLOOD_DURATION_Q = "duration_curve.q";
+    private static final String FACET_FLOOD_DURATION_Q = FacetTypes.DURATION_Q; // "duration_curve.q";
 
-    private static final String FACET_FLOOD_DURATION_MAINVALUES_W = "mainvalues.w";
+    public static final String FACET_FLOOD_DURATION_MAINVALUES_W = "sinfo.mainvalues.w";
 
-    private static final String FACET_FLOOD_DURATION_MAINVALUES_Q = "mainvalues.q";
+    public static final String FACET_FLOOD_DURATION_MAINVALUES_Q = "sinfo.mainvalues.q";
+
+    public static final String FACET_FLOOD_DURATION_INFRASTRUCTURE = "infrastructure.wq";
 
     private static final Set<String> HANDLED_FACET_TYPES = new HashSet<>();
 
@@ -46,6 +46,7 @@
         HANDLED_FACET_TYPES.add(FACET_FLOOD_DURATION_Q);
         HANDLED_FACET_TYPES.add(FACET_FLOOD_DURATION_MAINVALUES_W);
         HANDLED_FACET_TYPES.add(FACET_FLOOD_DURATION_MAINVALUES_Q);
+        HANDLED_FACET_TYPES.add(FACET_FLOOD_DURATION_INFRASTRUCTURE);
     }
 
     public static Facet createFloodDurationWCurveFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
@@ -72,12 +73,10 @@
         return new FloodDurationMainValuesQFacet(FACET_FLOOD_DURATION_MAINVALUES_Q, description);
     }
 
-    /**
-     * Processes data to generate a chart.
-     */
-    @Override
-    public void doOut(final XYChartGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible, final int index) {
+    public static Facet createInfrastructureWFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
+            final int facetIndex, final int resultIndex, final String description) {
 
+        return new FloodDurationInfrastructureFacet(FACET_FLOOD_DURATION_INFRASTRUCTURE, description);
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationInfrastructureFacet.java	Mon Jul 16 08:43:07 2018 +0200
@@ -0,0 +1,86 @@
+/** 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.flood_duration;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.dive4elements.artifactdatabase.state.DefaultFacet;
+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.states.DefaultState.ComputeType;
+import org.dive4elements.river.jfree.RiverAnnotation;
+import org.dive4elements.river.jfree.StickyAxisAnnotation;
+
+
+/**
+ * Facet to show W and Q annotation lines of an infrastructure height.
+ */
+public class FloodDurationInfrastructureFacet extends DefaultFacet {
+
+    /** Own log. */
+    private static Logger log = Logger.getLogger(FloodDurationInfrastructureFacet.class);
+
+    /** Trivial Constructor. */
+    public FloodDurationInfrastructureFacet(final String name, final String description) {
+        this.description = description;
+        this.name = name;
+        this.index = 0;
+    }
+
+
+    /**
+     * Returns the data this facet requires.
+     *
+     * @param artifact the owner artifact.
+     * @param context  the CallContext (can be used to find out if in
+     *                 navigable fixation-setting, or durationcurve).
+     *
+     * @return the data.
+     */
+    @Override
+    public Object getData(final Artifact artifact, final CallContext context) {
+
+        log.debug("Get data for flood duration curve infrastructure");
+
+        final D4EArtifact flys = (D4EArtifact) artifact;
+
+        final CalculationResult res = (CalculationResult) flys.compute(context, ComputeType.ADVANCE, false);
+
+        final FloodDurationCalculationResults data = (FloodDurationCalculationResults) res.getData();
+
+        final List<StickyAxisAnnotation> annotations = new ArrayList<>();
+        annotations.add(data.getInfrastructureWAnnotation());
+        annotations.add(data.getInfrastructureQAnnotation());
+        if (annotations.get(0) != null) {
+            this.description = annotations.get(0).getText(); // TODO Diagramm-Aktualisierung auslösen
+            return new RiverAnnotation(this.description, annotations);
+        }
+        else
+            return null;
+    }
+
+
+    /**
+     * Create a deep copy of this Facet.
+     * @return a deep copy.
+     */
+    @Override
+    public FloodDurationInfrastructureFacet deepCopy() {
+        final FloodDurationInfrastructureFacet copy = new FloodDurationInfrastructureFacet(this.name, this.description);
+        copy.set(this);
+        return copy;
+    }
+}
+
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationMainValuesQFacet.java	Mon Jul 16 08:41:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationMainValuesQFacet.java	Mon Jul 16 08:43:07 2018 +0200
@@ -16,6 +16,7 @@
 import org.dive4elements.river.artifacts.model.CalculationResult;
 import org.dive4elements.river.artifacts.model.WQDay;
 import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
+import org.dive4elements.river.jfree.RiverAnnotation;
 import org.dive4elements.river.jfree.StickyAxisAnnotation;
 
 
@@ -30,8 +31,8 @@
     /** Trivial Constructor. */
     public FloodDurationMainValuesQFacet(final String name, final String description) {
         this.description = description;
-        this.name        = name;
-        this.index       = 0;
+        this.name = name;
+        this.index = 1;
     }
 
     /**
@@ -39,17 +40,14 @@
      * curve in WQDay (if hit).
      * Employ linear interpolation.
      */
-    protected static void setHitPoint(final WQDay wqday, final StickyAxisAnnotation annotation) {
+    public static void setHitPoint(final WQDay wqday, final StickyAxisAnnotation annotation) {
 
         final float q = annotation.getPos();
         final Double day = wqday.interpolateDayByQ(q);
-
-        if (day != null) {
+        if (day != null)
             annotation.setHitPoint(day.floatValue());
-        }
-        else if (log.isDebugEnabled()) {
+        else
             log.debug("StickyAnnotation does not hit wqday curve: " + q);
-        }
     }
 
 
@@ -73,7 +71,7 @@
 
         final FloodDurationCalculationResults data = (FloodDurationCalculationResults) res.getData();
 
-        return data.getMainValueQAnnotation();
+        return new RiverAnnotation(this.description, data.getMainValueQAnnotations());
     }
 
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationMainValuesWFacet.java	Mon Jul 16 08:41:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationMainValuesWFacet.java	Mon Jul 16 08:43:07 2018 +0200
@@ -16,6 +16,7 @@
 import org.dive4elements.river.artifacts.model.CalculationResult;
 import org.dive4elements.river.artifacts.model.WQDay;
 import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
+import org.dive4elements.river.jfree.RiverAnnotation;
 import org.dive4elements.river.jfree.StickyAxisAnnotation;
 
 /**
@@ -39,18 +40,14 @@
      * curve in WQDay (if hit).
      * Employ linear interpolation.
      */
-    protected static void setHitPoint(final WQDay wqday, final StickyAxisAnnotation annotation) {
+    public static void setHitPoint(final WQDay wqday, final StickyAxisAnnotation annotation) {
 
         final float w = annotation.getPos();
-
         final Double day = wqday.interpolateDayByW(w);
-
-        if (day != null) {
+        if (day != null)
             annotation.setHitPoint(day.floatValue());
-        }
-        else if (log.isDebugEnabled()) {
+        else
             log.debug("StickyAnnotation does not hit wqday curve: " + w);
-        }
     }
 
 
@@ -74,7 +71,7 @@
 
         final FloodDurationCalculationResults data = (FloodDurationCalculationResults) res.getData();
 
-        return data.getMainValueWAnnotation();
+        return new RiverAnnotation(this.description, data.getMainValueWAnnotations());
     }
 
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationState.java	Mon Jul 16 08:41:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationState.java	Mon Jul 16 08:43:07 2018 +0200
@@ -1,5 +1,7 @@
-/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
- * Software engineering by Intevation GmbH
+/** 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
@@ -115,6 +117,8 @@
                 facets.add(FloodDurationCurveProcessor.createMainValuesQFacet(context, hash, this.id, result, 1, resultIndex,
                         Resources.getMsg(context.getMeta(), "sinfo.chart.flood_duration.curve.mainq")));
             }
+            facets.add(FloodDurationCurveProcessor.createInfrastructureWFacet(context, hash, this.id, result, 0, resultIndex,
+                    Resources.getMsg(context.getMeta(), "sinfo.chart.flood_duration.curve.facet.infrastructure")));
 
             facets.add(new DataFacet(FacetTypes.CSV, "CSV data", ComputeType.ADVANCE, hash, this.id));
             facets.add(new DataFacet(FacetTypes.PDF, "PDF data", ComputeType.ADVANCE, hash, this.id));
--- a/artifacts/src/main/resources/messages.properties	Mon Jul 16 08:41:51 2018 +0200
+++ b/artifacts/src/main/resources/messages.properties	Mon Jul 16 08:43:07 2018 +0200
@@ -1159,6 +1159,8 @@
 sinfo.chart.flood_duration.curve.q = Abflussdauerlinie
 sinfo.chart.flood_duration.curve.mainw = W (ausgew\u00e4hlte WSPL)
 sinfo.chart.flood_duration.curve.mainq = Q (ausgew\u00e4hlte WSPL)
+sinfo.chart.flood_duration.curve.infrastructure = Infrastruktur ({0})
+sinfo.chart.flood_duration.curve.facet.infrastructure = Infrastruktur
 
 bundu_bezugswst = Bezugswasserst\u00e4nde
 bundu_analysis = Fixinganalysis
--- a/artifacts/src/main/resources/messages_de.properties	Mon Jul 16 08:41:51 2018 +0200
+++ b/artifacts/src/main/resources/messages_de.properties	Mon Jul 16 08:43:07 2018 +0200
@@ -1159,6 +1159,8 @@
 sinfo.chart.flood_duration.curve.q = Abflussdauerlinie
 sinfo.chart.flood_duration.curve.mainw = W (ausgew\u00e4hlte WSPL)
 sinfo.chart.flood_duration.curve.mainq = Q (ausgew\u00e4hlte WSPL)
+sinfo.chart.flood_duration.curve.infrastructure = Infrastruktur ({0})
+sinfo.chart.flood_duration.curve.facet.infrastructure = Infrastruktur
 
 bundu_bezugswst = Bezugswasserst\u00e4nde
 bundu_analysis = Fixierungsanalyse

http://dive4elements.wald.intevation.org