changeset 9347:08f46ccd37ba

salix.regional refactoring
author gernotbelger
date Tue, 31 Jul 2018 16:04:01 +0200 (2018-07-31)
parents d89976700474
children 0ac8bbc63b38 0c8f170945d7
files artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/common/ResultFacet.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcFacet.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCountProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/D50Processor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/FlowDepthDevelopmentPerYearProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/FlowDepthDevelopmentProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/FlowDepthProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/InfrastructureHeightProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedChannelDepthProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedChannelWidthProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedDepthEvolPerYearProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedDepthEvolProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedFlowDepthProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedTkhProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/SInfoResultFacet.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/TauProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/TkhProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/VelocityProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationFacet.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodHeightProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculationNoScenarioResult.java artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculationSupraRegionalResult.java artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineResultFacet.java artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineState.java artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixMnwMwResultFacet.java artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixScenario.java artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixScenarioResultFacet.java artifacts/src/main/java/org/dive4elements/river/exports/StyledSeriesBuilder.java
diffstat 33 files changed, 473 insertions(+), 514 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractProcessor.java	Tue Jul 31 16:04:01 2018 +0200
@@ -0,0 +1,227 @@
+/* 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.common;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
+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.access.RiverAccess;
+import org.dive4elements.river.artifacts.context.RiverContext;
+import org.dive4elements.river.artifacts.math.MovingAverage;
+import org.dive4elements.river.artifacts.model.WQKms;
+import org.dive4elements.river.artifacts.model.ZoomScale;
+import org.dive4elements.river.artifacts.resources.Resources;
+import org.dive4elements.river.artifacts.sinfo.common.AbstractTkhCalculationResult;
+import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
+import org.dive4elements.river.exports.DiagramGenerator;
+import org.dive4elements.river.exports.StyledSeriesBuilder;
+import org.dive4elements.river.exports.process.DefaultProcessor;
+import org.dive4elements.river.jfree.StyledAreaSeriesCollection;
+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
+ *
+ */
+
+public abstract class AbstractProcessor extends DefaultProcessor {
+
+    protected static final double GAP_DISTANCE = 0.101;
+
+    private final static Logger log = Logger.getLogger(AbstractProcessor.class);
+
+    private String yAxisLabel;
+
+    private final Set<String> handled_facet_types;
+
+    private final String i18n_axis_label;
+
+    public AbstractProcessor(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) {
+        try {
+            this.yAxisLabel = generateSeries(generator, bundle, theme, visible);
+        }
+        catch (final Exception e) {
+            log.error(e.getMessage(), e);
+        }
+    }
+
+    protected static final AbstractCalculationResult getResult(final DiagramGenerator generator, final ArtifactAndFacet bundle) {
+        final CallContext context = generator.getContext();
+        final AbstractCalculationResult data = (AbstractCalculationResult) bundle.getData(context);
+        if (data == null) {
+            // Check has been here before so we keep it for security reasons
+            // this should never happen though.
+            final String facetName = bundle.getFacetName();
+            throw new IllegalStateException("Data is null for facet: " + facetName);
+        }
+
+        return data;
+    }
+
+    /**
+     * @return The axis label
+     */
+    protected abstract String generateSeries(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible);
+
+    protected final String buildSeriesForType(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible,
+            final IResultType resultType, final Double gapDistance) {
+
+        final AbstractCalculationResult data = getResult(generator, bundle);
+
+        final double[][] points = data.getStationPoints(resultType);
+
+        return buildSeriesForPoints(points, generator, bundle, theme, visible, gapDistance);
+    }
+
+    protected final String buildSeriesForPoints(final double[][] points, final DiagramGenerator generator, final ArtifactAndFacet bundle,
+            final ThemeDocument theme, final boolean visible, final Double gapDistance) {
+        final CallContext context = generator.getContext();
+        final Map<String, String> metaData = bundle.getFacet().getMetaData();
+
+        final Artifact artifact = bundle.getArtifact();
+
+        final StyledXYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme);
+        series.putMetaData(metaData, artifact, context);
+
+        final String facetName = bundle.getFacetName();
+
+        final double[][] filteredPoints = filterPoints(points, context, artifact, facetName);
+
+        if (gapDistance == null)
+            StyledSeriesBuilder.addPoints(series, filteredPoints, true);
+        else
+            StyledSeriesBuilder.addPoints(series, filteredPoints, true, gapDistance);
+
+        generator.addAxisSeries(series, getAxisName(), visible);
+
+        return metaData.get("Y");
+    }
+
+    protected final String buildStepLineSeriesForType(final double[][] points, final DiagramGenerator generator, final ArtifactAndFacet bundle,
+            final ThemeDocument theme, final boolean visible) {
+
+        final CallContext context = generator.getContext();
+        final Map<String, String> metaData = bundle.getFacet().getMetaData();
+
+        final Artifact artifact = bundle.getArtifact();
+
+        final StyledXYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme);
+        series.putMetaData(metaData, artifact, context);
+
+        final String facetName = bundle.getFacetName();
+
+        // Create WQKms to use the step points method
+        // REMARK: must have any values in w array; not sure whether the name is needed
+        final WQKms wqkms = new WQKms(points[0], points[1], points[1], facetName);
+
+        StyledSeriesBuilder.addStepPointsKmQ(series, wqkms);
+
+        generator.addAxisSeries(series, getAxisName(), visible);
+
+        return metaData.get("Y");
+    }
+
+    protected final String buildSeriesForTkh(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme,
+            final boolean visible) {
+
+        final AbstractTkhCalculationResult data = (AbstractTkhCalculationResult) getResult(generator, bundle);
+
+        final StyledXYSeries seriesUp = new StyledXYSeries(bundle.getFacetDescription(), theme);
+        final double[][] pointsUp = data.getTkhUpPoints();
+        StyledSeriesBuilder.addPoints(seriesUp, pointsUp, true);
+
+        // REMARK: we add " " because the description is misused as id, which must be unique.
+        final StyledXYSeries seriesDown = new StyledXYSeries(bundle.getFacetDescription() + " ", theme);
+        final double[][] pointsDown = data.getTkhDownPoints();
+        StyledSeriesBuilder.addPoints(seriesDown, pointsDown, true);
+
+        final StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(theme);
+        area.setMode(StyledAreaSeriesCollection.FILL_MODE.BETWEEN);
+        area.addSeries(seriesUp);
+        area.addSeries(seriesDown);
+
+        generator.addAreaSeries(area, getAxisName(), visible);
+
+        return null;
+    }
+
+    private Double findRadius(final CallContext context, final Artifact artifact) {
+        final Double start = (Double) context.getContextValue("startkm");
+        final Double end = (Double) context.getContextValue("endkm");
+
+        if (start == null || end == null)
+            return null;
+
+        final RiverContext fc = (RiverContext) context.globalContext();
+        final ZoomScale scales = (ZoomScale) fc.get("zoomscale");
+        final RiverAccess access = new RiverAccess((D4EArtifact) artifact);
+        final String river = access.getRiverName();
+
+        return scales.getRadius(river, start, end);
+    }
+
+    private double[][] filterPoints(final double[][] points, final CallContext context, final Artifact artifact, final String facetName) {
+
+        if (facetName.endsWith(".filtered")) {
+            final Double radius = findRadius(context, artifact);
+            return movingAverage(radius, points);
+        }
+
+        return points;
+    }
+
+    private double[][] movingAverage(final Double radius, final double[][] points) {
+
+        if (radius == null)
+            return points;
+
+        return MovingAverage.weighted(points, radius);
+    }
+
+    @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
+            // TODO: 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");
+    }
+
+    protected static final Facet createFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
+            final int resultIndex, final String axisLabel, final String facetId, final String description) {
+        final String facetFlowDepthFilteredDescription = Resources.getMsg(context.getMeta(), description, description, result.getLabel());
+        return new ResultFacet(resultIndex, facetId, facetFlowDepthFilteredDescription, axisLabel, ComputeType.ADVANCE, id, hash);
+    }
+}
\ 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/common/ResultFacet.java	Tue Jul 31 16:04:01 2018 +0200
@@ -0,0 +1,84 @@
+/* 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.common;
+
+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 one of the S-Info curves.
+ */
+// TODO: rename: hat nichts mehr mit sinfo zu tun
+public class ResultFacet extends DataFacet {
+
+    private static final long serialVersionUID = 1L;
+
+    private static Logger log = Logger.getLogger(ResultFacet.class);
+
+    private int resultIndex;
+
+    public ResultFacet() {
+        // required for clone operation deepCopy()
+    }
+
+    public ResultFacet(final int resultIndex, final String name, final String description, final String yAxisLabelKey, final ComputeType type,
+            final String stateId, final String hash) {
+        this(resultIndex, resultIndex, name, description, yAxisLabelKey, type, stateId, hash);
+    }
+
+    public ResultFacet(final int facetIndex, final int resultIndex, final String name, final String description, final String yAxisLabelKey,
+            final ComputeType type, final String stateId, final String hash) {
+        // REMARK: in some cases, we have several data-lines for the same result (which normally determines the facet index) and
+        // facet name. But index and name are used by the client side as unique keys for the chart themes...
+        // So we might have different facet index and result index.
+        super(facetIndex, name, description, type, hash, stateId);
+        this.resultIndex = resultIndex;
+
+        this.metaData.put("X", "sinfo.chart.km.xaxis.label");
+        this.metaData.put("Y", yAxisLabelKey);
+    }
+
+    @Override
+    public final Object getData(final Artifact artifact, final CallContext context) {
+        log.debug("Get data for result at index: " + this.resultIndex);
+
+        final D4EArtifact flys = (D4EArtifact) artifact;
+
+        final CalculationResult res = (CalculationResult) flys.compute(context, this.hash, this.stateId, this.type, false);
+
+        final AbstractCalculationResults<AbstractCalculationResult> data = (AbstractCalculationResults<AbstractCalculationResult>) res.getData();
+
+        return data.getResults().get(this.resultIndex);
+    }
+
+    /** Copy deeply. */
+    @Override
+    public Facet deepCopy() {
+        // FIXME: why not simply use the full constructor instead?
+        final ResultFacet copy = new ResultFacet();
+        // 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;
+    }
+
+    @Override
+    public void set(final Facet other) {
+        this.resultIndex = ((ResultFacet) other).resultIndex;
+        super.set(other);
+    }
+}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcFacet.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcFacet.java	Tue Jul 31 16:04:01 2018 +0200
@@ -11,7 +11,7 @@
 package org.dive4elements.river.artifacts.sinfo.collision;
 
 import org.dive4elements.artifactdatabase.state.Facet;
-import org.dive4elements.river.artifacts.sinfo.common.SInfoResultFacet;
+import org.dive4elements.river.artifacts.common.ResultFacet;
 import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
 
 /**
@@ -19,7 +19,7 @@
  *
  * @author Matthias Schäfer
  */
-public class CollisionCalcFacet extends SInfoResultFacet {
+public class CollisionCalcFacet extends ResultFacet {
 
     private static final long serialVersionUID = 1;
     private int year;
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcProcessor.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcProcessor.java	Tue Jul 31 16:04:01 2018 +0200
@@ -17,8 +17,8 @@
 import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
+import org.dive4elements.river.artifacts.common.AbstractProcessor;
 import org.dive4elements.river.artifacts.resources.Resources;
-import org.dive4elements.river.artifacts.sinfo.common.AbstractSInfoProcessor;
 import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType;
 import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
 import org.dive4elements.river.exports.DiagramGenerator;
@@ -30,7 +30,7 @@
  * @author Matthias Schäfer
  *
  */
-public final class CollisionCalcProcessor extends AbstractSInfoProcessor {
+public final class CollisionCalcProcessor extends AbstractProcessor {
 
     public static final String FACET_COLLISION_CALC_COUNT = "sinfo_facet_collision_calc_count";
 
@@ -66,7 +66,7 @@
 
         final double[][] points = result.getStationPointsByYear(SInfoResultType.collisionCount, year);
 
-        return buildSeriesForType(points, generator, bundle, theme, visible, null);
+        return buildSeriesForPoints(points, generator, bundle, theme, visible, null);
     }
 
     public static final Facet createFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCountProcessor.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCountProcessor.java	Tue Jul 31 16:04:01 2018 +0200
@@ -16,8 +16,8 @@
 import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
 import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.artifacts.CallMeta;
+import org.dive4elements.river.artifacts.common.AbstractProcessor;
 import org.dive4elements.river.artifacts.resources.Resources;
-import org.dive4elements.river.artifacts.sinfo.common.AbstractSInfoProcessor;
 import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType;
 import org.dive4elements.river.exports.DiagramGenerator;
 import org.dive4elements.river.themes.ThemeDocument;
@@ -28,7 +28,7 @@
  * @author Matthias Schäfer
  *
  */
-public class CollisionCountProcessor extends AbstractSInfoProcessor {
+public class CollisionCountProcessor extends AbstractProcessor {
 
     public static final String FACET_COLLISION_COUNT = "sinfo_facet_collision_count";
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoProcessor.java	Tue Jul 31 15:48:35 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,227 +0,0 @@
-/* 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.common;
-
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.log4j.Logger;
-import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
-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.access.RiverAccess;
-import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
-import org.dive4elements.river.artifacts.common.IResultType;
-import org.dive4elements.river.artifacts.context.RiverContext;
-import org.dive4elements.river.artifacts.math.MovingAverage;
-import org.dive4elements.river.artifacts.model.WQKms;
-import org.dive4elements.river.artifacts.model.ZoomScale;
-import org.dive4elements.river.artifacts.resources.Resources;
-import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
-import org.dive4elements.river.exports.DiagramGenerator;
-import org.dive4elements.river.exports.StyledSeriesBuilder;
-import org.dive4elements.river.exports.process.DefaultProcessor;
-import org.dive4elements.river.jfree.StyledAreaSeriesCollection;
-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
- *
- */
-public abstract class AbstractSInfoProcessor extends DefaultProcessor {
-
-    protected static final double GAP_DISTANCE = 0.101;
-
-    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) {
-        try {
-            this.yAxisLabel = generateSeries(generator, bundle, theme, visible);
-        }
-        catch (final Exception e) {
-            log.error(e.getMessage(), e);
-        }
-    }
-
-    protected static final AbstractCalculationResult getResult(final DiagramGenerator generator, final ArtifactAndFacet bundle) {
-        final CallContext context = generator.getContext();
-        final AbstractCalculationResult data = (AbstractCalculationResult) bundle.getData(context);
-        if (data == null) {
-            // Check has been here before so we keep it for security reasons
-            // this should never happen though.
-            final String facetName = bundle.getFacetName();
-            throw new IllegalStateException("Data is null for facet: " + facetName);
-        }
-
-        return data;
-    }
-
-    /**
-     * @return The axis label
-     */
-    protected abstract String generateSeries(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible);
-
-    protected final String buildSeriesForType(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible,
-            final IResultType resultType, final Double gapDistance) {
-
-        final AbstractCalculationResult data = getResult(generator, bundle);
-
-        final double[][] points = data.getStationPoints(resultType);
-
-        return buildSeriesForType(points, generator, bundle, theme, visible, gapDistance);
-    }
-
-    protected final String buildSeriesForType(final double[][] points, final DiagramGenerator generator, final ArtifactAndFacet bundle,
-            final ThemeDocument theme, final boolean visible, final Double gapDistance) {
-        final CallContext context = generator.getContext();
-        final Map<String, String> metaData = bundle.getFacet().getMetaData();
-
-        final Artifact artifact = bundle.getArtifact();
-
-        final StyledXYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme);
-        series.putMetaData(metaData, artifact, context);
-
-        final String facetName = bundle.getFacetName();
-
-        final double[][] filteredPoints = filterPoints(points, context, artifact, facetName);
-
-        if (gapDistance == null)
-            StyledSeriesBuilder.addPoints(series, filteredPoints, true);
-        else
-            StyledSeriesBuilder.addPoints(series, filteredPoints, true, gapDistance);
-
-        generator.addAxisSeries(series, getAxisName(), visible);
-
-        return metaData.get("Y");
-    }
-
-    protected final String buildStepLineSeriesForType(final double[][] points, final DiagramGenerator generator, final ArtifactAndFacet bundle,
-            final ThemeDocument theme, final boolean visible) {
-
-        final CallContext context = generator.getContext();
-        final Map<String, String> metaData = bundle.getFacet().getMetaData();
-
-        final Artifact artifact = bundle.getArtifact();
-
-        final StyledXYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme);
-        series.putMetaData(metaData, artifact, context);
-
-        final String facetName = bundle.getFacetName();
-
-        // Create WQKms to use the step points method
-        // REMARK: must have any values in w array; not sure whether the name is needed
-        final WQKms wqkms = new WQKms(points[0], points[1], points[1], facetName);
-
-        StyledSeriesBuilder.addStepPointsKmQ(series, wqkms);
-
-        generator.addAxisSeries(series, getAxisName(), visible);
-
-        return metaData.get("Y");
-    }
-
-    protected final String buildSeriesForTkh(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme,
-            final boolean visible) {
-
-        final AbstractTkhCalculationResult data = (AbstractTkhCalculationResult) getResult(generator, bundle);
-
-        final StyledXYSeries seriesUp = new StyledXYSeries(bundle.getFacetDescription(), theme);
-        final double[][] pointsUp = data.getTkhUpPoints();
-        StyledSeriesBuilder.addPoints(seriesUp, pointsUp, true);
-
-        // REMARK: we add " " because the description is misused as id, which must be unique.
-        final StyledXYSeries seriesDown = new StyledXYSeries(bundle.getFacetDescription() + " ", theme);
-        final double[][] pointsDown = data.getTkhDownPoints();
-        StyledSeriesBuilder.addPoints(seriesDown, pointsDown, true);
-
-        final StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(theme);
-        area.setMode(StyledAreaSeriesCollection.FILL_MODE.BETWEEN);
-        area.addSeries(seriesUp);
-        area.addSeries(seriesDown);
-
-        generator.addAreaSeries(area, getAxisName(), visible);
-
-        return null;
-    }
-
-    private Double findRadius(final CallContext context, final Artifact artifact) {
-        final Double start = (Double) context.getContextValue("startkm");
-        final Double end = (Double) context.getContextValue("endkm");
-
-        if (start == null || end == null)
-            return null;
-
-        final RiverContext fc = (RiverContext) context.globalContext();
-        final ZoomScale scales = (ZoomScale) fc.get("zoomscale");
-        final RiverAccess access = new RiverAccess((D4EArtifact) artifact);
-        final String river = access.getRiverName();
-
-        return scales.getRadius(river, start, end);
-    }
-
-    private double[][] filterPoints(final double[][] points, final CallContext context, final Artifact artifact, final String facetName) {
-
-        if (facetName.endsWith(".filtered")) {
-            final Double radius = findRadius(context, artifact);
-            return movingAverage(radius, points);
-        }
-
-        return points;
-    }
-
-    private double[][] movingAverage(final Double radius, final double[][] points) {
-
-        if (radius == null)
-            return points;
-
-        return MovingAverage.weighted(points, radius);
-    }
-
-    @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
-            // TODO: 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");
-    }
-
-    protected static final Facet createFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
-            final int resultIndex, final String axisLabel, final String facetId, final String description) {
-        final String facetFlowDepthFilteredDescription = Resources.getMsg(context.getMeta(), description, description, result.getLabel());
-        return new SInfoResultFacet(resultIndex, facetId, facetFlowDepthFilteredDescription, axisLabel, ComputeType.ADVANCE, id, hash);
-    }
-}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/D50Processor.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/D50Processor.java	Tue Jul 31 16:04:01 2018 +0200
@@ -17,10 +17,11 @@
 import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
+import org.dive4elements.river.artifacts.common.AbstractProcessor;
 import org.dive4elements.river.exports.DiagramGenerator;
 import org.dive4elements.river.themes.ThemeDocument;
 
-public final class D50Processor extends AbstractSInfoProcessor {
+public final class D50Processor extends AbstractProcessor {
 
     public static final String FACET_TKH_D50_FILTERED = "sinfo_facet_d50";
 
@@ -52,7 +53,7 @@
     }
 
     public static Facet createD50Facet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result, final int index) {
-        return AbstractSInfoProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_D50_YAXIS_LABEL, FACET_TKH_D50_FILTERED,
+        return AbstractProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_D50_YAXIS_LABEL, FACET_TKH_D50_FILTERED,
                 I18N_FACET_TKH_D50_FILTERED_DESCRIPTION);
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/FlowDepthDevelopmentPerYearProcessor.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/FlowDepthDevelopmentPerYearProcessor.java	Tue Jul 31 16:04:01 2018 +0200
@@ -17,10 +17,11 @@
 import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
+import org.dive4elements.river.artifacts.common.AbstractProcessor;
 import org.dive4elements.river.exports.DiagramGenerator;
 import org.dive4elements.river.themes.ThemeDocument;
 
-public final class FlowDepthDevelopmentPerYearProcessor extends AbstractSInfoProcessor {
+public final class FlowDepthDevelopmentPerYearProcessor extends AbstractProcessor {
 
     private static final String I18N_AXIS_LABEL = "sinfo.chart.flow_depth_development_per_year.section.yaxis.label";
 
@@ -63,13 +64,13 @@
 
     public static Facet createFlowDepthDevelopmentFilteredFacet(final CallContext context, final String hash, final String id,
             final AbstractCalculationResult result, final int index) {
-        return AbstractSInfoProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_DEVELOPMENT_PER_YEAR_YAXIS_LABEL,
+        return AbstractProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_DEVELOPMENT_PER_YEAR_YAXIS_LABEL,
                 FACET_FLOW_DEPTH_DEVELOPMENT_PER_YEAR_FILTERED, FACET_FLOW_DEPTH_DEVELOPMENT_PER_YEAR_FILTERED_DESCRIPTION);
     }
 
     public static Facet createFlowDepthDevelopmentRawFacet(final CallContext context, final String hash, final String id,
             final AbstractCalculationResult result, final int index) {
-        return AbstractSInfoProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_DEVELOPMENT_PER_YEAR_YAXIS_LABEL,
+        return AbstractProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_DEVELOPMENT_PER_YEAR_YAXIS_LABEL,
                 FACET_FLOW_DEPTH_DEVELOPMENT_PER_YEAR_RAW, FACET_FLOW_DEPTH_DEVELOPMENT_PER_YEAR_RAW_DESCRIPTION);
     }
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/FlowDepthDevelopmentProcessor.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/FlowDepthDevelopmentProcessor.java	Tue Jul 31 16:04:01 2018 +0200
@@ -17,12 +17,14 @@
 import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
+import org.dive4elements.river.artifacts.common.AbstractProcessor;
+import org.dive4elements.river.artifacts.common.ResultFacet;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
 import org.dive4elements.river.exports.DiagramGenerator;
 import org.dive4elements.river.themes.ThemeDocument;
 
-public final class FlowDepthDevelopmentProcessor extends AbstractSInfoProcessor {
+public final class FlowDepthDevelopmentProcessor extends AbstractProcessor {
 
     private static final String I18N_AXIS_LABEL = "sinfo.chart.flow_depth_development.section.yaxis.label";
 
@@ -79,13 +81,13 @@
 
     public static Facet createFlowDepthDevelopmentFilteredFacet(final CallContext context, final String hash, final String id,
             final AbstractCalculationResult result, final int index) {
-        return AbstractSInfoProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_DEVELOPMENT_YAXIS_LABEL,
+        return AbstractProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_DEVELOPMENT_YAXIS_LABEL,
                 FACET_FLOW_DEPTH_DEVELOPMENT_FILTERED, FACET_FLOW_DEPTH_DEVELOPMENT_FILTERED_DESCRIPTION);
     }
 
     public static Facet createFlowDepthDevelopmentRawFacet(final CallContext context, final String hash, final String id,
             final AbstractCalculationResult result, final int index) {
-        return AbstractSInfoProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_DEVELOPMENT_YAXIS_LABEL,
+        return AbstractProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_DEVELOPMENT_YAXIS_LABEL,
                 FACET_FLOW_DEPTH_DEVELOPMENT_RAW, FACET_FLOW_DEPTH_DEVELOPMENT_RAW_DESCRIPTION);
     }
 
@@ -93,7 +95,7 @@
             final int index) {
         final String facetFlowDepthTkhFilteredDescription = Resources.getMsg(context.getMeta(), FACET_WATERLEVEL_DIFFERENCE_FILTERED_DESCRIPTION,
                 FACET_WATERLEVEL_DIFFERENCE_FILTERED_DESCRIPTION, result.getLabel());
-        return new SInfoResultFacet(index, FACET_WATERLEVEL_DIFFERENCE_FILTERED, facetFlowDepthTkhFilteredDescription,
+        return new ResultFacet(index, FACET_WATERLEVEL_DIFFERENCE_FILTERED, facetFlowDepthTkhFilteredDescription,
                 SINFO_CHART_FLOW_DEPTH_DEVELOPMENT_YAXIS_LABEL, ComputeType.ADVANCE, id, hash);
     }
 
@@ -102,7 +104,7 @@
 
         final String facetFlowDepthFilteredDescription = Resources.getMsg(context.getMeta(), FACET_BEDHEIGHT_DIFFERENCE_FILTERED_DESCRIPTION,
                 FACET_BEDHEIGHT_DIFFERENCE_FILTERED_DESCRIPTION, result.getLabel());
-        return new SInfoResultFacet(index, FACET_BEDHEIGHT_DIFFERENCE_FILTERED, facetFlowDepthFilteredDescription,
+        return new ResultFacet(index, FACET_BEDHEIGHT_DIFFERENCE_FILTERED, facetFlowDepthFilteredDescription,
                 SINFO_CHART_FLOW_DEPTH_DEVELOPMENT_YAXIS_LABEL, ComputeType.ADVANCE, id, hash);
     }
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/FlowDepthProcessor.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/FlowDepthProcessor.java	Tue Jul 31 16:04:01 2018 +0200
@@ -17,10 +17,11 @@
 import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
+import org.dive4elements.river.artifacts.common.AbstractProcessor;
 import org.dive4elements.river.exports.DiagramGenerator;
 import org.dive4elements.river.themes.ThemeDocument;
 
-public final class FlowDepthProcessor extends AbstractSInfoProcessor {
+public final class FlowDepthProcessor extends AbstractProcessor {
 
     private static final String AXIS_LABEL = "sinfo.chart.flow_depth.section.yaxis.label";
 
@@ -143,73 +144,73 @@
 
     public static Facet createFlowDepthFilteredFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
             final int index) {
-        return AbstractSInfoProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_FILTERED,
+        return AbstractProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_FILTERED,
                 FACET_FLOW_DEPTH_FILTERED_DESCRIPTION);
     }
 
     public static Facet createFlowDepthRawFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
             final int index) {
-        return AbstractSInfoProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_RAW,
+        return AbstractProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_RAW,
                 FACET_FLOW_DEPTH_RAW_DESCRIPTION);
     }
 
     public static Facet createFlowDepthTkhFilteredFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
             final int index) {
-        return AbstractSInfoProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_TKH_FILTERED,
+        return AbstractProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_TKH_FILTERED,
                 FACET_FLOW_DEPTH_TKH_FILTERED_DESCRIPTION);
     }
 
     public static Facet createFlowDepthTkhRawFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
             final int index) {
-        return AbstractSInfoProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_TKH_RAW,
+        return AbstractProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_TKH_RAW,
                 FACET_FLOW_DEPTH_TKH_RAW_DESCRIPTION);
     }
 
     public static Facet createFlowDepthMinFilteredFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
             final int index) {
-        return AbstractSInfoProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_MIN_FILTERED,
+        return AbstractProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_MIN_FILTERED,
                 FACET_FLOW_DEPTH_MIN_FILTERED_DESCRIPTION);
     }
 
     public static Facet createFlowDepthMinRawFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
             final int index) {
-        return AbstractSInfoProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_MIN_RAW,
+        return AbstractProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_MIN_RAW,
                 FACET_FLOW_DEPTH_MIN_RAW_DESCRIPTION);
     }
 
     public static Facet createFlowDepthMaxFilteredFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
             final int index) {
-        return AbstractSInfoProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_MAX_FILTERED,
+        return AbstractProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_MAX_FILTERED,
                 FACET_FLOW_DEPTH_MAX_FILTERED_DESCRIPTION);
     }
 
     public static Facet createFlowDepthMaxRawFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
             final int index) {
-        return AbstractSInfoProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_MAX_RAW,
+        return AbstractProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_MAX_RAW,
                 FACET_FLOW_DEPTH_MAX_RAW_DESCRIPTION);
     }
 
     public static Facet createFlowDepthCurrentFilteredFacet(final CallContext context, final String hash, final String id,
             final AbstractCalculationResult result, final int index) {
-        return AbstractSInfoProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_CURRENT_FILTERED,
+        return AbstractProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_CURRENT_FILTERED,
                 FACET_FLOW_DEPTH_CURRENT_FILTERED_DESCRIPTION);
     }
 
     public static Facet createFlowDepthCurrentRawFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
             final int index) {
-        return AbstractSInfoProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_CURRENT_RAW,
+        return AbstractProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_CURRENT_RAW,
                 FACET_FLOW_DEPTH_CURRENT_RAW_DESCRIPTION);
     }
 
     public static Facet createFlowDepthHistoricalFilteredFacet(final CallContext context, final String hash, final String id,
             final AbstractCalculationResult result, final int index) {
-        return AbstractSInfoProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_HISTORICAL_FILTERED,
+        return AbstractProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_HISTORICAL_FILTERED,
                 FACET_FLOW_DEPTH_HISTORICAL_FILTERED_DESCRIPTION);
     }
 
     public static Facet createFlowDepthHistoricalRawFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
             final int index) {
-        return AbstractSInfoProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_HISTORICAL_RAW,
+        return AbstractProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, FACET_FLOW_DEPTH_HISTORICAL_RAW,
                 FACET_FLOW_DEPTH_HISTORICAL_RAW_DESCRIPTION);
     }
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/InfrastructureHeightProcessor.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/InfrastructureHeightProcessor.java	Tue Jul 31 16:04:01 2018 +0200
@@ -16,6 +16,7 @@
 import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
 import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.artifacts.CallMeta;
+import org.dive4elements.river.artifacts.common.AbstractProcessor;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.sinfo.flood_duration.InfrastructureFacet;
 import org.dive4elements.river.exports.DiagramGenerator;
@@ -27,7 +28,7 @@
  * @author Matthias Schäfer
  *
  */
-public class InfrastructureHeightProcessor extends AbstractSInfoProcessor {
+public class InfrastructureHeightProcessor extends AbstractProcessor {
 
     public static final String FACET_INFRASTRUCTURE_HEIGHT = "sinfo_facet_infrastructure_height";
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedChannelDepthProcessor.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedChannelDepthProcessor.java	Tue Jul 31 16:04:01 2018 +0200
@@ -16,6 +16,7 @@
 import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
 import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.artifacts.CallMeta;
+import org.dive4elements.river.artifacts.common.AbstractProcessor;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.sinfo.predefinedchannel.PredefinedChannelFacet;
 import org.dive4elements.river.exports.DiagramGenerator;
@@ -27,7 +28,7 @@
  * @author Matthias Schäfer
  *
  */
-public class PredefinedChannelDepthProcessor extends AbstractSInfoProcessor {
+public class PredefinedChannelDepthProcessor extends AbstractProcessor {
 
     // private final static Logger log = Logger.getLogger(PredefinedChannelDepthProcessor.class);
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedChannelWidthProcessor.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedChannelWidthProcessor.java	Tue Jul 31 16:04:01 2018 +0200
@@ -16,6 +16,7 @@
 import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
 import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.artifacts.CallMeta;
+import org.dive4elements.river.artifacts.common.AbstractProcessor;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.sinfo.predefinedchannel.PredefinedChannelFacet;
 import org.dive4elements.river.exports.DiagramGenerator;
@@ -27,7 +28,7 @@
  * @author Matthias Schäfer
  *
  */
-public class PredefinedChannelWidthProcessor extends AbstractSInfoProcessor {
+public class PredefinedChannelWidthProcessor extends AbstractProcessor {
 
     // private final static Logger log = Logger.getLogger(PredefinedChannelWidthProcessor.class);
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedDepthEvolPerYearProcessor.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedDepthEvolPerYearProcessor.java	Tue Jul 31 16:04:01 2018 +0200
@@ -16,6 +16,7 @@
 import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
 import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.artifacts.CallMeta;
+import org.dive4elements.river.artifacts.common.AbstractProcessor;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.sinfo.predefineddepthevol.PredefinedDepthEvolFacet;
 import org.dive4elements.river.exports.DiagramGenerator;
@@ -27,7 +28,7 @@
  * @author Matthias Schäfer
  *
  */
-public class PredefinedDepthEvolPerYearProcessor extends AbstractSInfoProcessor {
+public class PredefinedDepthEvolPerYearProcessor extends AbstractProcessor {
 
     // private final static Logger log = Logger.getLogger(PredefinedDepthEvolPerYearProcessor.class);
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedDepthEvolProcessor.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedDepthEvolProcessor.java	Tue Jul 31 16:04:01 2018 +0200
@@ -16,6 +16,7 @@
 import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
 import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.artifacts.CallMeta;
+import org.dive4elements.river.artifacts.common.AbstractProcessor;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.sinfo.predefineddepthevol.PredefinedDepthEvolFacet;
 import org.dive4elements.river.exports.DiagramGenerator;
@@ -27,7 +28,7 @@
  * @author Matthias Schäfer
  *
  */
-public class PredefinedDepthEvolProcessor extends AbstractSInfoProcessor {
+public class PredefinedDepthEvolProcessor extends AbstractProcessor {
 
     // private final static Logger log = Logger.getLogger(PredefinedDepthEvolProcessor.class);
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedFlowDepthProcessor.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedFlowDepthProcessor.java	Tue Jul 31 16:04:01 2018 +0200
@@ -18,6 +18,7 @@
 import org.dive4elements.artifacts.Artifact;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
+import org.dive4elements.river.artifacts.common.AbstractProcessor;
 import org.dive4elements.river.exports.DiagramGenerator;
 import org.dive4elements.river.exports.StyledSeriesBuilder;
 import org.dive4elements.river.jfree.StyledXYSeries;
@@ -29,7 +30,7 @@
  * @author Matthias Schäfer
  *
  */
-public class PredefinedFlowDepthProcessor extends AbstractSInfoProcessor {
+public class PredefinedFlowDepthProcessor extends AbstractProcessor {
 
     public static final String FACET_PREDEFINED_FLOW_DEPTH = "sinfo_facet_predefined_flowdepth";
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedTkhProcessor.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedTkhProcessor.java	Tue Jul 31 16:04:01 2018 +0200
@@ -14,6 +14,7 @@
 import java.util.Set;
 
 import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
+import org.dive4elements.river.artifacts.common.AbstractProcessor;
 import org.dive4elements.river.exports.DiagramGenerator;
 import org.dive4elements.river.themes.ThemeDocument;
 
@@ -23,7 +24,7 @@
  * @author Matthias Schäfer
  *
  */
-public class PredefinedTkhProcessor extends AbstractSInfoProcessor {
+public class PredefinedTkhProcessor extends AbstractProcessor {
 
     public static final String FACET_PREDEFINED_TKH = "sinfo_facet_predefined_tkh";
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/SInfoResultFacet.java	Tue Jul 31 15:48:35 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +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.common;
-
-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.common.AbstractCalculationResult;
-import org.dive4elements.river.artifacts.common.AbstractCalculationResults;
-import org.dive4elements.river.artifacts.model.CalculationResult;
-import org.dive4elements.river.artifacts.model.DataFacet;
-import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
-
-/**
- * Facet of one of the S-Info curves.
- */
-public class SInfoResultFacet extends DataFacet {
-
-    private static final long serialVersionUID = 1L;
-
-    private static Logger log = Logger.getLogger(SInfoResultFacet.class);
-
-    private int resultIndex;
-
-    public SInfoResultFacet() {
-        // required for clone operation deepCopy()
-    }
-
-    public SInfoResultFacet(final int resultIndex, final String name, final String description, final String yAxisLabelKey, final ComputeType type,
-            final String stateId, final String hash) {
-        this(resultIndex, resultIndex, name, description, yAxisLabelKey, type, stateId, hash);
-    }
-
-    public SInfoResultFacet(final int facetIndex, final int resultIndex, final String name, final String description, final String yAxisLabelKey,
-            final ComputeType type, final String stateId, final String hash) {
-        // REMARK: in some cases, we have several data-lines for the same result (which normally determines the facet index) and
-        // facet name. But index and name are used by the client side as unique keys for the chart themes...
-        // So we might have different facet index and result index.
-        super(facetIndex, name, description, type, hash, stateId);
-        this.resultIndex = resultIndex;
-
-        this.metaData.put("X", "sinfo.chart.km.xaxis.label");
-        this.metaData.put("Y", yAxisLabelKey);
-    }
-
-    @Override
-    public final Object getData(final Artifact artifact, final CallContext context) {
-        log.debug("Get data for result at index: " + this.resultIndex);
-
-        final D4EArtifact flys = (D4EArtifact) artifact;
-
-        final CalculationResult res = (CalculationResult) flys.compute(context, this.hash, this.stateId, this.type, false);
-
-        final AbstractCalculationResults<AbstractCalculationResult> data = (AbstractCalculationResults<AbstractCalculationResult>) res.getData();
-
-        return data.getResults().get(this.resultIndex);
-    }
-
-    /** Copy deeply. */
-    @Override
-    public Facet deepCopy() {
-        // FIXME: why not simply use the full constructor instead?
-        final SInfoResultFacet copy = new SInfoResultFacet();
-        // 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/common/TauProcessor.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/TauProcessor.java	Tue Jul 31 16:04:01 2018 +0200
@@ -17,10 +17,11 @@
 import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
+import org.dive4elements.river.artifacts.common.AbstractProcessor;
 import org.dive4elements.river.exports.DiagramGenerator;
 import org.dive4elements.river.themes.ThemeDocument;
 
-public final class TauProcessor extends AbstractSInfoProcessor {
+public final class TauProcessor extends AbstractProcessor {
 
     public static final String FACET_TKH_TAU_FILTERED = "sinfo_facet_tau";
 
@@ -50,7 +51,7 @@
     }
 
     public static Facet createTauFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result, final int index) {
-        return AbstractSInfoProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_TAU_YAXIS_LABEL, FACET_TKH_TAU_FILTERED,
+        return AbstractProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_TAU_YAXIS_LABEL, FACET_TKH_TAU_FILTERED,
                 I18N_FACET_TKH_TAU_FILTERED_DESCRIPTION);
     }
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/TkhProcessor.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/TkhProcessor.java	Tue Jul 31 16:04:01 2018 +0200
@@ -17,12 +17,14 @@
 import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
+import org.dive4elements.river.artifacts.common.AbstractProcessor;
+import org.dive4elements.river.artifacts.common.ResultFacet;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
 import org.dive4elements.river.exports.DiagramGenerator;
 import org.dive4elements.river.themes.ThemeDocument;
 
-public final class TkhProcessor extends AbstractSInfoProcessor {
+public final class TkhProcessor extends AbstractProcessor {
 
     private static String FACET_TKH = "sinfo_facet_tkh";
 
@@ -52,7 +54,7 @@
     public static Facet createTkhFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result, final int index) {
 
         final String facetTkhDescription = Resources.getMsg(context.getMeta(), I18N_FACET_TKH_DESCRIPTION, I18N_FACET_TKH_DESCRIPTION, result.getLabel());
-        return new SInfoResultFacet(index, TkhProcessor.FACET_TKH, facetTkhDescription, TkhProcessor.SINFO_CHART_TKX_YAXIS_LABEL, ComputeType.ADVANCE, id,
+        return new ResultFacet(index, TkhProcessor.FACET_TKH, facetTkhDescription, TkhProcessor.SINFO_CHART_TKX_YAXIS_LABEL, ComputeType.ADVANCE, id,
                 hash);
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/VelocityProcessor.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/VelocityProcessor.java	Tue Jul 31 16:04:01 2018 +0200
@@ -17,10 +17,11 @@
 import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
+import org.dive4elements.river.artifacts.common.AbstractProcessor;
 import org.dive4elements.river.exports.DiagramGenerator;
 import org.dive4elements.river.themes.ThemeDocument;
 
-public final class VelocityProcessor extends AbstractSInfoProcessor {
+public final class VelocityProcessor extends AbstractProcessor {
 
     public static final String FACET_TKH_VELOCITY_FILTERED = "sinfo_facet_velocity";
 
@@ -51,7 +52,7 @@
 
     public static Facet createVelocityFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
             final int index) {
-        return AbstractSInfoProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_VELOCITY_YAXIS_LABEL, FACET_TKH_VELOCITY_FILTERED,
+        return AbstractProcessor.createFacet(context, hash, id, result, index, SINFO_CHART_VELOCITY_YAXIS_LABEL, FACET_TKH_VELOCITY_FILTERED,
                 I18N_FACET_TKH_VELOCITY_FILTERED_DESCRIPTION);
     }
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationFacet.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationFacet.java	Tue Jul 31 16:04:01 2018 +0200
@@ -10,13 +10,13 @@
 package org.dive4elements.river.artifacts.sinfo.flood_duration;
 
 import org.dive4elements.artifactdatabase.state.Facet;
-import org.dive4elements.river.artifacts.sinfo.common.SInfoResultFacet;
+import org.dive4elements.river.artifacts.common.ResultFacet;
 import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
 
 /**
  * @author Domenico Nardi Tironi
  */
-final class FloodDurationFacet extends SInfoResultFacet {
+final class FloodDurationFacet extends ResultFacet {
 
     private static final long serialVersionUID = 1L;
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationProcessor.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationProcessor.java	Tue Jul 31 16:04:01 2018 +0200
@@ -17,9 +17,9 @@
 import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
+import org.dive4elements.river.artifacts.common.AbstractProcessor;
+import org.dive4elements.river.artifacts.common.ResultFacet;
 import org.dive4elements.river.artifacts.resources.Resources;
-import org.dive4elements.river.artifacts.sinfo.common.AbstractSInfoProcessor;
-import org.dive4elements.river.artifacts.sinfo.common.SInfoResultFacet;
 import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType;
 import org.dive4elements.river.artifacts.sinfo.flood_duration.FloodDurationCalculationResult.ValueGetter;
 import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
@@ -33,7 +33,7 @@
  * @author Matthias Schäfer
  *
  */
-public final class FloodDurationProcessor extends AbstractSInfoProcessor {
+public final class FloodDurationProcessor extends AbstractProcessor {
 
     private static final String FACET_FLOOD_DURATION_LEFT = "sinfo_facet_flood_duration.left";
 
@@ -65,12 +65,12 @@
         if (facetIndex == 0) {
             final String description = Resources.getMsg(context.getMeta(), FACET_FLOOD_DURATION_DESCRIPTION, FACET_FLOOD_DURATION_DESCRIPTION,
                     SInfoResultType.localizeRiverside(context, AttributeKey.LEFT));
-            return new SInfoResultFacet(facetIndex, resultIndex, FACET_FLOOD_DURATION_LEFT, description, I18N_AXIS_LABEL, ComputeType.ADVANCE, id, hash);
+            return new ResultFacet(facetIndex, resultIndex, FACET_FLOOD_DURATION_LEFT, description, I18N_AXIS_LABEL, ComputeType.ADVANCE, id, hash);
         }
         else {
             final String description = Resources.getMsg(context.getMeta(), FACET_FLOOD_DURATION_DESCRIPTION, FACET_FLOOD_DURATION_DESCRIPTION,
                     SInfoResultType.localizeRiverside(context, AttributeKey.RIGHT));
-            return new SInfoResultFacet(facetIndex, resultIndex, FACET_FLOOD_DURATION_RIGHT, description, I18N_AXIS_LABEL, ComputeType.ADVANCE, id, hash);
+            return new ResultFacet(facetIndex, resultIndex, FACET_FLOOD_DURATION_RIGHT, description, I18N_AXIS_LABEL, ComputeType.ADVANCE, id, hash);
         }
     }
 
@@ -126,6 +126,6 @@
 
         final double[][] points = data.getInfrastructurePoints(SInfoResultType.floodDuration, riverside);
 
-        return buildSeriesForType(points, generator, bundle, theme, visible, null);
+        return buildSeriesForPoints(points, generator, bundle, theme, visible, null);
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodHeightProcessor.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodHeightProcessor.java	Tue Jul 31 16:04:01 2018 +0200
@@ -17,9 +17,9 @@
 import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
+import org.dive4elements.river.artifacts.common.AbstractProcessor;
+import org.dive4elements.river.artifacts.common.ResultFacet;
 import org.dive4elements.river.artifacts.resources.Resources;
-import org.dive4elements.river.artifacts.sinfo.common.AbstractSInfoProcessor;
-import org.dive4elements.river.artifacts.sinfo.common.SInfoResultFacet;
 import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType;
 import org.dive4elements.river.artifacts.sinfo.flood_duration.FloodDurationCalculationResult.ValueGetter;
 import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
@@ -33,7 +33,7 @@
  * @author Matthias Schäfer
  *
  */
-public final class FloodHeightProcessor extends AbstractSInfoProcessor {
+public final class FloodHeightProcessor extends AbstractProcessor {
 
     private static final String FACET_FLOOD_HEIGHT_LEFT = "sinfo_facet_flood_height.left";
 
@@ -65,12 +65,12 @@
         if (facetIndex == 0) {
             final String description = Resources.getMsg(context.getMeta(), FACET_FLOOD_HEIGHT_DESCRIPTION, FACET_FLOOD_HEIGHT_DESCRIPTION,
                     SInfoResultType.localizeRiverside(context, AttributeKey.LEFT));
-            return new SInfoResultFacet(facetIndex, resultIndex, FACET_FLOOD_HEIGHT_LEFT, description, I18N_AXIS_LABEL, ComputeType.ADVANCE, id, hash);
+            return new ResultFacet(facetIndex, resultIndex, FACET_FLOOD_HEIGHT_LEFT, description, I18N_AXIS_LABEL, ComputeType.ADVANCE, id, hash);
         }
         else {
             final String description = Resources.getMsg(context.getMeta(), FACET_FLOOD_HEIGHT_DESCRIPTION, FACET_FLOOD_HEIGHT_DESCRIPTION,
                     SInfoResultType.localizeRiverside(context, AttributeKey.RIGHT));
-            return new SInfoResultFacet(facetIndex, resultIndex, FACET_FLOOD_HEIGHT_RIGHT, description, I18N_AXIS_LABEL, ComputeType.ADVANCE, id, hash);
+            return new ResultFacet(facetIndex, resultIndex, FACET_FLOOD_HEIGHT_RIGHT, description, I18N_AXIS_LABEL, ComputeType.ADVANCE, id, hash);
         }
     }
 
@@ -109,7 +109,7 @@
                     }
                 };
                 final double[][] points = ((FloodDurationCalculationResult) data).getMainValueDurationPoints(valuegetter, index);
-                return buildSeriesForType(points, generator, bundle, theme, visible, null);
+                return buildSeriesForPoints(points, generator, bundle, theme, visible, null);
             }
         }
 
@@ -124,6 +124,6 @@
 
         final double[][] points = data.getInfrastructurePoints(SInfoResultType.infrastructureHeight, riverside);
 
-        return buildSeriesForType(points, generator, bundle, theme, visible, null);
+        return buildSeriesForPoints(points, generator, bundle, theme, visible, null);
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculationNoScenarioResult.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculationNoScenarioResult.java	Tue Jul 31 16:04:01 2018 +0200
@@ -73,15 +73,7 @@
     }
 
     protected String[] formatRow(final IExportContext context, final ResultRow row) {
-
         final Collection<String> lines = getNoScenarioFormat(row, context);
-
-        // // ??
-        // // wenn "historisch" gewählt wurde, nur "historisch" anzeigen; sonst für jeden scen-wert ne neue Spalte und "hist"
-        // // ausblenden!...!..!!
-        // lines.add(context.formatRowValue(row, UInfoResultType.salixlinehist));
-        // lines.add(context.formatRowValue(row, UInfoResultType.salixlinescen));
-
         return lines.toArray(new String[lines.size()]);
     }
 
@@ -106,6 +98,5 @@
     @Override
     protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV) {
         // do nothing. subclass may override
-
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculationSupraRegionalResult.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculationSupraRegionalResult.java	Tue Jul 31 16:04:01 2018 +0200
@@ -9,7 +9,6 @@
  */
 package org.dive4elements.river.artifacts.uinfo.salix;
 
-import java.text.NumberFormat;
 import java.util.Collection;
 
 import org.dive4elements.river.artifacts.common.ExportContextCSV;
@@ -53,8 +52,6 @@
         final Collection<String> lines = super.getNoScenarioFormat(row, context);
 
         if (context instanceof ExportContextCSV) { // enum gespart - pdf-export hat ja nur die drei spalten
-            final NumberFormat formatter = ((ExportContextCSV) context).getSalixScenFormatter();
-
             lines.add(context.formatRowValue(row, UInfoResultType.salix_line_scenario));
             lines.add(context.formatRowValue(row, UInfoResultType.salix_line_scenario_dwspl));
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineProcessor.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineProcessor.java	Tue Jul 31 16:04:01 2018 +0200
@@ -16,18 +16,12 @@
 import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
 import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.artifacts.CallContext;
-import org.dive4elements.river.artifacts.D4EArtifact;
-import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
+import org.dive4elements.river.artifacts.common.AbstractProcessor;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.uinfo.common.UInfoResultType;
 import org.dive4elements.river.exports.DiagramGenerator;
-import org.dive4elements.river.exports.StyledSeriesBuilder;
-import org.dive4elements.river.exports.process.DefaultProcessor;
 import org.dive4elements.river.exports.process.WOutProcessor;
-import org.dive4elements.river.jfree.StyledXYSeries;
 import org.dive4elements.river.themes.ThemeDocument;
-import org.dive4elements.river.utils.RiverUtils;
-import org.jfree.data.xy.XYSeries;
 
 /**
  * Processor to generate the facets and data series of salix line
@@ -35,7 +29,7 @@
  * @author Matthias Schäfer
  *
  */
-public final class SalixLineProcessor extends DefaultProcessor {
+public final class SalixLineProcessor extends AbstractProcessor {
 
     private static final String FACET_SALIX_LINE = "uinfo_facet_salix_line";
 
@@ -57,70 +51,61 @@
         HANDLED_FACET_TYPES.add(FACET_SALIX_SCENARIO);
     }
 
-    public static Facet createSalixLineFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
-            final int facetIndex, final int resultIndex) {
+    public static Facet createSalixLineFacet(final CallContext context, final String hash, final String id, final int facetIndex, final int resultIndex) {
 
         final String description = Resources.getMsg(context.getMeta(), FACET_SALIX_LINE_DESCRIPTION, FACET_SALIX_LINE_DESCRIPTION);
-        return new SalixLineResultFacet(FACET_SALIX_LINE, description);
+        return new SalixLineResultFacet(facetIndex, resultIndex, FACET_SALIX_LINE, description, WOutProcessor.I18N_AXIS_LABEL, id, hash);
     }
 
-    public static Facet createSalixMnwMwFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
-            final int facetIndex, final int resultIndex) {
+    public static Facet createSalixMnwMwFacet(final CallContext context, final String hash, final String id, final int facetIndex, final int resultIndex) {
 
         final String description = Resources.getMsg(context.getMeta(), FACET_SALIX_MNWMW_DESCRIPTION, FACET_SALIX_MNWMW_DESCRIPTION);
-        return new SalixMnwMwResultFacet(FACET_SALIX_MNWMW, description);
+        return new SalixMnwMwResultFacet(facetIndex, resultIndex, FACET_SALIX_MNWMW, description, WOutProcessor.I18N_AXIS_LABEL, id, hash);
     }
 
-    public static Facet createSalixScenarioFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
-            final int facetIndex, final int resultIndex, final String subLabel) {
+    public static Facet createSalixScenarioFacet(final CallContext context, final String hash, final String id, final int dataIndex, final int resultIndex,
+            final int facetIndex, final String subLabel) {
 
         final String description = Resources.getMsg(context.getMeta(), FACET_SALIX_SCENARIO_DESCRIPTION, FACET_SALIX_SCENARIO_DESCRIPTION, subLabel);
-        return new SalixScenarioResultFacet(FACET_SALIX_SCENARIO, description, facetIndex, hash, id);
+        return new SalixScenarioResultFacet(facetIndex, resultIndex, dataIndex, FACET_SALIX_SCENARIO, description, WOutProcessor.I18N_AXIS_LABEL, hash, id);
+    }
+
+    public SalixLineProcessor() {
+        super(WOutProcessor.I18N_AXIS_LABEL, HANDLED_FACET_TYPES);
     }
 
     @Override
-    public final String getAxisLabel(final DiagramGenerator generator) {
-
-        final D4EArtifact flys = (D4EArtifact) generator.getMaster();
-        final String unit = RiverUtils.getRiver(flys).getWstUnit().getName();
-        return generator.msg(WOutProcessor.I18N_AXIS_LABEL, WOutProcessor.I18N_AXIS_LABEL_DEFAULT, unit);
-    }
-
-    @Override
-    public final boolean canHandle(final String facettype) {
-        return HANDLED_FACET_TYPES.contains(facettype);
-    }
-
-    @Override
-    public void doOut(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible) {
+    protected String generateSeries(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible) {
 
         // log.debug("Processing facet: " + bundle.getFacetName());
         final CallContext context = generator.getContext();
         final Object data = bundle.getData(context);
 
-        final XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme);
-        final SalixLineCalculationNoScenarioResult result = (SalixLineCalculationNoScenarioResult) data;
-
         if (bundle.getFacetName().equals(FACET_SALIX_LINE)) {
-            StyledSeriesBuilder.addPoints(series, result.getStationPoints(UInfoResultType.salixline), true);
-            generator.addAxisSeries(series, this.axisName, visible);
-            return;
+            return buildSeriesForType(generator, bundle, theme, visible, UInfoResultType.salixline, GAP_DISTANCE);
         }
 
         if (bundle.getFacetName().equals(FACET_SALIX_MNWMW)) {
-            StyledSeriesBuilder.addPoints(series, result.getStationPoints(UInfoResultType.salix_delta_mw), true);
-            generator.addAxisSeries(series, this.axisName, visible);
-            return;
+            return buildSeriesForType(generator, bundle, theme, visible, UInfoResultType.salix_delta_mw, GAP_DISTANCE);
         }
 
         if (bundle.getFacetName().equals(FACET_SALIX_SCENARIO)) {
             // TODO Differenzieren, Scenario 1 bis max. 5 bei Regional
-            if (data instanceof SalixLineCalculationRegionalResult)
-                StyledSeriesBuilder.addPoints(series, ((SalixLineCalculationRegionalResult) data).getScenarioPoints(bundle.getFacet().getIndex()), true);
-            else
-                StyledSeriesBuilder.addPoints(series, result.getStationPoints(UInfoResultType.salix_line_scenario), false);
-            generator.addAxisSeries(series, this.axisName, visible);
-            return;
+
+            // FIXME: warum so unterscheiden? bei den anderen beiden szenarien einfach nur ein szenario-ergebnis in die liste
+            // packen!
+
+            if (data instanceof SalixLineCalculationRegionalResult) {
+
+                final int dataIndex = ((SalixScenarioResultFacet) bundle.getFacet()).getDataIndex();
+
+                final double[][] scenarioPoints = ((SalixLineCalculationRegionalResult) data).getScenarioPoints(dataIndex);
+                return buildSeriesForPoints(scenarioPoints, generator, bundle, theme, visible, GAP_DISTANCE);
+
+            } else
+                return buildSeriesForType(generator, bundle, theme, visible, UInfoResultType.salix_line_scenario, GAP_DISTANCE);
         }
+
+        throw new UnsupportedOperationException();
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineResultFacet.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineResultFacet.java	Tue Jul 31 16:04:01 2018 +0200
@@ -10,45 +10,25 @@
 
 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.common.AbstractCalculationResult;
-import org.dive4elements.river.artifacts.common.AbstractCalculationResults;
-import org.dive4elements.river.artifacts.model.CalculationResult;
-import org.dive4elements.river.artifacts.model.DataFacet;
+import org.dive4elements.river.artifacts.common.ResultFacet;
+import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
 
 /**
  * Facet of the U-Info salix line curve.
  */
-public class SalixLineResultFacet extends DataFacet {
+public class SalixLineResultFacet extends ResultFacet {
 
     private static final long serialVersionUID = 1L;
 
     private static Logger log = Logger.getLogger(SalixLineResultFacet.class);
 
-    private int resultIndex;
-
     public SalixLineResultFacet() {
         // required for clone operation deepCopy()
     }
 
-    public SalixLineResultFacet(final String name, final String description) {
-        super(name, description);
-    }
-
-    @Override
-    public final Object getData(final Artifact artifact, final CallContext context) {
-
-        log.debug("Get data for result at index: " + this.resultIndex);
-
-        final D4EArtifact flys = (D4EArtifact) artifact;
-
-        final CalculationResult res = (CalculationResult) flys.compute(context, this.hash, this.stateId, this.type, false);
-
-        final AbstractCalculationResults<AbstractCalculationResult> data = (AbstractCalculationResults<AbstractCalculationResult>) res.getData();
-
-        return data.getResults().get(this.resultIndex);
+    public SalixLineResultFacet(final int facetIndex, final int resultIndex, final String name, final String description, final String yAxisLabelKey,
+            final String stateId, final String hash) {
+        super(facetIndex, resultIndex, name, description, yAxisLabelKey, ComputeType.ADVANCE, stateId, hash);
     }
 
     /** Copy deeply. */
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineState.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineState.java	Tue Jul 31 16:04:01 2018 +0200
@@ -77,25 +77,31 @@
 
         final List<SalixLineCalculationNoScenarioResult> resultList = results.getResults();
 
+        int facetIndex = 0;
+
         if (!resultList.isEmpty()) {
-            facets.add(SalixLineProcessor.createSalixLineFacet(context, hash, this.id, resultList.get(0), 0, 0));
-            facets.add(SalixLineProcessor.createSalixMnwMwFacet(context, hash, this.id, resultList.get(0), 0, 0));
+            facets.add(SalixLineProcessor.createSalixLineFacet(context, hash, this.id, facetIndex++, 0));
+            facets.add(SalixLineProcessor.createSalixMnwMwFacet(context, hash, this.id, facetIndex++, 0));
+
             if (resultList.get(0) instanceof SalixLineCalculationRegionalResult) {
+
                 final SalixLineCalculationRegionalResult result = (SalixLineCalculationRegionalResult) resultList.get(0);
+
                 for (int i = 0; i <= result.getScenarioCount() - 1; i++) {
                     final String sublabel = Resources.getMsg(context.getMeta(), "uinfo_salix_scenario_deltaw", "uinfo_salix_scenario_deltaw",
                             result.getScenarioLabel(i));
-                    facets.add(SalixLineProcessor.createSalixScenarioFacet(context, hash, this.id, result, i, 0, sublabel));
+                    // REMARK: using data index as facetIndex, as we know there is only one result of this type. Else we should just
+                    // increment
+                    facets.add(SalixLineProcessor.createSalixScenarioFacet(context, hash, this.id, i, 0, facetIndex++, sublabel));
                 }
-            }
-            else if (resultList.get(0) instanceof SalixLineCalculationSupraRegionalResult) {
+            } else if (resultList.get(0) instanceof SalixLineCalculationSupraRegionalResult) {
                 final String sublabel = Resources.getMsg(context.getMeta(), "uinfo_salix_scenario_supraregional");
-                facets.add(SalixLineProcessor.createSalixScenarioFacet(context, hash, this.id, resultList.get(0), 0, 0, sublabel));
+                facets.add(SalixLineProcessor.createSalixScenarioFacet(context, hash, this.id, 0, 0, facetIndex++, sublabel));
             }
 
             else if (resultList.get(0) instanceof SalixLineCalculationHistoricalResult) {
                 final String sublabel = Resources.getMsg(context.getMeta(), "uinfo_salix_scenario_historical");
-                facets.add(SalixLineProcessor.createSalixScenarioFacet(context, hash, this.id, resultList.get(0), 0, 0, sublabel));
+                facets.add(SalixLineProcessor.createSalixScenarioFacet(context, hash, this.id, 0, 0, facetIndex++, sublabel));
             }
 
             final Facet csv = new DataFacet(FacetTypes.CSV, "CSV data", ComputeType.ADVANCE, hash, this.id);
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixMnwMwResultFacet.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixMnwMwResultFacet.java	Tue Jul 31 16:04:01 2018 +0200
@@ -8,47 +8,24 @@
 
 package org.dive4elements.river.artifacts.uinfo.salix;
 
-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.common.AbstractCalculationResult;
-import org.dive4elements.river.artifacts.common.AbstractCalculationResults;
-import org.dive4elements.river.artifacts.model.CalculationResult;
-import org.dive4elements.river.artifacts.model.DataFacet;
+import org.dive4elements.river.artifacts.common.ResultFacet;
+import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
 
 /**
  * Facet of the U-Info salix mnw-mw curve.
  */
-public class SalixMnwMwResultFacet extends DataFacet {
+public class SalixMnwMwResultFacet extends ResultFacet {
 
     private static final long serialVersionUID = 1L;
 
-    private static Logger log = Logger.getLogger(SalixMnwMwResultFacet.class);
-
-    private int resultIndex;
-
     public SalixMnwMwResultFacet() {
         // required for clone operation deepCopy()
     }
 
-    public SalixMnwMwResultFacet(final String name, final String description) {
-        super(name, description);
-    }
-
-    @Override
-    public final Object getData(final Artifact artifact, final CallContext context) {
-
-        log.debug("Get data for result at index: " + this.resultIndex);
-
-        final D4EArtifact flys = (D4EArtifact) artifact;
-
-        final CalculationResult res = (CalculationResult) flys.compute(context, this.hash, this.stateId, this.type, false);
-
-        final AbstractCalculationResults<AbstractCalculationResult> data = (AbstractCalculationResults<AbstractCalculationResult>) res.getData();
-
-        return data.getResults().get(this.resultIndex);
+    public SalixMnwMwResultFacet(final int facetIndex, final int resultIndex, final String name, final String description, final String yAxisLabel,
+            final String id, final String hash) {
+        super(facetIndex, resultIndex, name, description, yAxisLabel, ComputeType.ADVANCE, id, hash);
     }
 
     /** Copy deeply. */
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixScenario.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixScenario.java	Tue Jul 31 16:04:01 2018 +0200
@@ -12,6 +12,8 @@
 import java.io.Serializable;
 import java.text.NumberFormat;
 
+import org.apache.commons.lang.StringUtils;
+
 /**
  * @author Domenico Nardi Tironi
  *
@@ -37,10 +39,16 @@
     }
 
     public String getDwsplFormatted() {
+        if (Double.isNaN(this.dwspl))
+            return StringUtils.EMPTY;
+
         return String.valueOf(this.dwspl);
     }
 
     public String getSalixValueFormatted(final NumberFormat formatter) {
+        if (Double.isNaN(this.salix_value))
+            return StringUtils.EMPTY;
+
         return formatter.format(this.salix_value);
     }
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixScenarioResultFacet.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixScenarioResultFacet.java	Tue Jul 31 16:04:01 2018 +0200
@@ -8,48 +8,28 @@
 
 package org.dive4elements.river.artifacts.uinfo.salix;
 
-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.common.AbstractCalculationResult;
-import org.dive4elements.river.artifacts.common.AbstractCalculationResults;
-import org.dive4elements.river.artifacts.model.CalculationResult;
-import org.dive4elements.river.artifacts.model.DataFacet;
+import org.dive4elements.river.artifacts.common.ResultFacet;
 import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
 
 /**
  * Facet of the U-Info salix scenario curve.
  */
-public class SalixScenarioResultFacet extends DataFacet {
+public class SalixScenarioResultFacet extends ResultFacet {
 
     private static final long serialVersionUID = 1L;
 
-    private static Logger log = Logger.getLogger(SalixScenarioResultFacet.class);
-
-    private int resultIndex;
+    private int dataIndex;
 
     public SalixScenarioResultFacet() {
         // required for clone operation deepCopy()
     }
 
-    public SalixScenarioResultFacet(final String name, final String description, final int facetIndex, final String hash, final String id) {
-        super(facetIndex, name, description, ComputeType.ADVANCE, hash, id);
-    }
-
-    @Override
-    public final Object getData(final Artifact artifact, final CallContext context) {
+    public SalixScenarioResultFacet(final int facetIndex, final int resultIndex, final int dataIndex, final String name, final String description,
+            final String yAxisLabelKey, final String hash, final String id) {
+        super(facetIndex, resultIndex, name, description, yAxisLabelKey, ComputeType.ADVANCE, id, hash);
 
-        log.debug("Get data for result at index: " + this.resultIndex);
-
-        final D4EArtifact flys = (D4EArtifact) artifact;
-
-        final CalculationResult res = (CalculationResult) flys.compute(context, this.hash, this.stateId, this.type, false);
-
-        final AbstractCalculationResults<AbstractCalculationResult> data = (AbstractCalculationResults<AbstractCalculationResult>) res.getData();
-
-        return data.getResults().get(this.resultIndex);
+        this.dataIndex = dataIndex;
     }
 
     /** Copy deeply. */
@@ -62,6 +42,11 @@
         copy.type = this.type;
         copy.hash = this.hash;
         copy.stateId = this.stateId;
+        copy.dataIndex = this.dataIndex;
         return copy;
     }
+
+    public int getDataIndex() {
+        return this.dataIndex;
+    }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/exports/StyledSeriesBuilder.java	Tue Jul 31 15:48:35 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/exports/StyledSeriesBuilder.java	Tue Jul 31 16:04:01 2018 +0200
@@ -63,17 +63,26 @@
         }
         double [] xPoints = points[0];
         double [] yPoints = points[1];
+        
+        Integer lastNonNaNIndex = null;
+        
         for (int i = 0; i < xPoints.length; i++) {
             if (skipNANs &&
                 (Double.isNaN(xPoints[i]) || Double.isNaN(yPoints[i]))) {
                 continue;
             }
+
             // Create gap if distance between points > distance.
-            if (i > 0 && Math.abs(xPoints[i-1] - xPoints[i]) > distance &&
-                !Double.isNaN(yPoints[i-1]) && !Double.isNaN(yPoints[i])) {
-                series.add((xPoints[i-1] + xPoints[i])/2, Double.NaN, false);
+            if (i > 0 && lastNonNaNIndex != null) 
+            {
+                double distanceToLastNonNan = Math.abs(xPoints[lastNonNaNIndex] - xPoints[i] );
+                if (distanceToLastNonNan > distance && !Double.isNaN(yPoints[lastNonNaNIndex]) && !Double.isNaN(yPoints[i]))
+                    series.add((xPoints[i-1] + xPoints[i])/2, Double.NaN, false);
             }
             series.add(xPoints[i], yPoints[i], false);
+            
+            if (skipNANs && !Double.isNaN(xPoints[i]) && !Double.isNaN(yPoints[i])) 
+                    lastNonNaNIndex = i;
         }
     }
 

http://dive4elements.wald.intevation.org