Mercurial > dive4elements > gnv-client
comparison 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 |
comparison
equal
deleted
inserted
replaced
590:5f5f273c8566 | 657:af3f56758f59 |
---|---|
1 package de.intevation.gnv.chart; | |
2 | |
3 import java.util.Collection; | |
4 import java.util.HashMap; | |
5 import java.util.Map; | |
6 import java.util.Iterator; | |
7 import java.util.Locale; | |
8 | |
9 import org.apache.log4j.Logger; | |
10 | |
11 import org.jfree.chart.ChartTheme; | |
12 import org.jfree.chart.axis.Axis; | |
13 import org.jfree.chart.axis.NumberAxis; | |
14 import org.jfree.chart.plot.XYPlot; | |
15 import org.jfree.chart.plot.PlotOrientation; | |
16 import org.jfree.data.Range; | |
17 import org.jfree.data.general.Series; | |
18 import org.jfree.data.xy.XYSeries; | |
19 import org.jfree.data.xy.XYSeriesCollection; | |
20 | |
21 import de.intevation.gnv.geobackend.base.Result; | |
22 import de.intevation.gnv.state.describedata.KeyValueDescibeData; | |
23 | |
24 | |
25 /** | |
26 * @author Ingo Weinzierl <ingo.weinzierl@intevation.de> | |
27 */ | |
28 public class VerticalProfileChart | |
29 extends AbstractXYLineChart | |
30 { | |
31 public static final String DEFAULT_AXIS = "KPOSITION"; | |
32 | |
33 private static Logger log = Logger.getLogger(VerticalProfileChart.class); | |
34 | |
35 protected final double PERCENTAGE = 5.0; | |
36 protected final double GAP_MAX_LEVEL = Math.sqrt(2.0); | |
37 protected final int GAP_MAX_VALUES = 60; | |
38 | |
39 /** Map to store max ranges of each parameter (axis.setAutoRange(true) | |
40 * doesn't seem to work properly. */ | |
41 protected Map values; | |
42 | |
43 | |
44 public VerticalProfileChart( | |
45 ChartLabels labels, | |
46 ChartTheme theme, | |
47 Collection parameters, | |
48 Collection measurements, | |
49 Collection dates, | |
50 Collection result, | |
51 Collection timeGaps, | |
52 Locale locale, | |
53 boolean linesVisible, | |
54 boolean shapesVisible | |
55 ) { | |
56 this.labels = labels; | |
57 this.theme = theme; | |
58 this.parameters = parameters; | |
59 this.measurements = measurements; | |
60 this.dates = dates; | |
61 this.resultSet = result; | |
62 this.timeGaps = timeGaps; | |
63 this.locale = locale; | |
64 this.PLOT_ORIENTATION = PlotOrientation.HORIZONTAL; | |
65 this.linesVisible = linesVisible; | |
66 this.shapesVisible = shapesVisible; | |
67 this.datasets = new HashMap(); | |
68 this.ranges = new HashMap(); | |
69 this.values = new HashMap(); | |
70 } | |
71 | |
72 | |
73 protected void initData() { | |
74 log.debug("init data for VerticalProfileChart"); | |
75 | |
76 String breakPoint1 = null; | |
77 String breakPoint2 = null; | |
78 String breakPoint3 = null; | |
79 | |
80 Iterator iter = resultSet.iterator(); | |
81 Result row = null; | |
82 String seriesName = null; | |
83 String parameter = null; | |
84 XYSeries series = null; | |
85 | |
86 int idx = 0; | |
87 int startPos = 0; | |
88 int endPos = 0; | |
89 double startValue = 0; | |
90 double endValue = 0; | |
91 | |
92 Result[] results = | |
93 (Result[]) resultSet.toArray(new Result[resultSet.size()]); | |
94 | |
95 while (iter.hasNext()) { | |
96 row = (Result) iter.next(); | |
97 | |
98 // add current data to plot and prepare for next one | |
99 if (!row.getString("GROUP1").equals(breakPoint1) || | |
100 !row.getString("GROUP2").equals(breakPoint2) || | |
101 !row.getString("GROUP3").equals(breakPoint3) | |
102 ) { | |
103 log.debug("prepare data/plot for next dataset"); | |
104 | |
105 if(series != null) { | |
106 gapDetection(results, series, startPos, endPos); | |
107 addSeries(series, parameter, idx); | |
108 | |
109 startPos = endPos +1; | |
110 } | |
111 | |
112 // prepare variables for next plot | |
113 breakPoint1 = row.getString("GROUP1"); | |
114 breakPoint2 = row.getString("GROUP2"); | |
115 breakPoint3 = row.getString("GROUP3"); | |
116 | |
117 seriesName = createSeriesName( | |
118 breakPoint1, | |
119 breakPoint2, | |
120 breakPoint3 | |
121 ); | |
122 parameter = findParameter(seriesName); | |
123 | |
124 log.debug("next dataset is '" + seriesName + "'"); | |
125 series = new XYSeries(seriesName); | |
126 } | |
127 | |
128 addValue(row, series); | |
129 Object x = getValue(row); | |
130 Double y = row.getDouble("YORDINATE"); | |
131 if (x != null && y != null) { | |
132 storeMaxRange(ranges, y, parameter); | |
133 storeMaxValue(values, x, parameter); | |
134 } | |
135 endPos++; | |
136 } | |
137 | |
138 if (results.length == 0) | |
139 return; | |
140 | |
141 gapDetection(results, series, startPos, endPos); | |
142 addSeries(series, parameter, idx); | |
143 | |
144 addDatasets(); | |
145 } | |
146 | |
147 | |
148 protected Object getValue(Result row) { | |
149 return row.getDouble("XORDINATE"); | |
150 } | |
151 | |
152 | |
153 protected void gapDetection( | |
154 Result[] results, | |
155 Series series, | |
156 int startPos, | |
157 int endPos | |
158 ) { | |
159 double startValue = results[startPos].getDouble("XORDINATE"); | |
160 double endValue = results[endPos-1].getDouble("XORDINATE"); | |
161 if (results[0].getInteger("DATAID") == 2) | |
162 addGapsOnGrid(results, series, startPos, endPos); | |
163 else | |
164 addGaps(results, series, startValue, endValue, startPos, endPos); | |
165 } | |
166 | |
167 | |
168 protected void prepareRangeAxis(String seriesKey, int idx) { | |
169 XYPlot plot = chart.getXYPlot(); | |
170 NumberAxis xAxis = (NumberAxis) plot.getDomainAxis(); | |
171 | |
172 Range xRange = (Range) values.get(seriesKey); | |
173 xAxis.setRange(Range.expand(xRange, LOWER_MARGIN, UPPER_MARGIN)); | |
174 log.debug("Max X-Range of dataset is: " + xRange.toString()); | |
175 } | |
176 | |
177 | |
178 protected void addValue(Result row, Series series) { | |
179 ((XYSeries) series).add( | |
180 row.getDouble("XORDINATE"), | |
181 row.getDouble("YORDINATE") | |
182 ); | |
183 } | |
184 | |
185 | |
186 protected void addSeries(Series series, String parameter, int idx) { | |
187 log.debug("add series (" + parameter + ")to chart"); | |
188 | |
189 if (series == null) { | |
190 log.warn("no data to add"); | |
191 return; | |
192 } | |
193 | |
194 XYSeriesCollection xysc = null; | |
195 | |
196 if (datasets.containsKey(parameter)) | |
197 xysc = (XYSeriesCollection) datasets.get(parameter); | |
198 else | |
199 xysc = new XYSeriesCollection(); | |
200 | |
201 xysc.addSeries((XYSeries) series); | |
202 datasets.put(parameter, xysc); | |
203 } | |
204 | |
205 | |
206 protected void addDatasets() { | |
207 Iterator iter = parameters.iterator(); | |
208 XYPlot plot = chart.getXYPlot(); | |
209 int idx = 0; | |
210 | |
211 XYSeriesCollection xysc = null; | |
212 KeyValueDescibeData data = null; | |
213 String key = null; | |
214 while (iter.hasNext()) { | |
215 data = (KeyValueDescibeData) iter.next(); | |
216 key = data.getValue(); | |
217 | |
218 if (datasets.containsKey(key)) { | |
219 xysc = (XYSeriesCollection)datasets.get(key); | |
220 plot.setDataset(idx, xysc ); | |
221 log.debug("Added " + key + " parameter to plot."); | |
222 prepareAxis(key, idx); | |
223 prepareRangeAxis(key, idx); | |
224 adjustRenderer( | |
225 idx++, | |
226 xysc.getSeriesCount(), | |
227 linesVisible, | |
228 shapesVisible | |
229 ); | |
230 } | |
231 } | |
232 } | |
233 | |
234 | |
235 protected void storeMaxValue(Map values, Object val, String parameter) { | |
236 double value = ((Double) val).doubleValue(); | |
237 Range range = null; | |
238 | |
239 range = values.containsKey(parameter) | |
240 ? (Range) values.get(parameter) | |
241 : new Range(value, value); | |
242 | |
243 double lower = range.getLowerBound(); | |
244 double upper = range.getUpperBound(); | |
245 | |
246 lower = value < lower ? value : lower; | |
247 upper = value > upper ? value : upper; | |
248 | |
249 values.put(parameter, new Range(lower, upper)); | |
250 } | |
251 | |
252 | |
253 protected void localizeDomainAxis(Axis axis, Locale locale) { | |
254 // call localizeRangeAxis from superclass which formats NumberAxis | |
255 super.localizeRangeAxis(axis, locale); | |
256 } | |
257 | |
258 | |
259 protected String createSeriesName( | |
260 String breakPoint1, | |
261 String breakPoint2, | |
262 String breakPoint3 | |
263 ) { | |
264 log.debug("create seriesname of verticalprofile chart"); | |
265 return findValueTitle(parameters, breakPoint1) + | |
266 " " + | |
267 findValueTitle(measurements, breakPoint2) + | |
268 "m"; | |
269 } | |
270 | |
271 | |
272 protected void addGapsOnGrid( | |
273 Result[] results, | |
274 Series series, | |
275 int startPos, | |
276 int endPos | |
277 ) { | |
278 String axis = null; | |
279 | |
280 if (results.length > (startPos+1)) { | |
281 axis = getDependendAxisName( | |
282 results[startPos], | |
283 results[startPos+1] | |
284 ); | |
285 } | |
286 else { | |
287 axis = DEFAULT_AXIS; | |
288 } | |
289 | |
290 double range = 0; | |
291 int last = 0; | |
292 int current = 0; | |
293 | |
294 for (int i = startPos+1; i < endPos; i++) { | |
295 last = results[i-1].getInteger(axis); | |
296 current = results[i].getInteger(axis); | |
297 | |
298 boolean detected = gridDetection(last, current); | |
299 | |
300 if (detected) { | |
301 double xOld = results[i-1].getDouble("XORDINATE"); | |
302 double xNow = results[i].getDouble("XORDINATE"); | |
303 log.debug("Gap detected on grid between "+ xOld +" and "+ xNow); | |
304 ((XYSeries) series).add(xOld+0.0001, null); | |
305 } | |
306 } | |
307 } | |
308 | |
309 | |
310 protected void addGaps( | |
311 Result[] results, | |
312 Series series, | |
313 double startValue, | |
314 double endValue, | |
315 int startPos, | |
316 int endPos | |
317 ) { | |
318 | |
319 double last = 0; | |
320 double current = 0; | |
321 int num = results.length; | |
322 | |
323 for (int i = startPos+1; i < endPos; i++) { | |
324 boolean detected = false; | |
325 | |
326 last = results[i-1].getDouble("YORDINATE"); | |
327 current = results[i].getDouble("YORDINATE"); | |
328 | |
329 // gap detection for more than GAP_MAX_VALUES values | |
330 if (num > GAP_MAX_VALUES) | |
331 detected = simpleDetection(startValue, endValue, last, current); | |
332 // gap detection for less than GAP_MAX_VALUES values | |
333 else | |
334 detected = specialDetection( | |
335 startValue, | |
336 endValue, | |
337 last, | |
338 current, | |
339 num | |
340 ); | |
341 | |
342 if (detected) { | |
343 log.info("Gap between " + last + " and " + current); | |
344 ((XYSeries) series).add((last+current)/2, null); | |
345 } | |
346 } | |
347 } | |
348 | |
349 | |
350 protected boolean simpleDetection( | |
351 double start, | |
352 double end, | |
353 double last, | |
354 double current | |
355 ) { | |
356 double delta = Math.abs(end - start); | |
357 double smallDelta = Math.abs(current - last); | |
358 | |
359 return (smallDelta > delta / 100 * PERCENTAGE); | |
360 } | |
361 | |
362 | |
363 protected boolean specialDetection( | |
364 double start, | |
365 double end, | |
366 double last, | |
367 double current, | |
368 int count | |
369 ) { | |
370 double delta = Math.abs(end - start); | |
371 double smallDelta = Math.abs(current - last); | |
372 | |
373 return (smallDelta > (3.0 / (count - 1) * delta)); | |
374 } | |
375 | |
376 | |
377 protected boolean gridDetection(double last, double current) { | |
378 if (log.isDebugEnabled()) { | |
379 log.debug("######################################################"); | |
380 log.debug("Parameters for gap detection"); | |
381 log.debug("Defined gap size for grids: " + GAP_MAX_LEVEL); | |
382 log.debug("1st value to compare: " + last); | |
383 log.debug("2nd value to compare: " + current); | |
384 log.debug("Difference: " + Math.abs(current - last)); | |
385 } | |
386 return (Math.abs(current - last) > GAP_MAX_LEVEL); | |
387 } | |
388 | |
389 | |
390 protected String getDependendAxisName(Result first, Result second) { | |
391 return "KPOSITION"; | |
392 } | |
393 } | |
394 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : |