comparison flys-artifacts/src/main/java/org/dive4elements/river/exports/LongitudinalSectionGenerator.java @ 5831:bd047b71ab37

Repaired internal references
author Sascha L. Teichmann <teichmann@intevation.de>
date Thu, 25 Apr 2013 12:06:39 +0200
parents flys-artifacts/src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java@9425b7c51b73
children
comparison
equal deleted inserted replaced
5830:160f53ee0870 5831:bd047b71ab37
1 package org.dive4elements.river.exports;
2
3 import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
4 import org.dive4elements.artifactdatabase.state.Facet;
5 import org.dive4elements.river.artifacts.FLYSArtifact;
6 import org.dive4elements.river.artifacts.geom.Lines;
7 import org.dive4elements.river.artifacts.model.AreaFacet;
8 import org.dive4elements.river.artifacts.model.FacetTypes;
9 import org.dive4elements.river.artifacts.model.WKms;
10 import org.dive4elements.river.artifacts.model.WQKms;
11 import org.dive4elements.river.exports.process.WOutProcessor;
12 import org.dive4elements.river.jfree.FLYSAnnotation;
13 import org.dive4elements.river.jfree.StyledAreaSeriesCollection;
14 import org.dive4elements.river.jfree.StyledXYSeries;
15 import org.dive4elements.river.utils.DataUtil;
16 import org.dive4elements.river.utils.FLYSUtils;
17 import org.apache.log4j.Logger;
18 import org.jfree.chart.axis.NumberAxis;
19 import org.jfree.chart.axis.ValueAxis;
20 import org.jfree.chart.plot.XYPlot;
21 import org.jfree.data.xy.XYSeries;
22 import org.w3c.dom.Document;
23
24
25 /**
26 * An OutGenerator that generates longitudinal section curves.
27 *
28 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
29 */
30 public class LongitudinalSectionGenerator
31 extends XYChartGenerator
32 implements FacetTypes
33 {
34 public enum YAXIS {
35 W(0),
36 D(1),
37 Q(2);
38 protected int idx;
39 private YAXIS(int c) {
40 idx = c;
41 }
42 }
43
44 /** The logger that is used in this generator. */
45 private static Logger logger =
46 Logger.getLogger(LongitudinalSectionGenerator.class);
47
48 /** Key to look up internationalized String for annotations label. */
49 public static final String I18N_ANNOTATIONS_LABEL =
50 "chart.longitudinal.annotations.label";
51
52 /**
53 * Key to look up internationalized String for LongitudinalSection diagrams
54 * titles.
55 */
56 public static final String I18N_CHART_TITLE =
57 "chart.longitudinal.section.title";
58
59 /**
60 * Key to look up internationalized String for LongitudinalSection diagrams
61 * subtitles.
62 */
63 public static final String I18N_CHART_SUBTITLE =
64 "chart.longitudinal.section.subtitle";
65
66 /**
67 * Key to look up internationalized String for LongitudinalSection diagrams
68 * short subtitles.
69 */
70 public static final String I18N_CHART_SHORT_SUBTITLE =
71 "chart.longitudinal.section.shortsubtitle";
72
73 public static final String I18N_XAXIS_LABEL =
74 "chart.longitudinal.section.xaxis.label";
75
76 public static final String I18N_YAXIS_LABEL =
77 "chart.longitudinal.section.yaxis.label";
78
79 public static final String I18N_2YAXIS_LABEL =
80 "chart.longitudinal.section.yaxis.second.label";
81
82 public static final String I18N_CHART_TITLE_DEFAULT = "W-L\u00e4ngsschnitt";
83 public static final String I18N_XAXIS_LABEL_DEFAULT = "km";
84 public static final String I18N_YAXIS_LABEL_DEFAULT = "W [NN + m]";
85 public static final String I18N_2YAXIS_LABEL_DEFAULT = "Q [m\u00b3/s]";
86
87 public final static String I18N_WDIFF_YAXIS_LABEL =
88 "chart.w_differences.yaxis.label";
89
90 public final static String I18N_WDIFF_YAXIS_LABEL_DEFAULT = "m";
91
92 public LongitudinalSectionGenerator() {
93 super();
94 }
95
96
97 @Override
98 protected YAxisWalker getYAxisWalker() {
99 return new YAxisWalker() {
100 @Override
101 public int length() {
102 return YAXIS.values().length;
103 }
104
105 @Override
106 public String getId(int idx) {
107 YAXIS[] yaxes = YAXIS.values();
108 return yaxes[idx].toString();
109 }
110 };
111 }
112
113
114 /**
115 * Return left most data points x value (on first axis).
116 * Overridden because axis could be inverted.
117 */
118 @Override
119 protected double getLeftX() {
120 if (isInverted()) {
121 return (Double)getXBounds(0).getUpper();
122 }
123 return (Double)getXBounds(0).getLower();
124 }
125
126
127 /**
128 * Return right most data points x value (on first axis).
129 * Overridden because axis could be inverted.
130 */
131 @Override
132 protected double getRightX() {
133 if (isInverted()) {
134 return (Double)getXBounds(0).getLower();
135 }
136 return (Double)getXBounds(0).getUpper();
137 }
138
139
140 /**
141 * Returns the default title for this chart.
142 *
143 * @return the default title for this chart.
144 */
145 @Override
146 public String getDefaultChartTitle() {
147 return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT);
148 }
149
150
151 /**
152 * Returns the default subtitle for this chart.
153 *
154 * @return the default subtitle for this chart.
155 */
156 @Override
157 protected String getDefaultChartSubtitle() {
158 double[] dist = getRange();
159
160 Object[] args = null;
161 if (dist == null) {
162 args = new Object[] {getRiverName()};
163 return msg(getChartShortSubtitleKey(), "", args);
164 }
165 args = new Object[] {
166 getRiverName(),
167 dist[0],
168 dist[1]
169 };
170 return msg(getChartSubtitleKey(), "", args);
171 }
172
173
174 /**
175 * Gets key to look up internationalized String for the charts subtitle.
176 * @return key to look up translated subtitle.
177 */
178 protected String getChartSubtitleKey() {
179 return I18N_CHART_SUBTITLE;
180 }
181
182
183 /**
184 * Gets key to look up internationalized String for the charts short
185 * subtitle.
186 * @return key to look up translated subtitle.
187 */
188 protected String getChartShortSubtitleKey() {
189 return I18N_CHART_SHORT_SUBTITLE;
190 }
191
192
193 /**
194 * Get internationalized label for the x axis.
195 */
196 @Override
197 protected String getDefaultXAxisLabel() {
198 FLYSArtifact flys = (FLYSArtifact) master;
199
200 return msg(
201 I18N_XAXIS_LABEL,
202 I18N_XAXIS_LABEL_DEFAULT,
203 new Object[] { FLYSUtils.getRiver(flys).getName() });
204 }
205
206
207 @Override
208 protected String getDefaultYAxisLabel(int index) {
209 String label = "default";
210
211 if (index == YAXIS.W.idx) {
212 label = getWAxisLabel();
213 }
214 else if (index == YAXIS.Q.idx) {
215 label = msg(getQAxisLabelKey(), getQAxisDefaultLabel());
216 }
217 else if (index == YAXIS.D.idx) {
218 label = msg(I18N_WDIFF_YAXIS_LABEL, I18N_WDIFF_YAXIS_LABEL_DEFAULT);
219 }
220
221 return label;
222 }
223
224
225 /**
226 * Get internationalized label for the y axis.
227 */
228 protected String getWAxisLabel() {
229 FLYSArtifact flys = (FLYSArtifact) master;
230
231 String unit = FLYSUtils.getRiver(flys).getWstUnit().getName();
232
233 return msg(
234 I18N_YAXIS_LABEL,
235 I18N_YAXIS_LABEL_DEFAULT,
236 new Object[] { unit });
237 }
238
239
240 /**
241 * Create Axis for given index.
242 * @return axis with according internationalized label.
243 */
244 @Override
245 protected NumberAxis createYAxis(int index) {
246 NumberAxis axis = super.createYAxis(index);
247
248 // "Q" Axis shall include 0.
249 if (index == YAXIS.Q.idx) {
250 axis.setAutoRangeIncludesZero(true);
251 }
252 else {
253 axis.setAutoRangeIncludesZero(false);
254 }
255
256 return axis;
257 }
258
259
260 /**
261 * Get default value for the second Y-Axis' label (if no translation was
262 * found).
263 */
264 protected String getQAxisDefaultLabel() {
265 return I18N_2YAXIS_LABEL_DEFAULT;
266 }
267
268
269 /**
270 * Get key for internationalization of the second Y-Axis' label.
271 */
272 protected String getQAxisLabelKey() {
273 return I18N_2YAXIS_LABEL;
274 }
275
276
277 /**
278 * Trigger inversion.
279 */
280 @Override
281 protected void adjustAxes(XYPlot plot) {
282 super.adjustAxes(plot);
283 invertXAxis(plot.getDomainAxis());
284 }
285
286
287 /**
288 * This method inverts the x-axis based on the kilometer information of the
289 * selected river. If the head of the river is at kilometer 0, the axis is
290 * not inverted, otherwise it is.
291 *
292 * @param xaxis The domain axis.
293 */
294 protected void invertXAxis(ValueAxis xaxis) {
295 if (isInverted()) {
296 logger.debug("X-Axis.setInverted(true)");
297 xaxis.setInverted(true);
298 }
299 }
300
301
302 /**
303 * Produce output.
304 * @param artifactAndFacet current facet and artifact.
305 * @param attr theme for facet
306 */
307 @Override
308 public void doOut(
309 ArtifactAndFacet artifactAndFacet,
310 Document attr,
311 boolean visible
312 ) {
313 String name = artifactAndFacet.getFacetName();
314
315 logger.debug("LongitudinalSectionGenerator.doOut: " + name);
316
317 if (name == null) {
318 logger.error("No facet name for doOut(). No output generated!");
319 return;
320 }
321
322 Facet facet = artifactAndFacet.getFacet();
323
324 if (facet == null) {
325 return;
326 }
327
328 WOutProcessor processor = new WOutProcessor();
329 if (processor.canHandle(name)) {
330 processor.doOut(this, artifactAndFacet, attr, visible, YAXIS.W.idx);
331 }
332 else if (name.equals(LONGITUDINAL_Q)) {
333 doQOut(
334 (WQKms) artifactAndFacet.getData(context),
335 artifactAndFacet,
336 attr,
337 visible);
338 }
339 else if (name.equals(LONGITUDINAL_ANNOTATION)) {
340 doAnnotations(
341 (FLYSAnnotation) artifactAndFacet.getData(context),
342 artifactAndFacet,
343 attr,
344 visible);
345 }
346 else if (name.equals(STATIC_WQKMS_Q)) {
347 doQOut(
348 (WQKms) artifactAndFacet.getData(context),
349 artifactAndFacet,
350 attr,
351 visible);
352 }
353 else if (name.equals(W_DIFFERENCES)) {
354 doWDifferencesOut(
355 (WKms) artifactAndFacet.getData(context),
356 artifactAndFacet,
357 attr,
358 visible);
359 }
360 else if (FacetTypes.IS.AREA(name)) {
361 doArea(
362 artifactAndFacet.getData(context),
363 artifactAndFacet,
364 attr,
365 visible);
366 }
367 else if (FacetTypes.IS.MANUALPOINTS(name)) {
368 doPoints(
369 artifactAndFacet.getData(context),
370 artifactAndFacet,
371 attr,
372 visible,
373 YAXIS.W.idx);
374 }
375 else {
376 logger.warn("Unknown facet name: " + name);
377 return;
378 }
379 }
380
381 /**
382 * Add items to dataseries which describes the differences.
383 */
384 protected void doWDifferencesOut(
385 WKms wkms,
386 ArtifactAndFacet aandf,
387 Document theme,
388 boolean visible
389 ) {
390 logger.debug("WDifferencesCurveGenerator.doWDifferencesOut");
391 if (wkms == null) {
392 logger.warn("No data to add to WDifferencesChart.");
393 return;
394 }
395
396 XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
397
398 if (logger.isDebugEnabled()) {
399 if (wkms.size() > 0) {
400 logger.debug("Generate series: " + series.getKey());
401 logger.debug("Start km: " + wkms.getKm(0));
402 logger.debug("End km: " + wkms.getKm(wkms.size() - 1));
403 logger.debug("Values : " + wkms.size());
404 }
405 }
406
407 StyledSeriesBuilder.addPoints(series, wkms);
408
409 addAxisSeries(series, YAXIS.D.idx, visible);
410 if (DataUtil.guessWaterIncreasing(wkms.allWs())) {
411 setInverted(true);
412 }
413 }
414
415
416 /**
417 * Process the output for Q facets in a longitudinal section curve.
418 *
419 * @param wqkms An array of WQKms values.
420 * @param aandf The facet and artifact. This facet does NOT support any data objects. Use
421 * FLYSArtifact.getNativeFacet() instead to retrieve a Facet which supports
422 * data.
423 * @param theme The theme that contains styling information.
424 * @param visible The visibility of the curve.
425 */
426 protected void doQOut(
427 WQKms wqkms,
428 ArtifactAndFacet aandf,
429 Document theme,
430 boolean visible
431 ) {
432 logger.debug("LongitudinalSectionGenerator.doQOut");
433
434 XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
435
436 StyledSeriesBuilder.addStepPointsKmQ(series, wqkms);
437
438 addAxisSeries(series, YAXIS.Q.idx, visible);
439
440 if (needInvertAxis(wqkms)) {
441 setInverted(true);
442 }
443 }
444
445 /**
446 * This method determines - taking JFreeCharts auto x value ordering into
447 * account - if the x axis need to be inverted. Waterlines in these charts
448 * should decrease.
449 *
450 * @param wkms The data object that stores the x and y values used for this
451 * chart.
452 */
453 public boolean needInvertAxis(WKms wkms) {
454 boolean wsUp = wkms.guessWaterIncreasing();
455 boolean kmUp = DataUtil.guessWaterIncreasing(wkms.allKms());
456 boolean inv = (wsUp && kmUp) || (!wsUp && !kmUp);
457
458 int size = wkms.size();
459
460 if (logger.isDebugEnabled()) {
461 logger.debug("(Wkms)Values : " + size);
462 if (size > 0) {
463 logger.debug("Start km: " + wkms.getKm(0));
464 logger.debug("End km: " + wkms.getKm(size-1));
465 }
466 logger.debug("wsUp: " + wsUp);
467 logger.debug("kmUp: " + kmUp);
468 logger.debug("inv: " + inv);
469 }
470
471 return inv;
472 }
473
474
475 /**
476 * Get name of series (displayed in legend).
477 * @return name of the series.
478 */
479 protected String getSeriesName(WQKms wqkms, String mode) {
480 String name = wqkms.getName();
481 String prefix = name != null && name.indexOf(mode) >= 0 ? null : mode;
482
483 return prefix != null && prefix.length() > 0
484 ? prefix + "(" + name +")"
485 : name;
486 }
487
488
489 /** Look up the axis identifier for a given facet type. */
490 public int axisIdxForFacet(String facetName) {
491 if (FacetTypes.IS.W(facetName)) {
492 return YAXIS.W.idx;
493 }
494 else if (FacetTypes.IS.Q(facetName)) {
495 return YAXIS.Q.idx;
496 }
497 else {
498 logger.warn("Could not find axis for facet " + facetName);
499 return YAXIS.W.idx;
500 }
501 }
502
503
504 /**
505 * Do Area out.
506 * @param theme styling information.
507 * @param visible whether or not visible.
508 */
509 protected void doArea(
510 Object o,
511 ArtifactAndFacet aandf,
512 Document theme,
513 boolean visible
514 ) {
515 logger.debug("LongitudinalSectionGenerator.doArea");
516 StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(theme);
517
518 String seriesName = aandf.getFacetDescription();
519
520 AreaFacet.Data data = (AreaFacet.Data) o;
521
522 XYSeries up = null;
523 XYSeries down = null;
524
525 if (data.getUpperData() != null) {
526 up = new StyledXYSeries(seriesName, false, theme);
527 if (data.getUpperData() instanceof WQKms) {
528 if (FacetTypes.IS.Q(data.getRootFacetName())) {
529 StyledSeriesBuilder.addPointsKmQ(up, (WQKms) data.getUpperData());
530 }
531 else {
532 StyledSeriesBuilder.addPoints(up, (WKms) data.getUpperData());
533 }
534 }
535 else if (data.getUpperData() instanceof double[][]) {
536 StyledSeriesBuilder.addPoints(up, (double [][]) data.getUpperData(), false);
537 }
538 else if (data.getUpperData() instanceof WKms) {
539 StyledSeriesBuilder.addPoints(up, (WKms) data.getUpperData());
540 }
541 else if (data.getUpperData() instanceof Lines.LineData) {
542 StyledSeriesBuilder.addPoints(up, ((Lines.LineData) data.getUpperData()).points, false);
543 }
544 else {
545 logger.error("Do not know how to deal with (up) area info from: "
546 + data.getUpperData());
547 }
548 }
549
550 // TODO Depending on style, the area (e.g. 20m^2) should be added as annotation.
551
552 if (data.getLowerData() != null) {
553 // TODO: Sort this out: when the two series have the same name,
554 // the renderer (or anything in between) will not work correctly.
555 down = new StyledXYSeries(seriesName + " ", false, theme);
556 if (data.getLowerData() instanceof WQKms) {
557 if (FacetTypes.IS.Q(data.getRootFacetName())) {
558 StyledSeriesBuilder.addPointsKmQ(down, (WQKms) data.getLowerData());
559 }
560 else {
561 StyledSeriesBuilder.addPoints(down, (WQKms) data.getLowerData());
562 }
563 }
564 else if (data.getLowerData() instanceof double[][]) {
565 StyledSeriesBuilder.addPoints(down, (double[][]) data.getLowerData(), false);
566 }
567 else if (data.getLowerData() instanceof WKms) {
568 StyledSeriesBuilder.addPoints(down, (WKms) data.getLowerData());
569 }
570 else if (data.getLowerData() instanceof Lines.LineData) {
571 StyledSeriesBuilder.addPoints(down, ((Lines.LineData) data.getLowerData()).points, false);
572 }
573 else {
574 logger.error("Do not know how to deal with (down) area info from: "
575 + data.getLowerData());
576 }
577 }
578
579 if (up == null && down != null) {
580 area.setMode(StyledAreaSeriesCollection.FILL_MODE.ABOVE);
581 down.setKey(seriesName);
582 area.addSeries(down);
583 area.addSeries(StyledSeriesBuilder.createGroundAtInfinity(down));
584 }
585 else if (up != null && down == null) {
586 area.setMode(StyledAreaSeriesCollection.FILL_MODE.UNDER);
587 area.addSeries(up);
588 area.addSeries(StyledSeriesBuilder.createGroundAtInfinity(up));
589 }
590 else if (up != null && down != null) {
591 if (data.doPaintBetween()) {
592 area.setMode(StyledAreaSeriesCollection.FILL_MODE.BETWEEN);
593 }
594 else {
595 area.setMode(StyledAreaSeriesCollection.FILL_MODE.ABOVE);
596 }
597 area.addSeries(up);
598 area.addSeries(down);
599 }
600 // Add area to the respective axis.
601 addAreaSeries(area, axisIdxForFacet(data.getRootFacetName()), visible);
602 }
603 }
604 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org