Mercurial > dive4elements > river
comparison artifacts/src/main/java/org/dive4elements/river/exports/CrossSectionGenerator.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/CrossSectionGenerator.java@bd047b71ab37 |
children | 4897a58c8746 |
comparison
equal
deleted
inserted
replaced
5837:d9901a08d0a6 | 5838:5aa05a7a34b7 |
---|---|
1 package org.dive4elements.river.exports; | |
2 | |
3 import java.awt.BasicStroke; | |
4 import java.awt.Color; | |
5 import java.awt.Paint; | |
6 import java.awt.Stroke; | |
7 import java.text.NumberFormat; | |
8 import java.util.List; | |
9 | |
10 import org.apache.log4j.Logger; | |
11 import org.jfree.chart.LegendItemCollection; | |
12 import org.jfree.chart.annotations.XYBoxAnnotation; | |
13 import org.jfree.chart.annotations.XYTextAnnotation; | |
14 import org.jfree.chart.plot.XYPlot; | |
15 import org.jfree.data.xy.XYSeries; | |
16 import org.w3c.dom.Document; | |
17 | |
18 import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; | |
19 import org.dive4elements.artifacts.DataProvider; | |
20 import org.dive4elements.river.artifacts.FLYSArtifact; | |
21 import org.dive4elements.river.artifacts.geom.Lines; | |
22 import org.dive4elements.river.artifacts.model.CrossSectionFacet; | |
23 import org.dive4elements.river.artifacts.model.FacetTypes; | |
24 import org.dive4elements.river.artifacts.model.HYKFactory; | |
25 import org.dive4elements.river.artifacts.resources.Resources; | |
26 import org.dive4elements.river.jfree.FLYSAnnotation; | |
27 import org.dive4elements.river.jfree.StyledXYSeries; | |
28 import org.dive4elements.river.model.FastCrossSectionLine; | |
29 import org.dive4elements.river.themes.LineStyle; | |
30 import org.dive4elements.river.themes.TextStyle; | |
31 import org.dive4elements.river.themes.ThemeAccess; | |
32 import org.dive4elements.river.utils.FLYSUtils; | |
33 import org.dive4elements.river.utils.Formatter; | |
34 import org.dive4elements.river.utils.ThemeUtil; | |
35 | |
36 | |
37 /** | |
38 * An OutGenerator that generates cross section graphs. | |
39 */ | |
40 public class CrossSectionGenerator | |
41 extends LongitudinalSectionGenerator | |
42 implements FacetTypes | |
43 { | |
44 /** The logger that is used in this generator. */ | |
45 private static Logger logger = | |
46 Logger.getLogger(CrossSectionGenerator.class); | |
47 | |
48 public static final String I18N_CHART_TITLE = | |
49 "chart.cross_section.title"; | |
50 | |
51 public static final String I18N_CHART_SUBTITLE = | |
52 "chart.cross_section.subtitle"; | |
53 | |
54 public static final String I18N_XAXIS_LABEL = | |
55 "chart.cross_section.xaxis.label"; | |
56 | |
57 public static final String I18N_YAXIS_LABEL = | |
58 "chart.cross_section.yaxis.label"; | |
59 | |
60 public static final String I18N_CHART_TITLE_DEFAULT = "Querprofildiagramm"; | |
61 public static final String I18N_XAXIS_LABEL_DEFAULT = "Abstand [m]"; | |
62 public static final String I18N_YAXIS_LABEL_DEFAULT = "W [NN + m]"; | |
63 | |
64 | |
65 /** Trivial Constructor. */ | |
66 public CrossSectionGenerator() { | |
67 super(); | |
68 } | |
69 | |
70 | |
71 @Override | |
72 protected YAxisWalker getYAxisWalker() { | |
73 return new YAxisWalker() { | |
74 @Override | |
75 public int length() { | |
76 return 1; | |
77 } | |
78 | |
79 /** Get identifier for this index. */ | |
80 @Override | |
81 public String getId(int idx) { | |
82 return "W"; | |
83 } | |
84 }; | |
85 } | |
86 | |
87 | |
88 /** | |
89 * Get localized chart title. | |
90 */ | |
91 @Override | |
92 public String getDefaultChartTitle() { | |
93 Object[] i18n_msg_args = new Object[] { | |
94 getRiverName() | |
95 }; | |
96 return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT, i18n_msg_args); | |
97 } | |
98 | |
99 | |
100 /** Always return default subtitle. */ | |
101 @Override | |
102 protected String getChartSubtitle() { | |
103 // XXX NOTE: overriding this method disables ChartSettings subtitle! | |
104 // The default implementation of this method in ChartGenerator returns | |
105 // the subtitle changed via the chart settings dialog. This method | |
106 // always returns the subtitle containing river and km, NEVER the | |
107 // ChartSettings subtitle! | |
108 return getDefaultChartSubtitle(); | |
109 } | |
110 | |
111 | |
112 /** Get Charts default subtitle. */ | |
113 @Override | |
114 protected String getDefaultChartSubtitle() { | |
115 List<DataProvider> providers = | |
116 context.getDataProvider(CrossSectionFacet.BLACKBOARD_CS_MASTER_DATA); | |
117 double km = 0d; | |
118 if (providers.size() > 0) { | |
119 FastCrossSectionLine csl = (FastCrossSectionLine) providers.get(0). | |
120 provideData(CrossSectionFacet.BLACKBOARD_CS_MASTER_DATA, | |
121 null, context); | |
122 km = csl == null ? -1 : csl.getKm(); | |
123 } | |
124 | |
125 Object[] args = new Object[] { | |
126 getRiverName(), | |
127 km | |
128 }; | |
129 | |
130 logger.debug("Locale: " + Resources.getLocale(context.getMeta())); | |
131 | |
132 return msg(I18N_CHART_SUBTITLE, "", args); | |
133 } | |
134 | |
135 | |
136 /** Get color for hyk zones by their type (which is the name). */ | |
137 protected Paint colorForHYKZone(String zoneName) { | |
138 if (zoneName.startsWith("R")) { | |
139 // Brownish. | |
140 return new Color(153, 60, 0); | |
141 } | |
142 else if (zoneName.startsWith("V")) { | |
143 // Greenish. | |
144 return new Color(0, 255, 0); | |
145 } | |
146 else if (zoneName.startsWith("B")) { | |
147 // Grayish. | |
148 return new Color(128, 128, 128); | |
149 } | |
150 else if (zoneName.startsWith("H")) { | |
151 // Blueish. | |
152 return new Color(0, 0, 255); | |
153 } | |
154 else { | |
155 // Default. | |
156 logger.debug("Unknown zone type found."); | |
157 return new Color(255, 0, 0); | |
158 } | |
159 } | |
160 | |
161 @Override | |
162 protected void addAnnotationsToRenderer(XYPlot plot) { | |
163 super.addAnnotationsToRenderer(plot); | |
164 | |
165 // Paints for the boxes/lines. | |
166 Stroke basicStroke = new BasicStroke(1.0f); | |
167 | |
168 // XXX: DEAD CODE // Paint linePaint = new Color(255, 0,0,60); | |
169 Paint fillPaint = new Color(0, 255,0,60); | |
170 Paint tranPaint = new Color(0, 0,0, 0); | |
171 | |
172 // OPTMIMIZE: Pre-calculate positions | |
173 ChartArea area = new ChartArea( | |
174 plot.getDomainAxis(0).getRange(), | |
175 plot.getRangeAxis().getRange()); | |
176 | |
177 for(FLYSAnnotation fa : this.annotations) { | |
178 | |
179 // Access text styling, if any. | |
180 Document theme = fa.getTheme(); | |
181 TextStyle textStyle = null; | |
182 // XXX: DEAD CODE // LineStyle lineStyle = null; | |
183 | |
184 // Get Themeing information and add legend item. | |
185 if (theme != null) { | |
186 ThemeAccess themeAccess = new ThemeAccess(theme); | |
187 textStyle = themeAccess.parseTextStyle(); | |
188 // XXX: DEAD CODE // lineStyle = themeAccess.parseLineStyle(); | |
189 if (fa.getLabel() != null) { | |
190 LegendItemCollection lic = new LegendItemCollection(); | |
191 LegendItemCollection old = plot.getFixedLegendItems(); | |
192 lic.add(createLegendItem(theme, fa.getLabel())); | |
193 // (Re-)Add prior legend entries. | |
194 if (old != null) { | |
195 old.addAll(lic); | |
196 } | |
197 else { | |
198 old = lic; | |
199 } | |
200 plot.setFixedLegendItems(old); | |
201 } | |
202 } | |
203 | |
204 // Hyks. | |
205 for (HYKFactory.Zone zone: fa.getBoxes()) { | |
206 // For each zone, create a box to fill with color, a box to draw | |
207 // the lines and a text to display the type. | |
208 fillPaint = colorForHYKZone(zone.getName()); | |
209 | |
210 XYBoxAnnotation boxA = new XYBoxAnnotation(zone.getFrom(), area.atGround(), | |
211 zone.getTo(), area.ofGround(0.03f), basicStroke, tranPaint, fillPaint); | |
212 XYBoxAnnotation boxB = new XYBoxAnnotation(zone.getFrom(), area.atGround(), | |
213 zone.getTo(), area.atTop(), basicStroke, fillPaint, tranPaint); | |
214 | |
215 XYTextAnnotation tex = new XYTextAnnotation(zone.getName(), | |
216 zone.getFrom() + (zone.getTo() - zone.getFrom()) / 2.0d, | |
217 area.ofGround(0.015f)); | |
218 if (textStyle != null) { | |
219 textStyle.apply(tex); | |
220 } | |
221 | |
222 plot.getRenderer().addAnnotation(boxA, org.jfree.ui.Layer.BACKGROUND); | |
223 plot.getRenderer().addAnnotation(boxB, org.jfree.ui.Layer.BACKGROUND); | |
224 plot.getRenderer().addAnnotation(tex, org.jfree.ui.Layer.BACKGROUND); | |
225 } | |
226 } | |
227 } | |
228 | |
229 @Override | |
230 protected String getDefaultXAxisLabel() { | |
231 return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT); | |
232 } | |
233 | |
234 | |
235 @Override | |
236 protected String getDefaultYAxisLabel(int pos) { | |
237 FLYSArtifact flys = (FLYSArtifact) master; | |
238 | |
239 String unit = FLYSUtils.getRiver(flys).getWstUnit().getName(); | |
240 | |
241 return msg(I18N_YAXIS_LABEL, | |
242 I18N_YAXIS_LABEL_DEFAULT, | |
243 new Object[] { unit }); | |
244 } | |
245 | |
246 | |
247 /** | |
248 * Let one facet do its job. | |
249 */ | |
250 @Override | |
251 public void doOut( | |
252 ArtifactAndFacet artifactFacet, | |
253 Document attr, | |
254 boolean visible | |
255 ) { | |
256 String name = artifactFacet.getFacetName(); | |
257 | |
258 logger.debug("CrossSectionGenerator.doOut: " + name); | |
259 | |
260 if (name == null) { | |
261 logger.error("No facet name for doOut(). No output generated!"); | |
262 return; | |
263 } | |
264 | |
265 if (name.equals(CROSS_SECTION)) { | |
266 doCrossSectionOut( | |
267 artifactFacet.getData(context), | |
268 artifactFacet.getFacetDescription(), | |
269 attr, | |
270 visible); | |
271 } | |
272 else if (name.equals(CROSS_SECTION_WATER_LINE)) { | |
273 doCrossSectionWaterLineOut( | |
274 artifactFacet.getData(context), | |
275 artifactFacet.getFacetDescription(), | |
276 attr, | |
277 visible); | |
278 } | |
279 else if (FacetTypes.IS.AREA(name)) { | |
280 doArea(artifactFacet.getData(context), | |
281 artifactFacet, | |
282 attr, | |
283 visible); | |
284 } | |
285 else if (name.equals(HYK)) { | |
286 doHyk(artifactFacet.getData(context), | |
287 artifactFacet.getFacetDescription(), | |
288 attr, | |
289 visible); | |
290 } | |
291 else if (FacetTypes.IS.MANUALLINE(name)) { | |
292 doCrossSectionWaterLineOut( | |
293 artifactFacet.getData(context), | |
294 artifactFacet.getFacetDescription(), | |
295 attr, | |
296 visible); | |
297 } | |
298 else if (FacetTypes.IS.MANUALPOINTS(name)) { | |
299 doPoints(artifactFacet.getData(context), | |
300 artifactFacet, | |
301 attr, visible, YAXIS.W.idx); | |
302 } | |
303 else { | |
304 logger.warn("CrossSection.doOut: Unknown facet name: " + name); | |
305 return; | |
306 } | |
307 } | |
308 | |
309 | |
310 /** Look up the axis identifier for a given facet type. */ | |
311 @Override | |
312 public int axisIdxForFacet(String facetName) { | |
313 // TODO Where to add thid axis too. | |
314 return 0; | |
315 } | |
316 | |
317 | |
318 /** | |
319 * Do cross sections waterline out. | |
320 * | |
321 * @param seriesName name of the data (line) to display in legend. | |
322 * @param theme Theme for the data series. | |
323 */ | |
324 protected void doCrossSectionWaterLineOut( | |
325 Object o, | |
326 String seriesName, | |
327 Document theme, | |
328 boolean visible | |
329 ) { | |
330 logger.debug("CrossSectionGenerator.doCrossSectionWaterLineOut"); | |
331 | |
332 Lines.LineData lines = (Lines.LineData) o; | |
333 // DO NOT SORT DATA! This destroys the gaps indicated by NaNs. | |
334 StyledXYSeries series = new StyledXYSeries(seriesName, false, theme); | |
335 | |
336 if (!ThemeUtil.parseShowLineLabel(theme)) { | |
337 series.setLabel(""); | |
338 } | |
339 if (ThemeUtil.parseShowWidth(theme)) { | |
340 NumberFormat nf = Formatter.getMeterFormat(this.context); | |
341 String labelAdd = "b=" + nf.format(lines.width) + "m"; | |
342 if (series.getLabel().length() == 0) { | |
343 series.setLabel(labelAdd); | |
344 } | |
345 else { | |
346 series.setLabel(series.getLabel() + ", " + labelAdd); | |
347 } | |
348 } | |
349 if (ThemeUtil.parseShowLevel(theme) && lines.points.length > 1 | |
350 && lines.points[1].length > 0) { | |
351 NumberFormat nf = Formatter.getMeterFormat(this.context); | |
352 FLYSArtifact flys = (FLYSArtifact) master; | |
353 | |
354 String unit = FLYSUtils.getRiver(flys).getWstUnit().getName(); | |
355 | |
356 String labelAdd = "W=" + nf.format(lines.points[1][0]) + unit; | |
357 if (series.getLabel().length() == 0) { | |
358 series.setLabel(labelAdd); | |
359 } | |
360 else { | |
361 series.setLabel(series.getLabel() + ", " + labelAdd); | |
362 } | |
363 } | |
364 if (ThemeUtil.parseShowMiddleHeight(theme) && lines.width != 0) { | |
365 NumberFormat nf = Formatter.getMeterFormat(this.context); | |
366 String labelAdd = "T=" + nf.format(lines.area / lines.width) + "m"; | |
367 // : " + lines.area + "/" + lines.width); | |
368 if (series.getLabel().length() == 0) { | |
369 series.setLabel(labelAdd); | |
370 } | |
371 else { | |
372 series.setLabel(series.getLabel() + ", " + labelAdd); | |
373 } | |
374 } | |
375 | |
376 StyledSeriesBuilder.addPoints(series, lines.points, false); | |
377 | |
378 addAxisSeries(series, 0, visible); | |
379 } | |
380 | |
381 | |
382 /** Add HYK-Annotations (colorize and label some areas, draw lines. */ | |
383 protected void doHyk( | |
384 Object o, | |
385 String seriesName, | |
386 Document theme, | |
387 boolean visible | |
388 ) { | |
389 logger.debug("CrossSectionGenerator.doHyk"); | |
390 | |
391 List<HYKFactory.Zone> zones = (List<HYKFactory.Zone>) o; | |
392 | |
393 if (zones == null || zones.isEmpty()) { | |
394 logger.warn("CrossSectionGenerator.doHYK: empty zone list received."); | |
395 return; | |
396 } | |
397 | |
398 // Actual Styling is done in XYChartGenerator. | |
399 if (visible) { | |
400 addAnnotations(new FLYSAnnotation(seriesName, null, zones, theme)); | |
401 } | |
402 } | |
403 | |
404 | |
405 /** | |
406 * Do cross sections out. | |
407 * | |
408 * @param seriesName name of the data (line) to display in legend. | |
409 * @param theme Theme for the data series. | |
410 */ | |
411 protected void doCrossSectionOut( | |
412 Object o, | |
413 String seriesName, | |
414 Document theme, | |
415 boolean visible | |
416 ) { | |
417 logger.debug("CrossSectionGenerator.doCrossSectionOut"); | |
418 | |
419 XYSeries series = new StyledXYSeries(seriesName, theme); | |
420 | |
421 StyledSeriesBuilder.addPoints(series, (double [][]) o, false); | |
422 | |
423 addAxisSeries(series, 0, visible); | |
424 } | |
425 | |
426 | |
427 /** | |
428 * Creates a new <i>ChartSection</i>. | |
429 * | |
430 * Overridden to prevent inclusion of subtitle. | |
431 * | |
432 * @return a new <i>ChartSection</i>. | |
433 */ | |
434 @Override | |
435 protected ChartSection buildChartSection() { | |
436 ChartSection chartSection = new ChartSection(); | |
437 chartSection.setTitle(getChartTitle()); | |
438 chartSection.setDisplayGrid(isGridVisible()); | |
439 chartSection.setDisplayLogo(showLogo()); | |
440 chartSection.setLogoVPlacement(logoVPlace()); | |
441 chartSection.setLogoHPlacement(logoHPlace()); | |
442 return chartSection; | |
443 } | |
444 } | |
445 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |