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; christian@3055: christian@3770: import java.awt.BasicStroke; christian@3770: import java.awt.Color; felix@6467: import java.awt.Font; christian@3770: import java.text.DateFormat; christian@3770: import java.util.ArrayList; christian@3770: import java.util.List; christian@3770: christian@3770: import org.apache.log4j.Logger; christian@3770: import org.jfree.chart.JFreeChart; christian@3770: import org.jfree.chart.annotations.XYTextAnnotation; felix@6467: import org.jfree.chart.axis.NumberAxis; christian@3770: import org.jfree.chart.plot.Marker; christian@3770: import org.jfree.chart.plot.ValueMarker; felix@6559: import org.jfree.chart.plot.XYPlot; christian@3770: import org.jfree.chart.title.TextTitle; christian@3770: import org.jfree.data.xy.XYSeries; christian@3770: import org.jfree.ui.RectangleAnchor; christian@3911: import org.jfree.ui.RectangleInsets; christian@3770: import org.jfree.ui.TextAnchor; christian@3770: teichmann@5831: import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; teichmann@5831: import org.dive4elements.artifactdatabase.state.Facet; teichmann@5867: import org.dive4elements.river.artifacts.D4EArtifact; teichmann@5831: import org.dive4elements.river.artifacts.StaticWKmsArtifact; teichmann@5831: import org.dive4elements.river.artifacts.WINFOArtifact; teichmann@5831: import org.dive4elements.river.artifacts.access.FixAnalysisAccess; teichmann@5831: import org.dive4elements.river.artifacts.model.DateRange; teichmann@5831: import org.dive4elements.river.artifacts.model.FacetTypes; teichmann@5831: import org.dive4elements.river.artifacts.model.NamedDouble; teichmann@5831: import org.dive4elements.river.artifacts.model.QWDDateRange; teichmann@5831: import org.dive4elements.river.artifacts.model.WKms; teichmann@5831: import org.dive4elements.river.artifacts.model.WQKms; teichmann@5831: import org.dive4elements.river.artifacts.model.fixings.FixFunction; teichmann@5831: import org.dive4elements.river.artifacts.model.fixings.FixWQCurveFacet; teichmann@5831: import org.dive4elements.river.artifacts.model.fixings.QWD; teichmann@5831: import org.dive4elements.river.artifacts.model.fixings.QWI; teichmann@5831: import org.dive4elements.river.artifacts.resources.Resources; teichmann@5831: import org.dive4elements.river.exports.ChartGenerator; felix@6467: import org.dive4elements.river.exports.DischargeCurveGenerator; felix@6467: import org.dive4elements.river.exports.SyncNumberAxis; teichmann@5831: import org.dive4elements.river.exports.StyledSeriesBuilder; teichmann@5831: import org.dive4elements.river.jfree.CollisionFreeXYTextAnnotation; teichmann@5864: import org.dive4elements.river.jfree.RiverAnnotation; teichmann@5831: import org.dive4elements.river.jfree.JFreeUtil; teichmann@5831: import org.dive4elements.river.jfree.StickyAxisAnnotation; teichmann@5831: import org.dive4elements.river.jfree.StyledXYSeries; teichmann@5831: import org.dive4elements.river.model.Gauge; teichmann@5831: import org.dive4elements.river.model.River; teichmann@6905: import org.dive4elements.river.themes.ThemeDocument; teichmann@5865: import org.dive4elements.river.utils.RiverUtils; christian@3055: christian@3254: /** christian@3286: * Generator for WQ fixing charts. christian@3254: * @author Christian Lins christian@3254: */ sascha@3076: public class FixWQCurveGenerator sascha@3215: extends FixChartGenerator sascha@3215: implements FacetTypes christian@3055: { felix@4147: /** Private logger. */ christian@3055: private static Logger logger = christian@3770: Logger.getLogger(FixWQCurveGenerator.class); christian@3055: christian@3055: public static final String I18N_CHART_TITLE = christian@3770: "chart.fixings.wq.title"; christian@3055: christian@3055: public static final String I18N_CHART_SUBTITLE = christian@3770: "chart.fixings.wq.subtitle"; christian@3055: christian@3410: public static final String I18N_CHART_SUBTITLE1 = christian@3770: "chart.fixings.wq.subtitle1"; christian@3410: christian@3055: public static final String I18N_XAXIS_LABEL = christian@3770: "chart.fixings.wq.xaxis.label"; christian@3055: christian@3055: public static final String I18N_YAXIS_LABEL = christian@3770: "chart.fixings.wq.yaxis.label"; christian@3055: christian@3055: public static final String I18N_CHART_TITLE_DEFAULT = christian@3770: "Fixierungsanalyse"; christian@3055: christian@3055: public static final String I18N_XAXIS_LABEL_DEFAULT = christian@3770: "Q [m\u00B3/s]"; christian@3055: christian@3055: public static final String I18N_YAXIS_LABEL_DEFAULT = christian@3770: "W [NN + m]"; christian@3055: felix@5739: public static final double EPSILON = 0.001d; felix@5739: christian@3055: public static enum YAXIS { felix@6467: WCm(0), felix@6467: W(1); christian@3055: public int idx; christian@3055: private YAXIS(int c) { christian@3055: idx = c; christian@3055: } christian@3055: } christian@3055: christian@3406: felix@4147: /** Needed to access data to create subtitle. */ teichmann@5867: protected D4EArtifact artifact; christian@3406: felix@6467: // TODO dupe of ComputedDischargeCurveGenerator felix@6467: protected SyncNumberAxis secondYAxis; felix@6467: // TODO dupe of ComputedDischargeCurveGenerator felix@6467: protected NumberAxis firstYAxis; felix@6467: felix@6467: felix@6467: /** felix@6467: * Create Y (range) axis for given index, here with a special axis felix@6467: * that depends on other axis (does translation and scaling for felix@6467: * special case at gauge in cm). felix@6467: */ felix@6467: // TODO dupe of ComputedDischargeCurveGenerator felix@6467: @Override felix@6467: protected NumberAxis createYAxis(int index) { felix@6467: logger.debug("createYAxis: " + index); felix@6467: if (index == 1) { felix@6467: firstYAxis = super.createYAxis(1); felix@6467: if (secondYAxis != null) { felix@6467: secondYAxis.setProxyAxis(firstYAxis); felix@6467: } felix@6467: return firstYAxis; felix@6467: } felix@6467: YAxisWalker walker = getYAxisWalker(); felix@6467: felix@6467: Font labelFont = new Font( felix@6467: DEFAULT_FONT_NAME, felix@6467: Font.BOLD, felix@6467: getYAxisFontSize(index)); felix@6467: felix@6467: SyncNumberAxis axis = new SyncNumberAxis( felix@6467: walker.getId(index), felix@6467: getYAxisLabel(index), felix@6467: firstYAxis); felix@6467: felix@6467: axis.setAutoRangeIncludesZero(false); felix@6467: axis.setLabelFont(labelFont); felix@6467: axis.setTickLabelFont(labelFont); felix@6467: axis.setShift((double)-getCurrentGaugeDatum()); felix@6467: felix@6467: secondYAxis = axis; felix@6467: return axis; felix@6467: } felix@6467: felix@6559: /** Returns value != 0 if the current km is not at a gauge. */ felix@6467: public double getCurrentGaugeDatum() { felix@6467: if (context.getContextValue(CURRENT_KM) != null) { felix@6467: return DischargeCurveGenerator.getCurrentGaugeDatum( felix@6467: (Double) context.getContextValue(CURRENT_KM), felix@6531: (D4EArtifact) getMaster(), 1e-4); felix@6467: } felix@6467: else return 0d; felix@6467: } felix@6467: felix@6559: /** Overriden to show second axis also if no visible data present. */ felix@6559: @Override felix@6559: protected void adjustAxes(XYPlot plot) { felix@6559: super.adjustAxes(plot); felix@6559: if (getCurrentGaugeDatum() != 0d) { felix@6559: // Show the W[*m] axis even if there is no data. felix@6559: plot.setRangeAxis(1, createYAxis(YAXIS.W.idx)); felix@6559: } felix@6559: } felix@6559: christian@3055: @Override teichmann@6905: public void doOut(ArtifactAndFacet aaf, ThemeDocument doc, boolean visible) { felix@4361: logger.debug("doOut: " + aaf.getFacetName()); felix@4361: if (!prepareChartData(aaf, doc, visible)) { felix@4361: logger.warn("Unknown facet, name " + aaf.getFacetName()); felix@4361: } felix@4361: } felix@4361: felix@6472: /** felix@6472: * Return true if data could be handled, felix@6472: * to be overridden to add more handled data. felix@6472: */ teichmann@6905: public boolean prepareChartData(ArtifactAndFacet aaf, ThemeDocument doc, boolean visible) { christian@3056: String name = aaf.getFacetName(); christian@3056: felix@6426: this.artifact = (D4EArtifact) aaf.getArtifact(); christian@3406: christian@3133: if(name.startsWith(FIX_SECTOR_AVERAGE_WQ)) { christian@3056: doSectorAverageOut(aaf, doc, visible); christian@3062: } christian@3062: else if(FIX_ANALYSIS_EVENTS_WQ.equals(name)) { christian@3056: doAnalysisEventsOut(aaf, doc, visible); christian@3062: } christian@3062: else if(FIX_REFERENCE_EVENTS_WQ.equals(name)) { christian@3056: doReferenceEventsOut(aaf, doc, visible); christian@3062: } christian@3062: else if(FIX_WQ_CURVE.equals(name)) { christian@3056: doWQCurveOut(aaf, doc, visible); christian@3062: } christian@3062: else if(FIX_OUTLIER.equals(name)) { christian@3056: doOutlierOut(aaf, doc, visible); christian@3062: } felix@3578: else if(QSECTOR.equals(name)) { felix@3578: doQSectorOut(aaf, doc, visible); felix@3578: } felix@5731: else if(FIX_EVENTS.equals(name)) { felix@5731: doEventsOut(aaf, doc, visible); felix@5731: } felix@4143: else if(/*STATIC_WKMS_INTERPOL.equals(name) ||*/ felix@4143: STATIC_WKMS_MARKS.equals(name) || felix@3587: STATIC_WKMS.equals(name) || felix@3587: HEIGHTMARKS_POINTS.equals(name) ) { felix@3587: doWAnnotations( felix@3587: aaf.getData(context), felix@3587: aaf, felix@3587: doc, felix@3587: visible); felix@3587: } felix@4143: else if (LONGITUDINAL_W.equals(name) || STATIC_WQ.equals(name) felix@6492: || STATIC_WKMS_INTERPOL.equals(name) felix@6492: || FIX_WQ_LS.equals(name)) { felix@3585: doWQOut(aaf.getData(context), aaf, doc, visible); felix@3585: } felix@3588: else if (name.equals(DISCHARGE_CURVE)) { felix@6474: logger.debug("diso " + name); felix@3588: doDischargeOut( christian@3770: (WINFOArtifact) aaf.getArtifact(), christian@3770: aaf.getData(context), christian@3770: aaf.getFacetDescription(), christian@3770: doc, christian@3770: visible); christian@3770: } rrenkert@5978: else if (name.equals(MAINVALUES_W) || name.equals(MAINVALUES_Q)) { felix@6527: RiverAnnotation mainValues = (RiverAnnotation) aaf.getData(context); rrenkert@5978: doAnnotations( felix@6527: mainValues, rrenkert@5978: aaf, rrenkert@5978: doc, rrenkert@5978: visible); rrenkert@5978: } christian@3770: else if (FacetTypes.IS.MANUALPOINTS(aaf.getFacetName())) { christian@3770: doPoints(aaf.getData(context), christian@3770: aaf, christian@3770: doc, visible, YAXIS.W.idx); felix@3588: } christian@3062: else { felix@4361: return false; christian@3055: } felix@4361: return true; christian@3055: } christian@3055: felix@4361: felix@6426: /** Add sector average points to chart. */ teichmann@6905: protected void doSectorAverageOut(ArtifactAndFacet aaf, ThemeDocument doc, boolean visible) { christian@3062: logger.debug("doSectorAverageOut"); christian@3055: ingo@3551: QWDDateRange qwdd = (QWDDateRange) aaf.getData(context); ingo@3551: QWD qwd = qwdd != null ? qwdd.getQWD() : null; ingo@3551: christian@3132: if(qwd != null) { christian@3194: addQWSeries(new QWD[] { qwd }, aaf, doc, visible); christian@3062: } christian@3133: else { christian@3133: logger.debug("doSectorAverageOut: qwd == null"); christian@3133: } christian@3055: } christian@3055: felix@6426: /** Add analysis event points to chart. */ teichmann@6905: protected void doAnalysisEventsOut(ArtifactAndFacet aaf, ThemeDocument doc, boolean visible) { christian@3194: logger.debug("doAnalysisEventsOut"); christian@3055: raimund@3610: QWD qwd = (QWD)aaf.getData(context); raimund@3610: if(qwd != null) { raimund@3610: XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), doc); raimund@3610: List textAnnos = new ArrayList(); raimund@3610: raimund@3610: DateFormat dateFormat = DateFormat.getDateInstance( christian@3770: DateFormat.SHORT); raimund@3610: felix@7260: double gaugeDatum = getCurrentGaugeDatum(); felix@7260: double factor = (gaugeDatum == 0d) ? 1d : 100d; raimund@3610: felix@7260: series.add(qwd.getQ(), factor*(qwd.getW()-gaugeDatum)); christian@3770: XYTextAnnotation anno = new CollisionFreeXYTextAnnotation( raimund@3610: dateFormat.format(qwd.getDate()), raimund@3610: qwd.getQ(), felix@7260: factor*(qwd.getW()-gaugeDatum)); christian@3770: textAnnos.add(anno); raimund@3610: felix@7260: if (gaugeDatum == 0d) { felix@7260: addAxisSeries(series, YAXIS.W.idx, visible); felix@7260: } felix@7260: else { felix@7260: addAxisSeries(series, YAXIS.WCm.idx, visible); felix@7260: } teichmann@6905: if(visible && doc.parseShowPointLabel()) { teichmann@5864: RiverAnnotation flysAnno = new RiverAnnotation(null, null, null, doc); raimund@3610: flysAnno.setTextAnnotations(textAnnos); raimund@3610: addAnnotations(flysAnno); raimund@3610: } christian@3062: } christian@3095: else { christian@3095: logger.debug("doAnalysisEventsOut: qwds == null"); christian@3095: } christian@3055: } christian@3055: felix@4323: felix@6426: /** Add reference event points to chart. */ teichmann@6905: protected void doReferenceEventsOut(ArtifactAndFacet aaf, ThemeDocument doc, boolean visible) { christian@3770: logger.debug("doReferenceEventsOut"); sascha@3110: christian@3770: QWI qwd = (QWI)aaf.getData(context); teichmann@6868: if (qwd == null) { teichmann@6868: logger.debug("doReferenceEventsOut: qwds == null"); teichmann@6868: return; teichmann@6868: } raimund@3610: teichmann@6876: XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), false, true, doc); teichmann@6868: List textAnnos = new ArrayList(); raimund@3610: teichmann@6868: DateFormat dateFormat = DateFormat.getDateInstance( teichmann@6868: DateFormat.SHORT); teichmann@6868: felix@7258: double gaugeDatum = getCurrentGaugeDatum(); felix@7258: double factor = (gaugeDatum == 0d) ? 1d : 100d; teichmann@6868: felix@7258: series.add(qwd.getQ(), factor*(qwd.getW()-gaugeDatum), false); teichmann@6868: XYTextAnnotation anno = new CollisionFreeXYTextAnnotation( teichmann@6868: dateFormat.format(qwd.getDate()), teichmann@6868: qwd.getQ(), felix@7258: factor*(qwd.getW()-gaugeDatum)); teichmann@6868: textAnnos.add(anno); teichmann@6868: teichmann@6905: if(visible && doc.parseShowPointLabel()) { teichmann@6868: RiverAnnotation flysAnno = new RiverAnnotation(null, null, null, doc); teichmann@6868: flysAnno.setTextAnnotations(textAnnos); teichmann@6868: addAnnotations(flysAnno); raimund@3610: } felix@7258: felix@7258: if (gaugeDatum == 0d) { felix@7258: addAxisSeries(series, YAXIS.W.idx, visible); felix@7258: } felix@7258: else { felix@7258: addAxisSeries(series, YAXIS.WCm.idx, visible); felix@7258: } christian@3055: } christian@3055: felix@5740: felix@5740: private void addPointFromWQKms(WQKms wqkms, teichmann@6905: String title, teichmann@6905: ThemeDocument theme, teichmann@6905: boolean visible felix@5740: ) { felix@5740: XYSeries series = new StyledXYSeries(title, theme); felix@5731: Double ckm = (Double) context.getContextValue(CURRENT_KM); felix@5739: if (wqkms == null || wqkms.getKms().length == 0 || ckm == null) { felix@5740: logger.info("addPointFromWQKms: No event data to show."); felix@5739: return; felix@5739: } felix@5731: double[] kms = wqkms.getKms(); felix@7260: double gaugeDatum = getCurrentGaugeDatum(); felix@7260: double factor = (gaugeDatum == 0d) ? 1d : 100d; felix@5731: for (int i = 0 ; i< kms.length; i++) { felix@5739: if (Math.abs(kms[i] - ckm) <= EPSILON) { teichmann@6876: series.add(wqkms.getQ(i), wqkms.getW(i), false); felix@5731: addAxisSeries(series, YAXIS.W.idx, visible); teichmann@6905: if(visible && theme.parseShowPointLabel()) { felix@6542: List textAnnos = new ArrayList(); felix@6542: XYTextAnnotation anno = new CollisionFreeXYTextAnnotation( felix@6542: title, felix@6542: wqkms.getQ(i), felix@7260: factor*(wqkms.getW(i)-gaugeDatum)); felix@6542: textAnnos.add(anno); felix@6542: RiverAnnotation flysAnno = new RiverAnnotation(null, null, null, theme); felix@6542: flysAnno.setTextAnnotations(textAnnos); felix@6542: addAnnotations(flysAnno); felix@6542: } felix@5731: return; felix@5731: } felix@5731: } felix@5731: } felix@4323: teichmann@6905: protected void doEventsOut(ArtifactAndFacet aaf, ThemeDocument doc, boolean visible) { felix@5740: logger.debug("doEventsOut"); felix@5740: // Find W/Q at km. felix@5740: addPointFromWQKms((WQKms) aaf.getData(context), felix@5740: aaf.getFacetDescription(), doc, visible); felix@5740: } felix@5740: felix@5740: teichmann@6905: protected void doWQCurveOut(ArtifactAndFacet aaf, ThemeDocument doc, boolean visible) { christian@3056: logger.debug("doWQCurveOut"); christian@3055: christian@3081: FixWQCurveFacet facet = (FixWQCurveFacet)aaf.getFacet(); christian@3081: FixFunction func = (FixFunction)facet.getData( christian@3770: aaf.getArtifact(), context); sascha@3073: sascha@3073: if (func == null) { christian@3081: logger.warn("doWQCurveOut: Facet does not contain FixFunction"); sascha@3073: return; sascha@3073: } sascha@3110: christian@3081: double maxQ = func.getMaxQ(); sascha@3073: sascha@3215: if (maxQ > 0) { christian@3192: StyledXYSeries series = JFreeUtil.sampleFunction2D( christian@3770: func.getFunction(), christian@3770: doc, christian@3770: aaf.getFacetDescription(), christian@3770: 500, // number of samples christian@3770: 0.0 , // start christian@3770: maxQ); // end christian@3155: felix@6474: double gaugeDatum = getCurrentGaugeDatum(); felix@6474: felix@6474: if (gaugeDatum == 0d) { felix@6474: addAxisSeries(series, YAXIS.W.idx, visible); felix@6474: } felix@6474: else { felix@6530: StyledXYSeries series2 = JFreeUtil.sampleFunction2D( felix@6530: func.getFunction(), felix@6530: doc, felix@6530: aaf.getFacetDescription(), felix@6530: 500, // number of samples felix@6530: 0.0 , // start felix@6530: maxQ); // end felix@6530: addAxisSeries(series2, YAXIS.W.idx, false); felix@6474: // Use second axis at cm if at gauge. felix@6474: for (int i = 0; i < series.getItemCount(); i++) { felix@7257: series.updateByIndex(i, new Double(100d*(series.getY(i).doubleValue()-gaugeDatum))); felix@6474: } felix@6474: addAxisSeries(series, YAXIS.WCm.idx, visible); felix@6474: } christian@3055: } christian@3062: else { christian@3081: logger.warn("doWQCurveOut: maxQ <= 0"); christian@3062: } christian@3055: } christian@3055: teichmann@6905: protected void doOutlierOut(ArtifactAndFacet aaf, ThemeDocument doc, boolean visible) { christian@3055: logger.debug("doOutlierOut"); christian@3055: sascha@3729: QWI[] qws = (QWI[])aaf.getData(context); christian@3062: addQWSeries(qws, aaf, doc, visible); christian@3062: } christian@3062: felix@3578: felix@3578: /** Add markers for q sectors. */ teichmann@6905: protected void doQSectorOut(ArtifactAndFacet aaf, ThemeDocument theme, boolean visible) { felix@3578: logger.debug("doQSectorOut"); felix@3578: if (!visible) { felix@3578: return; felix@3578: } felix@3578: christian@3770: Object qsectorsObj = aaf.getData(context); christian@3770: if (qsectorsObj == null || !(qsectorsObj instanceof List)) { felix@3578: logger.warn("No QSectors coming from data."); felix@3578: return; felix@3578: } christian@3770: christian@3770: List qsectorsList = (List) qsectorsObj; christian@3770: if (qsectorsList.size() == 0 || !(qsectorsList.get(0) instanceof NamedDouble)) { christian@3770: logger.warn("No QSectors coming from data."); christian@3770: return; christian@3770: } christian@3770: christian@3770: @SuppressWarnings("unchecked") christian@3770: List qsectors = (List) qsectorsList; christian@3770: felix@3578: for (NamedDouble qsector : qsectors) { felix@3578: if (Double.isNaN(qsector.getValue())) { felix@3578: continue; felix@3578: } felix@3578: Marker m = new ValueMarker(qsector.getValue()); felix@3578: m.setPaint(Color.black); felix@3578: teichmann@6905: float[] dashes = theme.parseLineStyle(); teichmann@6905: int size = theme.parseLineWidth(); sascha@3593: BasicStroke stroke; felix@3578: if (dashes.length <= 1) { sascha@3593: stroke = new BasicStroke(size); felix@3578: } felix@3578: else { sascha@3593: stroke = new BasicStroke(size, christian@3770: BasicStroke.CAP_BUTT, christian@3770: BasicStroke.JOIN_ROUND, christian@3770: 1.0f, christian@3770: dashes, christian@3770: 0.0f); sascha@3593: } felix@3578: m.setStroke(stroke); felix@3578: teichmann@6905: if (theme.parseShowLineLabel()) { felix@3578: m.setLabel(qsector.getName()); teichmann@6905: m.setPaint(theme.parseTextColor()); teichmann@6905: m.setLabelFont(theme.parseTextFont()); felix@3578: } teichmann@6905: Color paint = theme.parseLineColorField(); felix@3578: if (paint != null) { felix@3578: m.setPaint(paint); felix@3578: } felix@3578: m.setLabelAnchor(RectangleAnchor.TOP_LEFT); felix@3578: m.setLabelTextAnchor(TextAnchor.TOP_LEFT); christian@3911: m.setLabelOffset(new RectangleInsets(5, 5, 10, 10)); felix@3578: addDomainMarker(m); felix@3578: } felix@3578: } felix@3578: felix@3596: felix@3596: /** felix@3587: * Add W-Annotations to plot. felix@3587: * @param wqkms actual data (double[][]). felix@3587: * @param theme theme to use. felix@3587: */ felix@3587: protected void doWAnnotations( teichmann@6905: Object wqkms, christian@3770: ArtifactAndFacet aandf, teichmann@6905: ThemeDocument theme, teichmann@6905: boolean visible christian@3770: ) { felix@3587: Facet facet = aandf.getFacet(); felix@3587: felix@3587: List xy = new ArrayList(); felix@3587: if (wqkms instanceof double[][]) { felix@3587: logger.debug("Got double[][]"); felix@3587: double [][] data = (double [][]) wqkms; felix@3587: for (int i = 0; i< data[0].length; i++) { felix@3587: xy.add(new StickyAxisAnnotation(aandf.getFacetDescription(), christian@3770: (float) data[1][i], StickyAxisAnnotation.SimpleAxis.Y_AXIS)); felix@3587: } felix@3587: teichmann@5864: doAnnotations(new RiverAnnotation(facet.getDescription(), xy), christian@3770: aandf, theme, visible); felix@3587: } felix@3587: else { felix@3587: // Assume its WKms. felix@3587: logger.debug("Got WKms"); felix@3587: WKms data = (WKms) wqkms; felix@3596: felix@3596: Double ckm = (Double) context.getContextValue(CURRENT_KM); felix@3587: double location = (ckm != null) christian@3770: ? ckm.doubleValue() felix@4147: : getRange()[0]; felix@4147: double w = StaticWKmsArtifact.getWAtKmLin(data, location); felix@4147: xy.add(new StickyAxisAnnotation(aandf.getFacetDescription(), felix@4147: (float) w, StickyAxisAnnotation.SimpleAxis.Y_AXIS)); felix@3587: teichmann@5864: doAnnotations(new RiverAnnotation(facet.getDescription(), xy), felix@4147: aandf, theme, visible); felix@3587: } felix@3587: } felix@3587: felix@3587: felix@3585: /** felix@3588: * Add series with discharge curve to diagram. felix@3588: */ felix@3588: protected void doDischargeOut( christian@3770: WINFOArtifact artifact, christian@3770: Object o, christian@3770: String description, teichmann@6905: ThemeDocument theme, christian@3770: boolean visible) felix@3588: { felix@3588: WQKms wqkms = (WQKms) o; felix@3588: felix@3588: String gaugeName = wqkms.getName(); felix@3588: teichmann@5865: River river = RiverUtils.getRiver(artifact); felix@3588: felix@3588: if (river == null) { felix@3588: logger.debug("no river found"); felix@3588: return; felix@3588: } felix@3588: felix@3588: Gauge gauge = river.determineGaugeByName(gaugeName); felix@3588: felix@3588: if (gauge == null) { felix@3588: logger.debug("no gauge found"); felix@3588: return; felix@3588: } felix@3588: felix@3588: XYSeries series = new StyledXYSeries(description, theme); felix@7258: felix@7258: double gaugeDatum = getCurrentGaugeDatum(); felix@7258: felix@7258: if (true || gaugeDatum == 0d) { felix@7258: StyledSeriesBuilder.addPointsQW(series, wqkms); felix@7258: addAxisSeries(series, YAXIS.W.idx, visible); felix@7258: } felix@7258: else { felix@7258: XYSeries series2 = new StyledXYSeries(description, theme); felix@7258: StyledSeriesBuilder.addPointsQW(series2, wqkms); felix@7258: addAxisSeries(series2, YAXIS.W.idx, false); felix@7258: felix@7258: // Use second axis... felix@7258: StyledSeriesBuilder.addPointsQW(series, wqkms, -gaugeDatum, 100d); felix@7258: addAxisSeries(series, YAXIS.WCm.idx, visible); felix@7258: } felix@3588: } felix@3588: felix@3596: felix@3588: /** felix@3585: * Add WQ Data to plot. felix@3585: * @param wqkms data as double[][] felix@3585: */ felix@3585: protected void doWQOut( christian@3770: Object wqkms, christian@3770: ArtifactAndFacet aaf, teichmann@6905: ThemeDocument theme, christian@3770: boolean visible christian@3770: ) { felix@3585: logger.debug("FixWQCurveGenerator: doWQOut"); felix@3596: if (wqkms instanceof WQKms) { felix@5739: // TODO As in doEventsOut, the value-searching should felix@5739: // be delivered by the facet already (instead of in the Generator). felix@5739: logger.debug("FixWQCurveGenerator: doWQOut: WQKms"); felix@3585: felix@5740: addPointFromWQKms((WQKms) aaf.getData(context), aaf.getFacetDescription(), theme, visible); felix@3596: } felix@3596: else { felix@5740: logger.debug("FixWQCurveGenerator: doWQOut: double[][]"); felix@3596: double [][] data = (double [][]) wqkms; felix@3596: teichmann@6876: XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), false, true, theme); felix@3596: StyledSeriesBuilder.addPoints(series, data, true); felix@3596: felix@3596: addAxisSeries(series, YAXIS.W.idx, visible); felix@3596: } felix@3585: } felix@3585: felix@3596: sascha@3729: protected void addQWSeries( christian@3770: QWI [] qws, christian@3770: ArtifactAndFacet aaf, teichmann@6905: ThemeDocument theme, christian@3770: boolean visible christian@3770: ) { sascha@3729: if (qws == null) { sascha@3729: return; sascha@3729: } christian@3194: teichmann@6876: XYSeries series = new StyledXYSeries( teichmann@6876: aaf.getFacetDescription(), teichmann@6876: false, true, teichmann@6876: theme); teichmann@6876: sascha@3729: List textAnnos = christian@3770: new ArrayList(qws.length); christian@3062: sascha@3729: DateFormat dateFormat = DateFormat.getDateInstance( christian@3770: DateFormat.SHORT); sascha@3729: felix@7259: double gaugeDatum = getCurrentGaugeDatum(); felix@7259: double factor = (gaugeDatum == 0d) ? 1d : 100d; sascha@3729: for (QWI qw: qws) { felix@7259: series.add(qw.getQ(), factor*(qw.getW()-gaugeDatum), false); sascha@3729: sascha@3729: XYTextAnnotation anno = new CollisionFreeXYTextAnnotation( christian@3770: dateFormat.format(qw.getDate()), christian@3770: qw.getQ(), felix@7259: factor*(qw.getW()-gaugeDatum)); sascha@3729: textAnnos.add(anno); sascha@3729: } sascha@3729: felix@7259: if (gaugeDatum == 0d) { felix@7259: addAxisSeries(series, YAXIS.W.idx, visible); felix@7259: } felix@7259: else { felix@7259: addAxisSeries(series, YAXIS.WCm.idx, visible); felix@7259: } teichmann@6905: if (visible && theme.parseShowPointLabel()) { teichmann@5864: RiverAnnotation flysAnno = teichmann@5864: new RiverAnnotation(null, null, null, theme); sascha@3729: flysAnno.setTextAnnotations(textAnnos); sascha@3729: addAnnotations(flysAnno); christian@3055: } christian@3055: } christian@3055: christian@3055: @Override christian@3406: protected String getChartTitle() { christian@3406: return Resources.format( christian@3406: context.getMeta(), christian@3406: I18N_CHART_TITLE, christian@3406: I18N_CHART_TITLE_DEFAULT, christian@3406: context.getContextValue(CURRENT_KM)); christian@3406: } christian@3406: christian@3406: @Override christian@3055: protected String getDefaultChartTitle() { christian@3055: return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT); christian@3055: } christian@3055: christian@3055: @Override christian@3406: protected String getDefaultChartSubtitle() { teichmann@6101: FixAnalysisAccess access = new FixAnalysisAccess(artifact); christian@3409: DateRange dateRange = access.getDateRange(); christian@3409: DateRange refRange = access.getReferencePeriod(); ingo@3466: ingo@3466: if (dateRange != null && refRange != null) { ingo@3466: return Resources.format( ingo@3466: context.getMeta(), ingo@3466: I18N_CHART_SUBTITLE, ingo@3466: "", felix@7261: access.getRiverName(), ingo@3466: dateRange.getFrom(), ingo@3466: dateRange.getTo(), ingo@3466: refRange.getFrom(), ingo@3466: refRange.getTo()); ingo@3466: } ingo@3466: ingo@3466: return null; christian@3406: } christian@3406: christian@3406: @Override christian@3410: protected void addSubtitles(JFreeChart chart) { ingo@3466: String defaultSubtitle = getDefaultChartSubtitle(); ingo@3466: ingo@3466: if (defaultSubtitle == null || defaultSubtitle.length() == 0) { ingo@3466: return; ingo@3466: } ingo@3466: ingo@3466: chart.addSubtitle(new TextTitle(defaultSubtitle)); ingo@3466: christian@3410: StringBuilder buf = new StringBuilder(); christian@3410: christian@3410: // Add analysis periods as additional subtitle teichmann@6101: FixAnalysisAccess access = new FixAnalysisAccess(artifact); christian@3410: DateRange[] aperiods = access.getAnalysisPeriods(); christian@3410: buf.append(msg("fix.analysis.periods")); christian@3410: buf.append(": "); christian@3410: for(int n = 0; n < aperiods.length; n++) { christian@3410: buf.append( christian@3410: Resources.format( christian@3410: context.getMeta(), christian@3410: I18N_CHART_SUBTITLE1, christian@3410: "", christian@3410: aperiods[n].getFrom(), christian@3410: aperiods[n].getTo())); christian@3410: if(n + 1 < aperiods.length) { christian@3410: buf.append("; "); christian@3410: } christian@3410: } christian@3410: christian@3410: chart.addSubtitle(new TextTitle(buf.toString())); christian@3410: } christian@3410: christian@3410: @Override christian@3055: protected String getDefaultXAxisLabel() { christian@3055: return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT); christian@3055: } christian@3055: christian@3055: @Override christian@3055: protected String getDefaultYAxisLabel(int pos) { felix@6467: D4EArtifact flys = (D4EArtifact) master; felix@6467: felix@6467: String unit = RiverUtils.getRiver(flys).getWstUnit().getName(); felix@6473: if (pos == 0) { felix@6467: unit = "cm"; felix@6473: } felix@6467: felix@6467: return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT, new Object[] { unit }); christian@3055: } christian@3055: christian@3055: @Override christian@3055: protected ChartGenerator.YAxisWalker getYAxisWalker() { christian@3055: return new YAxisWalker() { christian@3055: @Override christian@3055: public int length() { christian@3055: return YAXIS.values().length; christian@3055: } christian@3055: christian@3055: @Override christian@3770: public String getId(int idx) { christian@3055: YAXIS[] yaxes = YAXIS.values(); christian@3055: return yaxes[idx].toString(); christian@3055: } christian@3055: }; sascha@3076: } christian@3055: } christian@3055: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :