changeset 362:1ab23cd66870

Added result set handling. Needs some testing. gnv-artifacts/trunk@436 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Wed, 16 Dec 2009 01:32:19 +0000
parents aec85d00d82c
children 22229249e9fc
files gnv-artifacts/ChangeLog gnv-artifacts/src/main/java/de/intevation/gnv/state/profile/horizontal/HorizontalProfileMeshCrossOutputState.java gnv-artifacts/src/main/java/de/intevation/gnv/utils/DistanceCalculator.java
diffstat 3 files changed, 260 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/gnv-artifacts/ChangeLog	Tue Dec 15 22:25:53 2009 +0000
+++ b/gnv-artifacts/ChangeLog	Wed Dec 16 01:32:19 2009 +0000
@@ -1,3 +1,25 @@
+2009-12-16	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/gnv/utils/DistanceCalculator.java:
+	  Added method to calculate distance of path.
+	  TODO: Move this class into math package and and add
+	  an slerp interpolator so it can be used as a metric inside
+	  the interpolation code.
+
+	* src/main/java/de/intevation/gnv/state/profile/horizontal/HorizontalProfileMeshCrossOutputState.java:
+	  Added code to disassemble the incoming result set, interpolate
+	  along a given path and returns an adjusted result set.
+	  The (i, j) got lost on this track because we don't travel along
+	  the main axis of the grid any more. The test for gaps has to be
+	  adjusted because, because the dx/dy on the path depends on how
+	  many steps are made on the way [*]. This is controlled by the system
+	  property 'interpolation.step.width'. It is set in meters
+	  and defaults to 100m. TODO: This should be configurable
+	  in the conf.xml file.
+
+	  [*] I opt strongly for integration of the outlier test based gap
+	  detection to overcome this problem.
+
 2009-12-15	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
 
 	* src/main/java/de/intevation/gnv/math/LinearToMap.java:
--- a/gnv-artifacts/src/main/java/de/intevation/gnv/state/profile/horizontal/HorizontalProfileMeshCrossOutputState.java	Tue Dec 15 22:25:53 2009 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/state/profile/horizontal/HorizontalProfileMeshCrossOutputState.java	Wed Dec 16 01:32:19 2009 +0000
@@ -12,7 +12,9 @@
 import org.w3c.dom.Node;
 
 import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Point;
 import com.vividsolutions.jts.geom.LineString;
+
 import com.vividsolutions.jts.io.ParseException;
 import com.vividsolutions.jts.io.WKTReader;
 
@@ -20,15 +22,25 @@
 
 import de.intevation.gnv.artifacts.cache.CacheFactory;
 
+import de.intevation.gnv.geobackend.base.DefaultResultDescriptor;
+import de.intevation.gnv.geobackend.base.ResultDescriptor;
+import de.intevation.gnv.geobackend.base.DefaultResult;
 import de.intevation.gnv.geobackend.base.Result;
+
+import de.intevation.gnv.math.Point2d;
+import de.intevation.gnv.math.Interpolation2D;
+
 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.utils.DistanceCalculator;
 
 import de.intevation.gnv.math.LinearFunction;
+import de.intevation.gnv.math.LinearMetrics;
 
 import org.apache.commons.math.optimization.fitting.CurveFitter;
 
@@ -194,6 +206,7 @@
                         addedFilterValues[filterValues.length] = additionWhere;
                         
                         result = process(
+                            Arrays.asList(coords),
                             queryExecutor.executeQuery(
                                 this.queryID,
                                 addedFilterValues));
@@ -216,11 +229,209 @@
         return result;
     }
 
-    protected Collection<Result> process(Collection<Result> input) {
-        // TODO: split by additional parameters, interpolate the
-        // values, and create a new dummy result set.
+    private static final String [] COLUMN_BLACKLIST = {
+        "MEDIAN.MESHPOINT.JPOSITION",
+        "MEDIAN.MESHPOINT.IPOSITION"
+    };
 
-        return input;
+    private static final boolean blacklisted(String column) {
+        for (int i = 0; i < COLUMN_BLACKLIST.length; ++i) {
+            if (COLUMN_BLACKLIST.equals(column)) {
+                return true;
+            }
+        }
+        return false;
+    }
 
+    private static boolean different(Result a, Result b, int [] indices) {
+        for (int i = 0; i < indices.length; ++i) {
+            Object oa = a.getObject(indices[i]);
+            Object ob = b.getObject(indices[i]);
+            if ((oa == null && ob != null)
+            ||  (oa != null && ob == null)
+            ||  (oa != null && !oa.equals(ob))) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static final String [] DIFF_COLUMS = {
+        "GROUP1",
+        "GROUP2",
+        "GROUP3"
+    };
+
+    public static final class SectionHandler
+    implements                Interpolation2D.Consumer
+    {
+        private ArrayList<Point2d> points;
+        private List<Coordinate>   path;
+        private Collection<Result> output;
+        private Result             prototyp;
+        private ResultDescriptor   descriptor;
+
+        public SectionHandler() {
+        }
+
+        public SectionHandler(
+            List<Coordinate>   path,
+            Collection<Result> output,
+            ResultDescriptor   descriptor
+        ) {
+            this.path       = path;
+            this.output     = output;
+            this.descriptor = descriptor;
+        }
+
+        public void finish() {
+            if (!points.isEmpty()) {
+                double distance = toKM(
+                    DistanceCalculator.calculateDistance(path));
+
+                Interpolation2D.interpolate(
+                    path,
+                    points,
+                    0d,
+                    distance,
+                    steps(distance),
+                    LinearMetrics.INSTANCE, // XXX: This wrong!!!
+                    this);
+
+                points.clear();
+            }
+        }
+
+        public void setPrototyp(Result prototyp) {
+            this.prototyp = prototyp;
+        }
+
+        public void handle(Result result) {
+            Coordinate coordinate = 
+                toCoordinate(result.getString("SHAPE"));
+            double value = result.getDouble("YORDINATE");
+            int iPos     = result.getInteger("MEDIAN.MESHPOINT.JPOSITION");
+            int jPos     = result.getInteger("MEDIAN.MESHPOINT.JPOSITION");
+            Point2d p = new Point2d(
+                coordinate.x,
+                coordinate.y,
+                value,
+                iPos, jPos);
+            points.add(p);
+        }
+
+        public void interpolated(Coordinate coordinate) {
+            DefaultResult result = new DefaultResult(descriptor);
+            ResultDescriptor pd = prototyp.getResultDescriptor();
+
+            int pcolums = pd.getColumnCount();
+            for (int i = 0, j = 0; i < pcolums; ++i) {
+                String colname = pd.getColumnName(i);
+                if (blacklisted(colname)) {
+                    continue;
+                }
+                if (colname.equals("SHAPE")) {
+                    result.addColumnValue(j, toWKT(coordinate));
+                }
+                else if (colname.equals("YORDINATE")) {
+                    result.addColumnValue(j, Double.valueOf(coordinate.z));
+                }
+                ++j;
+            }
+            output.add(result);
+        }
+    } // class SectionHandler
+
+    public static final double NAUTICAL_MILE = 1852.216d;
+    public static final double KILOMETER     = 1000d;
+
+    public static final double toKM(double distance) {
+        return (distance * NAUTICAL_MILE) / KILOMETER;
+    }
+
+    public static final double INTERPOLATION_STEP_WIDTH =
+        Double.parseDouble(System.getProperty(
+            "interpolation.step.width", "100"));
+
+    public static int steps(double km) {
+        return (int)Math.ceil(
+            Math.max(1d, (km * KILOMETER)/INTERPOLATION_STEP_WIDTH));
+    }
+
+    public static Coordinate toCoordinate(String shape) {
+        try {
+            return ((Point)(new WKTReader().read(shape))).getCoordinate();
+        }
+        catch (ParseException pe) {
+            log.error(pe);
+        }
+        return null;
+    }
+
+    public static String toWKT(Coordinate coordinate) {
+        StringBuilder sb = new StringBuilder("POINT(");
+        sb.append(coordinate.x)
+          .append(' ')
+          .append(coordinate.y)
+          .append(')');
+        return sb.toString();
+    }
+
+    protected Collection<Result> process(
+        List<Coordinate>   path,
+        Collection<Result> input
+    ) {
+        ArrayList<Result> output = new ArrayList<Result>();
+
+
+        Result last = null;
+
+        int [] diffColums = null;
+
+        SectionHandler sectionHandler = null;
+
+        for (Result result: input) {
+
+            if (sectionHandler == null) {
+
+                ResultDescriptor rd = result.getResultDescriptor();
+                diffColums = rd.getColumnIndices(DIFF_COLUMS);
+                int columns = rd.getColumnCount();
+
+                DefaultResultDescriptor resultDescriptor =
+                    new DefaultResultDescriptor();
+
+                for (int j = 0; j < columns; ++j) {
+                    String columnName = rd.getColumnName(j);
+                    if (!blacklisted(columnName)) {
+                        resultDescriptor.addColumn(
+                            columnName,
+                            rd.getColumnClassName(j));
+                    }
+                }
+
+                sectionHandler = new SectionHandler(
+                    path,
+                    output,
+                    resultDescriptor);
+
+                sectionHandler.setPrototyp(result);
+            }
+
+            if (last != null && different(last, result, diffColums)) {
+                sectionHandler.finish();
+                sectionHandler.setPrototyp(result);
+            }
+
+            sectionHandler.handle(result);
+
+            last = result;
+        }
+
+        if (sectionHandler != null) {
+            sectionHandler.finish();
+        }
+
+        return output;
     }
 }
--- a/gnv-artifacts/src/main/java/de/intevation/gnv/utils/DistanceCalculator.java	Tue Dec 15 22:25:53 2009 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/utils/DistanceCalculator.java	Wed Dec 16 01:32:19 2009 +0000
@@ -4,6 +4,9 @@
 package de.intevation.gnv.utils;
 
 import com.vividsolutions.jts.geom.Point;
+import com.vividsolutions.jts.geom.Coordinate;
+
+import java.util.List;
 
 /**
  * @author Tim Englich <tim.englich@intevation.de>
@@ -22,13 +25,17 @@
     }
     
     public static double calculateDistance(Point p1, Point p2){
+        return calculateDistance(p1.getCoordinate(), p2.getCoordinate());
+    }
+
+    public static double calculateDistance(Coordinate p1, Coordinate p2){
         double resultValue = 0.0;
         
-        double b1 = p1.getY();
-        double b2 = p2.getY();
+        double b1 = p1.y;
+        double b2 = p2.y;
         
-        double l1 = p1.getX();
-        double l2 = p2.getX();
+        double l1 = p1.x;
+        double l2 = p2.x;
         
         
         double F = (b1 + b2) / 2.0;
@@ -62,4 +69,16 @@
         return resultValue;
     }
 
+    public static final double calculateDistance(List<Coordinate> path) {
+        int N = path.size();
+        if (N < 2) {
+            return 0d;
+        }
+        double sum = 0d;
+        for (int i = 1; i < N; ++i) {
+            sum += calculateDistance(path.get(i-1), path.get(i));
+        }
+        return sum;
+    }
+
 }

http://dive4elements.wald.intevation.org