ingo@420: package de.intevation.gnv.utils; ingo@420: ingo@420: import com.vividsolutions.jts.geom.Coordinate; ingo@420: import com.vividsolutions.jts.geom.Point; ingo@420: import com.vividsolutions.jts.geom.LineString; ingo@420: import com.vividsolutions.jts.io.ParseException; ingo@420: import com.vividsolutions.jts.io.WKTReader; ingo@420: ingo@420: import de.intevation.gnv.geobackend.base.Result; ingo@420: import de.intevation.gnv.geobackend.base.query.QueryExecutor; ingo@420: import de.intevation.gnv.geobackend.base.query.QueryExecutorFactory; ingo@420: import de.intevation.gnv.geobackend.base.query.exception.QueryException; ingo@420: import de.intevation.gnv.math.LinearFunction; ingo@420: import de.intevation.gnv.state.InputData; ingo@420: ingo@420: import java.util.ArrayList; ingo@420: import java.util.Collection; ingo@420: import java.util.List; ingo@420: import java.util.Map; ingo@420: ingo@420: import org.apache.commons.math.optimization.OptimizationException; ingo@420: import org.apache.commons.math.optimization.fitting.CurveFitter; ingo@420: import org.apache.commons.math.optimization.general.GaussNewtonOptimizer; ingo@420: import org.apache.commons.math.FunctionEvaluationException; ingo@420: ingo@420: import org.apache.log4j.Logger; ingo@420: ingo@420: public abstract class WKTUtils { ingo@420: ingo@420: private static Logger log = Logger.getLogger(WKTUtils.class); ingo@420: ingo@420: public static final double NAUTICAL_MILE = 1852.216d; ingo@420: public static final double KILOMETER = 1000d; ingo@420: ingo@423: public static boolean different(Result a, Result b, int [] indices) { ingo@420: for (int i = 0; i < indices.length; ++i) { ingo@420: String oa = a.getString(indices[i]); ingo@420: String ob = b.getString(indices[i]); ingo@420: ingo@420: if (oa == null && ob == null) { ingo@420: continue; ingo@420: } ingo@420: ingo@420: if (oa == null || ob == null) { ingo@420: return true; ingo@420: } ingo@420: ingo@420: if (!oa.equals(ob)) { ingo@420: if (log.isDebugEnabled()) { ingo@420: log.debug("+++++++++++++++ differs ++++++++++++++"); ingo@420: log.debug(" " + oa + " != " + ob); ingo@420: } ingo@420: return true; ingo@420: } ingo@420: } ingo@420: return false; ingo@420: } ingo@420: ingo@420: ingo@420: public static Coordinate toCoordinate(String shape) { ingo@420: try { ingo@420: return ((Point)(new WKTReader().read(shape))).getCoordinate(); ingo@420: } ingo@420: catch (ParseException pe) { ingo@420: log.error(pe); ingo@420: } ingo@420: return null; ingo@420: } ingo@420: ingo@420: ingo@420: public static final double toKM(double distance) { ingo@420: return (distance * NAUTICAL_MILE) / KILOMETER; ingo@420: } ingo@420: ingo@420: ingo@420: public static String toWKT(Coordinate coordinate) { ingo@420: StringBuilder sb = new StringBuilder("POINT("); ingo@420: sb.append(coordinate.x) ingo@420: .append(' ') ingo@420: .append(coordinate.y) ingo@420: .append(')'); ingo@420: return sb.toString(); ingo@420: } ingo@420: ingo@420: ingo@423: public static String worldCoordinatesToIndex( ingo@420: Collection result, ingo@420: Map inputData, ingo@423: String ijkQueryID ingo@420: ) throws ParseException, QueryException ingo@420: { ingo@420: // 1. IJK Anfragen für Stuetzpunkte im Netz ausführen. ingo@420: LineString ls = (LineString)new WKTReader().read( ingo@420: inputData.get("mesh_linestring").getValue()); ingo@420: ingo@420: Coordinate[] coords = ls.getCoordinates(); ingo@420: ingo@420: List points = new ArrayList(coords.length); ingo@420: ingo@420: String meshid = inputData.get("meshid").getValue(); ingo@420: QueryExecutor queryExecutor = QueryExecutorFactory ingo@420: .getInstance() ingo@420: .getQueryExecutor(); ingo@420: ingo@420: ArrayList missingPoints = new ArrayList(); ingo@420: ingo@420: String additionWhere = "FEATUREID=FEATUREID"; ingo@420: ingo@420: for (int i = 0; i < coords.length; i++) { ingo@420: ingo@420: String wkt = toWKT(coords[i]); ingo@420: ingo@420: result = queryExecutor.executeQuery(ijkQueryID, ingo@420: new String[]{meshid,wkt}); ingo@420: if (!result.isEmpty()){ ingo@420: Result resultValue = result.iterator().next(); ingo@420: int iPos = resultValue.getInteger(1); ingo@420: int jPos = resultValue.getInteger(0); ingo@420: log.debug("Found Pos "+iPos+"/"+jPos +" for "+wkt); ingo@420: points.add(i, new java.awt.Point(iPos,jPos)); ingo@420: }else{ ingo@420: log.debug("No i/j Pos found for "+wkt); ingo@420: missingPoints.add(new Object [] { Integer.valueOf(i), coords[i] }); ingo@420: points.add(i, null); ingo@420: // Special Case no i,j found for Coordinate ingo@420: } ingo@420: } ingo@420: ingo@420: if (missingPoints.size() == coords.length) { ingo@420: log.debug("cannot create index buffer"); ingo@420: } ingo@420: else { // generate index filter ingo@420: boolean remainsMissingPoints = !missingPoints.isEmpty(); ingo@420: ingo@420: if (remainsMissingPoints) { ingo@420: // try to guess the missing (i, j) ingo@420: CurveFitter iFitter = new CurveFitter(new GaussNewtonOptimizer(true)); ingo@420: CurveFitter jFitter = new CurveFitter(new GaussNewtonOptimizer(true)); ingo@420: ingo@420: for (int i = 0, N = points.size(); i < N; ++i) { ingo@420: java.awt.Point p = (java.awt.Point)points.get(i); ingo@420: if (p != null) { ingo@420: Coordinate coord = coords[i]; ingo@420: iFitter.addObservedPoint(coord.x, p.x); ingo@420: jFitter.addObservedPoint(coord.y, p.y); ingo@420: } ingo@420: } ingo@420: try { ingo@420: // XXX: Assumption: (i, j) are created by componentwise linear function. ingo@420: // This is surely not correct because (x, y) are in a ellipsoid projection. ingo@420: // TODO: use ellipsoid functions and fit with Levenberg Marquardt. ingo@420: double [] iParams = iFitter.fit( ingo@420: LinearFunction.INSTANCE, new double [] { 1d, 1d }); ingo@420: ingo@420: double [] jParams = jFitter.fit( ingo@420: LinearFunction.INSTANCE, new double [] { 1d, 1d }); ingo@420: ingo@420: for (int i = missingPoints.size()-1; i >= 0; --i) { ingo@420: Object [] a = (Object [])missingPoints.get(i); ingo@420: Coordinate coord = (Coordinate)a[1]; ingo@420: int pi = (int)Math.round(iParams[0]*coord.x + iParams[1]); ingo@420: int pj = (int)Math.round(jParams[0]*coord.y + jParams[1]); ingo@420: points.set( ingo@420: ((Integer)a[0]).intValue(), ingo@420: new java.awt.Point(pi, pj)); ingo@420: } ingo@420: ingo@420: remainsMissingPoints = false; // we filled the gaps ingo@420: } ingo@420: catch (FunctionEvaluationException fee) { ingo@420: log.error(fee); ingo@420: } ingo@420: catch (OptimizationException oe) { ingo@420: log.error(oe); ingo@420: } ingo@420: } ingo@420: ingo@420: if (!remainsMissingPoints) { ingo@420: // TODO: Make Tablenames and Columns Configurable ingo@420: IndexBuffer ib = new IndexBuffer( ingo@420: points, ingo@420: "MEDIAN.MESHPOINT.IPOSITION", ingo@420: "MEDIAN.MESHPOINT.JPOSITION" ); ingo@420: additionWhere = ib.toWhereClause(); ingo@420: log.debug("Additional Where Clause = "+additionWhere); ingo@420: // 2. Aus diesen Stuetzpunkten den Resultset generieren. ingo@420: } ingo@420: } // if generate index filter ingo@420: ingo@423: return additionWhere; ingo@420: } ingo@420: }