changeset 357:25e4724aa504

Fill (i, j)-gaps when building index buffer. gnv-artifacts/trunk@430 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Tue, 15 Dec 2009 15:14:21 +0000
parents 3eee1369c79b
children 2f7a28f211c7
files gnv-artifacts/ChangeLog gnv-artifacts/src/main/java/de/intevation/gnv/math/LinearFunction.java gnv-artifacts/src/main/java/de/intevation/gnv/state/profile/horizontal/HorizontalProfileMeshCrossOutputState.java
diffstat 3 files changed, 131 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/gnv-artifacts/ChangeLog	Tue Dec 15 14:55:42 2009 +0000
+++ b/gnv-artifacts/ChangeLog	Tue Dec 15 15:14:21 2009 +0000
@@ -1,3 +1,17 @@
+2009-12-15	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/gnv/state/profile/horizontal/HorizontalProfileMeshCrossOutputState.java:
+	  If a few (i, j) values are not available (gaps in the grid) try
+	  to fill the holes with guessing the values by the ones which could
+	  be fetched. We are using a componentwise linear function here.
+	  This is surely slightly wrong because world coordinates are
+	  in WGS84 which is ellipsoid in nature. TODO: Look at the errors
+	  and if needed compensate them by using cubic polynonial or ellipsoid 
+	  function terms.
+
+	* src/main/java/de/intevation/gnv/math/LinearFunction.java: New.
+	  Linear function to be used in curve fitting process.
+
 2009-12-15  Tim Englich  <tim.englich@intevation.de>
 
 	* doc/conf/queries.properties: 
@@ -16,9 +30,11 @@
 	  math api.
 
 2009-12-15  Tim Englich  <tim.englich@intevation.de>
-Added the Unit of the Parameter to the Query for Parameters in 
-      TimeSeries. Now teh Unit will be displaied in the Combobox and
-      in the Diagramm-Axis-Description.
+
+	Added the Unit of the Parameter to the Query for Parameters in 
+	TimeSeries. Now teh Unit will be displaied in the Combobox and
+	in the Diagramm-Axis-Description.
+
 	* src/main/resources/lang/artifactMessages*.properties: 
 	  Added the name Productname for "horizontale Schnittprofile". to the
 	  Resources so that it could be displaied properly in the GUI
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/math/LinearFunction.java	Tue Dec 15 15:14:21 2009 +0000
@@ -0,0 +1,30 @@
+package de.intevation.gnv.math;
+
+import org.apache.commons.math.optimization.fitting.ParametricRealFunction;
+
+import org.apache.commons.math.FunctionEvaluationException;
+
+/**
+ *  @author Sascha L. Teichmann
+ */
+public class LinearFunction
+implements   ParametricRealFunction
+{
+    public static final LinearFunction INSTANCE = new LinearFunction();
+
+    public LinearFunction() {
+    }
+
+    public double value(double x, double [] parameters)
+    throws FunctionEvaluationException 
+    {
+        return x*parameters[0] + parameters[1];
+    }
+
+    public double [] gradient(double x, double [] parameters) 
+    throws FunctionEvaluationException 
+    {
+        return new double [] { x, 1f };
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8:
--- a/gnv-artifacts/src/main/java/de/intevation/gnv/state/profile/horizontal/HorizontalProfileMeshCrossOutputState.java	Tue Dec 15 14:55:42 2009 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/state/profile/horizontal/HorizontalProfileMeshCrossOutputState.java	Tue Dec 15 15:14:21 2009 +0000
@@ -17,14 +17,26 @@
 import com.vividsolutions.jts.io.WKTReader;
 
 import de.intevation.artifactdatabase.Config;
+
 import de.intevation.gnv.artifacts.cache.CacheFactory;
+
 import de.intevation.gnv.geobackend.base.Result;
 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.ResultSet;
+
 import de.intevation.gnv.utils.IndexBuffer;
 
+import de.intevation.gnv.math.LinearFunction;
+
+import org.apache.commons.math.optimization.fitting.CurveFitter;
+
+import org.apache.commons.math.optimization.general.GaussNewtonOptimizer;
+import org.apache.commons.math.optimization.OptimizationException;
+
+import org.apache.commons.math.FunctionEvaluationException;
+
 /**
  * @author Tim Englich <tim.englich@intevation.de>
  *
@@ -78,7 +90,7 @@
                 if (this.inputData.containsKey("mesh_linestring")){
                     
                     try {
-                        // 1. IJK Anfragen für Stützpunkte im Netz ausführen.
+                        // 1. IJK Anfragen für Stuetzpunkte im Netz ausführen.
                         LineString ls = (LineString)new WKTReader().read(this.inputData
                                                                          .get("mesh_linestring")
                                                                          .getValue());
@@ -90,7 +102,13 @@
                         QueryExecutor queryExecutor = QueryExecutorFactory
                                                         .getInstance()
                                                         .getQueryExecutor();
-                        for (int i = 0; i < coords.length; i++){
+
+                        ArrayList missingPoints = new ArrayList();
+
+                        String additionWhere = "TRUE";
+
+                        for (int i = 0; i < coords.length; i++) {
+
                             String wkt = "POINT( "+coords[i].x+" "+coords[i].y+" )";
 
                             result = queryExecutor.executeQuery(this.ijkQueryID,
@@ -103,15 +121,72 @@
                                 points.add(i, new java.awt.Point(iPos,jPos));
                             }else{
                                 log.debug("No i/j Pos found for "+wkt);
+                                missingPoints.add(new Object [] { Integer.valueOf(i), coords[i] });
                                 points.add(i, null);
                                 // Special Case no i,j found for Coordinate
                             }
                         }
-                        // TODO: Make Tablenames and Columns Configurable
-                        IndexBuffer ib = new IndexBuffer(points, "MEDIAN.MESHPOINT.IPOSITION", " MEDIAN.MESHPOINT.JPOSITION" );
-                        String additionWhere = ib.toWhereClause();
-                        log.debug("Additional Where Clause = "+additionWhere);
-                        // 2. Aus diesen Stützpunkten den Resultset generieren.
+
+                        if (missingPoints.size() == coords.length) {
+                            log.debug("cannot create index buffer");
+                        }
+                        else { // generate index filter
+                            boolean remainsMissingPoints = !missingPoints.isEmpty();
+
+                            if (remainsMissingPoints) {
+                                // try to guess the missing (i, j)
+                                CurveFitter iFitter = new CurveFitter(new GaussNewtonOptimizer(true));
+                                CurveFitter jFitter = new CurveFitter(new GaussNewtonOptimizer(true));
+
+                                for (int i = 0, N = points.size(); i < N; ++i) {
+                                    java.awt.Point p = (java.awt.Point)points.get(i);
+                                    if (p != null) {
+                                        Coordinate coord = coords[i];
+                                        iFitter.addObservedPoint(coord.x, p.x);
+                                        jFitter.addObservedPoint(coord.y, p.y);
+                                    }
+                                }
+                                try {
+                                    // XXX: Assumption: (i, j) are created by componentwise linear function.
+                                    // This is surely not correct because (x, y) are in a ellipsoid projection.
+                                    // TODO: use ellipsoid functions and fit with Levenberg Marquardt.
+                                    double [] iParams = iFitter.fit(
+                                        LinearFunction.INSTANCE, new double [] { 1d, 1d });
+
+                                    double [] jParams = jFitter.fit(
+                                        LinearFunction.INSTANCE, new double [] { 1d, 1d });
+
+                                    for (int i = missingPoints.size()-1; i >= 0; --i) {
+                                        Object [] a = (Object [])missingPoints.get(i);
+                                        Coordinate coord = (Coordinate)a[1];
+                                        int pi = (int)Math.round(iParams[0]*coord.x + iParams[1]);
+                                        int pj = (int)Math.round(jParams[0]*coord.y + jParams[1]);
+                                        points.set(
+                                            ((Integer)a[0]).intValue(),
+                                            new java.awt.Point(pi, pj));
+                                    }
+
+                                    remainsMissingPoints = false; // we filled the gaps
+                                }
+                                catch (FunctionEvaluationException fee) {
+                                    log.error(fee);
+                                }
+                                catch (OptimizationException oe) {
+                                    log.error(oe);
+                                }
+                            }
+
+                            if (!remainsMissingPoints) {
+                                // TODO: Make Tablenames and Columns Configurable
+                                IndexBuffer ib = new IndexBuffer(
+                                    points, 
+                                    "MEDIAN.MESHPOINT.IPOSITION", 
+                                    "MEDIAN.MESHPOINT.JPOSITION" );
+                                additionWhere = ib.toWhereClause();
+                                log.debug("Additional Where Clause = "+additionWhere);
+                                // 2. Aus diesen Stuetzpunkten den Resultset generieren.
+                            }
+                        } // if generate index filter
                         
                         String[] filterValues = this.generateFilterValuesFromInputData();
                         String[] addedFilterValues = new String[filterValues.length+1];
@@ -121,7 +196,6 @@
                         result = queryExecutor.executeQuery(this.queryID,
                                                             addedFilterValues);
                         
-                        
                     } catch (ParseException e) {
                         log.error(e,e);
                     }catch (QueryException e) {

http://dive4elements.wald.intevation.org