view gnv-artifacts/src/main/java/de/intevation/gnv/state/profile/horizontalcrosssection/HorizontalCrossSectionMeshOutputState.java @ 1115:f953c9a559d8

Added license file and license headers. gnv-artifacts/trunk@1260 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Tue, 02 Nov 2010 17:46:55 +0000
parents 9a24c743efa6
children dec4257ad570
line wrap: on
line source
/*
 * Copyright (c) 2010 by Intevation GmbH
 *
 * This program is free software under the LGPL (>=v2.1)
 * Read the file LGPL.txt coming with the software for details
 * or visit http://www.gnu.org/licenses/ if it does not exist.
 */

package de.intevation.gnv.state.profile.horizontalcrosssection;

import java.awt.Dimension;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Polygon;

import de.intevation.artifactdatabase.Config;
import de.intevation.artifactdatabase.XMLUtils;
import de.intevation.artifacts.ArtifactNamespaceContext;
import de.intevation.artifacts.CallContext;
import de.intevation.gnv.artifacts.cache.CacheFactory;
import de.intevation.gnv.artifacts.context.GNVArtifactContext;
import de.intevation.gnv.geobackend.base.Result;
import de.intevation.gnv.geobackend.base.ResultDescriptor;
import de.intevation.gnv.geobackend.base.query.QueryExecutor;
import de.intevation.gnv.geobackend.base.query.QueryExecutorFactory;
import de.intevation.gnv.geobackend.base.query.exception.QueryException;
import de.intevation.gnv.geobackend.sde.datasources.RasterObject;
import de.intevation.gnv.math.AreaInterpolation;
import de.intevation.gnv.math.AttributedPoint2ds;
import de.intevation.gnv.math.Point2d;
import de.intevation.gnv.math.QueriedXYDepth;
import de.intevation.gnv.raster.ExternalIndexConverter;
import de.intevation.gnv.raster.IsoAttributeGenerator;
import de.intevation.gnv.raster.JTSMultiLineStringProducer;
import de.intevation.gnv.raster.JTSMultiPolygonProducer;
import de.intevation.gnv.raster.Palette;
import de.intevation.gnv.raster.PaletteManager;
import de.intevation.gnv.raster.Raster;
import de.intevation.gnv.raster.Vectorizer;
import de.intevation.gnv.state.InputData;
import de.intevation.gnv.state.OutputStateBase;
import de.intevation.gnv.state.exception.StateException;
import de.intevation.gnv.utils.ExclusiveExec;
import de.intevation.gnv.utils.FileUtils;
import de.intevation.gnv.utils.MapfileGenerator;
import de.intevation.gnv.utils.MetaWriter;
import de.intevation.gnv.utils.Pair;
import de.intevation.gnv.utils.ShapeFileWriter;
import de.intevation.gnv.utils.StringUtils;
import de.intevation.gnv.utils.WKTUtils;

/**
 * @author <a href="mailto:tim.englich@intevation.de">Tim Englich</a>
 * @author <a href="mailto:sascha.teichmann@intevation.de">Sascha L. Teichmann</a>
 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
 */
public class HorizontalCrossSectionMeshOutputState
extends      OutputStateBase
{
    private static Logger log = Logger
        .getLogger(HorizontalCrossSectionMeshOutputState.class);

    /**
     * The UID of this Class
     */
    private static final long serialVersionUID = 3233620652465061860L;

    public static final boolean USE_INDEX_BUFFER =
        Boolean.getBoolean("gnv.horizontal.cross.section.mesh.index.buffer");

    /**
     * Shapefile name for isolines.
     */
    public static final String ISOLINES_NAME  = "isolines.shp";

    /**
     * Shapefile name for polygons.
     */
    public static final String POLYGON_NAME   = "polygons.shp";

    public static final String LAYER_MODEL    = "horizontalcrosssection";

    private String ijkQueryID;

    private Boolean shapeFileLock = new Boolean(true);

    private String shapeFilePath;
    
    private Envelope  bbox = null;

    /**
     * Constructor
     */
    public HorizontalCrossSectionMeshOutputState() {
    }

    @Override
    public void initialize(String uuid, CallContext callContext)
    throws StateException {
        super.initialize(uuid, callContext);
        if (log.isDebugEnabled()) {
            log.debug("initialize output state " + uuid);
        }
        // fill the cache
        getResult(uuid, callContext);
    }

    /**
     * Returns the shapefile directory path.
     *
     * @return the shapefile path.
     */
    public String getShapeFilePath() {
        synchronized (shapeFileLock) {
            return shapeFilePath;
        }
    }

    /**
     * Set the shapefile path.
     *
     * @param shapeFilePath Destination path to write shapefiles.
     */
    public void setShapeFilePath(String shapeFilePath) {
        synchronized (shapeFileLock) {
            this.shapeFilePath = shapeFilePath;
        }
    }

    /**
     * Method to reset the shapefile path.
     *
     * @return the old path.
     */
    public String resetShapeFilePath() {
        synchronized (shapeFileLock) {
            String path = shapeFilePath;
            shapeFilePath = null;
            return path;
        }
    }


    /**
     * This method removes all shapefiles which might have been written by this
     * artifact and resets the shapefile path.
     *
     * @param globalContext CallContext
     */
    @Override
    public void endOfLife(Object globalContext) {
        super.endOfLife(globalContext);

        // do it in background
        new Thread() {
            @Override
            public void run() {
                String path = resetShapeFilePath();

                if (path == null) {
                    return;
                }

                File dir = new File(path);

                for (int i = 0; i < 10; ++i) {
                    if (!dir.exists() || FileUtils.deleteRecursive(dir)) {
                        MapfileGenerator.getInstance().update();
                        return;
                    }

                    try {
                        Thread.sleep(10000L);
                    }
                    catch (InterruptedException ie) {
                    }
                }

                log.error("failed to remove directory '" + path + "'");
            } // run
        }.start();
    }


    /**
     * This out target has two options:<br>
     * <ol>
     *  <li>zip: Write the resulting data to shapefiles and export them as
     * zip-archive.</li>
     *  <li>wms: Write the resulting data to shapefiles and feed a map service
     * with a layer displaying these shapefiles.</li>
     * </ol>
     *
     * @param format
     * @param inputData
     * @param outputStream
     * @param uuid
     * @param callContext
     * @throws StateException
     */
    public void out(
        Document              format,
        Collection<InputData> inputData,
        OutputStream          outputStream,
        String                uuid,
        CallContext           callContext
    )
    throws StateException
    {
        String outputMode = XMLUtils.xpathString(
            format, XPATH_OUTPUT_MODE, ArtifactNamespaceContext.INSTANCE);

        if (outputMode == null) {
            throw new StateException("cannot find outputMode or mime");
        }

        outputMode = outputMode.toLowerCase();

        if (log.isDebugEnabled()) {
            log.debug("---- asking for: " + outputMode);
        }

        if ("zip".equals(outputMode)) {
            writeZip(uuid, callContext, outputStream);
        }
        else if ("wms".equals(outputMode)) {
            XMLUtils.toStream(
                getWMS(uuid, callContext, inputData),
                outputStream);
        }
        else {
            throw new StateException("unsupported output mode");
        }
    }

    /**
     * Create a zip archive with the shapefiles of the given shapefiles path and
     * write it to <code>output</code>.
     *
     * @param uuid The UUID of the current artifact.
     * @param callContext The CallContext object.
     * @param output The output stream.
     * @throws StateException if an error occured while zipfile creation.
     */
    protected void writeZip(
        String       uuid,
        CallContext  callContext,
        OutputStream output
    )
    throws StateException
    {
        try {
            String p = getShapeFilePath();
            if (p != null) {
                File dir = new File(p);
                if (dir.isDirectory()) {
                    FileUtils.createZipArchive(dir, output);
                }
            }
            else {
                AttributedPoint2ds result = getResult(uuid, callContext);
                ExclusiveExec.UniqueKey k = ExclusiveExec.INSTANCE.acquire(uuid);
                if (result != null
                && (p = writeToShapeFile(uuid, result, callContext)) != null) {
                    FileUtils.createZipArchive(new File(p), output);
                    ExclusiveExec.INSTANCE.release(k);
                }
            }
        }
        catch (IOException ioe) {
            log.error(ioe.getLocalizedMessage(), ioe);
        }
    }

    /**
     * Write data to shapefiles and feed a map service with information about
     * these shapefiles. The map service can be queried for displaying
     * corresponding layers as WMS.
     *
     * @param uuid The UUID of the current artifact.
     * @param callContext The CallContext object.
     * @param inputData A collection with some input data.
     * @return a document with some meta information (shapefile path, geometry
     * type, time to live of the current artifact, etc).
     * @throws StateException if an error occured while shapefile writing.
     */
    protected Document getWMS(
        String                uuid,
        CallContext           callContext,
        Collection<InputData> inputData
    )
    throws StateException
    {
        Document document = XMLUtils.newDocument();

        Element pathElement = document.createElement("path");
        document.appendChild(pathElement);

        String path  = getShapeFilePath();

        if (path != null && new File(path).isDirectory()) {
            Document meta = MetaWriter.initMeta();
            MetaWriter.insertAbstractMeta(callContext, meta);

            String prefix = getLayerPrefix(inputData);
            if (prefix == null) {
                prefix = uuid;
            }

            // append polygon meta
            String model  = findParameterType(callContext);
            String type   = "POLYGON";
            String name   = getLayerName(uuid, type);
            String title  = getLayerTitle(prefix, type);
            String data   = getLayerData(uuid, POLYGON_NAME);
            String status = "OFF";
            MetaWriter.insertLayer(
                callContext, meta, name, title, data, model, type, status);

            // append isoline meta
            model += "_isolines";
            type  = "LINE";
            name  = getLayerName(uuid, type);
            title = getLayerTitle(prefix, type);
            data  = getLayerData(uuid, ISOLINES_NAME);
            MetaWriter.insertLayer(
                callContext, meta, name, title, data, model, type, status);

            if (meta != null) {
                MetaWriter.insertMbr(this.bbox, "EPSG:4326", meta);
                MetaWriter.writeMetaFile(path, meta);
                MapfileGenerator.getInstance().update();
                return meta;
            }

            pathElement.setTextContent(path);
        }
        else {
            AttributedPoint2ds result = getResult(uuid, callContext);
            ExclusiveExec.UniqueKey key = ExclusiveExec.INSTANCE.acquire(uuid);
            try{
            if (result != null
            && (path = writeToShapeFile(uuid, result, callContext)) != null) {
                Document meta = MetaWriter.initMeta();
                MetaWriter.insertAbstractMeta(callContext, meta);

                String prefix = getLayerPrefix(inputData);
                if (prefix == null) {
                    prefix = uuid;
                }

                // append polygon meta
                String model  = findParameterType(callContext);
                String type   = "POLYGON";
                String name   = getLayerName(uuid, type);
                String title  = getLayerTitle(prefix, type);
                String data   = getLayerData(uuid, POLYGON_NAME);
                String status = "OFF";
                MetaWriter.insertLayer(
                    callContext, meta, name, title, data, model, type, status);

                // append isoline meta
                model += "_isolines";
                type   = "LINE";
                name   = getLayerName(uuid, type);
                title  = getLayerTitle(prefix, type);
                data   = getLayerData(uuid, ISOLINES_NAME);
                MetaWriter.insertLayer(
                    callContext, meta, name, title, data, model, type, status);

                if (meta != null) {
                    MetaWriter.insertMbr(this.bbox, "EPSG:4326", meta);
                    MetaWriter.writeMetaFile(path, meta);
                    MapfileGenerator.getInstance().update();
                    return meta;
                }

                pathElement.setTextContent(path);
            }
            }finally{
                ExclusiveExec.INSTANCE.release(key);
            }
        }

        return document;
    }

    /**
     * Find the parameter name which is used during mapfile creation in
     * MapfileGenerator.
     *
     * @param callContext The CallContext object.
     * @return the parameter name of the current parameterization.
     */
    protected String findParameterType(CallContext callContext) {
        InputData inputParam = inputData.get("parameterid");

        Map<Integer, PaletteManager> paletteManagers = getPalettes(callContext);

        if (inputParam == null || paletteManagers == null) {
            log.warn("Parameter-id not found.");
            return LAYER_MODEL;
        }
        else {
            Integer parameterId = Integer.parseInt(inputParam.getValue());
            PaletteManager paletteManager = paletteManagers.get(parameterId);

            return LAYER_MODEL + "_" + paletteManager.getName();
        }
    }


    /**
     * Find the title for a wms layer specified by the user.
     *
     * @param inputData A collection with InputData objects.
     * @return the title.
     */
    protected String getLayerPrefix(Collection<InputData> inputData) {
        for (InputData data: inputData) {
            String name = data.getName();
            if (name != null && name.equals("title")) {
                return (String) data.getValue();
            }
        }

        return null;
    }


    /**
     * Returns the name of the layer.
     *
     * @param uuid The uuid the the current session. It is the base part of the
     * layername.
     * @param type The type of the layer ('POLYGON' or 'LINE').
     * @return the name of the layer.
     */
    protected String getLayerName(String uuid, String type) {
        return "GNV_" + uuid + "-" + type;
    }

    /**
     * Returns the layer title.
     *
     * @param prefix A prefix (null not permitted).
     * @param type The layer type.
     * @return the title of the layer.
     */
    protected String getLayerTitle(String prefix, String type) {
        return "GNV_" + prefix + "-" + type;
    }


    /**
     * Returns the path to the shapefile that serves the layer data.
     *
     * @param shapeDir The shapefile directory.
     * @param filename The name of the shapefile.
     * @return the relative path to the shapefile.
     */
    protected String getLayerData(String shapeDir, String filename) {
        File path = new File(shapeDir, filename);

        return path.toString();
    }

    /**
     * Write the resulting data to shapefiles.
     *
     * @param uuid The UUID of the current artifact.
     * @param result The finalized data used for shapefile creation.
     * @param callContext The CallContext object.
     * @return the shapefile path.
     */
    protected String writeToShapeFile(
        String             uuid,
        AttributedPoint2ds result,
        CallContext        callContext
    ) {
        File baseDir = shapefileDirectory(callContext);

        File shapeDir = new File(baseDir, uuid);

        boolean success    = false;
        boolean createdDir = false;

        try {
            synchronized (shapeFileLock) {
                if (shapeDir.exists()) {
                    FileUtils.deleteContent(shapeDir);
                }
                else if (!shapeDir.mkdirs()) {
                    log.error("cannot create directory '"
                        + shapeDir.getAbsolutePath() + "'");
                    return null;
                }
                createdDir = true;
            }

            Map<Integer, MultiPolygon> polygons = result.getPolygons();

            List<Pair<Object, MultiLineString>> isolines =
                result.getLineStrings();

            File polygonsFile = new File(shapeDir, POLYGON_NAME);
            File isolinesFile = new File(shapeDir, ISOLINES_NAME);

            if (!ShapeFileWriter.writeMultiPolygonsToFile(
                polygonsFile,
                (Integer)result.getAttribute("parameter"),
                (Integer)result.getAttribute("layer"),
                (Date)   result.getAttribute("date"),
                polygons)
            ) {
                log.error("writing polygons failed");
                return null;
            }

            if (!ShapeFileWriter.writeMultiLineStringsToFile(
                isolinesFile,
                (Integer)result.getAttribute("parameter"),
                (Integer)result.getAttribute("layer"),
                (Date)   result.getAttribute("date"),
                isolines)
            ) {
                log.error("writing isolines failed");
                return null;
            }

            shapeFilePath = shapeDir.getAbsolutePath();
            success = true;

            callContext.afterCall(CallContext.STORE);

            return shapeFilePath;
        }
        finally {
            if (!success && createdDir) {
                FileUtils.deleteRecursive(shapeDir);
            }
        }
    }


    /**
     * Return the processed results ready for being written to shapefile.
     *
     * @param uuid The UUID of the current artifacts.
     * @param callContext The CallContext object.
     * @return the processed data.
     * @throws StateException if an error occured while processing data.
     */
    protected AttributedPoint2ds getResult(String uuid, CallContext callContext)
    throws StateException
    {
        CacheFactory cf  = CacheFactory.getInstance();
        String       key = getHash();

        if (cf.isInitialized()) {
            log.debug("Using cache - key: " + key);
            net.sf.ehcache.Element value = cf.getCache().get(key);
            if (value != null) {
                log.debug("Found element in cache.");
                return (AttributedPoint2ds)value.getObjectValue();
            }
        }

        log.debug("Not using cache or element not found.");
        AttributedPoint2ds result = produceResult(callContext);

        if (result != null && cf.isInitialized()) {
            cf.getCache().put(new net.sf.ehcache.Element(key, result));
        }

        return result;
    }

    /**
     * Query the database for result data and turn it into a useful format to
     * write this data into shapefiles.
     *
     * @param callContext The CallContext object.
     * @return the processed data.
     * @throws StateException if an error occured while processing data.
     */
    protected AttributedPoint2ds produceResult(CallContext callContext)
    throws StateException
    {
        InputData meshPolygon = inputData.get("mesh_polygon");
        InputData meshId      = inputData.get("meshid");

        if (meshPolygon == null) {
            log.error("mesh_polygon is not defined");
            throw new StateException("missing mesh_linestring");
        }

        if (meshId == null) {
            log.error("meshid is not defined");
            throw new StateException("missing meshid");
        }

        Polygon p = WKTUtils.toPolygon(meshPolygon.getValue());

        if (p == null) {
            log.error("no valid polygon");
            throw new StateException("no valid polygon");
        }

        try {
            Envelope env  = p.getEnvelopeInternal();

            this.bbox = env;
            String additionWhere;

            if (USE_INDEX_BUFFER) {
                Coordinate [] coords = new Coordinate [] {
                    new Coordinate(env.getMinX(), env.getMinY()),
                    new Coordinate(env.getMinX(), env.getMaxY()),
                    new Coordinate(env.getMaxX(), env.getMaxY()),
                    new Coordinate(env.getMaxX(), env.getMinY()) };

                additionWhere =
                    WKTUtils.worldEnvelopeCoordinatesToIndex(
                        coords,
                        meshId.getValue(),
                        ijkQueryID);
            }
            else {
                additionWhere = WKTUtils.TRUE_EXPRESSION;
            }

            String[] addedFilterValues = StringUtils.append(
                generateFilterValuesFromInputData(),
                additionWhere);

            QueryExecutor queryExecutor = QueryExecutorFactory
                .getInstance()
                .getQueryExecutor();

            return process(
                env,
                p,
                callContext,
                preProcess(
                    queryExecutor.executeQuery(
                        queryID,
                        addedFilterValues)));
        }
        catch (QueryException e) {
            log.error(e,e);
        }

        throw new StateException("no result produced");
    }

    /**
     * First step of finalizing the data returned from database.
     *
     * @param results Resulting data from database.
     * @return the pre-processed data which is still not useful for being
     * written to shapefiles.
     */
    public AttributedPoint2ds preProcess(Collection<Result> results) {

        boolean debug = log.isDebugEnabled();

        if (debug) {
            log.debug("--- preProcess: " + results.size() + " results");
        }

        AttributedPoint2ds ap2ds = new AttributedPoint2ds();

        ArrayList<Point2d> points = new ArrayList<Point2d>(results.size());

        int sIdx = -1;
        int iIdx = -1;
        int jIdx = -1;
        int vIdx = -1;

        boolean firstWarn = true;

        for (Result result: results) {

            if (sIdx == -1) {
                ResultDescriptor rd = result.getResultDescriptor();
                sIdx     = rd.getColumnIndex("SHAPE");
                iIdx     = rd.getColumnIndex("IPOSITION");
                jIdx     = rd.getColumnIndex("JPOSITION");
                vIdx     = rd.getColumnIndex("YORDINATE");
                int kIdx = rd.getColumnIndex("KPOSITION");
                int tIdx = rd.getColumnIndex("TIMEVALUE");
                int pIdx = rd.getColumnIndex("PARAMETERID");

                if (sIdx == -1 || iIdx == -1
                ||  jIdx == -1 || kIdx == -1
                ||  vIdx == -1 || tIdx == -1
                ||  pIdx == -1
                ) {
                    log.error("missing column in result set");
                    return null;
                }

                ap2ds.setAttribute("date",      result.getDate(tIdx));
                ap2ds.setAttribute("parameter", result.getInteger(pIdx));
                ap2ds.setAttribute("layer",     result.getInteger(kIdx));
            }
            Coordinate coord = WKTUtils.toCoordinate(result.getString(sIdx));
            if (coord == null) {
                if (firstWarn) {
                    firstWarn = false;
                    log.warn("cannot fetch coordinate from result");
                }
                continue;
            }
            double v = result.getDouble(vIdx);
            int    i = result.getInteger(iIdx);
            int    j = result.getInteger(jIdx);

            Point2d p2d = new Point2d(coord.x, coord.y, v, i, j);
            points.add(p2d);

        }
        ap2ds.setPoints(points);

        return ap2ds;
    }

    /**
     * The last step of finalizing the data. The returned data is useful for
     * shapefile creation.
     *
     * @param boundingBox The bounding box.
     * @param polygon A polygon.
     * @param callContext CallContext.
     * @param input The pre-processed data.
     * @return the finalized data ready for shapefile creation.
     */
    public AttributedPoint2ds process(
        Envelope           boundingBox,
        Polygon            polygon,
        CallContext        callContext,
        AttributedPoint2ds input
    ) {
        if (input == null) {
            log.error("no data to interpolate");
            return null;
        }

        Integer parameterId =
            (Integer)input.getAttribute("parameter"); // XXX: hardcoded

        if (parameterId == null) {
            log.error("missing parameter id");
            return null;
        }

        Map<Integer, PaletteManager> paletteManagers =
            getPalettes(callContext);

        PaletteManager paletteManager = paletteManagers.get(parameterId);

        if (paletteManager == null) {
            log.error("no palette found for parameter id " + parameterId);
            return null;
        }

        boolean debug = log.isDebugEnabled();

        if (debug) {
            log.debug("interpolation");
        }

        AreaInterpolation interpolation =
            new AreaInterpolation();

        int numSamples          = numSamples(callContext);
        int groundInterpolation = getGroundInterpolation(callContext);
        int extrapolationRounds = extrapolationRounds(callContext);

        if (!interpolation.interpolate(
            input.getPoints(),
            boundingBox,
            new Dimension(numSamples, numSamples),
            new QueriedXYDepth(groundInterpolation),
            extrapolationRounds
        )) {
            log.error("interpolation failed");
            return null;
        }

        // Do the post processing
        Raster raster = new Raster(
            interpolation.getRaster(),
            numSamples);

        // TODO: Filter operations.

        if (debug) {
            log.debug("to indexed raster");
        }

        // scan for regions with base palette
        Palette basePalette = paletteManager.getBase();

        int [] intRaster = raster.toIndexed(basePalette);

        // produce JFreeChart compatible polygons

        if (debug) {
            log.debug("vectorize indexed raster");
        }

        // produce JTS compatible polygons

        JTSMultiPolygonProducer jtsmpp = new JTSMultiPolygonProducer(
            polygon,
            boundingBox.getMinX(), boundingBox.getMinY(),
            boundingBox.getMaxX(), boundingBox.getMaxY());

        int numRegions = new Vectorizer(intRaster, numSamples)
            .process(jtsmpp);

        Map<Integer, MultiPolygon> polygons = jtsmpp.getMultiPolygons(
            new ExternalIndexConverter(basePalette));

        jtsmpp.clear(); jtsmpp = null; // help gc

        int numColors = polygons.size();

        if (debug) {
            log.debug("number of regions: " + numRegions);
            log.debug("number of colors:  " + numColors);
        }
        // generate iso lines

        int numIso;

             if (numColors <  5) { numIso = 5; }
        else if (numColors < 10) { numIso = 2; }
        else                     { numIso = 0; }

        Palette isoPalette;

        if (numIso == 0) { // same palette
            isoPalette = basePalette;
            /* intRaster = intRaster; */
        }
        else {
            isoPalette = paletteManager.getLevel(numIso);
            intRaster  = raster.toIndexed(isoPalette);
        }

        JTSMultiLineStringProducer jtslsp = new JTSMultiLineStringProducer(
            polygon,
            boundingBox.getMinX(), boundingBox.getMinY(),
            boundingBox.getMaxX(), boundingBox.getMaxY());

        numRegions = new Vectorizer(false, intRaster, numSamples)
            .process(jtslsp);

        IsoAttributeGenerator iag = new IsoAttributeGenerator(isoPalette);

        List<Pair<Object, MultiLineString>> lineStrings =
            jtslsp.getMultiLineStrings(iag);

        jtslsp.clear(); jtslsp = null; // help gc

        input.setInterpolation(interpolation);

        input.setPolygons(polygons);
        input.setLineStrings(lineStrings);

        return input;
    }


    @Override
    public void setup(Node configuration) {
        super.setup(configuration);
        this.ijkQueryID = Config.getStringXPath(configuration,"queryID-ijk");

    }

    private static int numSamples(CallContext callContext) {
        GNVArtifactContext context =
            (GNVArtifactContext)callContext.globalContext();
        Integer samples = (Integer)context.get(
            GNVArtifactContext.HORIZONTAL_CROSS_SECTION_SAMPLES_KEY);
        return samples != null
            ? samples.intValue()
            : GNVArtifactContext.DEFAULT_HORIZONTAL_CROSS_SECTION_SAMPLES;
    }

    private static int extrapolationRounds(CallContext callContext) {
        GNVArtifactContext context =
            (GNVArtifactContext)callContext.globalContext();
        Integer extrapolationRounds = (Integer)context.get(
            GNVArtifactContext.HORIZONTAL_CROSS_SECTION_EXTRAPOLATION_ROUNDS_KEY);
        return extrapolationRounds != null
            ? extrapolationRounds.intValue()
            : GNVArtifactContext.DEFAULT_HORIZONTAL_CROSS_SECTION_EXTRAPOLATION_ROUNDS;
    }

    private static File shapefileDirectory(CallContext callContext) {
        GNVArtifactContext context =
            (GNVArtifactContext)callContext.globalContext();
        File dir = (File)context.get(
            GNVArtifactContext.HORIZONTAL_CROSS_SECTION_RESULT_SHAPEFILE_PATH_KEY);
        return dir != null
            ? dir
            : GNVArtifactContext.DEFAULT_HORIZONTAL_CROSS_SECTION_PROFILE_SHAPEFILE_PATH;
    }

    private static int getGroundInterpolation(CallContext callContext) {
        GNVArtifactContext context =
            (GNVArtifactContext)callContext.globalContext();

        String interpolation = (String)context.get(
            GNVArtifactContext.HORIZONTAL_CROSS_SECTION_GROUND_INTERPOLATION_KEY);

        return RasterObject.getInterpolationType(interpolation);
    }

    private static Map<Integer, PaletteManager> getPalettes(
        CallContext callContext
    ) {
        GNVArtifactContext context =
            (GNVArtifactContext)callContext.globalContext();
        Map<Integer, PaletteManager> palettes =
            (Map<Integer, PaletteManager>)context.get(
                GNVArtifactContext.PALETTES_KEY);
        return palettes != null
            ? palettes
            : new HashMap<Integer, PaletteManager>();
    }


    @Override
    public void cleanup(Object context) {
        resetShapeFilePath();
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org