changeset 365:f66088a43ecc

Added horizontal crossprofile charts to chart pallet. Fixed some bugs before interpolation. gnv-artifacts/trunk@440 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Wed, 16 Dec 2009 19:29:05 +0000
parents 2413273f1c13
children 086e3af38b96
files gnv-artifacts/ChangeLog gnv-artifacts/src/main/java/de/intevation/gnv/chart/HorizontalCrossProfileChart.java gnv-artifacts/src/main/java/de/intevation/gnv/math/Interpolation2D.java gnv-artifacts/src/main/java/de/intevation/gnv/math/Point2d.java gnv-artifacts/src/main/java/de/intevation/gnv/state/profile/horizontal/HorizontalProfileMeshCrossOutputState.java
diffstat 5 files changed, 248 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/gnv-artifacts/ChangeLog	Wed Dec 16 11:58:44 2009 +0000
+++ b/gnv-artifacts/ChangeLog	Wed Dec 16 19:29:05 2009 +0000
@@ -1,3 +1,20 @@
+2009-12-16  Ingo Weinzierl <ingo.weinzierl@intevation.de>
+
+	* src/main/java/de/intevation/gnv/state/profile/horizontal/HorizontalProfileMeshCrossOutputState.java:
+	  Override method to create chart. Fixed some bugs for interpolation.
+
+	* src/main/java/de/intevation/gnv/chart/HorizontalCrossProfileChart.java:
+	  Chart class for generating horizontal crossprofile charts. Horizontal
+	  crossprofile charts are a subclass of horizontal profile charts.
+
+	* src/main/java/de/intevation/gnv/math/Point2d.java: Changed epsilon value.
+
+	* src/main/java/de/intevation/gnv/math/Interpolation2D.java: Fixed some bugs
+	  regarding buffer size to limit data for interpolation.
+
+	  TODO: At the moment, there is no gap detection for horizontal crossprofile
+	  charts.
+
 2009-12-16  Ingo Weinzierl <ingo.weinzierl@intevation.de>
 
 	  Issue100
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/chart/HorizontalCrossProfileChart.java	Wed Dec 16 19:29:05 2009 +0000
@@ -0,0 +1,62 @@
+package de.intevation.gnv.chart;
+
+import java.util.Collection;
+import java.util.Locale;
+
+import de.intevation.gnv.chart.ChartLabels;
+import de.intevation.gnv.geobackend.base.Result;
+
+import org.apache.log4j.Logger;
+
+import org.jfree.chart.ChartTheme;
+import org.jfree.data.general.Series;
+
+/**
+ * @author Ingo Weinzierl <ingo.weinzierl@intevation.de>
+ */
+public class HorizontalCrossProfileChart
+extends      HorizontalProfileChart
+{
+    private static Logger log = Logger.getLogger(HorizontalCrossProfileChart.class);
+
+    public HorizontalCrossProfileChart(
+        ChartLabels labels,
+        ChartTheme  theme,
+        Collection  parameters,
+        Collection  measurements,
+        Collection  dates,
+        Collection  result,
+        Collection  timeGaps,
+        Locale      locale,
+        boolean     linesVisible,
+        boolean     shapesVisible
+    ) {
+        super(
+            labels,
+            theme,
+            parameters,
+            measurements,
+            dates,
+            result,
+            timeGaps,
+            locale,
+            linesVisible,
+            shapesVisible
+        );
+    }
+
+
+    @Override
+    protected void gapDetection(
+        Result[] results,
+        Series   series,
+        int      startPos,
+        int      endPos
+    ) {
+        log.warn(
+            "No gap detection for horizontalcrossprofile charts " + 
+            "implemented yet."
+        );
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/gnv-artifacts/src/main/java/de/intevation/gnv/math/Interpolation2D.java	Wed Dec 16 11:58:44 2009 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/math/Interpolation2D.java	Wed Dec 16 19:29:05 2009 +0000
@@ -1,6 +1,8 @@
 package de.intevation.gnv.math;
 
+import java.util.ArrayList;
 import java.util.List;
+import java.util.HashMap;
 import java.util.Collections;
 
 import com.vividsolutions.jts.geom.Coordinate;
@@ -8,11 +10,15 @@
 
 import com.vividsolutions.jts.index.quadtree.Quadtree;
 
+import org.apache.log4j.Logger;
+
 /**
  *  @author Sascha L. Teichmann
  */
 public final class Interpolation2D
 {
+    private static Logger log = Logger.getLogger(Interpolation2D.class);
+
     public interface Consumer {
         void interpolated(Coordinate point);
     } // interface Consumer
@@ -32,32 +38,70 @@
         int N = path.size();
         int M = points.size();
 
+        log.debug("Size of path: " + N);
+        log.debug("Size of points: " + M);
+
         if (M < 1 || N < 2) { // nothing to do
             return;
         }
-        // figure out max delta(p[i].x, p[i-1].x) 
-        Collections.sort(points, Point2d.X_COMPARATOR);
+
+        HashMap<Integer, ArrayList<Point2d>> map = new HashMap<Integer, ArrayList<Point2d>>();
+
+        for (int k = M-1; k >= 0; --k) {
+            Point2d p = points.get(k);
+
+            ArrayList<Point2d> list = map.get(p.j);
+
+            if (list == null) {
+                map.put(p.j, list = new ArrayList<Point2d>());
+            }
+            list.add(p);
+        }
+
         double dxMax = -Double.MAX_VALUE;
-        for (int i = 1; i < M; ++i) {
-            double dx = Math.abs(path.get(i).x - path.get(i-1).x);
-            if (dx > dxMax) {
-                dxMax = dx;
+
+        for (ArrayList<Point2d> v: map.values()) {
+            Collections.sort(v, Point2d.X_COMPARATOR);
+            for (int i = 1, L = v.size(); i < L; ++i) {
+                double dx = Math.abs(v.get(i).x - v.get(i-1).x);
+                if (dx > dxMax) {
+                    dxMax = dx;
+                }
             }
         }
 
-        dxMax = dxMax*0.5d + 1e-5d;
+        dxMax = dxMax + 1e-5d;
 
-        // figure out max delta(p[i].y, p[i-1].y) 
-        Collections.sort(path, Point2d.X_COMPARATOR);
+        map.clear();
+
+        for (int k = M-1; k >= 0; --k) {
+            Point2d p = points.get(k);
+
+            ArrayList<Point2d> list = map.get(p.i);
+
+            if (list == null) {
+                map.put(p.i, list = new ArrayList<Point2d>());
+            }
+            list.add(p);
+        }
+
         double dyMax = -Double.MAX_VALUE;
-        for (int i = 1; i < M; ++i) {
-            double dy = Math.abs(path.get(i).y - path.get(i-1).y);
-            if (dy > dyMax) {
-                dyMax = dy;
+
+        for (ArrayList<Point2d> v: map.values()) {
+            Collections.sort(v, Point2d.Y_COMPARATOR);
+            for (int i = 1, L = v.size(); i < L; ++i) {
+                double dy = Math.abs(v.get(i).y - v.get(i-1).y);
+                if (dy > dyMax) {
+                    dyMax = dy;
+                }
             }
         }
 
-        dyMax = dyMax*0.5d + 1e-5d;
+        dyMax = dyMax + 1e-5d;
+
+        map = null;
+
+        log.debug("buffer size: " + dxMax + " / " + dyMax);
 
         // put into spatial index to speed up finding neighbors.
         Quadtree spatialIndex = new Quadtree();
@@ -78,7 +122,10 @@
 
         Point2d [] neighbors = new Point2d[4];
 
-        for (double p = to; p <= from; p += dP) {
+        int missedInterpolations = 0;
+        int interpolations = 0;
+
+        for (double p = from; p <= to; p += dP) {
             if (!linearToMap.locate(p, center)) {
                 continue;
             }
@@ -141,8 +188,14 @@
                     y2, z2,
                     center.y);
                 consumer.interpolated(center);
+                ++interpolations;
+            }
+            else {
+                ++missedInterpolations;
             }
         }
+
+        log.debug("interpolations: " + interpolations + " / " + missedInterpolations);
     }
 
     public static final double interpolate(
--- a/gnv-artifacts/src/main/java/de/intevation/gnv/math/Point2d.java	Wed Dec 16 11:58:44 2009 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/math/Point2d.java	Wed Dec 16 19:29:05 2009 +0000
@@ -11,7 +11,7 @@
 public class Point2d
 extends      Coordinate
 {
-    public static final double EPSILON = 1e-5d;
+    public static final double EPSILON = 1e-3d;
 
     public static final Comparator X_COMPARATOR = new Comparator() {
         public int compare(Object a, Object b) {
--- a/gnv-artifacts/src/main/java/de/intevation/gnv/state/profile/horizontal/HorizontalProfileMeshCrossOutputState.java	Wed Dec 16 11:58:44 2009 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/state/profile/horizontal/HorizontalProfileMeshCrossOutputState.java	Wed Dec 16 19:29:05 2009 +0000
@@ -7,6 +7,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
+import java.util.Locale;
 
 import org.apache.log4j.Logger;
 import org.w3c.dom.Node;
@@ -22,6 +23,10 @@
 
 import de.intevation.gnv.artifacts.cache.CacheFactory;
 
+import de.intevation.gnv.chart.Chart;
+import de.intevation.gnv.chart.ChartLabels;
+import de.intevation.gnv.chart.HorizontalCrossProfileChart;
+
 import de.intevation.gnv.geobackend.base.DefaultResultDescriptor;
 import de.intevation.gnv.geobackend.base.ResultDescriptor;
 import de.intevation.gnv.geobackend.base.DefaultResult;
@@ -49,6 +54,8 @@
 
 import org.apache.commons.math.FunctionEvaluationException;
 
+import org.jfree.chart.ChartTheme;
+
 /**
  * @author Tim Englich <tim.englich@intevation.de>
  *
@@ -87,9 +94,55 @@
         
     }
 
+
+    @Override
+    protected Chart getChart(
+        ChartLabels  chartLables,
+        ChartTheme   theme,
+        Collection   parameters,
+        Collection   measurements,
+        Collection   dates,
+        Collection   result,
+        Locale       locale,
+        String       uuid,
+        boolean      linesVisible,
+        boolean      shapesVisible
+    ) {
+        Chart chart = null;
+        if (CACHE_CHART) {
+            log.info("Try to get horizontalprofilemeshcross chart from cache.");
+            chart = (Chart) getChartFromCache(uuid);
+        }
+
+        if (chart != null)
+            return chart;
+
+        log.info("Chart not in cache yet.");
+        chart = new HorizontalCrossProfileChart(
+            chartLables,
+            theme,
+            parameters,
+            measurements,
+            dates,
+            result,
+            null,
+            locale,
+            linesVisible,
+            shapesVisible
+        );
+        chart.generateChart();
+
+        if (CACHE_CHART) {
+            log.info("Put chart into cache.");
+            purifyChart(chart, uuid);
+        }
+
+        return chart;
+    }
+
     @Override
     protected Collection<Result> getChartResult(String uuid) {
-        log.debug("OutputStateBase.getChartResult");
+        log.debug("HorizontalProfileMeshCrossOutputState.getChartResult");
         Collection<Result> result = null;
         if (CacheFactory.getInstance().isInitialized()) {
             String key = uuid + super.getID();
@@ -117,11 +170,11 @@
 
                         ArrayList missingPoints = new ArrayList();
 
-                        String additionWhere = "TRUE";
+                        String additionWhere = "FEATUREID=FEATUREID";
 
                         for (int i = 0; i < coords.length; i++) {
 
-                            String wkt = "POINT( "+coords[i].x+" "+coords[i].y+" )";
+                            String wkt = toWKT(coords[i]);
 
                             result = queryExecutor.executeQuery(this.ijkQueryID,
                                                                new String[]{meshid,wkt});
@@ -229,6 +282,15 @@
         return result;
     }
 
+
+    @Override
+    protected String createChartSubtitle(Locale locale, String uuid) {
+        log.debug("create chart subtitle for horizontal crossprofile charts.");
+        String subtitle = createTimePeriod(locale, uuid);
+
+        return subtitle;
+    }
+
     private static final String [] COLUMN_BLACKLIST = {
         "MEDIAN.MESHPOINT.JPOSITION",
         "MEDIAN.MESHPOINT.IPOSITION"
@@ -245,11 +307,20 @@
 
     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))) {
+            String oa = a.getString(indices[i]);
+            String ob = b.getString(indices[i]);
+
+            if (oa == null && ob == null)  {
+                continue;
+            }
+
+            if (oa == null || ob == null) {
+                return true;
+            }
+
+            if (!oa.equals(ob)) {
+                log.debug("+++++++++++++++ differs ++++++++++++++");
+                log.debug("   " + oa + " != " + ob);
                 return true;
             }
         }
@@ -282,21 +353,25 @@
             this.path       = path;
             this.output     = output;
             this.descriptor = descriptor;
+            points = new ArrayList<Point2d>();
         }
 
         public void finish() {
             if (!points.isEmpty()) {
                 double distance = toKM(
                     DistanceCalculator.calculateDistance(path));
+                
+                if (distance > EPSILON) {
 
-                Interpolation2D.interpolate(
-                    path,
-                    points,
-                    0d,
-                    distance,
-                    steps(distance),
-                    LinearMetrics.INSTANCE, // XXX: This wrong!!!
-                    this);
+                    Interpolation2D.interpolate(
+                        path,
+                        points,
+                        0d,
+                        distance,
+                        INTERPOLATION_STEPS,
+                        LinearMetrics.INSTANCE,
+                        this);
+                }
 
                 points.clear();
             }
@@ -336,6 +411,9 @@
                 else if (colname.equals("YORDINATE")) {
                     result.addColumnValue(j, Double.valueOf(coordinate.z));
                 }
+                else {
+                    result.addColumnValue(j, prototyp.getObject(i));
+                }
                 ++j;
             }
             output.add(result);
@@ -349,14 +427,9 @@
         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 final double EPSILON = 1e-5d;
+    public static final int    INTERPOLATION_STEPS =
+        Integer.getInteger("interpolation.steps", 500).intValue();
 
     public static Coordinate toCoordinate(String shape) {
         try {
@@ -381,6 +454,7 @@
         List<Coordinate>   path,
         Collection<Result> input
     ) {
+        log.debug("------  number of points before processing: " + input.size());
         ArrayList<Result> output = new ArrayList<Result>();
 
 
@@ -432,6 +506,8 @@
             sectionHandler.finish();
         }
 
+        log.debug("------  number of points after processing: " + output.size());
+
         return output;
     }
 }

http://dive4elements.wald.intevation.org