tim@335: package de.intevation.gnv.state.profile.horizontalcrosssection;
tim@335:
tim@829: import java.awt.Dimension;
tim@829: import java.io.File;
tim@829: import java.io.IOException;
tim@829: import java.io.OutputStream;
tim@829: import java.util.ArrayList;
tim@829: import java.util.Collection;
tim@829: import java.util.Date;
tim@829: import java.util.HashMap;
tim@829: import java.util.List;
tim@829: import java.util.Map;
tim@829:
tim@829: import org.apache.log4j.Logger;
tim@829: import org.w3c.dom.Document;
tim@829: import org.w3c.dom.Element;
tim@829: import org.w3c.dom.Node;
tim@829:
tim@468: import com.vividsolutions.jts.geom.Coordinate;
tim@468: import com.vividsolutions.jts.geom.Envelope;
sascha@484: import com.vividsolutions.jts.geom.MultiLineString;
sascha@484: import com.vividsolutions.jts.geom.MultiPolygon;
tim@468: import com.vividsolutions.jts.geom.Polygon;
ingo@358:
sascha@480: import de.intevation.artifactdatabase.Config;
sascha@480: import de.intevation.artifactdatabase.XMLUtils;
sascha@480: import de.intevation.artifacts.ArtifactNamespaceContext;
sascha@480: import de.intevation.artifacts.CallContext;
tim@468: import de.intevation.gnv.artifacts.cache.CacheFactory;
tim@468: import de.intevation.gnv.artifacts.context.GNVArtifactContext;
tim@335: import de.intevation.gnv.geobackend.base.Result;
sascha@480: import de.intevation.gnv.geobackend.base.ResultDescriptor;
tim@468: import de.intevation.gnv.geobackend.base.query.QueryExecutor;
tim@468: import de.intevation.gnv.geobackend.base.query.QueryExecutorFactory;
tim@468: import de.intevation.gnv.geobackend.base.query.exception.QueryException;
sascha@480: import de.intevation.gnv.geobackend.sde.datasources.RasterObject;
sascha@482: import de.intevation.gnv.math.AreaInterpolation;
sascha@480: import de.intevation.gnv.math.AttributedPoint2ds;
sascha@482: import de.intevation.gnv.math.Point2d;
sascha@482: import de.intevation.gnv.math.QueriedXYDepth;
sascha@484: import de.intevation.gnv.raster.ExternalIndexConverter;
sascha@484: import de.intevation.gnv.raster.IsoAttributeGenerator;
sascha@484: import de.intevation.gnv.raster.JTSMultiLineStringProducer;
sascha@484: import de.intevation.gnv.raster.JTSMultiPolygonProducer;
sascha@484: import de.intevation.gnv.raster.Palette;
sascha@484: import de.intevation.gnv.raster.PaletteManager;
sascha@484: import de.intevation.gnv.raster.Raster;
sascha@484: import de.intevation.gnv.raster.Vectorizer;
tim@459: import de.intevation.gnv.state.InputData;
sascha@480: import de.intevation.gnv.state.OutputStateBase;
tim@335: import de.intevation.gnv.state.exception.StateException;
ingo@775: import de.intevation.gnv.utils.ExclusiveExec;
sascha@481: import de.intevation.gnv.utils.FileUtils;
ingo@621: import de.intevation.gnv.utils.MapfileGenerator;
ingo@646: import de.intevation.gnv.utils.MetaWriter;
sascha@484: import de.intevation.gnv.utils.Pair;
sascha@498: import de.intevation.gnv.utils.ShapeFileWriter;
tim@468: import de.intevation.gnv.utils.StringUtils;
tim@468: import de.intevation.gnv.utils.WKTUtils;
tim@335:
tim@335: /**
sascha@780: * @author Tim Englich
sascha@780: * @author Sascha L. Teichmann
sascha@780: * @author Ingo Weinzierl
tim@335: */
ingo@622: public class HorizontalCrossSectionMeshOutputState
sascha@480: extends OutputStateBase
sascha@474: {
tim@335: private static Logger log = Logger
sascha@474: .getLogger(HorizontalCrossSectionMeshOutputState.class);
ingo@622:
tim@335: /**
tim@335: * The UID of this Class
tim@335: */
tim@335: private static final long serialVersionUID = 3233620652465061860L;
ingo@622:
sascha@528: public static final boolean USE_INDEX_BUFFER =
sascha@528: Boolean.getBoolean("gnv.horizontal.cross.section.mesh.index.buffer");
sascha@528:
ingo@804: /**
ingo@804: * Shapefile name for isolines.
ingo@804: */
ingo@622: public static final String ISOLINES_NAME = "isolines.shp";
ingo@804:
ingo@804: /**
ingo@804: * Shapefile name for polygons.
ingo@804: */
ingo@622: public static final String POLYGON_NAME = "polygons.shp";
ingo@804:
ingo@622: public static final String LAYER_MODEL = "horizontalcrosssection";
ingo@622:
sascha@481: private String ijkQueryID;
sascha@481:
sascha@481: private Boolean shapeFileLock = new Boolean(true);
sascha@481:
sascha@481: private String shapeFilePath;
tim@335:
tim@335: /**
tim@335: * Constructor
tim@335: */
tim@335: public HorizontalCrossSectionMeshOutputState() {
tim@335: }
tim@335:
ingo@804: @Override
sascha@504: public void initialize(String uuid, CallContext callContext)
sascha@778: throws StateException {
sascha@504: super.initialize(uuid, callContext);
sascha@504: if (log.isDebugEnabled()) {
sascha@504: log.debug("initialize output state " + uuid);
sascha@504: }
sascha@504: // fill the cache
sascha@504: getResult(uuid, callContext);
sascha@504: }
sascha@504:
ingo@804: /**
ingo@804: * Returns the shapefile directory path.
ingo@804: *
ingo@804: * @return the shapefile path.
ingo@804: */
sascha@481: public String getShapeFilePath() {
sascha@481: synchronized (shapeFileLock) {
sascha@481: return shapeFilePath;
sascha@481: }
sascha@481: }
sascha@481:
ingo@804: /**
ingo@804: * Set the shapefile path.
ingo@804: *
ingo@804: * @param shapeFilePath Destination path to write shapefiles.
ingo@804: */
sascha@481: public void setShapeFilePath(String shapeFilePath) {
sascha@481: synchronized (shapeFileLock) {
sascha@481: this.shapeFilePath = shapeFilePath;
sascha@481: }
sascha@481: }
sascha@481:
ingo@804: /**
ingo@804: * Method to reset the shapefile path.
ingo@804: *
ingo@804: * @return the old path.
ingo@804: */
sascha@481: public String resetShapeFilePath() {
sascha@481: synchronized (shapeFileLock) {
sascha@481: String path = shapeFilePath;
sascha@481: shapeFilePath = null;
sascha@481: return path;
sascha@481: }
sascha@481: }
sascha@481:
ingo@804:
ingo@804: /**
ingo@804: * This method removes all shapefiles which might have been written by this
ingo@804: * artifact and resets the shapefile path.
ingo@804: *
ingo@804: * @param globalContext CallContext
ingo@804: */
ingo@804: @Override
sascha@481: public void endOfLife(Object globalContext) {
sascha@481: super.endOfLife(globalContext);
sascha@481:
sascha@481: // do it in background
sascha@481: new Thread() {
ingo@804: @Override
sascha@481: public void run() {
sascha@481: // TODO: Do the un-publishing WMS stuff.
sascha@481: String path = resetShapeFilePath();
sascha@481:
sascha@481: if (path == null) {
sascha@481: return;
sascha@481: }
sascha@481:
sascha@481: File dir = new File(path);
sascha@481:
sascha@481: for (int i = 0; i < 10; ++i) {
sascha@481: if (!dir.exists() || FileUtils.deleteRecursive(dir)) {
ingo@621: MapfileGenerator.getInstance().update();
sascha@481: return;
sascha@481: }
ingo@621:
sascha@481: try {
sascha@481: Thread.sleep(10000L);
sascha@481: }
sascha@481: catch (InterruptedException ie) {
sascha@481: }
sascha@481: }
sascha@481:
sascha@481: log.error("failed to remove directory '" + path + "'");
sascha@481: } // run
sascha@481: }.start();
sascha@481: }
sascha@481:
ingo@804:
ingo@804: /**
ingo@804: * This out target has two options:
ingo@804: *
ingo@804: * - zip: Write the resulting data to shapefiles and export them as
ingo@804: * zip-archive.
ingo@804: * - wms: Write the resulting data to shapefiles and feed a map service
ingo@804: * with a layer displaying these shapefiles.
ingo@804: *
ingo@804: *
ingo@804: * @param format
ingo@804: * @param inputData
ingo@804: * @param outputStream
ingo@804: * @param uuid
ingo@804: * @param callContext
ingo@804: * @throws StateException
ingo@804: */
sascha@480: public void out(
sascha@778: Document format,
sascha@480: Collection inputData,
sascha@480: OutputStream outputStream,
sascha@480: String uuid,
sascha@480: CallContext callContext
sascha@480: )
sascha@778: throws StateException
sascha@480: {
sascha@480: String outputMode = XMLUtils.xpathString(
sascha@480: format, XPATH_OUTPUT_MODE, ArtifactNamespaceContext.INSTANCE);
tim@335:
ingo@537: if (outputMode == null) {
sascha@480: throw new StateException("cannot find outputMode or mime");
tim@335: }
tim@335:
sascha@480: outputMode = outputMode.toLowerCase();
sascha@471:
sascha@504: if (log.isDebugEnabled()) {
sascha@504: log.debug("---- asking for: " + outputMode);
sascha@504: }
tim@468:
sascha@480: if ("zip".equals(outputMode)) {
sascha@481: writeZip(uuid, callContext, outputStream);
sascha@480: }
sascha@480: else if ("wms".equals(outputMode)) {
sascha@481: XMLUtils.toStream(
ingo@730: getWMS(uuid, callContext, inputData),
sascha@481: outputStream);
sascha@480: }
sascha@480: else {
sascha@480: throw new StateException("unsupported output mode");
sascha@480: }
sascha@480: }
sascha@480:
ingo@804: /**
ingo@804: * Create a zip archive with the shapefiles of the given shapefiles path and
ingo@804: * write it to output
.
ingo@804: *
ingo@804: * @param uuid The UUID of the current artifact.
ingo@804: * @param callContext The CallContext object.
ingo@804: * @param output The output stream.
ingo@804: * @throws StateException if an error occured while zipfile creation.
ingo@804: */
sascha@481: protected void writeZip(
sascha@481: String uuid,
sascha@481: CallContext callContext,
sascha@481: OutputStream output
sascha@778: )
sascha@481: throws StateException
sascha@481: {
sascha@481: try {
sascha@481: String p = getShapeFilePath();
sascha@481: if (p != null) {
sascha@481: File dir = new File(p);
sascha@481: if (dir.isDirectory()) {
sascha@481: FileUtils.createZipArchive(dir, output);
sascha@481: }
sascha@481: }
ingo@537: else {
ingo@537: AttributedPoint2ds result = getResult(uuid, callContext);
ingo@775: ExclusiveExec.UniqueKey k = ExclusiveExec.INSTANCE.acquire(uuid);
ingo@537: if (result != null
ingo@537: && (p = writeToShapeFile(uuid, result, callContext)) != null) {
ingo@537: FileUtils.createZipArchive(new File(p), output);
ingo@775: ExclusiveExec.INSTANCE.release(k);
ingo@537: }
sascha@481: }
sascha@481: }
sascha@481: catch (IOException ioe) {
sascha@481: log.error(ioe.getLocalizedMessage(), ioe);
sascha@481: }
sascha@481: }
sascha@481:
ingo@804: /**
ingo@804: * Write data to shapefiles and feed a map service with information about
ingo@804: * these shapefiles. The map service can be queried for displaying
ingo@804: * corresponding layers as WMS.
ingo@804: *
ingo@804: * @param uuid The UUID of the current artifact.
ingo@804: * @param callContext The CallContext object.
ingo@804: * @param inputData A collection with some input data.
ingo@804: * @return a document with some meta information (shapefile path, geometry
ingo@804: * type, time to live of the current artifact, etc).
ingo@804: * @throws StateException if an error occured while shapefile writing.
ingo@804: */
ingo@730: protected Document getWMS(
ingo@730: String uuid,
ingo@730: CallContext callContext,
ingo@730: Collection inputData
ingo@730: )
sascha@481: throws StateException
sascha@481: {
sascha@481: Document document = XMLUtils.newDocument();
sascha@481:
sascha@481: Element pathElement = document.createElement("path");
sascha@481: document.appendChild(pathElement);
sascha@481:
ingo@730: String path = getShapeFilePath();
sascha@481:
sascha@481: if (path != null && new File(path).isDirectory()) {
ingo@730: String title = getLayerTitle(inputData);
ingo@730: if (title == null) {
ingo@730: title = uuid;
ingo@730: }
ingo@730:
ingo@730: callContext.putContextValue(
ingo@730: MetaWriter.CONTEXT_LAYER_TITLE, title);
ingo@730:
ingo@730: String paramType = findParameterType(callContext);
ingo@730:
ingo@730: if (log.isDebugEnabled()) {
ingo@730: log.debug("Layer title: " + title);
ingo@730: log.debug("Layer type: " + paramType);
ingo@730: }
ingo@730:
ingo@730: Document meta = MetaWriter.writeHorizontalcrosssectionMeta(
ingo@730: callContext, uuid, path, paramType);
ingo@730: if (meta != null) {
ingo@730: MapfileGenerator.getInstance().update();
ingo@730: return meta;
ingo@730: }
ingo@730:
sascha@481: pathElement.setTextContent(path);
sascha@481: }
sascha@481: else {
sascha@481: AttributedPoint2ds result = getResult(uuid, callContext);
ingo@775: ExclusiveExec.UniqueKey key = ExclusiveExec.INSTANCE.acquire(uuid);
tim@829: try{
sascha@481: if (result != null
sascha@481: && (path = writeToShapeFile(uuid, result, callContext)) != null) {
ingo@622:
ingo@730: String paramType = findParameterType(callContext);
sascha@835:
ingo@730: String title = getLayerTitle(inputData);
ingo@730: if (title == null) {
ingo@730: title = uuid;
ingo@646: }
ingo@730: callContext.putContextValue(
ingo@730: MetaWriter.CONTEXT_LAYER_TITLE, title);
ingo@646:
ingo@730: if (log.isDebugEnabled()) {
ingo@730: log.debug("Parameter type: " + paramType);
ingo@730: log.debug("Layer title: " + title);
ingo@646: }
ingo@646:
ingo@646: Document meta = MetaWriter.writeHorizontalcrosssectionMeta(
ingo@646: callContext, uuid, path, paramType);
ingo@775:
ingo@646: if (meta != null) {
ingo@622: MapfileGenerator.getInstance().update();
ingo@622: return meta;
ingo@622: }
ingo@622:
sascha@481: pathElement.setTextContent(path);
sascha@481: }
tim@829: }finally{
tim@829: ExclusiveExec.INSTANCE.release(key);
tim@829: }
sascha@481: }
sascha@481:
sascha@481: return document;
sascha@481: }
sascha@481:
ingo@804: /**
ingo@804: * Find the parameter name which is used during mapfile creation in
ingo@804: * MapfileGenerator.
sascha@805: *
ingo@804: * @param callContext The CallContext object.
ingo@804: * @return the parameter name of the current parameterization.
ingo@804: */
ingo@730: protected String findParameterType(CallContext callContext) {
ingo@730: InputData inputParam = inputData.get("parameterid");
ingo@730:
ingo@730: Map paletteManagers = getPalettes(callContext);
ingo@730:
ingo@730: if (inputParam == null || paletteManagers == null) {
ingo@730: log.warn("Parameter-id not found.");
ingo@730: return LAYER_MODEL;
ingo@730: }
ingo@730: else {
ingo@730: Integer parameterId = Integer.parseInt(inputParam.getValue());
ingo@730: PaletteManager paletteManager = paletteManagers.get(parameterId);
ingo@730:
ingo@730: return LAYER_MODEL + "_" + paletteManager.getName();
ingo@730: }
ingo@730: }
ingo@730:
ingo@730:
ingo@804: /**
ingo@804: * Find the title for a wms layer specified by the user.
ingo@804: *
ingo@804: * @param inputData A collection with InputData objects.
ingo@804: * @return the title.
ingo@804: */
ingo@730: protected String getLayerTitle(Collection inputData) {
ingo@730: for (InputData data: inputData) {
ingo@730: String name = data.getName();
ingo@730: if (name != null && name.equals("title")) {
ingo@730: return (String) data.getValue();
ingo@730: }
ingo@730: }
ingo@730:
ingo@730: return null;
ingo@730: }
ingo@730:
ingo@804: /**
ingo@804: * Write the resulting data to shapefiles.
ingo@804: *
ingo@804: * @param uuid The UUID of the current artifact.
ingo@804: * @param result The finalized data used for shapefile creation.
ingo@804: * @param callContext The CallContext object.
ingo@804: * @return the shapefile path.
ingo@804: */
sascha@481: protected String writeToShapeFile(
sascha@481: String uuid,
sascha@481: AttributedPoint2ds result,
sascha@481: CallContext callContext
sascha@481: ) {
sascha@481: File baseDir = shapefileDirectory(callContext);
sascha@481:
sascha@481: File shapeDir = new File(baseDir, uuid);
sascha@481:
sascha@498: boolean success = false;
sascha@498: boolean createdDir = false;
sascha@481:
sascha@498: try {
sascha@498: synchronized (shapeFileLock) {
ingo@775: if (shapeDir.exists()) {
ingo@775: FileUtils.deleteContent(shapeDir);
sascha@498: }
ingo@775: else if (!shapeDir.mkdirs()) {
sascha@778: log.error("cannot create directory '"
sascha@498: + shapeDir.getAbsolutePath() + "'");
sascha@498: return null;
sascha@498: }
sascha@498: createdDir = true;
sascha@481: }
sascha@481:
sascha@498: Map polygons = result.getPolygons();
sascha@498:
sascha@498: List> isolines =
sascha@498: result.getLineStrings();
sascha@498:
ingo@622: File polygonsFile = new File(shapeDir, POLYGON_NAME);
ingo@622: File isolinesFile = new File(shapeDir, ISOLINES_NAME);
sascha@498:
sascha@498: if (!ShapeFileWriter.writeMultiPolygonsToFile(
sascha@498: polygonsFile,
sascha@498: (Integer)result.getAttribute("parameter"),
sascha@498: (Integer)result.getAttribute("layer"),
sascha@498: (Date) result.getAttribute("date"),
sascha@498: polygons)
sascha@498: ) {
sascha@498: log.error("writing polygons failed");
sascha@481: return null;
sascha@481: }
sascha@498:
sascha@498: if (!ShapeFileWriter.writeMultiLineStringsToFile(
sascha@498: isolinesFile,
sascha@498: (Integer)result.getAttribute("parameter"),
sascha@498: (Integer)result.getAttribute("layer"),
sascha@498: (Date) result.getAttribute("date"),
sascha@498: isolines)
sascha@498: ) {
sascha@498: log.error("writing isolines failed");
sascha@498: return null;
sascha@498: }
sascha@498:
ingo@537: shapeFilePath = shapeDir.getAbsolutePath();
sascha@498: success = true;
ingo@537:
ingo@537: callContext.afterCall(CallContext.STORE);
ingo@537:
ingo@537: return shapeFilePath;
sascha@498: }
sascha@498: finally {
sascha@498: if (!success && createdDir) {
sascha@498: FileUtils.deleteRecursive(shapeDir);
sascha@498: }
sascha@481: }
sascha@778: }
ingo@622:
ingo@622:
ingo@804: /**
ingo@804: * Return the processed results ready for being written to shapefile.
ingo@804: *
ingo@804: * @param uuid The UUID of the current artifacts.
ingo@804: * @param callContext The CallContext object.
ingo@804: * @return the processed data.
ingo@804: * @throws StateException if an error occured while processing data.
ingo@804: */
sascha@481: protected AttributedPoint2ds getResult(String uuid, CallContext callContext)
sascha@480: throws StateException
sascha@480: {
sascha@480: CacheFactory cf = CacheFactory.getInstance();
ingo@726: String key = getHash();
sascha@480:
sascha@480: if (cf.isInitialized()) {
sascha@480: net.sf.ehcache.Element value = cf.getCache().get(key);
sascha@480: if (value != null) {
sascha@481: return (AttributedPoint2ds)value.getObjectValue();
sascha@480: }
sascha@480: }
sascha@480:
sascha@481: AttributedPoint2ds result = produceResult(callContext);
sascha@480:
sascha@480: if (result != null && cf.isInitialized()) {
sascha@480: cf.getCache().put(new net.sf.ehcache.Element(key, result));
sascha@480: }
sascha@480:
tim@468: return result;
tim@468: }
sascha@778:
ingo@804: /**
ingo@804: * Query the database for result data and turn it into a useful format to
ingo@804: * write this data into shapefiles.
ingo@804: *
ingo@804: * @param callContext The CallContext object.
ingo@804: * @return the processed data.
ingo@804: * @throws StateException if an error occured while processing data.
ingo@804: */
sascha@778: protected AttributedPoint2ds produceResult(CallContext callContext)
sascha@480: throws StateException
sascha@480: {
sascha@480: InputData meshPolygon = inputData.get("mesh_polygon");
sascha@480: InputData meshId = inputData.get("meshid");
sascha@480:
sascha@480: if (meshPolygon == null) {
sascha@480: log.error("mesh_polygon is not defined");
sascha@480: throw new StateException("missing mesh_linestring");
sascha@480: }
sascha@480:
sascha@480: if (meshId == null) {
sascha@480: log.error("meshid is not defined");
sascha@480: throw new StateException("missing meshid");
sascha@480: }
sascha@480:
sascha@480: Polygon p = WKTUtils.toPolygon(meshPolygon.getValue());
sascha@480:
sascha@480: if (p == null) {
sascha@480: log.error("no valid polygon");
sascha@480: throw new StateException("no valid polygon");
sascha@480: }
sascha@480:
sascha@480: try {
sascha@480: Envelope env = p.getEnvelopeInternal();
sascha@480:
sascha@528: String additionWhere;
sascha@480:
sascha@528: if (USE_INDEX_BUFFER) {
sascha@528: Coordinate [] coords = new Coordinate [] {
sascha@528: new Coordinate(env.getMinX(), env.getMinY()),
sascha@528: new Coordinate(env.getMinX(), env.getMaxY()),
sascha@528: new Coordinate(env.getMaxX(), env.getMaxY()),
sascha@528: new Coordinate(env.getMaxX(), env.getMinY()) };
sascha@528:
sascha@528: additionWhere =
sascha@528: WKTUtils.worldEnvelopeCoordinatesToIndex(
sascha@528: coords,
sascha@528: meshId.getValue(),
sascha@528: ijkQueryID);
sascha@528: }
sascha@528: else {
sascha@528: additionWhere = WKTUtils.TRUE_EXPRESSION;
sascha@528: }
sascha@480:
sascha@480: String[] addedFilterValues = StringUtils.append(
sascha@480: generateFilterValuesFromInputData(),
sascha@480: additionWhere);
sascha@480:
sascha@480: QueryExecutor queryExecutor = QueryExecutorFactory
sascha@480: .getInstance()
sascha@480: .getQueryExecutor();
sascha@480:
sascha@480: return process(
sascha@480: env,
sascha@480: p,
sascha@484: callContext,
sascha@484: preProcess(
sascha@480: queryExecutor.executeQuery(
sascha@480: queryID,
sascha@484: addedFilterValues)));
sascha@480: }
sascha@480: catch (QueryException e) {
sascha@480: log.error(e,e);
sascha@480: }
sascha@480:
sascha@480: throw new StateException("no result produced");
tim@468: }
tim@335:
ingo@804: /**
ingo@804: * First step of finalizing the data returned from database.
ingo@804: *
ingo@804: * @param results Resulting data from database.
ingo@804: * @return the pre-processed data which is still not useful for being
ingo@804: * written to shapefiles.
ingo@804: */
sascha@484: public AttributedPoint2ds preProcess(Collection results) {
sascha@480:
sascha@480: boolean debug = log.isDebugEnabled();
sascha@480:
sascha@480: if (debug) {
sascha@484: log.debug("--- preProcess: " + results.size() + " results");
sascha@480: }
sascha@480:
sascha@480: AttributedPoint2ds ap2ds = new AttributedPoint2ds();
sascha@480:
sascha@482: ArrayList points = new ArrayList(results.size());
sascha@482:
sascha@482: int sIdx = -1;
sascha@482: int iIdx = -1;
sascha@482: int jIdx = -1;
sascha@482: int vIdx = -1;
sascha@482:
sascha@482: boolean firstWarn = true;
sascha@480:
sascha@480: for (Result result: results) {
sascha@480:
sascha@482: if (sIdx == -1) {
sascha@480: ResultDescriptor rd = result.getResultDescriptor();
sascha@482: sIdx = rd.getColumnIndex("SHAPE");
sascha@482: iIdx = rd.getColumnIndex("IPOSITION");
sascha@482: jIdx = rd.getColumnIndex("JPOSITION");
sascha@482: vIdx = rd.getColumnIndex("YORDINATE");
sascha@498: int kIdx = rd.getColumnIndex("KPOSITION");
sascha@482: int tIdx = rd.getColumnIndex("TIMEVALUE");
sascha@482: int pIdx = rd.getColumnIndex("PARAMETERID");
sascha@482:
sascha@482: if (sIdx == -1 || iIdx == -1
sascha@778: || jIdx == -1 || kIdx == -1
sascha@482: || vIdx == -1 || tIdx == -1
sascha@482: || pIdx == -1
sascha@482: ) {
sascha@482: log.error("missing column in result set");
sascha@482: return null;
sascha@482: }
sascha@482:
sascha@482: ap2ds.setAttribute("date", result.getDate(tIdx));
sascha@482: ap2ds.setAttribute("parameter", result.getInteger(pIdx));
sascha@498: ap2ds.setAttribute("layer", result.getInteger(kIdx));
sascha@480: }
sascha@482: Coordinate coord = WKTUtils.toCoordinate(result.getString(sIdx));
sascha@482: if (coord == null) {
sascha@482: if (firstWarn) {
sascha@482: firstWarn = false;
sascha@482: log.warn("cannot fetch coordinate from result");
sascha@482: }
sascha@482: continue;
sascha@482: }
sascha@482: double v = result.getDouble(vIdx);
sascha@482: int i = result.getInteger(iIdx);
sascha@482: int j = result.getInteger(jIdx);
sascha@482:
sascha@482: Point2d p2d = new Point2d(coord.x, coord.y, v, i, j);
sascha@482: points.add(p2d);
sascha@778:
sascha@480: }
sascha@482: ap2ds.setPoints(points);
sascha@481:
sascha@480: return ap2ds;
tim@335: }
ingo@622:
ingo@804: /**
ingo@804: * The last step of finalizing the data. The returned data is useful for
ingo@804: * shapefile creation.
ingo@804: *
ingo@804: * @param boundingBox The bounding box.
ingo@804: * @param polygon A polygon.
ingo@804: * @param callContext CallContext.
ingo@804: * @param input The pre-processed data.
ingo@804: * @return the finalized data ready for shapefile creation.
ingo@804: */
sascha@481: public AttributedPoint2ds process(
sascha@482: Envelope boundingBox,
sascha@480: Polygon polygon,
sascha@484: CallContext callContext,
sascha@484: AttributedPoint2ds input
sascha@480: ) {
sascha@482: if (input == null) {
sascha@482: log.error("no data to interpolate");
sascha@482: return null;
sascha@482: }
sascha@482:
sascha@484: Integer parameterId =
sascha@495: (Integer)input.getAttribute("parameter"); // XXX: hardcoded
sascha@484:
sascha@484: if (parameterId == null) {
sascha@484: log.error("missing parameter id");
sascha@484: return null;
sascha@484: }
sascha@484:
sascha@484: Map paletteManagers =
sascha@484: getPalettes(callContext);
sascha@484:
sascha@484: PaletteManager paletteManager = paletteManagers.get(parameterId);
sascha@484:
sascha@484: if (paletteManager == null) {
sascha@484: log.error("no palette found for parameter id " + parameterId);
sascha@484: return null;
sascha@484: }
sascha@484:
sascha@482: boolean debug = log.isDebugEnabled();
sascha@482:
sascha@482: if (debug) {
sascha@484: log.debug("interpolation");
sascha@482: }
sascha@482:
sascha@482: AreaInterpolation interpolation =
sascha@482: new AreaInterpolation();
sascha@482:
sascha@484: int numSamples = numSamples(callContext);
sascha@484: int groundInterpolation = getGroundInterpolation(callContext);
sascha@593: int extrapolationRounds = extrapolationRounds(callContext);
sascha@482:
sascha@482: if (!interpolation.interpolate(
sascha@778: input.getPoints(),
sascha@482: boundingBox,
sascha@482: new Dimension(numSamples, numSamples),
sascha@593: new QueriedXYDepth(groundInterpolation),
sascha@593: extrapolationRounds
sascha@482: )) {
sascha@482: log.error("interpolation failed");
sascha@482: return null;
sascha@482: }
sascha@482:
sascha@484: // Do the post processing
sascha@484: Raster raster = new Raster(
sascha@484: interpolation.getRaster(),
sascha@484: numSamples);
sascha@484:
sascha@484: // TODO: Filter operations.
sascha@484:
sascha@482: if (debug) {
sascha@484: log.debug("to indexed raster");
sascha@482: }
sascha@482:
sascha@484: // scan for regions with base palette
sascha@484: Palette basePalette = paletteManager.getBase();
sascha@484:
sascha@484: int [] intRaster = raster.toIndexed(basePalette);
sascha@484:
sascha@484: // produce JFreeChart compatible polygons
sascha@484:
sascha@484: if (debug) {
sascha@484: log.debug("vectorize indexed raster");
sascha@484: }
sascha@484:
sascha@484: // produce JTS compatible polygons
sascha@484:
sascha@484: JTSMultiPolygonProducer jtsmpp = new JTSMultiPolygonProducer(
sascha@499: polygon,
sascha@484: boundingBox.getMinX(), boundingBox.getMinY(),
sascha@484: boundingBox.getMaxX(), boundingBox.getMaxY());
sascha@778:
sascha@484: int numRegions = new Vectorizer(intRaster, numSamples)
sascha@484: .process(jtsmpp);
sascha@484:
sascha@484: Map polygons = jtsmpp.getMultiPolygons(
sascha@484: new ExternalIndexConverter(basePalette));
sascha@484:
sascha@484: jtsmpp.clear(); jtsmpp = null; // help gc
sascha@484:
sascha@484: int numColors = polygons.size();
sascha@484:
sascha@484: if (debug) {
sascha@484: log.debug("number of regions: " + numRegions);
sascha@484: log.debug("number of colors: " + numColors);
sascha@484: }
sascha@484: // generate iso lines
sascha@484:
sascha@484: int numIso;
sascha@484:
sascha@484: if (numColors < 5) { numIso = 5; }
sascha@484: else if (numColors < 10) { numIso = 2; }
sascha@484: else { numIso = 0; }
sascha@484:
sascha@484: Palette isoPalette;
sascha@484:
sascha@484: if (numIso == 0) { // same palette
sascha@484: isoPalette = basePalette;
sascha@484: /* intRaster = intRaster; */
sascha@484: }
sascha@484: else {
sascha@484: isoPalette = paletteManager.getLevel(numIso);
sascha@484: intRaster = raster.toIndexed(isoPalette);
sascha@484: }
sascha@484:
sascha@484: JTSMultiLineStringProducer jtslsp = new JTSMultiLineStringProducer(
sascha@499: polygon,
sascha@484: boundingBox.getMinX(), boundingBox.getMinY(),
sascha@484: boundingBox.getMaxX(), boundingBox.getMaxY());
sascha@484:
sascha@484: numRegions = new Vectorizer(false, intRaster, numSamples)
sascha@484: .process(jtslsp);
sascha@484:
sascha@484: IsoAttributeGenerator iag = new IsoAttributeGenerator(isoPalette);
sascha@484:
sascha@484: List> lineStrings =
sascha@484: jtslsp.getMultiLineStrings(iag);
sascha@484:
sascha@484: jtslsp.clear(); jtslsp = null; // help gc
sascha@484:
sascha@484: input.setInterpolation(interpolation);
sascha@484:
sascha@484: input.setPolygons(polygons);
sascha@484: input.setLineStrings(lineStrings);
sascha@484:
sascha@484: return input;
tim@335: }
sascha@480:
sascha@778:
tim@468: @Override
tim@468: public void setup(Node configuration) {
tim@468: super.setup(configuration);
tim@468: this.ijkQueryID = Config.getStringXPath(configuration,"queryID-ijk");
sascha@778:
tim@468: }
sascha@778:
tim@468: private static int numSamples(CallContext callContext) {
tim@468: GNVArtifactContext context =
tim@468: (GNVArtifactContext)callContext.globalContext();
tim@468: Integer samples = (Integer)context.get(
tim@468: GNVArtifactContext.HORIZONTAL_CROSS_SECTION_SAMPLES_KEY);
tim@468: return samples != null
tim@468: ? samples.intValue()
tim@468: : GNVArtifactContext.DEFAULT_HORIZONTAL_CROSS_SECTION_SAMPLES;
tim@468: }
tim@335:
sascha@593: private static int extrapolationRounds(CallContext callContext) {
sascha@593: GNVArtifactContext context =
sascha@593: (GNVArtifactContext)callContext.globalContext();
sascha@593: Integer extrapolationRounds = (Integer)context.get(
sascha@593: GNVArtifactContext.HORIZONTAL_CROSS_SECTION_EXTRAPOLATION_ROUNDS_KEY);
sascha@593: return extrapolationRounds != null
sascha@593: ? extrapolationRounds.intValue()
sascha@593: : GNVArtifactContext.DEFAULT_HORIZONTAL_CROSS_SECTION_EXTRAPOLATION_ROUNDS;
sascha@593: }
sascha@593:
sascha@474: private static File shapefileDirectory(CallContext callContext) {
sascha@474: GNVArtifactContext context =
sascha@474: (GNVArtifactContext)callContext.globalContext();
sascha@474: File dir = (File)context.get(
sascha@474: GNVArtifactContext.HORIZONTAL_CROSS_SECTION_RESULT_SHAPEFILE_PATH_KEY);
sascha@474: return dir != null
sascha@474: ? dir
sascha@474: : GNVArtifactContext.DEFAULT_HORIZONTAL_CROSS_SECTION_PROFILE_SHAPEFILE_PATH;
sascha@474: }
sascha@474:
sascha@474: private static int getGroundInterpolation(CallContext callContext) {
sascha@778: GNVArtifactContext context =
sascha@474: (GNVArtifactContext)callContext.globalContext();
sascha@474:
sascha@474: String interpolation = (String)context.get(
sascha@474: GNVArtifactContext.HORIZONTAL_CROSS_SECTION_GROUND_INTERPOLATION_KEY);
sascha@474:
sascha@474: return RasterObject.getInterpolationType(interpolation);
sascha@474: }
sascha@484:
sascha@484: private static Map getPalettes(
sascha@484: CallContext callContext
sascha@484: ) {
sascha@778: GNVArtifactContext context =
sascha@484: (GNVArtifactContext)callContext.globalContext();
sascha@484: Map palettes =
sascha@484: (Map)context.get(
sascha@484: GNVArtifactContext.PALETTES_KEY);
sascha@484: return palettes != null
sascha@484: ? palettes
sascha@484: : new HashMap();
sascha@484: }
ingo@759:
ingo@759:
ingo@759: @Override
ingo@759: public void cleanup(Object context) {
ingo@759: resetShapeFilePath();
ingo@759: }
tim@335: }
sascha@474: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :