Mercurial > dive4elements > river
comparison artifacts/src/main/java/org/dive4elements/river/exports/InfoGeneratorHelper.java @ 5838:5aa05a7a34b7
Rename modules to more fitting names.
author | Sascha L. Teichmann <teichmann@intevation.de> |
---|---|
date | Thu, 25 Apr 2013 15:23:37 +0200 |
parents | flys-artifacts/src/main/java/org/dive4elements/river/exports/InfoGeneratorHelper.java@bd047b71ab37 |
children | 4897a58c8746 |
comparison
equal
deleted
inserted
replaced
5837:d9901a08d0a6 | 5838:5aa05a7a34b7 |
---|---|
1 package org.dive4elements.river.exports; | |
2 | |
3 import java.awt.geom.AffineTransform; | |
4 import java.awt.geom.NoninvertibleTransformException; | |
5 import java.awt.geom.Rectangle2D; | |
6 | |
7 import java.util.Date; | |
8 | |
9 import org.w3c.dom.Document; | |
10 import org.w3c.dom.Element; | |
11 | |
12 import org.apache.log4j.Logger; | |
13 | |
14 import org.jfree.chart.ChartRenderingInfo; | |
15 import org.jfree.chart.JFreeChart; | |
16 import org.jfree.chart.axis.DateAxis; | |
17 import org.jfree.chart.axis.NumberAxis; | |
18 import org.jfree.chart.axis.ValueAxis; | |
19 import org.jfree.chart.plot.XYPlot; | |
20 import org.jfree.data.Range; | |
21 import org.jfree.data.xy.XYDataset; | |
22 | |
23 import org.dive4elements.artifacts.common.ArtifactNamespaceContext; | |
24 import org.dive4elements.artifacts.common.utils.XMLUtils; | |
25 import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator; | |
26 | |
27 import org.dive4elements.river.jfree.Bounds; | |
28 | |
29 | |
30 /** | |
31 * This class helps generating chart info documents. | |
32 * | |
33 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> | |
34 */ | |
35 public class InfoGeneratorHelper { | |
36 | |
37 /** Private logging instance. */ | |
38 private static final Logger logger = | |
39 Logger.getLogger(InfoGeneratorHelper.class); | |
40 | |
41 protected ChartGenerator generator; | |
42 | |
43 | |
44 public InfoGeneratorHelper(ChartGenerator generator) { | |
45 this.generator = generator; | |
46 } | |
47 | |
48 | |
49 /** | |
50 * Triggers the creation of the chart info document. | |
51 * | |
52 * @param chart The JFreeChart chart. | |
53 * @param info An info object that has been created while chart creation. | |
54 * | |
55 * @return the info document. | |
56 */ | |
57 public Document createInfoDocument( | |
58 JFreeChart chart, | |
59 ChartRenderingInfo info) | |
60 { | |
61 logger.debug("InfoGeneratorHelper.createInfoDocument"); | |
62 | |
63 Document doc = XMLUtils.newDocument(); | |
64 | |
65 ElementCreator cr = new ElementCreator( | |
66 doc, | |
67 ArtifactNamespaceContext.NAMESPACE_URI, | |
68 ArtifactNamespaceContext.NAMESPACE_PREFIX); | |
69 | |
70 Element chartinfo = cr.create("chartinfo"); | |
71 | |
72 chartinfo.appendChild(createAxesElements(cr, chart)); | |
73 chartinfo.appendChild(createTransformationElements(cr, chart, info)); | |
74 | |
75 doc.appendChild(chartinfo); | |
76 | |
77 return doc; | |
78 } | |
79 | |
80 | |
81 /** | |
82 * This method create a axes element that contains all domain and range | |
83 * axes of the given chart. | |
84 * | |
85 * @param cr The ElementCreator. | |
86 * @param chart The chart that provides range information of its axes. | |
87 * | |
88 * @return an element with axes information. | |
89 */ | |
90 protected Element createAxesElements( | |
91 ElementCreator cr, | |
92 JFreeChart chart) | |
93 { | |
94 logger.debug("InfoGeneratorHelper.createRangeElements"); | |
95 | |
96 Element axes = cr.create("axes"); | |
97 | |
98 XYPlot plot = (XYPlot) chart.getPlot(); | |
99 | |
100 int dAxisCount = plot.getDomainAxisCount(); | |
101 for (int i = 0; i < dAxisCount; i++) { | |
102 ValueAxis axis = plot.getDomainAxis(i); | |
103 XYDataset data = plot.getDataset(i); | |
104 | |
105 if (axis != null) { | |
106 Element e = createAxisElement(cr, axis, data, "domain", i); | |
107 axes.appendChild(e); | |
108 } | |
109 } | |
110 | |
111 int rAxisCount = plot.getRangeAxisCount(); | |
112 for (int i = 0; i < rAxisCount; i++) { | |
113 ValueAxis axis = plot.getRangeAxis(i); | |
114 XYDataset data = plot.getDataset(i); | |
115 | |
116 if (axis == null || data == null) { | |
117 logger.warn("Axis or dataset is empty at pos: " + i); | |
118 continue; | |
119 } | |
120 | |
121 Element e = createAxisElement(cr, axis, data, "range", i); | |
122 axes.appendChild(e); | |
123 } | |
124 | |
125 return axes; | |
126 } | |
127 | |
128 | |
129 /** | |
130 * This method create a axis element for a given <i>axis</i> and | |
131 * <i>type</i>. Type can be one of 'domain' or 'range'. | |
132 * | |
133 * @param cr The ElementCreator | |
134 * @param axis The axis that provides range information. | |
135 * @param dataset The dataset for min/max determination. | |
136 * @param type The axis type ('domain' or 'range'). | |
137 * @param pos The position in the chart. | |
138 * | |
139 * @return An element that contains range information of a given axis. | |
140 */ | |
141 protected Element createAxisElement( | |
142 ElementCreator cr, | |
143 ValueAxis axis, | |
144 XYDataset dataset, | |
145 String type, | |
146 int pos) | |
147 { | |
148 logger.debug("createAxisElement " + pos); | |
149 logger.debug("Axis is from type: " + axis.getClass()); | |
150 | |
151 Element e = cr.create(type); | |
152 cr.addAttr(e, "pos", String.valueOf(pos), true); | |
153 | |
154 if (axis instanceof DateAxis) { | |
155 prepareDateAxisElement( | |
156 e, cr, (DateAxis) axis, dataset, type, pos); | |
157 } | |
158 else { | |
159 prepareNumberAxisElement( | |
160 e, cr, (NumberAxis) axis, dataset, type, pos); | |
161 } | |
162 | |
163 return e; | |
164 } | |
165 | |
166 | |
167 protected Element prepareNumberAxisElement( | |
168 Element e, | |
169 ElementCreator cr, | |
170 NumberAxis axis, | |
171 XYDataset dataset, | |
172 String type, | |
173 int pos | |
174 ) { | |
175 Range range = axis.getRange(); | |
176 | |
177 cr.addAttr(e, "from", String.valueOf(range.getLowerBound()), true); | |
178 cr.addAttr(e, "to", String.valueOf(range.getUpperBound()), true); | |
179 cr.addAttr(e, "axistype", "number", true); | |
180 | |
181 Range[] rs = generator.getRangesForAxis(pos); | |
182 Range r = null; | |
183 | |
184 if (type.equals("range")) { | |
185 r = rs[1]; | |
186 } | |
187 else { | |
188 r = rs[0]; | |
189 } | |
190 | |
191 cr.addAttr(e, "min", String.valueOf(r.getLowerBound()), true); | |
192 cr.addAttr(e, "max", String.valueOf(r.getUpperBound()), true); | |
193 | |
194 return e; | |
195 } | |
196 | |
197 | |
198 protected Element prepareDateAxisElement( | |
199 Element e, | |
200 ElementCreator cr, | |
201 DateAxis axis, | |
202 XYDataset dataset, | |
203 String type, | |
204 int pos | |
205 ) { | |
206 Date from = axis.getMinimumDate(); | |
207 Date to = axis.getMaximumDate(); | |
208 | |
209 Bounds bounds = null; | |
210 if (type.equals("range")) { | |
211 bounds = generator.getYBounds(pos); | |
212 } | |
213 else { | |
214 bounds = generator.getXBounds(pos); | |
215 } | |
216 | |
217 cr.addAttr(e, "axistype", "date", true); | |
218 cr.addAttr(e, "from", String.valueOf(from.getTime()), true); | |
219 cr.addAttr(e, "to", String.valueOf(to.getTime()), true); | |
220 | |
221 cr.addAttr(e, "min", bounds.getLower().toString(), true); | |
222 cr.addAttr(e, "max", bounds.getUpper().toString(), true); | |
223 | |
224 return e; | |
225 } | |
226 | |
227 | |
228 /** | |
229 * This method appends the values of a transformation matrix to transform | |
230 * image pixel coordinates into chart coordinates. | |
231 * | |
232 * @param cr The ElementCreator. | |
233 * @param chart The chart object. | |
234 * @param info The ChartRenderingInfo that is filled while chart creation. | |
235 * | |
236 * @return an element that contains one or more transformation matrix. | |
237 */ | |
238 protected Element createTransformationElements( | |
239 ElementCreator cr, | |
240 JFreeChart chart, | |
241 ChartRenderingInfo info) | |
242 { | |
243 logger.debug("InfoGeneratorHelper.createTransformationElements"); | |
244 | |
245 Element tf = cr.create("transformation-matrix"); | |
246 | |
247 Rectangle2D dataArea = info.getPlotInfo().getDataArea(); | |
248 | |
249 XYPlot plot = (XYPlot) chart.getPlot(); | |
250 ValueAxis xAxis = plot.getDomainAxis(); | |
251 | |
252 if (xAxis == null) { | |
253 logger.error("There is no x axis in the chart!"); | |
254 return null; | |
255 } | |
256 | |
257 for (int i = 0, num = plot.getRangeAxisCount(); i < num; i++) { | |
258 ValueAxis yAxis = plot.getRangeAxis(i); | |
259 | |
260 if (yAxis == null) { | |
261 logger.warn("No y axis at pos " + i + " existing."); | |
262 continue; | |
263 } | |
264 | |
265 Element matrix = createTransformationElement( | |
266 cr, xAxis, yAxis, dataArea, i); | |
267 | |
268 tf.appendChild(matrix); | |
269 } | |
270 | |
271 return tf; | |
272 } | |
273 | |
274 | |
275 /** | |
276 * Creates an element that contains values used to transform coordinates | |
277 * of a coordinate system A into a coordinate system B. | |
278 * | |
279 * @param cr The ElementCreator. | |
280 * @param xAxis The x axis of the target coordinate system. | |
281 * @param yAxis The y axis of the target coordinate system. | |
282 * @param dataArea The pixel coordinates of the chart image. | |
283 * @param pos The dataset position. | |
284 * | |
285 * @return an element that contains transformation matrix values. | |
286 */ | |
287 protected Element createTransformationElement( | |
288 ElementCreator cr, | |
289 ValueAxis xAxis, | |
290 ValueAxis yAxis, | |
291 Rectangle2D dataArea, | |
292 int pos) | |
293 { | |
294 double[] tm = createTransformationMatrix(dataArea, xAxis, yAxis); | |
295 | |
296 Element matrix = cr.create("matrix"); | |
297 | |
298 cr.addAttr(matrix, "pos", String.valueOf(pos), true); | |
299 cr.addAttr(matrix, "sx", String.valueOf(tm[0]), true); | |
300 cr.addAttr(matrix, "sy", String.valueOf(tm[1]), true); | |
301 cr.addAttr(matrix, "tx", String.valueOf(tm[2]), true); | |
302 cr.addAttr(matrix, "ty", String.valueOf(tm[3]), true); | |
303 | |
304 if (xAxis instanceof DateAxis) { | |
305 cr.addAttr(matrix, "xtype", "date", true); | |
306 } | |
307 else { | |
308 cr.addAttr(matrix, "xtype", "number", true); | |
309 } | |
310 | |
311 if (yAxis instanceof DateAxis) { | |
312 cr.addAttr(matrix, "ytype", "date", true); | |
313 } | |
314 else { | |
315 cr.addAttr(matrix, "ytype", "number", true); | |
316 } | |
317 | |
318 return matrix; | |
319 } | |
320 | |
321 | |
322 /** | |
323 * This method determines a transformation matrix to transform pixel | |
324 * coordinates of the chart image into chart coordinates. | |
325 * | |
326 * @param dataArea The rectangle that contains the data points of the chart. | |
327 * @param xAxis The x axis. | |
328 * @param yAxis The y axis. | |
329 * | |
330 * @return a double array as follows: [sx, sy, tx, ty]. | |
331 */ | |
332 protected static double[] createTransformationMatrix( | |
333 Rectangle2D dataArea, | |
334 ValueAxis xAxis, | |
335 ValueAxis yAxis) | |
336 { | |
337 logger.debug("InfoGeneratorHelper.createTransformationMatrix"); | |
338 | |
339 double offsetX = dataArea.getX(); | |
340 double width = dataArea.getWidth(); | |
341 double offsetY = dataArea.getY(); | |
342 double height = dataArea.getHeight(); | |
343 | |
344 Range xRange = getRangeFromAxis(xAxis); | |
345 Range yRange = getRangeFromAxis(yAxis); | |
346 | |
347 double lowerX = xRange.getLowerBound(); | |
348 double upperX = xRange.getUpperBound(); | |
349 double lowerY = yRange.getLowerBound(); | |
350 double upperY = yRange.getUpperBound(); | |
351 | |
352 if (xAxis.isInverted()) { | |
353 logger.info("X-Axis is inverted!"); | |
354 | |
355 double tmp = upperX; | |
356 upperX = lowerX; | |
357 lowerX = tmp; | |
358 } | |
359 | |
360 double dMoveX = upperX - lowerX; | |
361 double fMoveX = width * lowerX; | |
362 double dMoveY = lowerY - upperY; | |
363 double fMoveY = height * upperY; | |
364 | |
365 AffineTransform t1 = AffineTransform.getTranslateInstance( | |
366 offsetX - ( fMoveX / dMoveX ), | |
367 offsetY - ( fMoveY / dMoveY ) ); | |
368 | |
369 AffineTransform t2 = AffineTransform.getScaleInstance( | |
370 width / (upperX - lowerX), | |
371 height / (lowerY - upperY)); | |
372 | |
373 t1.concatenate(t2); | |
374 | |
375 try { | |
376 t1.invert(); | |
377 | |
378 double[] c = new double[6]; | |
379 t1.getMatrix(c); | |
380 | |
381 return new double[] { c[0], c[3], c[4], c[5] }; | |
382 } | |
383 catch (NoninvertibleTransformException e) { | |
384 // do nothing | |
385 logger.warn("Matrix is not invertible."); | |
386 } | |
387 | |
388 return new double[] { 1d, 1d, 0d, 0d }; | |
389 } | |
390 | |
391 | |
392 protected static Range getRangeFromAxis(ValueAxis axis) { | |
393 if (axis instanceof DateAxis) { | |
394 DateAxis dAxis = (DateAxis) axis; | |
395 Date min = dAxis.getMinimumDate(); | |
396 Date max = dAxis.getMaximumDate(); | |
397 | |
398 return new Range(min.getTime(), max.getTime()); | |
399 } | |
400 else { | |
401 return axis.getRange(); | |
402 } | |
403 } | |
404 } | |
405 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |