rrenkert@8181: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde rrenkert@8181: * Software engineering by Intevation GmbH rrenkert@8181: * rrenkert@8181: * This file is Free Software under the GNU AGPL (>=v3) rrenkert@8181: * and comes with ABSOLUTELY NO WARRANTY! Check out the rrenkert@8181: * documentation coming with Dive4Elements River for details. rrenkert@8181: */ rrenkert@8181: rrenkert@8181: package org.dive4elements.river.exports.process; rrenkert@8181: rrenkert@8181: import java.util.ArrayList; rrenkert@8181: import java.util.List; rrenkert@8181: rrenkert@8181: import org.apache.log4j.Logger; rrenkert@8181: import org.jfree.data.xy.XYSeries; rrenkert@8181: rrenkert@8181: import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; rrenkert@8181: import org.dive4elements.artifacts.CallContext; rrenkert@8354: import org.dive4elements.artifacts.CallMeta; rrenkert@8354: import org.dive4elements.river.artifacts.D4EArtifact; rrenkert@8354: import org.dive4elements.river.artifacts.access.RiverAccess; rrenkert@8181: import org.dive4elements.river.artifacts.model.FacetTypes; rrenkert@8181: import org.dive4elements.river.artifacts.model.WQKms; rrenkert@8354: import org.dive4elements.river.artifacts.resources.Resources; rrenkert@8181: import org.dive4elements.river.exports.DiagramGenerator; rrenkert@8181: import org.dive4elements.river.exports.DischargeCurveGenerator; rrenkert@8181: import org.dive4elements.river.exports.StyledSeriesBuilder; rrenkert@8181: import org.dive4elements.river.exports.XYChartGenerator; rrenkert@8181: import org.dive4elements.river.jfree.CollisionFreeXYTextAnnotation; rrenkert@8181: import org.dive4elements.river.jfree.RiverAnnotation; rrenkert@8181: import org.dive4elements.river.jfree.StickyAxisAnnotation; rrenkert@8188: import org.dive4elements.river.jfree.StyledValueMarker; rrenkert@8181: import org.dive4elements.river.jfree.StyledXYSeries; rrenkert@8181: import org.dive4elements.river.themes.ThemeDocument; rrenkert@8181: rrenkert@8181: import org.jfree.chart.annotations.XYTextAnnotation; rrenkert@8181: rrenkert@8181: rrenkert@8181: /** Helper for data handling in discharge diagrams. */ rrenkert@8181: public class MiscDischargeProcessor rrenkert@8181: extends DefaultProcessor implements FacetTypes { rrenkert@8181: teichmann@8202: private final static Logger log = rrenkert@8181: Logger.getLogger(MiscDischargeProcessor.class); rrenkert@8181: rrenkert@8181: /** Station for which the diagram is shown. */ rrenkert@8181: private double km; rrenkert@8181: rrenkert@8181: /** Tolerance for comparison of kilometers. */ rrenkert@8181: public static final double KM_EPSILON = 0.001d; rrenkert@8181: rrenkert@8354: private String I18N_AXIS_LABEL = "chart.discharge.curve.yaxis.label"; rrenkert@8181: rrenkert@8181: /** This processor needs to be constructed with a given km. */ rrenkert@8181: public MiscDischargeProcessor() { rrenkert@8181: km = Double.NaN; rrenkert@8181: } rrenkert@8181: rrenkert@8181: rrenkert@8181: public MiscDischargeProcessor(double km) { rrenkert@8181: this.km = km; rrenkert@8181: } rrenkert@8181: rrenkert@8181: public void doOut( rrenkert@8181: DiagramGenerator generator, rrenkert@8181: ArtifactAndFacet bundle, rrenkert@8181: ThemeDocument theme, rrenkert@8181: boolean visible) { gernotbelger@9123: CallContext context = generator.getContext(); rrenkert@8181: Object data = bundle.getData(context); rrenkert@8188: if (HISTORICAL_DISCHARGE_WQ_Q.equals(bundle.getFacetName())) { rrenkert@8188: doHistoricalDischargeOutQ(generator, bundle, theme, visible); rrenkert@8188: } rrenkert@8188: else if (HISTORICAL_DISCHARGE_WQ_W.equals(bundle.getFacetName())) { rrenkert@8188: doHistoricalDischargeOutW(generator, bundle, theme, visible); rrenkert@8188: } rrenkert@8188: else if (data instanceof WQKms) { rrenkert@8181: doWQKmsPointOut( rrenkert@8181: generator, (WQKms) data, bundle, theme, visible); rrenkert@8181: return; rrenkert@8181: } tom@8341: if (MAINVALUES_W.equals(bundle.getFacetName())) { tom@8341: doYRiverAnnotationOut( tom@8341: generator, (RiverAnnotation)data, theme, visible); tom@8341: return; tom@8341: } rrenkert@8181: else if (data instanceof RiverAnnotation) { rrenkert@8181: doRiverAnnotationOut( tom@8341: generator, (RiverAnnotation)data, theme, visible); rrenkert@8181: return; rrenkert@8181: } rrenkert@8181: else if (data instanceof double[][]) { rrenkert@8181: doPointsOut(generator, (double[][])data, bundle, theme, visible); rrenkert@8181: } rrenkert@8181: else { teichmann@8202: log.error("Can't process " rrenkert@8181: + data.getClass().getName() + " objects of facet " rrenkert@8181: + bundle.getFacetName()); rrenkert@8181: } rrenkert@8181: } rrenkert@8181: rrenkert@8181: /** Process data, add it to plot. */ rrenkert@8181: @Override rrenkert@8181: public void doOut( rrenkert@8181: XYChartGenerator generator, rrenkert@8181: ArtifactAndFacet bundle, rrenkert@8181: ThemeDocument theme, rrenkert@8181: boolean visible, rrenkert@8181: int axisIndex rrenkert@8181: ) { gernotbelger@9123: CallContext context = generator.getContext(); rrenkert@8181: Object data = bundle.getData(context); rrenkert@8181: /* TODO: Remove the first case.*/ rrenkert@8181: if (bundle.getFacetName().equals(STATIC_WQ)) { rrenkert@8181: doPointOut( rrenkert@8181: generator, bundle, theme, visible, axisIndex); rrenkert@8181: } rrenkert@8181: else if (data instanceof WQKms) { rrenkert@8181: doWQKmsPointOut( rrenkert@8181: generator, (WQKms) data, bundle, theme, visible, axisIndex); rrenkert@8181: return; rrenkert@8181: } rrenkert@8181: else if (data instanceof RiverAnnotation) { rrenkert@8181: doRiverAnnotationOut( rrenkert@8181: generator, (RiverAnnotation) data, bundle, theme, visible); rrenkert@8181: return; rrenkert@8181: } rrenkert@8181: else if (data instanceof double[][]) { rrenkert@8181: doMarksOut( rrenkert@8181: generator, (double[][]) data, bundle, theme, visible); rrenkert@8181: return; rrenkert@8181: } rrenkert@8181: else { teichmann@8202: log.error("Can't process " rrenkert@8181: + data.getClass().getName() + " objects of facet " rrenkert@8181: + bundle.getFacetName()); rrenkert@8181: } rrenkert@8181: } rrenkert@8181: rrenkert@8181: private void doPointOut(XYChartGenerator generator, rrenkert@8181: ArtifactAndFacet bundle, rrenkert@8181: ThemeDocument theme, rrenkert@8181: boolean visible, rrenkert@8181: int axisIndex rrenkert@8181: ) { gernotbelger@9556: XYSeries series = new StyledXYSeries(bundle.getFacetName(), tom@8856: bundle.getFacetDescription(), theme); gernotbelger@9123: Object wq = bundle.getData(generator.getContext()); rrenkert@8181: if (wq instanceof double[][]) { rrenkert@8181: double [][] data = (double [][]) wq; rrenkert@8181: StyledSeriesBuilder.addPoints(series, data, true); rrenkert@8181: } else if (wq instanceof WQKms) { rrenkert@8181: WQKms wqkms = (WQKms) wq; rrenkert@8181: StyledSeriesBuilder.addPointsQW(series, (WQKms) wq); rrenkert@8181: } rrenkert@8181: rrenkert@8181: generator.addAxisSeries(series, axisIndex, visible); rrenkert@8181: } rrenkert@8181: rrenkert@8181: /** Handle WQKms data by finding w/q values at given km. */ rrenkert@8181: protected void doWQKmsPointOut(XYChartGenerator generator, rrenkert@8181: WQKms wqkms, rrenkert@8181: ArtifactAndFacet bundle, rrenkert@8181: ThemeDocument theme, rrenkert@8181: boolean visible, rrenkert@8181: int axidx rrenkert@8181: ) { teichmann@8202: log.debug("doWQKmsPointOut"); rrenkert@8181: String title = bundle.getFacetDescription(); gernotbelger@9556: XYSeries series = new StyledXYSeries(bundle.getFacetName(), rrenkert@8181: title, rrenkert@8181: theme); rrenkert@8181: rrenkert@8181: double[] kms = wqkms.getKms(); rrenkert@8181: rrenkert@8181: for (int i = 0 ; i< kms.length; i++) { rrenkert@8181: if (Math.abs(kms[i] - getKm()) <= KM_EPSILON) { rrenkert@8181: series.add(wqkms.getQ(i), wqkms.getW(i)); rrenkert@8181: generator.addAxisSeries(series, axidx, visible); rrenkert@8181: if(visible && theme.parseShowPointLabel()) { tom@8856: List textAnnos = tom@8856: new ArrayList(); rrenkert@8181: XYTextAnnotation anno = new CollisionFreeXYTextAnnotation( rrenkert@8181: title, rrenkert@8181: wqkms.getQ(i), rrenkert@8181: // TODO add a percentage to the extend of W axis rrenkert@8181: wqkms.getW(i)); rrenkert@8181: textAnnos.add(anno); tom@8856: RiverAnnotation flysAnno = tom@8856: new RiverAnnotation(null, null, null, theme); rrenkert@8181: flysAnno.setTextAnnotations(textAnnos); rrenkert@8181: generator.addAnnotations(flysAnno); rrenkert@8181: } rrenkert@8181: return; rrenkert@8181: } rrenkert@8181: } rrenkert@8181: teichmann@8202: log.warn("No WQ found for km " + getKm()); rrenkert@8181: } rrenkert@8181: rrenkert@8181: protected void doRiverAnnotationOut(XYChartGenerator generator, rrenkert@8181: RiverAnnotation annotations, rrenkert@8181: ArtifactAndFacet bundle, rrenkert@8181: ThemeDocument theme, rrenkert@8181: boolean visible rrenkert@8181: ) { rrenkert@8181: if (!(generator instanceof DischargeCurveGenerator)) { teichmann@8202: log.error("DischargeProcessor can only be used in " + tom@8316: "DischargeCurveGenerator-classes."); rrenkert@8181: return; rrenkert@8181: } teichmann@8202: log.debug("doRiverAnnotationOut"); rrenkert@8181: DischargeCurveGenerator dGenerator = rrenkert@8181: (DischargeCurveGenerator) generator; rrenkert@8181: rrenkert@8181: dGenerator.translateRiverAnnotation(annotations); rrenkert@8181: dGenerator.doAnnotations( rrenkert@8181: annotations, rrenkert@8181: bundle, theme, visible); rrenkert@8181: } rrenkert@8181: rrenkert@8181: rrenkert@8181: /** rrenkert@8181: * Put Sticky Axis Markers to Y-axis for each value. rrenkert@8181: * @param data [[-,y1],[-,y2],...] ('x'-coordinates ignored) rrenkert@8181: */ rrenkert@8181: protected void doMarksOut(XYChartGenerator generator, rrenkert@8181: double[][] data, rrenkert@8181: ArtifactAndFacet bundle, rrenkert@8181: ThemeDocument theme, rrenkert@8181: boolean visible rrenkert@8181: ) { teichmann@8202: log.debug("doMarksOut"); rrenkert@8181: rrenkert@8181: if (!visible) { rrenkert@8181: return; rrenkert@8181: } rrenkert@8181: rrenkert@8181: // TODO subtract gauge null point if at gauge. rrenkert@8181: String title = bundle.getFacetDescription(); tom@8856: List yMarks = tom@8856: new ArrayList(); rrenkert@8181: rrenkert@8181: for (double yPos: data[1]) { rrenkert@8181: yMarks.add(new StickyAxisAnnotation( rrenkert@8181: title, rrenkert@8181: (float) yPos, rrenkert@8181: StickyAxisAnnotation.SimpleAxis.Y_AXIS)); rrenkert@8181: } rrenkert@8181: rrenkert@8181: generator.doAnnotations(new RiverAnnotation(title, yMarks), rrenkert@8181: bundle, theme, visible); rrenkert@8181: } rrenkert@8181: rrenkert@8181: /** True if this processor knows how to deal with facetType. */ rrenkert@8181: @Override rrenkert@8181: public boolean canHandle(String facetType) { rrenkert@8181: return STATIC_WQKMS_W.equals(facetType) rrenkert@8181: || MAINVALUES_Q.equals(facetType) rrenkert@8181: || MAINVALUES_W.equals(facetType) rrenkert@8181: || STATIC_W_INTERPOL.equals(facetType) rrenkert@8181: || STATIC_WQ.equals(facetType) rrenkert@8188: || STATIC_WQ_ANNOTATIONS.equals(facetType) rrenkert@8188: || HISTORICAL_DISCHARGE_WQ_W.equals(facetType) rrenkert@8188: || HISTORICAL_DISCHARGE_WQ_Q.equals(facetType); rrenkert@8181: } rrenkert@8181: rrenkert@8181: rrenkert@8181: /** The station of the current calculation/view. */ rrenkert@8181: protected double getKm() { rrenkert@8181: return km; rrenkert@8181: } rrenkert@8181: rrenkert@8188: protected void doHistoricalDischargeOutQ( rrenkert@8188: DiagramGenerator generator, rrenkert@8188: ArtifactAndFacet bundle, rrenkert@8188: ThemeDocument theme, rrenkert@8188: boolean visible rrenkert@8188: ) { rrenkert@8188: double value = Double.valueOf( gernotbelger@9123: bundle.getData(generator.getContext()).toString()); tom@8856: generator.addDomainMarker( tom@8856: new StyledValueMarker(value, theme), visible); rrenkert@8188: } rrenkert@8188: rrenkert@8188: protected void doHistoricalDischargeOutW( rrenkert@8188: DiagramGenerator generator, rrenkert@8188: ArtifactAndFacet bundle, rrenkert@8188: ThemeDocument theme, rrenkert@8188: boolean visible rrenkert@8188: ) { rrenkert@8188: double value = Double.valueOf( gernotbelger@9123: bundle.getData(generator.getContext()).toString()); tom@8856: generator.addValueMarker( tom@8856: new StyledValueMarker(value, theme), visible); rrenkert@8188: } rrenkert@8188: rrenkert@8181: private void doPointsOut( rrenkert@8181: DiagramGenerator generator, rrenkert@8181: double[][] data, rrenkert@8181: ArtifactAndFacet bundle, rrenkert@8181: ThemeDocument theme, rrenkert@8181: boolean visible rrenkert@8181: ) { gernotbelger@9556: XYSeries series = new StyledXYSeries(bundle.getFacetName(), tom@8856: bundle.getFacetDescription(), theme); rrenkert@8181: StyledSeriesBuilder.addPoints(series, data, true); rrenkert@8181: generator.addAxisSeries(series, axisName, visible); rrenkert@8181: } rrenkert@8181: rrenkert@8181: /** Handle WQKms data by finding w/q values at given km. */ rrenkert@8181: protected void doWQKmsPointOut( rrenkert@8181: DiagramGenerator generator, rrenkert@8181: WQKms wqkms, rrenkert@8181: ArtifactAndFacet bundle, rrenkert@8181: ThemeDocument theme, rrenkert@8181: boolean visible rrenkert@8181: ) { teichmann@8202: log.debug("doWQKmsPointOut"); rrenkert@8181: String title = bundle.getFacetDescription(); gernotbelger@9556: XYSeries series = new StyledXYSeries(bundle.getFacetName(), rrenkert@8181: title, rrenkert@8181: theme); rrenkert@8181: rrenkert@8181: double[] kms = wqkms.getKms(); rrenkert@8181: rrenkert@8181: for (int i = 0 ; i< kms.length; i++) { rrenkert@8181: if (Math.abs(kms[i] - getKm()) <= KM_EPSILON) { rrenkert@8181: series.add(wqkms.getQ(i), wqkms.getW(i)); rrenkert@8181: generator.addAxisSeries(series, axisName, visible); rrenkert@8181: if(visible && theme.parseShowPointLabel()) { tom@8856: List textAnnos = tom@8856: new ArrayList(); rrenkert@8181: XYTextAnnotation anno = new CollisionFreeXYTextAnnotation( rrenkert@8181: title, rrenkert@8181: wqkms.getQ(i), rrenkert@8181: // TODO add a percentage to the extend of W axis rrenkert@8181: wqkms.getW(i)); rrenkert@8181: textAnnos.add(anno); tom@8856: RiverAnnotation flysAnno = new RiverAnnotation( tom@8856: null, null, null, theme); rrenkert@8181: flysAnno.setTextAnnotations(textAnnos); rrenkert@8181: generator.addAnnotations(flysAnno); rrenkert@8181: } rrenkert@8181: return; rrenkert@8181: } rrenkert@8181: } rrenkert@8181: teichmann@8202: log.warn("No WQ found for km " + getKm()); rrenkert@8181: } rrenkert@8181: tom@8341: protected void doYRiverAnnotationOut(DiagramGenerator generator, tom@8341: RiverAnnotation annotations, tom@8341: ThemeDocument theme, tom@8341: boolean visible tom@8341: ) { tom@8341: if (visible) { tom@8341: annotations.setTheme(theme); tom@8341: generator.addYAnnotation(annotations, axisName); tom@8341: } tom@8341: } tom@8341: rrenkert@8181: protected void doRiverAnnotationOut(DiagramGenerator generator, rrenkert@8181: RiverAnnotation annotations, rrenkert@8181: ThemeDocument theme, rrenkert@8181: boolean visible rrenkert@8181: ) { rrenkert@8181: if (visible) { rrenkert@8181: annotations.setTheme(theme); rrenkert@8181: generator.addAnnotations(annotations); rrenkert@8181: } rrenkert@8181: } rrenkert@8354: rrenkert@8354: @Override rrenkert@8354: public String getAxisLabel(DiagramGenerator generator) { gernotbelger@9123: CallMeta meta = generator.getContext().getMeta(); tom@8856: RiverAccess access = new RiverAccess((D4EArtifact)generator tom@8856: .getMaster()); rrenkert@8354: String unit = access.getRiver().getWstUnit().getName(); rrenkert@8354: rrenkert@8354: return Resources.getMsg( rrenkert@8354: meta, rrenkert@8354: I18N_AXIS_LABEL, rrenkert@8354: new Object[] { unit }); rrenkert@8354: } rrenkert@8181: } rrenkert@8181: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :