diff flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java @ 3814:8083f6384023

merged flys-artifacts/pre2.6-2012-01-04
author Thomas Arendsen Hein <thomas@intevation.de>
date Fri, 28 Sep 2012 12:14:56 +0200
parents 368040e5c400
children cbeeaaad1056
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java	Fri Sep 28 12:14:56 2012 +0200
@@ -0,0 +1,738 @@
+package de.intevation.flys.artifacts.states;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Geometry;
+import com.vividsolutions.jts.geom.LineString;
+import com.vividsolutions.jts.geom.Polygon;
+
+import org.apache.log4j.Logger;
+
+import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.feature.simple.SimpleFeatureType;
+
+import org.geotools.feature.FeatureCollection;
+import org.geotools.feature.FeatureCollections;
+import org.geotools.feature.simple.SimpleFeatureBuilder;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.GlobalContext;
+
+import de.intevation.artifacts.common.utils.FileTools;
+
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.flys.model.CrossSectionTrack;
+import de.intevation.flys.model.DGM;
+import de.intevation.flys.model.Floodplain;
+import de.intevation.flys.model.RiverAxis;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.context.FLYSContext;
+import de.intevation.flys.artifacts.model.CalculationMessage;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.WQKms;
+import de.intevation.flys.artifacts.model.WSPLGENCalculation;
+import de.intevation.flys.artifacts.model.WSPLGENJob;
+import de.intevation.flys.artifacts.model.WSPLGENReportFacet;
+import de.intevation.flys.artifacts.resources.Resources;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+import de.intevation.flys.exports.WstWriter;
+import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.MapfileGenerator;
+import de.intevation.flys.utils.GeometryUtils;
+import de.intevation.flys.wsplgen.FacetCreator;
+import de.intevation.flys.wsplgen.JobObserver;
+import de.intevation.flys.wsplgen.Scheduler;
+
+
+public class FloodMapState
+extends      DefaultState
+implements   FacetTypes
+{
+    /** The logger that is used in this state. */
+    private static Logger logger = Logger.getLogger(FloodMapState.class);
+
+
+    public static final String KEEP_ARTIFACT_DIR =
+        System.getProperty("flys.uesk.keep.artifactsdir", "false");
+
+
+    public static final String WSP_ARTIFACT = "wsp";
+
+    public static final String WINFO_WSP_STATE_ID = "state.winfo.waterlevel";
+
+    public static final String WSPLGEN_PARAMETER_FILE = "wsplgen.par";
+    public static final String WSPLGEN_BARRIERS_LINES = "barrier_lines.shp";
+    public static final String WSPLGEN_BARRIERS_POLY  = "barrier_polygons.shp";
+    public static final String WSPLGEN_AXIS           = "axis.shp";
+    public static final String WSPLGEN_QPS            = "qps.shp";
+    public static final String WSPLGEN_FLOODPLAIN     = "talaue.shp";
+    public static final String WSPLGEN_WSP_FILE       = "waterlevel.wst";
+    public static final String WSPLGEN_OUTPUT_FILE    = "wsplgen.shp";
+
+    public static final int WSPLGEN_DEFAULT_OUTPUT = 0;
+
+
+
+    @Override
+    public Object computeAdvance(
+        FLYSArtifact artifact,
+        String       hash,
+        CallContext  context,
+        List<Facet>  facets,
+        Object       old
+    ) {
+        logger.debug("FloodMapState.computeAdvance");
+
+        File artifactDir = getDirectory(artifact);
+
+        if (artifactDir == null) {
+            logger.error("Could not create directory for WSPLGEN results!");
+            return null;
+        }
+
+        WSPLGENCalculation calculation = new WSPLGENCalculation();
+
+        FacetCreator facetCreator = new FacetCreator(
+            artifact, context, hash, getID(), facets);
+
+        WSPLGENJob job = prepareWSPLGENJob(
+            artifact,
+            facetCreator,
+            artifactDir,
+            context,
+            calculation);
+
+        CalculationResult  res   = new CalculationResult(null, calculation);
+        WSPLGENReportFacet report= new WSPLGENReportFacet(
+            ComputeType.ADVANCE, hash, getID(), res);
+
+        facets.add(report);
+
+        if (job == null) {
+            if (KEEP_ARTIFACT_DIR.equals("false")) {
+                removeDirectory(artifact);
+            }
+
+            calculation.addError(-1, Resources.getMsg(
+                context.getMeta(),
+                "wsplgen.job.error",
+                "wsplgen.job.error"));
+
+            logger.error("No WSPLGEN processing has been started!");
+
+            return null;
+        }
+
+        context.afterCall(CallContext.BACKGROUND);
+        context.addBackgroundMessage(new CalculationMessage(
+            JobObserver.STEPS.length,
+            0,
+            Resources.getMsg(
+                context.getMeta(),
+                "wsplgen.job.queued",
+                "wsplgen.job.queued")
+        ));
+
+        GlobalContext gc    = (GlobalContext) context.globalContext();
+        Scheduler scheduler = (Scheduler) gc.get(FLYSContext.SCHEDULER);
+        scheduler.addJob(job);
+
+        return null;
+    }
+
+
+    /**
+     * Returns (and creates if not existing) the directory for storing WSPLEN
+     * data for the owner artifact.
+     *
+     * @param artifact The owner Artifact.
+     *
+     * @return the directory for WSPLEN data.
+     */
+    protected File getDirectory(FLYSArtifact artifact) {
+        String shapePath = FLYSUtils.getXPathString(
+            FLYSUtils.XPATH_SHAPEFILE_DIR);
+
+        File artifactDir = FileTools.getDirectory(
+            shapePath, artifact.identifier());
+
+        return artifactDir;
+    }
+
+
+    /**
+     * Removes the directory and all its content where the required data and the
+     * results of WSPLGEN are stored. Should be called in endOfLife().
+     */
+    protected void removeDirectory(FLYSArtifact artifact) {
+        String shapePath = FLYSUtils.getXPathString(
+            FLYSUtils.XPATH_SHAPEFILE_DIR);
+
+        File artifactDir = new File(shapePath, artifact.identifier());
+
+        if (artifactDir.exists()) {
+            logger.info("Delete directory: " + artifactDir.getAbsolutePath());
+            boolean success = FileTools.deleteRecursive(artifactDir);
+        }
+        else {
+            logger.debug("There is no directory to remove.");
+        }
+    }
+
+
+    @Override
+    public void endOfLife(Artifact artifact, Object callContext) {
+        logger.info("FloodMapState.endOfLife: " + artifact.identifier());
+
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+        removeDirectory(flys);
+
+        Scheduler scheduler = Scheduler.getInstance();
+        scheduler.cancelJob(flys.identifier());
+
+        MapfileGenerator.getInstance().update();
+    }
+
+
+    protected WSPLGENJob prepareWSPLGENJob(
+        FLYSArtifact       artifact,
+        FacetCreator       facetCreator,
+        File               artifactDir,
+        CallContext        context,
+        WSPLGENCalculation calculation
+    ) {
+        logger.debug("FloodMapState.prepareWSPLGENJob");
+
+        WSPLGENJob job = new WSPLGENJob(
+            artifact,
+            artifactDir,
+            facetCreator,
+            context,
+            calculation);
+
+        File paraFile = new File(artifactDir, WSPLGEN_PARAMETER_FILE);
+
+        setOut(artifact, job);
+        setRange(artifact, job);
+        setDelta(artifact, job);
+        setGel(artifact, job);
+        setDist(artifact, job);
+        setLine(artifact, facetCreator, artifactDir, job);
+        setAxis(artifact, artifactDir, job);
+        setPro(artifact, artifactDir, job);
+        setDgm(artifact, job);
+        setArea(artifact, artifactDir, job);
+        setOutFile(artifact, job);
+        setWsp(artifact, context, artifactDir, job);    // WSP
+
+        // TODO
+        // setWspTag(artifact, job);
+
+        try {
+            job.toFile(paraFile);
+
+            return job;
+        }
+        catch (IOException ioe) {
+            logger.warn("Cannot write PAR file: " + ioe.getMessage());
+        }
+        catch (IllegalArgumentException iae) {
+            logger.warn("Cannot write PAR file: " + iae.getMessage());
+        }
+
+        return null;
+    }
+
+
+    protected void setOut(FLYSArtifact artifact, WSPLGENJob job) {
+        job.setOut(WSPLGEN_DEFAULT_OUTPUT);
+    }
+
+
+    protected void setRange(FLYSArtifact artifact, WSPLGENJob job) {
+        double[] range = FLYSUtils.getKmRange(artifact);
+
+        job.setStart(range[0]);
+        job.setEnd(range[1]);
+    }
+
+
+    protected void setDelta(FLYSArtifact artifact, WSPLGENJob job) {
+        String from = artifact.getDataAsString("diff_from");
+        String to   = artifact.getDataAsString("diff_to");
+        String diff = artifact.getDataAsString("diff_diff");
+
+        try {
+            job.setFrom(Double.parseDouble(from));
+        }
+        catch (NumberFormatException nfe) {
+        }
+
+        try {
+            job.setTo(Double.parseDouble(to));
+        }
+        catch (NumberFormatException nfe) {
+        }
+
+        try {
+            job.setDiff(Double.parseDouble(diff));
+        }
+        catch (NumberFormatException nfe) {
+        }
+    }
+
+
+    protected void setGel(FLYSArtifact artifact, WSPLGENJob job) {
+        String gel = artifact.getDataAsString("scenario");
+
+        logger.debug("Selected gel = '" + gel + "'");
+
+        if (gel == null || gel.length() == 0) {
+            job.setGel(WSPLGENJob.GEL_NOSPERRE);
+        }
+        else if (gel.equals("scenario.current")) {
+            job.setGel(WSPLGENJob.GEL_SPERRE);
+        }
+        else if (gel.equals("scenario.scenario")) {
+            job.setGel(WSPLGENJob.GEL_SPERRE);
+        }
+        else {
+            job.setGel(WSPLGENJob.GEL_NOSPERRE);
+        }
+    }
+
+
+    protected void setDist(FLYSArtifact artifact, WSPLGENJob job) {
+        String dist = artifact.getDataAsString("profile_distance");
+
+        try {
+            job.setDist(Double.parseDouble(dist));
+        }
+        catch (NumberFormatException nfe) {
+            // nothing to do here
+        }
+    }
+
+
+    protected void setLine(
+        FLYSArtifact artifact,
+        FacetCreator facetCreator,
+        File         dir,
+        WSPLGENJob   job
+    ) {
+        String geoJSON = artifact.getDataAsString("uesk.barriers");
+        String srid    = FLYSUtils.getRiverSrid(artifact);
+        String srs     = "EPSG:" + srid;
+
+        if (geoJSON == null || geoJSON.length() == 0) {
+            logger.debug("No barrier features in parameterization existing.");
+            return;
+        }
+
+        SimpleFeatureType ft = getBarriersFeatureType(
+            "barriers", srs, Geometry.class);
+
+        List<SimpleFeature> features = GeometryUtils.parseGeoJSON(geoJSON, ft);
+        if (features == null || features.size() == 0) {
+            logger.debug("No barrier features extracted.");
+            return;
+        }
+
+        FeatureCollection[] fcs = splitLinesAndPolygons(features);
+
+        File shapeLines = new File(dir, WSPLGEN_BARRIERS_LINES);
+        File shapePolys = new File(dir, WSPLGEN_BARRIERS_POLY);
+
+        Object[][] obj = new Object[][] {
+            new Object[] { "typ", String.class }
+        };
+
+        String scenario = job.getGel();
+
+        boolean l = GeometryUtils.writeShapefile(
+            shapeLines,
+            GeometryUtils.buildFeatureType("lines", srs, LineString.class, obj),
+            fcs[0]);
+
+        if (l) {
+            logger.debug(
+                "Successfully created barrier line shapefile. " +
+                "Write shapefile path into WSPLGEN job.");
+
+            if (scenario.equals(WSPLGENJob.GEL_NOSPERRE)) {
+                logger.debug("WSPLGEN will not use barrier features.");
+            }
+            else {
+                job.addLin(shapeLines.getAbsolutePath());
+            }
+        }
+
+        boolean p = GeometryUtils.writeShapefile(
+            shapePolys,
+            GeometryUtils.buildFeatureType("polygons", srs, Polygon.class, obj),
+            fcs[1]);
+
+        if (p) {
+            logger.debug(
+                "Successfully created barrier polygon shapefile. " +
+                "Write shapefile path into WSPLGEN job.");
+
+            if (scenario.equals(WSPLGENJob.GEL_NOSPERRE)) {
+                logger.debug("WSPLGEN will not use barrier features.");
+            }
+            else {
+                job.addLin(shapePolys.getAbsolutePath());
+            }
+        }
+
+        if (p || l) {
+            facetCreator.createBarrierFacet();
+        }
+    }
+
+
+    protected SimpleFeatureType getBarriersFeatureType(
+        String name,
+        String srs,
+        Class  type
+    ) {
+        Object[][] attrs = new Object[3][];
+        attrs[0] = new Object[] { "typ", String.class };
+        attrs[1] = new Object[] { "elevation", Double.class };
+        attrs[2] = new Object[] { "mark.selected", Integer.class };
+
+        return GeometryUtils.buildFeatureType(name, srs, type, attrs);
+    }
+
+
+    protected FeatureCollection[] splitLinesAndPolygons(List<SimpleFeature> f) {
+        FeatureCollection lines    = FeatureCollections.newCollection();
+        FeatureCollection polygons = FeatureCollections.newCollection();
+
+        for (SimpleFeature feature: f) {
+            Geometry geom = (Geometry) feature.getDefaultGeometry();
+
+
+            if (geom instanceof LineString) {
+                geom = applyElevationAttribute(feature, (LineString) geom);
+                lines.add(feature);
+            }
+            else if (geom instanceof Polygon) {
+                geom = applyElevationAttribute(feature, (Polygon) geom);
+                polygons.add(feature);
+            }
+            else {
+                logger.warn("Feature not supported: " + geom.getClass());
+            }
+        }
+
+        logger.debug("Found " + lines.size() + " barrier lines.");
+        logger.debug("Found " + polygons.size() + " barrier polygons.");
+
+        return new FeatureCollection[] { lines, polygons };
+    }
+
+
+    protected static Geometry applyElevationAttribute(
+        SimpleFeature feature,
+        Geometry      geom
+    ) {
+        logger.debug("Apply elevations for: " + geom.getClass());
+
+        List<Double> elevations = extractElevations(feature);
+        int           numPoints = geom.getNumPoints();
+        int        numElevation = elevations.size();
+
+        String typ = (String) feature.getAttribute("typ");
+
+        if (numPoints > numElevation) {
+            logger.warn("More vertices in Geometry than elevations given.");
+        }
+
+        Coordinate[] c = geom.getCoordinates();
+        for (int i = 0; i < numPoints; i++) {
+            if (i < numElevation) {
+                c[i].z = elevations.get(i);
+            }
+            else if (typ != null && typ.equals("Graben")) {
+                c[i].z = -9999d;
+            }
+            else {
+                c[i].z = 9999d;
+            }
+        }
+
+        return geom;
+    }
+
+
+    protected static List<Double> extractElevations(SimpleFeature feature) {
+        String tmp = (String) feature.getAttribute("elevation");
+        String typ = (String) feature.getAttribute("typ");
+
+        String[] elevations = tmp == null ? null : tmp.split(" ");
+
+        int num = elevations != null ? elevations.length : 0;
+
+        List<Double> list = new ArrayList<Double>(num);
+
+        for (int i = 0; i < num; i++) {
+            try {
+                list.add(Double.parseDouble(elevations[i]));
+            }
+            catch (NumberFormatException nfe) {
+                logger.warn("Error while parsing elevation at pos: " + i);
+                if (typ != null && typ.equals("Graben")) {
+                    list.add(new Double(-9999.0));
+                }
+                else {
+                    list.add(new Double(9999.0));
+                }
+            }
+        }
+
+        return list;
+    }
+
+
+    protected void setAxis(FLYSArtifact artifact, File dir, WSPLGENJob job) {
+        String river = artifact.getDataAsString("river");
+        String srid    = FLYSUtils.getRiverSrid(artifact);
+        String srs     = "EPSG:" + srid;
+
+        RiverAxis axis = RiverAxis.getRiverAxis(river);
+        if (axis == null) {
+            logger.warn("Could not find river axis for: '" + river + "'");
+            return;
+        }
+
+        Geometry geom = axis.getGeom();
+
+        SimpleFeatureType ft = GeometryUtils.buildFeatureType(
+            "axis", srs, LineString.class);
+
+        SimpleFeatureBuilder builder = new SimpleFeatureBuilder(ft);
+        builder.add(geom);
+
+        FeatureCollection collection = FeatureCollections.newCollection();
+        collection.add(builder.buildFeature("0"));
+
+        File axisShape = new File(dir, WSPLGEN_AXIS);
+
+        boolean a = GeometryUtils.writeShapefile(
+            axisShape,
+            GeometryUtils.buildFeatureType("axis", srs, LineString.class),
+            collection);
+
+        if (a) {
+            job.setAxis(axisShape.getAbsolutePath());
+        }
+    }
+
+
+    protected void setPro(FLYSArtifact artifact, File dir, WSPLGENJob job) {
+        String river = artifact.getDataAsString("river");
+        String srid    = FLYSUtils.getRiverSrid(artifact);
+        String srs     = "EPSG:" + srid;
+
+        List<CrossSectionTrack> cst =
+            CrossSectionTrack.getCrossSectionTrack(river);
+
+        logger.debug("Found " + cst.size() + " CrossSectionTracks.");
+
+        Object[][] attrs = new Object[2][];
+        attrs[0] = new Object[] { "ELEVATION", Double.class };
+        attrs[1] = new Object[] { "KILOMETER", Double.class };
+
+        SimpleFeatureType ft = GeometryUtils.buildFeatureType(
+            "qps", srs, LineString.class, attrs);
+
+        SimpleFeatureBuilder builder = new SimpleFeatureBuilder(ft);
+        FeatureCollection collection = FeatureCollections.newCollection();
+
+        int i = 0;
+        for (CrossSectionTrack track: cst) {
+            builder.reset();
+            builder.add(track.getGeom());
+            builder.add(track.getZ().doubleValue());
+            builder.add(track.getKm().doubleValue());
+
+            collection.add(builder.buildFeature(String.valueOf(i++)));
+        }
+
+        File qpsShape = new File(dir, WSPLGEN_QPS);
+
+        boolean q = GeometryUtils.writeShapefile(
+            qpsShape,
+            GeometryUtils.buildFeatureType("qps", srs, LineString.class, attrs),
+            collection);
+
+        if (q) {
+            job.setPro(qpsShape.getAbsolutePath());
+        }
+    }
+
+
+    protected void setDgm(FLYSArtifact artifact, WSPLGENJob job) {
+        String dgm_id = artifact.getDataAsString("dgm");
+
+        int id = -1;
+        try {
+            id = Integer.parseInt(dgm_id);
+        }
+        catch (NumberFormatException nfe) { /* do nothing */ }
+
+        DGM dgm = DGM.getDGM(id);
+
+        if (dgm == null) {
+            logger.warn("Could not find specified DGM.");
+
+            return;
+        }
+
+        job.setDgm(dgm.getPath());
+    }
+
+
+    protected void setArea(FLYSArtifact artifact, File dir, WSPLGENJob job) {
+        String useFloodplain = artifact.getDataAsString("use_floodplain");
+        if (!Boolean.valueOf(useFloodplain)) {
+            logger.debug("WSPLGEN will not use floodplain.");
+            return;
+        }
+
+        String river = artifact.getDataAsString("river");
+        String srid  = FLYSUtils.getRiverSrid(artifact);
+        String srs   = "EPSG:" + srid;
+
+        Floodplain plain = Floodplain.getFloodplain(river);
+
+        SimpleFeatureType ft = GeometryUtils.buildFeatureType(
+            "talaue", srs, Polygon.class);
+
+        SimpleFeatureBuilder builder = new SimpleFeatureBuilder(ft);
+        builder.add(plain.getGeom());
+
+        FeatureCollection collection = FeatureCollections.newCollection();
+        collection.add(builder.buildFeature("0"));
+
+        File talaueShape = new File(dir, WSPLGEN_FLOODPLAIN);
+
+        boolean t = GeometryUtils.writeShapefile(
+            talaueShape,
+            GeometryUtils.buildFeatureType("talaue", srs, Polygon.class),
+            collection);
+
+        if (t) {
+            job.setArea(talaueShape.getAbsolutePath());
+        }
+    }
+
+
+    protected void setOutFile(FLYSArtifact artifact, WSPLGENJob job) {
+        job.setOutFile(WSPLGEN_OUTPUT_FILE);
+    }
+
+
+    protected WQKms getWQKms(FLYSArtifact flys, CallContext cc) {
+        String   wspString = flys.getDataAsString(WSP_ARTIFACT);
+        String[] parts     = wspString.split(";");
+
+        String otherArtifact = parts[0];
+
+        int idx = -1;
+        try {
+            idx = Integer.parseInt(parts[2]);
+        }
+        catch (NumberFormatException nfe) { /* do nothing */ }
+
+        FLYSArtifact src = otherArtifact != null
+            ? FLYSUtils.getArtifact(otherArtifact, cc)
+            : flys;
+
+        logger.debug("Use waterlevel provided by Artifact: " + src.identifier());
+
+        CalculationResult rawData = (CalculationResult) src.compute(
+            cc,
+            null,
+            WINFO_WSP_STATE_ID,
+            ComputeType.ADVANCE,
+            false);
+
+        WQKms[] wqkms = (WQKms[]) rawData.getData();
+
+        return wqkms == null || idx == -1 || idx >= wqkms.length
+            ? null
+            : wqkms[idx];
+    }
+
+
+    protected void setWsp(
+        FLYSArtifact artifact,
+        CallContext  context,
+        File         dir,
+        WSPLGENJob   job)
+    {
+        logger.debug("FloodMapState.setWsp");
+
+        WQKms data = getWQKms(artifact, context);
+
+        if (data == null) {
+            logger.warn("No WST data found!");
+            return;
+        }
+
+        WstWriter writer = new WstWriter(1);
+
+        // TODO REMOVE job.setWspTag(...) This is only used until the user is
+        // able to select the WSP column himself!
+        boolean writeWspTag = true;
+
+        double[] buf = new double[4];
+        logger.debug("Add WST column: " + data.getName());
+        writer.addColumn(data.getName());
+
+        if (writeWspTag) {
+            job.setWspTag(data.getName());
+            writeWspTag = false;
+        }
+
+        for (int i = 0, num = data.size(); i < num; i++) {
+            data.get(i, buf);
+            writer.add(buf);
+        }
+
+        FileOutputStream fout = null;
+
+        try {
+            File wspFile = new File(dir, WSPLGEN_WSP_FILE);
+            fout         = new FileOutputStream(wspFile);
+
+            writer.write(fout);
+
+            job.setWsp(wspFile.getAbsolutePath());
+        }
+        catch (FileNotFoundException fnfe) {
+            logger.warn("Error while writing wsp file: " + fnfe.getMessage());
+        }
+        finally {
+            if (fout != null) {
+                try {
+                    fout.close();
+                }
+                catch (IOException ioe) { /* do nothing */ }
+            }
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :

http://dive4elements.wald.intevation.org