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@1070: tim@1070: private Envelope bbox = null; 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: 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: *
  1. zip: Write the resulting data to shapefiles and export them as ingo@804: * zip-archive.
  2. ingo@804: *
  3. wms: Write the resulting data to shapefiles and feed a map service ingo@804: * with a layer displaying these shapefiles.
  4. 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@1057: Document meta = MetaWriter.initMeta(); ingo@1057: MetaWriter.insertAbstractMeta(callContext, meta); ingo@1057: ingo@1057: String prefix = getLayerPrefix(inputData); ingo@1057: if (prefix == null) { ingo@1057: prefix = uuid; ingo@730: } ingo@730: ingo@1057: // append polygon meta ingo@1057: String model = findParameterType(callContext); ingo@1057: String type = "POLYGON"; ingo@1057: String name = getLayerName(uuid, type); ingo@1057: String title = getLayerTitle(prefix, type); ingo@1057: String data = getLayerData(uuid, POLYGON_NAME); ingo@1057: String status = "OFF"; ingo@1057: MetaWriter.insertLayer( ingo@1057: callContext, meta, name, title, data, model, type, status); ingo@730: ingo@1057: // append isoline meta ingo@1057: model += "_isolines"; ingo@1057: type = "LINE"; ingo@1057: name = getLayerName(uuid, type); ingo@1057: title = getLayerTitle(prefix, type); ingo@1057: data = getLayerData(uuid, ISOLINES_NAME); ingo@1057: MetaWriter.insertLayer( ingo@1057: callContext, meta, name, title, data, model, type, status); ingo@730: ingo@730: if (meta != null) { tim@1070: MetaWriter.insertMbr(this.bbox, "EPSG:4326", meta); ingo@1057: MetaWriter.writeMetaFile(path, meta); 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@1057: Document meta = MetaWriter.initMeta(); ingo@1057: MetaWriter.insertAbstractMeta(callContext, meta); sascha@835: ingo@1057: String prefix = getLayerPrefix(inputData); ingo@1057: if (prefix == null) { ingo@1057: prefix = uuid; ingo@646: } ingo@646: ingo@1057: // append polygon meta ingo@1057: String model = findParameterType(callContext); ingo@1057: String type = "POLYGON"; ingo@1057: String name = getLayerName(uuid, type); ingo@1057: String title = getLayerTitle(prefix, type); ingo@1057: String data = getLayerData(uuid, POLYGON_NAME); ingo@1057: String status = "OFF"; ingo@1057: MetaWriter.insertLayer( ingo@1057: callContext, meta, name, title, data, model, type, status); ingo@1057: ingo@1057: // append isoline meta ingo@1057: model += "_isolines"; ingo@1057: type = "LINE"; ingo@1057: name = getLayerName(uuid, type); ingo@1057: title = getLayerTitle(prefix, type); ingo@1057: data = getLayerData(uuid, ISOLINES_NAME); ingo@1057: MetaWriter.insertLayer( ingo@1057: callContext, meta, name, title, data, model, type, status); ingo@775: ingo@646: if (meta != null) { ingo@1057: MetaWriter.writeMetaFile(path, meta); 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@1057: protected String getLayerPrefix(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@1057: ingo@1057: /** ingo@1057: * Returns the name of the layer. ingo@1057: * ingo@1057: * @param uuid The uuid the the current session. It is the base part of the ingo@1057: * layername. ingo@1057: * @param type The type of the layer ('POLYGON' or 'LINE'). ingo@1057: * @return the name of the layer. ingo@1057: */ ingo@1057: protected String getLayerName(String uuid, String type) { ingo@1111: return "GNV_" + uuid + "-" + type; ingo@1057: } ingo@1057: ingo@1057: /** ingo@1057: * Returns the layer title. ingo@1057: * ingo@1057: * @param prefix A prefix (null not permitted). ingo@1057: * @param type The layer type. ingo@1057: * @return the title of the layer. ingo@1057: */ ingo@1057: protected String getLayerTitle(String prefix, String type) { ingo@1111: return "GNV_" + prefix + "-" + type; ingo@1057: } ingo@1057: ingo@1057: ingo@1057: /** ingo@1057: * Returns the path to the shapefile that serves the layer data. ingo@1057: * ingo@1057: * @param shapeDir The shapefile directory. ingo@1057: * @param filename The name of the shapefile. ingo@1057: * @return the relative path to the shapefile. ingo@1057: */ ingo@1057: protected String getLayerData(String shapeDir, String filename) { ingo@1057: File path = new File(shapeDir, filename); ingo@1057: ingo@1057: return path.toString(); ingo@1057: } ingo@1057: 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@1060: String key = getHash(); sascha@480: sascha@480: if (cf.isInitialized()) { ingo@1030: log.debug("Using cache - key: " + key); sascha@480: net.sf.ehcache.Element value = cf.getCache().get(key); sascha@480: if (value != null) { ingo@1030: log.debug("Found element in cache."); ingo@1030: return (AttributedPoint2ds)value.getObjectValue(); sascha@480: } sascha@480: } sascha@480: ingo@1030: log.debug("Not using cache or element not found."); 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: tim@1070: this.bbox = env; 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 :