# HG changeset patch # User Ingo Weinzierl # Date 1260991745 0 # Node ID f66088a43ecc5b194a77d8eea203faa537a39341 # Parent 2413273f1c13e8bf5c8cb4f9e09d985980c90352 Added horizontal crossprofile charts to chart pallet. Fixed some bugs before interpolation. gnv-artifacts/trunk@440 c6561f87-3c4e-4783-a992-168aeb5c3f6f diff -r 2413273f1c13 -r f66088a43ecc gnv-artifacts/ChangeLog --- 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 + + * 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 Issue100 diff -r 2413273f1c13 -r f66088a43ecc gnv-artifacts/src/main/java/de/intevation/gnv/chart/HorizontalCrossProfileChart.java --- /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 + */ +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 : diff -r 2413273f1c13 -r f66088a43ecc gnv-artifacts/src/main/java/de/intevation/gnv/math/Interpolation2D.java --- 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> map = new HashMap>(); + + for (int k = M-1; k >= 0; --k) { + Point2d p = points.get(k); + + ArrayList list = map.get(p.j); + + if (list == null) { + map.put(p.j, list = new ArrayList()); + } + 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 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 list = map.get(p.i); + + if (list == null) { + map.put(p.i, list = new ArrayList()); + } + 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 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( diff -r 2413273f1c13 -r f66088a43ecc gnv-artifacts/src/main/java/de/intevation/gnv/math/Point2d.java --- 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) { diff -r 2413273f1c13 -r f66088a43ecc gnv-artifacts/src/main/java/de/intevation/gnv/state/profile/horizontal/HorizontalProfileMeshCrossOutputState.java --- 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 * @@ -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 getChartResult(String uuid) { - log.debug("OutputStateBase.getChartResult"); + log.debug("HorizontalProfileMeshCrossOutputState.getChartResult"); Collection 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(); } 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 path, Collection input ) { + log.debug("------ number of points before processing: " + input.size()); ArrayList output = new ArrayList(); @@ -432,6 +506,8 @@ sectionHandler.finish(); } + log.debug("------ number of points after processing: " + output.size()); + return output; } }