Mercurial > dive4elements > gnv-client
diff gnv-artifacts/src/main/java/de/intevation/gnv/chart/VerticalProfileChart.java @ 657:af3f56758f59
merged gnv-artifacts/0.5
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:13:53 +0200 |
parents | b98d1adee7a6 |
children | 79401c871da4 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gnv-artifacts/src/main/java/de/intevation/gnv/chart/VerticalProfileChart.java Fri Sep 28 12:13:53 2012 +0200 @@ -0,0 +1,394 @@ +package de.intevation.gnv.chart; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Iterator; +import java.util.Locale; + +import org.apache.log4j.Logger; + +import org.jfree.chart.ChartTheme; +import org.jfree.chart.axis.Axis; +import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.data.Range; +import org.jfree.data.general.Series; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; + +import de.intevation.gnv.geobackend.base.Result; +import de.intevation.gnv.state.describedata.KeyValueDescibeData; + + +/** + * @author Ingo Weinzierl <ingo.weinzierl@intevation.de> + */ +public class VerticalProfileChart +extends AbstractXYLineChart +{ + public static final String DEFAULT_AXIS = "KPOSITION"; + + private static Logger log = Logger.getLogger(VerticalProfileChart.class); + + protected final double PERCENTAGE = 5.0; + protected final double GAP_MAX_LEVEL = Math.sqrt(2.0); + protected final int GAP_MAX_VALUES = 60; + + /** Map to store max ranges of each parameter (axis.setAutoRange(true) + * doesn't seem to work properly. */ + protected Map values; + + + public VerticalProfileChart( + ChartLabels labels, + ChartTheme theme, + Collection parameters, + Collection measurements, + Collection dates, + Collection result, + Collection timeGaps, + Locale locale, + boolean linesVisible, + boolean shapesVisible + ) { + this.labels = labels; + this.theme = theme; + this.parameters = parameters; + this.measurements = measurements; + this.dates = dates; + this.resultSet = result; + this.timeGaps = timeGaps; + this.locale = locale; + this.PLOT_ORIENTATION = PlotOrientation.HORIZONTAL; + this.linesVisible = linesVisible; + this.shapesVisible = shapesVisible; + this.datasets = new HashMap(); + this.ranges = new HashMap(); + this.values = new HashMap(); + } + + + protected void initData() { + log.debug("init data for VerticalProfileChart"); + + String breakPoint1 = null; + String breakPoint2 = null; + String breakPoint3 = null; + + Iterator iter = resultSet.iterator(); + Result row = null; + String seriesName = null; + String parameter = null; + XYSeries series = null; + + int idx = 0; + int startPos = 0; + int endPos = 0; + double startValue = 0; + double endValue = 0; + + Result[] results = + (Result[]) resultSet.toArray(new Result[resultSet.size()]); + + while (iter.hasNext()) { + row = (Result) iter.next(); + + // add current data to plot and prepare for next one + if (!row.getString("GROUP1").equals(breakPoint1) || + !row.getString("GROUP2").equals(breakPoint2) || + !row.getString("GROUP3").equals(breakPoint3) + ) { + log.debug("prepare data/plot for next dataset"); + + if(series != null) { + gapDetection(results, series, startPos, endPos); + addSeries(series, parameter, idx); + + startPos = endPos +1; + } + + // prepare variables for next plot + breakPoint1 = row.getString("GROUP1"); + breakPoint2 = row.getString("GROUP2"); + breakPoint3 = row.getString("GROUP3"); + + seriesName = createSeriesName( + breakPoint1, + breakPoint2, + breakPoint3 + ); + parameter = findParameter(seriesName); + + log.debug("next dataset is '" + seriesName + "'"); + series = new XYSeries(seriesName); + } + + addValue(row, series); + Object x = getValue(row); + Double y = row.getDouble("YORDINATE"); + if (x != null && y != null) { + storeMaxRange(ranges, y, parameter); + storeMaxValue(values, x, parameter); + } + endPos++; + } + + if (results.length == 0) + return; + + gapDetection(results, series, startPos, endPos); + addSeries(series, parameter, idx); + + addDatasets(); + } + + + protected Object getValue(Result row) { + return row.getDouble("XORDINATE"); + } + + + protected void gapDetection( + Result[] results, + Series series, + int startPos, + int endPos + ) { + double startValue = results[startPos].getDouble("XORDINATE"); + double endValue = results[endPos-1].getDouble("XORDINATE"); + if (results[0].getInteger("DATAID") == 2) + addGapsOnGrid(results, series, startPos, endPos); + else + addGaps(results, series, startValue, endValue, startPos, endPos); + } + + + protected void prepareRangeAxis(String seriesKey, int idx) { + XYPlot plot = chart.getXYPlot(); + NumberAxis xAxis = (NumberAxis) plot.getDomainAxis(); + + Range xRange = (Range) values.get(seriesKey); + xAxis.setRange(Range.expand(xRange, LOWER_MARGIN, UPPER_MARGIN)); + log.debug("Max X-Range of dataset is: " + xRange.toString()); + } + + + protected void addValue(Result row, Series series) { + ((XYSeries) series).add( + row.getDouble("XORDINATE"), + row.getDouble("YORDINATE") + ); + } + + + protected void addSeries(Series series, String parameter, int idx) { + log.debug("add series (" + parameter + ")to chart"); + + if (series == null) { + log.warn("no data to add"); + return; + } + + XYSeriesCollection xysc = null; + + if (datasets.containsKey(parameter)) + xysc = (XYSeriesCollection) datasets.get(parameter); + else + xysc = new XYSeriesCollection(); + + xysc.addSeries((XYSeries) series); + datasets.put(parameter, xysc); + } + + + protected void addDatasets() { + Iterator iter = parameters.iterator(); + XYPlot plot = chart.getXYPlot(); + int idx = 0; + + XYSeriesCollection xysc = null; + KeyValueDescibeData data = null; + String key = null; + while (iter.hasNext()) { + data = (KeyValueDescibeData) iter.next(); + key = data.getValue(); + + if (datasets.containsKey(key)) { + xysc = (XYSeriesCollection)datasets.get(key); + plot.setDataset(idx, xysc ); + log.debug("Added " + key + " parameter to plot."); + prepareAxis(key, idx); + prepareRangeAxis(key, idx); + adjustRenderer( + idx++, + xysc.getSeriesCount(), + linesVisible, + shapesVisible + ); + } + } + } + + + protected void storeMaxValue(Map values, Object val, String parameter) { + double value = ((Double) val).doubleValue(); + Range range = null; + + range = values.containsKey(parameter) + ? (Range) values.get(parameter) + : new Range(value, value); + + double lower = range.getLowerBound(); + double upper = range.getUpperBound(); + + lower = value < lower ? value : lower; + upper = value > upper ? value : upper; + + values.put(parameter, new Range(lower, upper)); + } + + + protected void localizeDomainAxis(Axis axis, Locale locale) { + // call localizeRangeAxis from superclass which formats NumberAxis + super.localizeRangeAxis(axis, locale); + } + + + protected String createSeriesName( + String breakPoint1, + String breakPoint2, + String breakPoint3 + ) { + log.debug("create seriesname of verticalprofile chart"); + return findValueTitle(parameters, breakPoint1) + + " " + + findValueTitle(measurements, breakPoint2) + + "m"; + } + + + protected void addGapsOnGrid( + Result[] results, + Series series, + int startPos, + int endPos + ) { + String axis = null; + + if (results.length > (startPos+1)) { + axis = getDependendAxisName( + results[startPos], + results[startPos+1] + ); + } + else { + axis = DEFAULT_AXIS; + } + + double range = 0; + int last = 0; + int current = 0; + + for (int i = startPos+1; i < endPos; i++) { + last = results[i-1].getInteger(axis); + current = results[i].getInteger(axis); + + boolean detected = gridDetection(last, current); + + if (detected) { + double xOld = results[i-1].getDouble("XORDINATE"); + double xNow = results[i].getDouble("XORDINATE"); + log.debug("Gap detected on grid between "+ xOld +" and "+ xNow); + ((XYSeries) series).add(xOld+0.0001, null); + } + } + } + + + protected void addGaps( + Result[] results, + Series series, + double startValue, + double endValue, + int startPos, + int endPos + ) { + + double last = 0; + double current = 0; + int num = results.length; + + for (int i = startPos+1; i < endPos; i++) { + boolean detected = false; + + last = results[i-1].getDouble("YORDINATE"); + current = results[i].getDouble("YORDINATE"); + + // gap detection for more than GAP_MAX_VALUES values + if (num > GAP_MAX_VALUES) + detected = simpleDetection(startValue, endValue, last, current); + // gap detection for less than GAP_MAX_VALUES values + else + detected = specialDetection( + startValue, + endValue, + last, + current, + num + ); + + if (detected) { + log.info("Gap between " + last + " and " + current); + ((XYSeries) series).add((last+current)/2, null); + } + } + } + + + protected boolean simpleDetection( + double start, + double end, + double last, + double current + ) { + double delta = Math.abs(end - start); + double smallDelta = Math.abs(current - last); + + return (smallDelta > delta / 100 * PERCENTAGE); + } + + + protected boolean specialDetection( + double start, + double end, + double last, + double current, + int count + ) { + double delta = Math.abs(end - start); + double smallDelta = Math.abs(current - last); + + return (smallDelta > (3.0 / (count - 1) * delta)); + } + + + protected boolean gridDetection(double last, double current) { + if (log.isDebugEnabled()) { + log.debug("######################################################"); + log.debug("Parameters for gap detection"); + log.debug("Defined gap size for grids: " + GAP_MAX_LEVEL); + log.debug("1st value to compare: " + last); + log.debug("2nd value to compare: " + current); + log.debug("Difference: " + Math.abs(current - last)); + } + return (Math.abs(current - last) > GAP_MAX_LEVEL); + } + + + protected String getDependendAxisName(Result first, Result second) { + return "KPOSITION"; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :