teichmann@5863: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@5863: * Software engineering by Intevation GmbH teichmann@5863: * teichmann@5994: * This file is Free Software under the GNU AGPL (>=v3) teichmann@5863: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@5994: * documentation coming with Dive4Elements River for details. teichmann@5863: */ teichmann@5863: teichmann@5831: package org.dive4elements.river.exports.fixings; raimund@3169: raimund@3169: import java.awt.BasicStroke; raimund@3169: import java.awt.Color; raimund@3169: raimund@3169: import org.apache.log4j.Logger; rrenkert@6439: import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; rrenkert@6439: import org.dive4elements.river.artifacts.D4EArtifact; rrenkert@6439: import org.dive4elements.river.artifacts.model.FacetTypes; rrenkert@6439: import org.dive4elements.river.artifacts.model.WKms; rrenkert@6439: import org.dive4elements.river.artifacts.model.WQKms; rrenkert@6439: import org.dive4elements.river.artifacts.model.fixings.AnalysisPeriod; rrenkert@6439: import org.dive4elements.river.artifacts.model.fixings.QWD; rrenkert@6439: import org.dive4elements.river.exports.ChartGenerator; rrenkert@6439: import org.dive4elements.river.exports.StyledSeriesBuilder; rrenkert@6439: import org.dive4elements.river.exports.process.KMIndexProcessor; rrenkert@6439: import org.dive4elements.river.exports.process.Processor; rrenkert@6439: import org.dive4elements.river.exports.process.WOutProcessor; rrenkert@6439: import org.dive4elements.river.jfree.RiverAnnotation; rrenkert@6439: import org.dive4elements.river.jfree.StyledAreaSeriesCollection; rrenkert@6439: import org.dive4elements.river.jfree.StyledXYSeries; teichmann@6905: import org.dive4elements.river.themes.ThemeDocument; rrenkert@6439: import org.dive4elements.river.utils.DataUtil; rrenkert@6439: import org.dive4elements.river.utils.KMIndex; rrenkert@6439: import org.dive4elements.river.utils.RiverUtils; raimund@3169: import org.jfree.chart.plot.Marker; raimund@3169: import org.jfree.chart.plot.ValueMarker; christian@3286: import org.jfree.data.xy.XYSeries; sascha@3612: raimund@3169: public class FixLongitudinalSectionGenerator bjoern@4446: extends FixChartGenerator raimund@3169: implements FacetTypes raimund@3169: { raimund@3169: private static Logger logger = christian@3770: Logger.getLogger(FixLongitudinalSectionGenerator.class); raimund@3169: raimund@3169: public static final String I18N_CHART_TITLE = christian@3770: "chart.fixings.longitudinalsection.title"; raimund@3169: raimund@3169: public static final String I18N_CHART_SUBTITLE = christian@3770: "chart.fixings.longitudinalsection.subtitle"; raimund@3169: raimund@3169: public static final String I18N_XAXIS_LABEL = christian@3770: "chart.fixings.longitudinalsection.xaxis.label"; raimund@3169: raimund@3169: public static final String I18N_CHART_TITLE_DEFAULT = christian@3770: "Fixierungsanalyse"; raimund@3169: raimund@3169: public static final String I18N_XAXIS_LABEL_DEFAULT = christian@3770: "[km]"; raimund@3169: bjoern@4446: public static final String I18N_DW_YAXIS_LABEL_DEFAULT = bjoern@4446: "delta W [cm]"; bjoern@4446: bjoern@4446: public static final String I18N_DW_YAXIS_LABEL = bjoern@4446: "chart.fixings.longitudinalsection.yaxis.label"; raimund@3169: rrenkert@6439: public static final String I18N_W_YAXIS_LABEL = rrenkert@6439: "chart.longitudinal.section.yaxis.label"; rrenkert@6439: rrenkert@6439: public static final String I18N_Q_YAXIS_LABEL = rrenkert@6439: "chart.longitudinal.section.yaxis.second.label"; rrenkert@6439: rrenkert@6439: public static final String I18N_W_YAXIS_LABEL_DEFAULT = "W [NN + m]"; rrenkert@6439: public static final String I18N_Q_YAXIS_LABEL_DEFAULT = "Q [m\u00b3/s]"; rrenkert@6439: raimund@3169: public static enum YAXIS { rrenkert@6439: dW(0), W(1), Q(2); raimund@3169: public int idx; raimund@3169: private YAXIS(int c) { raimund@3169: idx = c; raimund@3169: } raimund@3169: } raimund@3169: raimund@3169: @Override teichmann@6905: public void doOut(ArtifactAndFacet aaf, ThemeDocument doc, boolean visible) { raimund@3169: String name = aaf.getFacetName(); felix@3579: logger.debug("FixLongitudinalSectionGenerator: doOut: " + name); raimund@3169: bjoern@4446: Processor processor = new KMIndexProcessor(); rrenkert@6439: Processor wProcessor = new WOutProcessor(); raimund@3169: if (name.contains(FIX_SECTOR_AVERAGE_LS_DEVIATION)) { raimund@3169: doSectorAverageDeviationOut(aaf, doc, visible); raimund@3169: } bjoern@4446: else if (processor.canHandle(name)) { bjoern@4446: processor.doOut(this, aaf, doc, visible, YAXIS.dW.idx); raimund@3169: } rrenkert@6439: else if (wProcessor.canHandle(name)) { rrenkert@6439: wProcessor.doOut(this, aaf, doc, visible, YAXIS.W.idx); rrenkert@6439: } rrenkert@6439: else if (name.equals(STATIC_WQKMS_Q)) { rrenkert@6439: doQOut( rrenkert@6439: (WQKms) aaf.getData(context), rrenkert@6439: aaf, rrenkert@6439: doc, rrenkert@6439: visible); rrenkert@6439: } raimund@3169: else if (name.equals(FIX_DEVIATION_LS)) { raimund@3169: doReferenceDeviationOut(aaf, doc, visible); raimund@3169: } felix@3579: else if (name.equals(LONGITUDINAL_ANNOTATION)) { felix@3579: doAnnotations( teichmann@5864: (RiverAnnotation) aaf.getData(context), christian@3770: aaf, christian@3770: doc, christian@3770: visible); christian@3770: } christian@3770: else if (FacetTypes.IS.MANUALPOINTS(name)) { christian@3770: doPoints (aaf.getData(context), christian@3770: aaf, christian@3770: doc, visible, YAXIS.dW.idx); felix@3579: } raimund@3169: else { raimund@3169: logger.warn("Unknown facet name " + name); raimund@3169: } raimund@3169: } raimund@3169: rrenkert@6439: /** rrenkert@6439: * Process the output for Q facets in a longitudinal section curve. rrenkert@6439: * rrenkert@6439: * @param wqkms An array of WQKms values. rrenkert@6439: * @param aandf The facet and artifact. This facet does NOT support any data objects. Use rrenkert@6439: * D4EArtifact.getNativeFacet() instead to retrieve a Facet which supports rrenkert@6439: * data. rrenkert@6439: * @param theme The theme that contains styling information. rrenkert@6439: * @param visible The visibility of the curve. rrenkert@6439: */ rrenkert@6439: protected void doQOut( rrenkert@6439: WQKms wqkms, rrenkert@6439: ArtifactAndFacet aandf, teichmann@6905: ThemeDocument theme, rrenkert@6439: boolean visible rrenkert@6439: ) { rrenkert@6439: logger.debug("LongitudinalSectionGenerator.doQOut"); rrenkert@6439: rrenkert@6439: XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); rrenkert@6439: rrenkert@6439: StyledSeriesBuilder.addStepPointsKmQ(series, wqkms); rrenkert@6439: rrenkert@6439: addAxisSeries(series, YAXIS.Q.idx, visible); rrenkert@6439: rrenkert@6439: if (needInvertAxis(wqkms)) { rrenkert@6439: setInverted(true); rrenkert@6439: } rrenkert@6439: } rrenkert@6439: rrenkert@6439: /** rrenkert@6439: * This method determines - taking JFreeCharts auto x value ordering into rrenkert@6439: * account - if the x axis need to be inverted. Waterlines in these charts rrenkert@6439: * should decrease. rrenkert@6439: * rrenkert@6439: * @param wkms The data object that stores the x and y values used for this rrenkert@6439: * chart. rrenkert@6439: */ rrenkert@6439: public boolean needInvertAxis(WKms wkms) { rrenkert@6439: boolean wsUp = wkms.guessWaterIncreasing(); rrenkert@6439: boolean kmUp = DataUtil.guessWaterIncreasing(wkms.allKms()); rrenkert@6439: boolean inv = (wsUp && kmUp) || (!wsUp && !kmUp); rrenkert@6439: rrenkert@6439: int size = wkms.size(); rrenkert@6439: rrenkert@6439: if (logger.isDebugEnabled()) { rrenkert@6439: logger.debug("(Wkms)Values : " + size); rrenkert@6439: if (size > 0) { rrenkert@6439: logger.debug("Start km: " + wkms.getKm(0)); rrenkert@6439: logger.debug("End km: " + wkms.getKm(size-1)); rrenkert@6439: } rrenkert@6439: logger.debug("wsUp: " + wsUp); rrenkert@6439: logger.debug("kmUp: " + kmUp); rrenkert@6439: logger.debug("inv: " + inv); rrenkert@6439: } rrenkert@6439: rrenkert@6439: return inv; rrenkert@6439: } rrenkert@6439: christian@3286: @SuppressWarnings("unchecked") raimund@3169: protected void doSectorAverageDeviationOut( christian@3770: ArtifactAndFacet aaf, teichmann@6905: ThemeDocument doc, christian@3770: boolean visible) raimund@3169: { raimund@3169: logger.debug("doSectorAverageOut" + aaf.getFacet().getIndex()); raimund@3169: raimund@3169: int index = aaf.getFacet().getIndex(); raimund@3169: int sectorNdx = index & 3; raimund@3169: raimund@3610: KMIndex kms = christian@3770: (KMIndex)aaf.getData(context); raimund@3169: raimund@3169: if(kms == null) { raimund@3169: return; raimund@3169: } raimund@3169: raimund@3169: StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(doc); raimund@3169: XYSeries upper = christian@3770: new StyledXYSeries(aaf.getFacetDescription(), false, doc); raimund@3169: XYSeries lower = christian@3770: new StyledXYSeries(aaf.getFacetDescription() + " ", false, doc); raimund@3169: raimund@3610: for (KMIndex.Entry entry: kms) { raimund@3169: double km = entry.getKm(); raimund@3610: AnalysisPeriod ap = entry.getValue(); raimund@3610: QWD qwd = ap.getQSectorAverages()[sectorNdx]; raimund@3610: double dev = ap.getQSectorStdDev(sectorNdx); raimund@3169: logger.debug("std-dev: " + dev); raimund@3169: if (qwd == null) { raimund@3169: continue; raimund@3169: } raimund@3169: double deltaW = qwd.getDeltaW(); raimund@3169: double up = deltaW + dev; raimund@3169: double lo = deltaW - dev; raimund@3169: upper.add(km, up); raimund@3169: lower.add(km, lo); raimund@3169: } raimund@3169: area.addSeries(upper); raimund@3169: area.addSeries(lower); raimund@3169: raimund@3169: addAreaSeries(area, 0, visible); raimund@3169: } raimund@3169: raimund@3169: christian@3286: @SuppressWarnings("unchecked") raimund@3169: protected void doReferenceDeviationOut( christian@3770: ArtifactAndFacet aaf, teichmann@6905: ThemeDocument doc, christian@3770: boolean visible) raimund@3169: { raimund@3169: logger.debug("doReferenceOut"); raimund@3169: raimund@3169: KMIndex kms = christian@3770: (KMIndex)aaf.getData(context); raimund@3169: raimund@3169: if(kms == null) { raimund@3169: return; raimund@3169: } raimund@3169: raimund@3169: StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(doc); raimund@3169: XYSeries upper = christian@3770: new StyledXYSeries(aaf.getFacetDescription(), false, doc); raimund@3169: XYSeries lower = christian@3770: new StyledXYSeries(aaf.getFacetDescription() + " ", false, doc); raimund@3169: raimund@3169: raimund@3169: for (KMIndex.Entry entry: kms) { raimund@3169: double km = entry.getKm(); raimund@3169: double[] devArray = entry.getValue(); raimund@3169: if (devArray == null) { raimund@3169: continue; raimund@3169: } raimund@3169: double dev = devArray[0]; raimund@3169: double up = dev; raimund@3169: double lo = -dev; sascha@3215: upper.add(km, up, false); sascha@3215: lower.add(km, lo, false); raimund@3169: } raimund@3169: area.addSeries(upper); raimund@3169: area.addSeries(lower); raimund@3169: raimund@3169: Marker marker = new ValueMarker(0); raimund@3169: marker.setStroke(new BasicStroke(2)); raimund@3169: marker.setPaint(Color.BLACK); raimund@3169: addValueMarker(marker); raimund@3169: addAreaSeries(area, 0, visible); raimund@3169: } raimund@3169: raimund@3169: @Override raimund@3169: protected String getDefaultChartTitle() { raimund@3169: return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT); raimund@3169: } raimund@3169: raimund@3169: @Override raimund@3169: protected String getDefaultXAxisLabel() { raimund@3169: return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT); raimund@3169: } raimund@3169: raimund@3169: @Override raimund@3169: protected String getDefaultYAxisLabel(int pos) { rrenkert@6439: if (pos == YAXIS.dW.idx) { rrenkert@6439: return msg(I18N_DW_YAXIS_LABEL, I18N_DW_YAXIS_LABEL_DEFAULT); rrenkert@6439: } rrenkert@6439: else if (pos == YAXIS.W.idx) { rrenkert@6439: D4EArtifact flys = (D4EArtifact) master; rrenkert@6439: String unit = RiverUtils.getRiver(flys).getWstUnit().getName(); rrenkert@6439: return msg( rrenkert@6439: I18N_W_YAXIS_LABEL, rrenkert@6439: I18N_W_YAXIS_LABEL_DEFAULT, rrenkert@6439: new Object[] { unit }); rrenkert@6439: } rrenkert@6439: else if (pos == YAXIS.Q.idx) { rrenkert@6439: return msg(I18N_Q_YAXIS_LABEL, I18N_Q_YAXIS_LABEL_DEFAULT); rrenkert@6439: } rrenkert@6439: return ""; raimund@3169: } raimund@3169: raimund@3169: @Override raimund@3169: protected ChartGenerator.YAxisWalker getYAxisWalker() { raimund@3169: return new YAxisWalker() { raimund@3169: @Override raimund@3169: public int length() { raimund@3169: return YAXIS.values().length; raimund@3169: } raimund@3169: raimund@3169: @Override christian@3770: public String getId(int idx) { raimund@3169: YAXIS[] yaxes = YAXIS.values(); raimund@3169: return yaxes[idx].toString(); raimund@3169: } raimund@3169: }; raimund@3169: } raimund@3169: } raimund@3169: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :