changeset 927:53a2be494765

Enhanced the transition model to continue the parameterization in the waterlevel state to compute flood maps. flys-artifacts/trunk@2281 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Tue, 05 Jul 2011 15:34:54 +0000
parents 659608128823
children e7664917dbdf
files flys-artifacts/ChangeLog flys-artifacts/doc/conf/artifacts/winfo.xml flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DGMSelect.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/FloodplainChoice.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/ProfileDistanceSelect.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/ScenarioSelect.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WaterlevelGroundDifferences.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java flys-artifacts/src/main/resources/messages.properties flys-artifacts/src/main/resources/messages_de.properties flys-artifacts/src/main/resources/messages_de_DE.properties flys-artifacts/src/main/resources/messages_en.properties
diffstat 13 files changed, 510 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/flys-artifacts/ChangeLog	Mon Jul 04 13:23:54 2011 +0000
+++ b/flys-artifacts/ChangeLog	Tue Jul 05 15:34:54 2011 +0000
@@ -1,3 +1,30 @@
+2011-07-05  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Added the option to continue the
+	  waterlevel parameterization with the intent to create flood maps.
+
+	* src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java:
+	  This state is no longer a final state. The user has the option to
+	  continue with the parameterization for flood maps based on the current
+	  waterlevel. Therefore, this states desires the "continue" UI provider.
+	  Clients should recognice this to just step to the next state or display
+	  a button that lets the user step to the next state manually.
+
+	* src/main/java/de/intevation/flys/artifacts/states/FloodplainChoice.java,
+	  src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java,
+	  src/main/java/de/intevation/flys/artifacts/states/ScenarioSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/DGMSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/ProfileDistanceSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/WaterlevelGroundDifferences.java:
+	  New. These states are used to parameterize a further calculation type:
+	  flood map.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties: Required strings for the
+	  flood maps states.
+
 2011-07-04  Sascha L. Teichmann <sascha.teichmann@intevation.de>
 
 	Fix(?) for flys/issue114
--- a/flys-artifacts/doc/conf/artifacts/winfo.xml	Mon Jul 04 13:23:54 2011 +0000
+++ b/flys-artifacts/doc/conf/artifacts/winfo.xml	Tue Jul 05 15:34:54 2011 +0000
@@ -224,5 +224,60 @@
             </outputmodes>
         </state>
 
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.winfo.waterlevel"/>
+            <to state="state.winfo.uesk.dgm"/>
+        </transition>
+
+        <state id="state.winfo.uesk.dgm" description="state.winfo.uesk.dgm" state="de.intevation.flys.artifacts.states.DGMSelect">
+            <data name="dgm" type="String" />
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.winfo.uesk.dgm"/>
+            <to state="state.winfo.uesk.profiles"/>
+        </transition>
+
+        <state id="state.winfo.uesk.profiles" description="state.winfo.uesk.profiles" state="de.intevation.flys.artifacts.states.ProfileDistanceSelect">
+            <data name="profile_distance" type="String" />
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.winfo.uesk.profiles"/>
+            <to state="state.winfo.uesk.floodplain"/>
+        </transition>
+
+        <state id="state.winfo.uesk.floodplain" description="state.winfo.uesk.floodplain.description" state="de.intevation.flys.artifacts.states.FloodplainChoice">
+            <data name="use_floodplain" type="Boolean" />
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.winfo.uesk.floodplain"/>
+            <to state="state.winfo.uesk.differences"/>
+        </transition>
+
+        <state id="state.winfo.uesk.differences" description="state.winfo.uesk.differences" state="de.intevation.flys.artifacts.states.WaterlevelGroundDifferences">
+            <data name="diff_from" type="Double" />
+            <data name="diff_to"   type="Double" />
+            <data name="diff_diff" type="Double" />
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.winfo.uesk.differences"/>
+            <to state="state.winfo.uesk.szenario"/>
+        </transition>
+
+        <state id="state.winfo.uesk.szenario" description="state.winfo.uesk.szenario" state="de.intevation.flys.artifacts.states.ScenarioSelect">
+            <data name="scenario" type="String" />
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.winfo.uesk.szenario"/>
+            <to state="state.winfo.uesk.uesk"/>
+        </transition>
+
+        <state id="state.winfo.uesk.uesk" description="state.winfo.uesk.uesk" state="de.intevation.flys.artifacts.states.FloodMapState">
+        </state>
+
     </states>
 </artifact>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DGMSelect.java	Tue Jul 05 15:34:54 2011 +0000
@@ -0,0 +1,26 @@
+package de.intevation.flys.artifacts.states;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class DGMSelect extends DefaultState {
+
+    @Override
+    protected String getUIProvider() {
+        return "datacage_panel";
+    }
+
+
+    @Override
+    public boolean validate(Artifact artifact, CallContext context)
+    throws IllegalArgumentException
+    {
+        // TODO We have to check the user data if there is a real input!
+        return true;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java	Tue Jul 05 15:34:54 2011 +0000
@@ -0,0 +1,16 @@
+package de.intevation.flys.artifacts.states;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.artifacts.model.FacetTypes;
+
+
+public class FloodMapState
+extends      DefaultState
+implements   FacetTypes
+{
+    /** The logger that is used in this state.*/
+    private static Logger logger = Logger.getLogger(FloodMapState.class);
+
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/FloodplainChoice.java	Tue Jul 05 15:34:54 2011 +0000
@@ -0,0 +1,72 @@
+package de.intevation.flys.artifacts.states;
+
+import org.w3c.dom.Element;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.artifactdatabase.ProtocolUtils;
+
+import de.intevation.flys.artifacts.resources.Resources;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class FloodplainChoice extends DefaultState {
+
+    public static final String OPTION = "floodplain.option";
+
+
+    @Override
+    protected String getUIProvider() {
+        return "boolean_panel";
+    }
+
+
+    @Override
+    protected Element[] createItems(
+        XMLUtils.ElementCreator cr,
+        Artifact    artifact,
+        String      name,
+        CallContext context)
+    {
+        CallMeta meta = context.getMeta();
+
+        Element option = createItem(
+            cr,
+            new String[] { Resources.getMsg(meta, OPTION, OPTION), "true" });
+
+        return new Element[] { option };
+    }
+
+
+    protected Element createItem(XMLUtils.ElementCreator cr, Object obj) {
+        Element item  = ProtocolUtils.createArtNode(cr, "item", null, null);
+        Element label = ProtocolUtils.createArtNode(cr, "label", null, null);
+        Element value = ProtocolUtils.createArtNode(cr, "value", null, null);
+
+        String[] arr = (String[]) obj;
+
+        label.setTextContent(arr[0]);
+        value.setTextContent(arr[1]);
+
+        item.appendChild(label);
+        item.appendChild(value);
+
+        return item;
+    }
+
+
+    @Override
+    public boolean validate(Artifact artifact, CallContext context)
+    throws IllegalArgumentException
+    {
+        // TODO We have to check the user data if there is a real input!
+        return true;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/ProfileDistanceSelect.java	Tue Jul 05 15:34:54 2011 +0000
@@ -0,0 +1,26 @@
+package de.intevation.flys.artifacts.states;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class ProfileDistanceSelect extends DefaultState {
+
+    @Override
+    protected String getUIProvider() {
+        return "auto_integer";
+    }
+
+
+    @Override
+    public boolean validate(Artifact artifact, CallContext context)
+    throws IllegalArgumentException
+    {
+        // TODO We have to check the user data if there is a real input!
+        return true;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/ScenarioSelect.java	Tue Jul 05 15:34:54 2011 +0000
@@ -0,0 +1,88 @@
+package de.intevation.flys.artifacts.states;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Element;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.artifactdatabase.ProtocolUtils;
+
+import de.intevation.flys.artifacts.resources.Resources;
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class ScenarioSelect extends DefaultState {
+
+    /** The logger that is used in this class.*/
+    private static Logger logger = Logger.getLogger(ScenarioSelect.class);
+
+
+    public static final String FIELD_MODE = "szenario";
+
+    public static final String SCENARIO_CURRENT   = "scenario.current";
+    public static final String SCENARIO_POTENTIEL = "scenario.potentiel";
+    public static final String SCENARIO_SCENRAIO  = "scenario.scenario";
+
+    public static final String[] SCENARIOS = {
+        SCENARIO_CURRENT,
+        SCENARIO_POTENTIEL,
+        SCENARIO_SCENRAIO };
+
+
+    @Override
+    protected Element[] createItems(
+        XMLUtils.ElementCreator cr,
+        Artifact    artifact,
+        String      name,
+        CallContext context)
+    {
+        CallMeta meta       = context.getMeta();
+        Element[] scenarios = new Element[SCENARIOS.length];
+
+        int i = 0;
+
+        for (String scenario: SCENARIOS) {
+            scenarios[i++] = createItem(
+                cr, new String[] {
+                    Resources.getMsg(meta, scenario, scenario),
+                    scenario
+                });
+        }
+
+        return scenarios;
+    }
+
+
+    protected Element createItem(XMLUtils.ElementCreator cr, Object obj) {
+        Element item  = ProtocolUtils.createArtNode(cr, "item", null, null);
+        Element label = ProtocolUtils.createArtNode(cr, "label", null, null);
+        Element value = ProtocolUtils.createArtNode(cr, "value", null, null);
+
+        String[] arr = (String[]) obj;
+
+        label.setTextContent(arr[0]);
+        value.setTextContent(arr[1]);
+
+        item.appendChild(label);
+        item.appendChild(value);
+
+        return item;
+    }
+
+
+    @Override
+    public boolean validate(Artifact artifact, CallContext context)
+    throws IllegalArgumentException
+    {
+        // TODO
+
+        return true;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WaterlevelGroundDifferences.java	Tue Jul 05 15:34:54 2011 +0000
@@ -0,0 +1,126 @@
+package de.intevation.flys.artifacts.states;
+
+import org.w3c.dom.Element;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.artifactdatabase.ProtocolUtils;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class WaterlevelGroundDifferences extends RangeState {
+
+    public static final String LOWER_FIELD  = "diff_from";
+    public static final String UPPER_FIELD  = "diff_to";
+    public static final String DIFF_FIELD   = "diff_diff";
+
+    public static final double DEFAULT_STEP = 0d;
+
+
+    private static Logger logger =
+        Logger.getLogger(WaterlevelGroundDifferences.class);
+
+
+
+    @Override
+    protected String getLowerField() {
+        return LOWER_FIELD;
+    }
+
+
+    @Override
+    protected String getUpperField() {
+        return UPPER_FIELD;
+    }
+
+
+    @Override
+    protected String getStepField() {
+        return DIFF_FIELD;
+    }
+
+
+    @Override
+    protected double[] getMinMax(Artifact artifact) {
+        return new double[] { -Double.MAX_VALUE, Double.MAX_VALUE };
+    }
+
+
+    @Override
+    protected String getUIProvider() {
+        return "distance_panel";
+    }
+
+
+    protected double getDefaultStep() {
+        return DEFAULT_STEP;
+    }
+
+
+    @Override
+    protected Element[] createItems(
+        XMLUtils.ElementCreator cr,
+        Artifact    artifact,
+        String      name,
+        CallContext context)
+    {
+        double[] minmax = getMinMax(artifact);
+
+        double minVal = Double.MIN_VALUE;
+        double maxVal = Double.MAX_VALUE;
+
+        if (minmax != null) {
+            minVal = minmax[0];
+            maxVal = minmax[1];
+        }
+        else {
+            logger.warn("Could not read min/max distance values!");
+        }
+
+        if (name.equals(LOWER_FIELD)) {
+            Element min = createItem(
+                cr,
+                new String[] {"min", new Double(minVal).toString()});
+
+            return new Element[] { min };
+        }
+        else if (name.equals(UPPER_FIELD)) {
+            Element max = createItem(
+                cr,
+                new String[] {"max", new Double(maxVal).toString()});
+
+            return new Element[] { max };
+        }
+        else {
+            Element step = createItem(
+                cr,
+                new String[] {"step", String.valueOf(getDefaultStep())});
+            return new Element[] { step };
+        }
+    }
+
+
+    protected Element createItem(XMLUtils.ElementCreator cr, Object obj) {
+        Element item  = ProtocolUtils.createArtNode(cr, "item", null, null);
+        Element label = ProtocolUtils.createArtNode(cr, "label", null, null);
+        Element value = ProtocolUtils.createArtNode(cr, "value", null, null);
+
+        String[] arr = (String[]) obj;
+
+        label.setTextContent(arr[0]);
+        value.setTextContent(arr[1]);
+
+        item.appendChild(label);
+        item.appendChild(value);
+
+        return item;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java	Mon Jul 04 13:23:54 2011 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java	Tue Jul 05 15:34:54 2011 +0000
@@ -4,6 +4,7 @@
 
 import org.apache.log4j.Logger;
 
+import de.intevation.artifacts.Artifact;
 import de.intevation.artifacts.CallContext;
 
 import de.intevation.artifactdatabase.state.Facet;
@@ -28,6 +29,28 @@
 
 
     @Override
+    protected String getUIProvider() {
+        return "continue";
+    }
+
+
+    /**
+     * This method returns always true, because there is no data to validate.
+     *
+     * @param artifact The Artifact.
+     * @param context The CallContext.
+     *
+     * @return always true.
+     */
+    @Override
+    public boolean validate(Artifact artifact, CallContext context)
+    throws IllegalArgumentException
+    {
+        return true;
+    }
+
+
+    @Override
     public Object computeAdvance(
         FLYSArtifact artifact,
         String       hash,
--- a/flys-artifacts/src/main/resources/messages.properties	Mon Jul 04 13:23:54 2011 +0000
+++ b/flys-artifacts/src/main/resources/messages.properties	Tue Jul 05 15:34:54 2011 +0000
@@ -5,6 +5,11 @@
 state.winfo.wq_adapted = Input for W/Q data
 state.winfo.location = Choose the location
 state.winfo.distance = Choose the range
+state.winfo.uesk.dgm = Digital Terrain Model
+state.winfo.uesk.profiles = Interpolated Profiles
+state.winfo.uesk.floodplain = Lateral Boundary
+state.winfo.uesk.differences = Differenzen between waterlevel and terrain
+state.winfo.uesk.scenario = Flood Plain / Scenario
 
 calc.surface.curve = Water Level/Surface Curve
 calc.flood.map = Flood Plain
@@ -12,6 +17,12 @@
 calc.duration.curve = Duration Curve
 calc.discharge.longitudinal.section = TODO (W bei...)
 
+scenario.current = Current
+scenario.potentiel = Potentiel
+scenario.scenario = Scenario
+
+floodplain.option = Use Floodplain?
+
 river = River
 calculation_mode = Calculation Mode
 ld_locations = Location(s)
--- a/flys-artifacts/src/main/resources/messages_de.properties	Mon Jul 04 13:23:54 2011 +0000
+++ b/flys-artifacts/src/main/resources/messages_de.properties	Tue Jul 05 15:34:54 2011 +0000
@@ -5,16 +5,27 @@
 state.winfo.wq_adapted = Eingabe f\u00fcr W/Q Daten
 state.winfo.location = Wahl des Berechnungsortes
 state.winfo.distance = Wahl der Berechnungsstrecke
+state.winfo.uesk.dgm = Digitales Gel\u00e4ndemodell
+state.winfo.uesk.profiles = Interpolierte Profile
+state.winfo.uesk.floodplain = Laterale Begrenzung
+state.winfo.uesk.differences = Differenzen zwischen Wasserspiegellage und Gel\u00e4nde
+state.winfo.uesk.scenario = \u00dcberschwemmungsfl\u00e4che / Szenario
 
-calc.surface.curve = Wasserstand/Wasserspiegellage
+calc.surface.curve = wasserstand/wasserspiegellage
 calc.flood.map = \u00dcberschwemmungsfl\u00e4che
-calc.discharge.curve = Abflusskurve/Abflusstafel
-calc.duration.curve = Dauerlinie
-calc.discharge.longitudinal.section = W bei ungleichwertigem Abflussl\u00e4ngsschnitt
+calc.discharge.curve = abflusskurve/abflusstafel
+calc.duration.curve = dauerlinie
+calc.discharge.longitudinal.section = w bei ungleichwertigem abflussl\u00e4ngsschnitt
 
-river = Fluss
-calculation_mode = Berechnungsart
-ld_locations = Ort(e)
+scenario.current = Aktuell
+scenario.potentiel = Potentiell
+scenario.scenario = Szenario
+
+floodplain.option = Talaue verwenden?
+
+river = fluss
+calculation_mode = berechnungsart
+ld_locations = ort(e)
 
 chart.longitudinal.section.title = W-L\u00e4ngsschnitt
 chart.longitudinal.section.subtitle = Bereich: {0}-km {1,number,#.###} - {2,number,#.###}
--- a/flys-artifacts/src/main/resources/messages_de_DE.properties	Mon Jul 04 13:23:54 2011 +0000
+++ b/flys-artifacts/src/main/resources/messages_de_DE.properties	Tue Jul 05 15:34:54 2011 +0000
@@ -5,6 +5,11 @@
 state.winfo.wq_adapted = Eingabe f\u00fcr W/Q Daten
 state.winfo.location = Wahl des Berechnungsortes
 state.winfo.distance = Wahl der Berechnungsstrecke
+state.winfo.uesk.dgm = Digitales Gel\u00e4ndemodell
+state.winfo.uesk.profiles = Interpolierte Profile
+state.winfo.uesk.floodplain = Laterale Begrenzung
+state.winfo.uesk.differences = Differenzen zwischen Wasserspiegellage und Gel\u00e4nde
+state.winfo.uesk.scenario = \u00dcberschwemmungsfl\u00e4che / Szenario
 
 calc.surface.curve = Wasserstand/Wasserspiegellage
 calc.flood.map = \u00dcberschwemmungsfl\u00e4che
@@ -12,6 +17,12 @@
 calc.duration.curve = Dauerlinie
 calc.discharge.longitudinal.section = W bei ungleichwertigem Abflussl\u00e4ngsschnitt
 
+scenario.current = Aktuell
+scenario.potentiel = Potentiell
+scenario.scenario = Szenario
+
+floodplain.option = Talaue verwenden?
+
 river = Fluss
 calculation_mode = Berechnungsart
 ld_locations = Ort(e)
--- a/flys-artifacts/src/main/resources/messages_en.properties	Mon Jul 04 13:23:54 2011 +0000
+++ b/flys-artifacts/src/main/resources/messages_en.properties	Tue Jul 05 15:34:54 2011 +0000
@@ -5,6 +5,11 @@
 state.winfo.wq_adapted = Input for W/Q data
 state.winfo.location = Choose the location
 state.winfo.distance = Choose the range
+state.winfo.uesk.dgm = Digital Terrain Model
+state.winfo.uesk.profiles = Interpolated Profiles
+state.winfo.uesk.floodplain = Lateral Boundary
+state.winfo.uesk.differences = Differenzen between waterlevel and terrain
+state.winfo.uesk.scenario = Flood Plain / Scenario
 
 calc.surface.curve = Water Level/Surface Curve
 calc.flood.map = Flood Plain
@@ -12,6 +17,12 @@
 calc.duration.curve = Duration Curve
 calc.discharge.longitudinal.section = TODO (W bei...)
 
+scenario.current = Current
+scenario.potentiel = Potentiel
+scenario.scenario = Scenario
+
+floodplain.option = Use Floodplain?
+
 river = River
 calculation_mode = Calculation Mode
 ld_locations = Location(s)

http://dive4elements.wald.intevation.org