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@3131:
teichmann@5831: import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
teichmann@5831: import org.dive4elements.artifacts.CallContext;
teichmann@5867: import org.dive4elements.river.artifacts.D4EArtifact;
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.QWDDateRange;
teichmann@5831: import org.dive4elements.river.artifacts.model.fixings.QWD;
teichmann@5831: import org.dive4elements.river.artifacts.resources.Resources;
teichmann@5831: import org.dive4elements.river.exports.TimeseriesChartGenerator;
teichmann@5831: import org.dive4elements.river.jfree.CollisionFreeXYTextAnnotation;
teichmann@5864: import org.dive4elements.river.jfree.RiverAnnotation;
teichmann@5831: import org.dive4elements.river.jfree.StyledDomainMarker;
teichmann@5831: import org.dive4elements.river.jfree.StyledTimeSeries;
teichmann@5831: import org.dive4elements.river.jfree.StyledValueMarker;
teichmann@6905: import org.dive4elements.river.themes.ThemeDocument;
christian@3988:
christian@3746: import java.io.OutputStream;
christian@3908: import java.text.NumberFormat;
christian@3746: import java.util.ArrayList;
christian@3746: import java.util.HashMap;
christian@3746: import java.util.List;
christian@3908: import java.util.Locale;
christian@3746: import java.util.Map;
christian@3746:
christian@3746: import org.apache.log4j.Logger;
christian@3746: import org.jfree.chart.annotations.XYTextAnnotation;
christian@3746: import org.jfree.data.time.RegularTimePeriod;
aheinecke@6159: import org.jfree.data.time.FixedMillisecond;
christian@3746: import org.jfree.data.time.TimeSeries;
christian@3746: import org.jfree.data.time.TimeSeriesCollection;
christian@3746: import org.w3c.dom.Document;
christian@3746:
teichmann@6874: import gnu.trove.TLongHashSet;
teichmann@6874:
rrenkert@8381: import static org.dive4elements.river.exports.injector.InjectorConstants.CURRENT_KM;
christian@3251:
raimund@3131: /**
christian@3251: * Generator for Delta W(t) charts.
raimund@3131: * @author Raimund Renkert
raimund@3131: */
raimund@3131: public class FixDeltaWtGenerator
raimund@3131: extends TimeseriesChartGenerator
raimund@3131: implements FacetTypes
raimund@3131: {
teichmann@8202: /** Private log. */
teichmann@8202: private static Logger log =
christian@3746: Logger.getLogger(FixDeltaWtGenerator.class);
raimund@3131:
raimund@3131: public static final String I18N_CHART_TITLE =
christian@3746: "chart.fix.deltawt.title";
raimund@3131:
raimund@3131: public static final String I18N_CHART_SUBTITLE =
christian@3746: "chart.fix.deltawt.subtitle";
raimund@3131:
raimund@3131: public static final String I18N_XAXIS_LABEL =
christian@3746: "chart.fix.deltawt.xaxis.label";
raimund@3131:
raimund@3131: public static final String I18N_YAXIS_LABEL =
christian@3746: "chart.fix.deltawt.yaxis.label";
raimund@3131:
raimund@3131: public static final String I18N_YAXIS_SECOND_LABEL =
christian@3746: "chart.fix.deltawt.yaxis.second.label";
raimund@3131:
raimund@3131:
raimund@3131: public static enum YAXIS {
raimund@3131: dW(0);
raimund@3131: protected int idx;
raimund@3131: private YAXIS(int c) {
raimund@3131: idx = c;
raimund@3131: }
raimund@3131: }
sascha@3280:
sascha@3280:
teichmann@6874: private D4EArtifact artifact;
teichmann@6874:
teichmann@6874: // Used to make the dates collision free.
teichmann@6874: private TLongHashSet uniqueDates = new TLongHashSet();
raimund@3131:
raimund@3131:
raimund@3131: @Override
raimund@3131: protected YAxisWalker getYAxisWalker() {
raimund@3131: return new YAxisWalker() {
raimund@3131: @Override
raimund@3131: public int length() {
raimund@3131: return YAXIS.values().length;
raimund@3131: }
raimund@3131:
raimund@3131: @Override
raimund@3131: public String getId(int idx) {
raimund@3131: YAXIS[] yaxes = YAXIS.values();
raimund@3131: return yaxes[idx].toString();
raimund@3131: }
raimund@3131: };
raimund@3131: }
raimund@3131:
raimund@3131:
raimund@3131: @Override
gernotbelger@9123: protected String getDefaultChartTitle(final CallContext context) {
raimund@3131: return msg(I18N_CHART_TITLE, I18N_CHART_TITLE);
raimund@3131: }
raimund@3131:
raimund@3131:
raimund@3131: @Override
gernotbelger@9123: protected String getChartTitle(final CallContext context) {
christian@3406: return Resources.format(
christian@3406: context.getMeta(),
christian@3406: I18N_CHART_TITLE,
christian@3406: "",
sascha@3727: FixChartGenerator
gernotbelger@9123: .getCurrentKmFromRequest(getRequest()).doubleValue());
christian@3406: }
christian@3406:
christian@3406:
christian@3406: @Override
gernotbelger@9123: protected String getDefaultChartSubtitle(final CallContext context) {
teichmann@6101: FixAnalysisAccess access = new FixAnalysisAccess(artifact);
christian@3409: DateRange dateRange = access.getDateRange();
christian@3409: DateRange refRange = access.getReferencePeriod();
christian@3279: return Resources.format(
sascha@3280: context.getMeta(),
sascha@3280: I18N_CHART_SUBTITLE,
sascha@3280: "",
felix@7261: access.getRiverName(),
christian@3409: dateRange.getFrom(),
christian@3409: dateRange.getTo(),
christian@3409: refRange.getFrom(),
christian@3409: refRange.getTo());
raimund@3131: }
raimund@3131:
raimund@3131:
raimund@3131: @Override
gernotbelger@9123: protected String getDefaultXAxisLabel(final CallContext context) {
raimund@3131: return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL);
raimund@3131: }
raimund@3131:
raimund@3131: @Override
raimund@3131: protected String getDefaultYAxisLabel(int pos) {
raimund@3131: if (pos == 0) {
raimund@3131: return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL);
raimund@3131: }
raimund@3131: else if (pos == 1) {
raimund@3131: return msg(I18N_YAXIS_SECOND_LABEL, I18N_YAXIS_SECOND_LABEL);
raimund@3131: }
raimund@3131: else {
raimund@3131: return "NO TITLE FOR Y AXIS: " + pos;
raimund@3131: }
raimund@3131: }
raimund@3131:
raimund@3131:
christian@3251: @Override
raimund@3131: public void doOut(
christian@3746: ArtifactAndFacet artifactFacet,
teichmann@6905: ThemeDocument theme,
christian@3746: boolean visible
christian@3746: ) {
raimund@3131: String name = artifactFacet.getFacetName();
teichmann@8202: log.debug("FixDeltaWtGenerator.doOut: " + name);
tom@8856: log.debug("Theme description is: "
tom@8856: + artifactFacet.getFacetDescription());
sascha@3280:
teichmann@5867: this.artifact = (D4EArtifact)artifactFacet.getArtifact();
raimund@3131:
gernotbelger@9123: final CallContext context = getContext();
gernotbelger@9123:
raimund@3131: if (name.contains(FIX_SECTOR_AVERAGE_DWT)) {
raimund@3131: doSectorAverageOut(
teichmann@5867: (D4EArtifact) artifactFacet.getArtifact(),
christian@3746: artifactFacet.getData(context),
christian@3746: artifactFacet.getFacetDescription(),
christian@3746: theme,
christian@3746: visible);
raimund@3131: }
raimund@3131: else if (name.equals(FIX_REFERENCE_EVENTS_DWT)) {
raimund@3131: doReferenceEventsOut(
teichmann@5867: (D4EArtifact) artifactFacet.getArtifact(),
christian@3746: artifactFacet.getData(context),
christian@3746: artifactFacet.getFacetDescription(),
christian@3746: theme,
christian@3746: visible);
raimund@3131: }
raimund@3131: else if (name.equals(FIX_ANALYSIS_EVENTS_DWT)) {
raimund@3131: doAnalysisEventsOut(
teichmann@5867: (D4EArtifact) artifactFacet.getArtifact(),
christian@3746: artifactFacet.getData(context),
christian@3746: artifactFacet.getFacetDescription(),
christian@3746: theme,
christian@3746: visible);
raimund@3131: }
raimund@3131: else if (name.equals(FIX_DEVIATION_DWT)) {
raimund@3131: doDeviationOut(
teichmann@5867: (D4EArtifact) artifactFacet.getArtifact(),
christian@3746: artifactFacet.getData(context),
christian@3746: artifactFacet.getFacetDescription(),
christian@3746: theme,
christian@3746: visible);
raimund@3131: }
raimund@3131: else if (name.equals(FIX_ANALYSIS_PERIODS_DWT)) {
raimund@3131: doAnalysisPeriodsOut(
teichmann@5867: (D4EArtifact) artifactFacet.getArtifact(),
christian@3746: artifactFacet.getData(context),
christian@3746: artifactFacet.getFacetDescription(),
christian@3746: theme,
christian@3746: visible);
raimund@3131: }
christian@3907: else if (name.equals(FIX_REFERENCE_PERIOD_DWT)) {
christian@3907: doReferencePeriodsOut(
teichmann@5867: (D4EArtifact) artifactFacet.getArtifact(),
christian@3907: artifactFacet.getData(context),
christian@3907: artifactFacet.getFacetDescription(),
christian@3907: theme,
christian@3907: visible);
christian@3907: }
christian@3770: else if (FacetTypes.IS.MANUALPOINTS(name)) {
christian@3770: doPoints (artifactFacet.getData(context),
christian@3770: artifactFacet,
christian@3770: theme, visible, YAXIS.dW.idx);
christian@3770: }
raimund@3131: else {
teichmann@8202: log.warn("doOut(): unknown facet name: " + name);
christian@3746: return;
raimund@3131: }
raimund@3131: }
raimund@3131:
raimund@3131:
christian@3907: protected void doReferencePeriodsOut(
teichmann@6905: D4EArtifact artifact,
teichmann@6905: Object data,
teichmann@6905: String desc,
teichmann@6905: ThemeDocument theme,
teichmann@6905: boolean visible)
christian@3907: {
teichmann@8202: log.debug("doReferencePeriodsOut()");
christian@3907:
christian@3988: if (visible) {
teichmann@6101: FixAnalysisAccess access = new FixAnalysisAccess(artifact);
christian@3988: DateRange refRange = access.getReferencePeriod();
christian@3907:
aheinecke@6159: RegularTimePeriod start = new FixedMillisecond(refRange.getFrom());
aheinecke@6159: RegularTimePeriod end = new FixedMillisecond(refRange.getTo());
christian@3988: StyledDomainMarker marker = new StyledDomainMarker(
christian@3988: start.getMiddleMillisecond(),
christian@3988: end.getMiddleMillisecond(),
christian@3988: theme);
christian@3988: domainMarker.add(marker);
christian@3988: }
christian@3907: }
christian@3907:
teichmann@6874: private long uniqueDate(long date) {
teichmann@6874: return uniqueDates.add(date)
teichmann@6874: ? date
teichmann@6874: : uniqueDate(date+30L*1000L); // add 30secs.
teichmann@6874: }
teichmann@6874:
christian@3907:
raimund@3131: protected void doSectorAverageOut(
teichmann@6905: D4EArtifact artifact,
teichmann@6905: Object data,
teichmann@6905: String desc,
teichmann@6905: ThemeDocument theme,
teichmann@6905: boolean visible)
raimund@3131: {
teichmann@8202: log.debug("doSectorAverageOut(): description = " + desc);
raimund@3131:
felix@3467: QWDDateRange qwd = (QWDDateRange) data;
raimund@3131: TimeSeriesCollection tsc = new TimeSeriesCollection();
raimund@3131: TimeSeries series = new StyledTimeSeries(desc, theme);
raimund@3131:
felix@3467: if (qwd == null || qwd.qwd == null || qwd.dateRange == null) {
raimund@3131: return;
raimund@3131: }
aheinecke@6159: RegularTimePeriod rtp = new FixedMillisecond(qwd.qwd.getDate());
felix@3467: double value = qwd.qwd.getDeltaW();
raimund@3611:
felix@3467: // Draw a line spanning the analysis time.
raimund@3131: series.add(rtp, value);
teichmann@6835: rtp = new FixedMillisecond(qwd.dateRange.getFrom());
raimund@3611: series.addOrUpdate(rtp, value);
teichmann@6835: rtp = new FixedMillisecond(qwd.dateRange.getTo());
raimund@3611: series.addOrUpdate(rtp, value);
felix@3467:
raimund@3131: tsc.addSeries(series);
raimund@3131:
raimund@3131: addAxisDataset(tsc, 0, visible);
christian@3746:
teichmann@6905: if (visible && theme.parseShowLineLabel()) {
tom@8856: List textAnnos =
tom@8856: new ArrayList();
christian@3746: XYTextAnnotation anno = new CollisionFreeXYTextAnnotation(
tom@8856: "\u0394 W(t) [cm] "
tom@8856: + (float)Math.round(qwd.qwd.getDeltaW() * 10000) / 10000,
christian@3746: tsc.getXValue(0, 0),
christian@3746: qwd.qwd.getDeltaW());
christian@3746: textAnnos.add(anno);
christian@3746:
tom@8856: RiverAnnotation flysAnno =
tom@8856: new RiverAnnotation(null, null, null, theme);
christian@3746: flysAnno.setTextAnnotations(textAnnos);
christian@3746: addAnnotations(flysAnno);
christian@3746: }
raimund@3131: }
raimund@3131:
raimund@3131:
raimund@3131: protected void doAnalysisEventsOut(
teichmann@5867: D4EArtifact artifact,
christian@3746: Object data,
christian@3746: String desc,
teichmann@6905: ThemeDocument theme,
christian@3746: boolean visible
christian@3746: ) {
teichmann@8202: log.debug("doAnalysisEventsOut: desc = " + desc);
raimund@3131:
raimund@3610: QWD qwd = (QWD) data;
raimund@3610: doQWDEventsOut(qwd, desc, theme, visible);
christian@3438: }
christian@3438:
christian@3438:
tom@8856: protected void doQWDEventsOut(
tom@8856: QWD qwd,
tom@8856: String desc,
tom@8856: ThemeDocument theme,
tom@8856: boolean visible
tom@8856: ) {
raimund@3131: TimeSeriesCollection tsc = new TimeSeriesCollection();
raimund@3134:
raimund@3134: TimeSeries series = new StyledTimeSeries(desc, theme);
raimund@3134: TimeSeries interpol = new StyledTimeSeries(desc + "interpol", theme);
raimund@3131:
raimund@3610: if (qwd == null) {
teichmann@8202: log.debug("doQWDEventsOut: qwd == null");
christian@3212: return;
christian@3212: }
christian@3212:
christian@3212: Map annoIdxMap = new HashMap();
christian@3212:
felix@3237: int idxInterpol = 0;
felix@3237: int idxRegular = 0;
teichmann@6874: long time = uniqueDate(qwd.getDate().getTime());
teichmann@6874: RegularTimePeriod rtp = new FixedMillisecond(time);
raimund@3610: double value = qwd.getDeltaW();
raimund@3610: boolean interpolate = qwd.getInterpolated();
raimund@3610: if (interpolate) {
raimund@3610: if(interpol.addOrUpdate(rtp, value) == null) {
raimund@3610: annoIdxMap.put(
raimund@3610: 0,
raimund@3610: new int[]{1, idxInterpol});
raimund@3610: idxInterpol++;
raimund@3134: }
raimund@3131: }
raimund@3610: else {
raimund@3610: if(series.addOrUpdate(rtp, value) == null) {
raimund@3610: annoIdxMap.put(
raimund@3610: 0,
raimund@3610: new int[]{0, idxRegular});
raimund@3610: idxRegular++;
raimund@3610: }
raimund@3610: }
raimund@3610:
raimund@3131: tsc.addSeries(series);
raimund@3134: tsc.addSeries(interpol);
raimund@3131: addAxisDataset(tsc, 0, visible);
raimund@3134: addAttribute(desc + "interpol", "interpolate");
raimund@3168: addAttribute(desc, "outline");
christian@3212:
raimund@3610: doQWDTextAnnotations(annoIdxMap, tsc, qwd, theme, visible);
raimund@3131: }
raimund@3131:
raimund@3131:
christian@3438: /**
tom@8856: * @param annoIdxMap map of index in qwds to series/data item indices
tom@8856: * in tsc.
christian@3438: */
christian@3438: protected void doQWDTextAnnotations(Map annoIdxMap,
teichmann@6905: TimeSeriesCollection tsc, QWD qwd, ThemeDocument theme,
christian@3438: boolean visible) {
teichmann@8202: log.debug("doQWDTextAnnotation()");
christian@3438:
teichmann@6905: if (!visible || !theme.parseShowPointLabel()) {
teichmann@8202: log.debug("doQWDTextAnnotation: annotation not visible");
christian@3438: return;
christian@3438: }
christian@3438:
gernotbelger@9123: Locale locale = Resources.getLocale(getContext().getMeta());
christian@3908: NumberFormat nf = NumberFormat.getInstance(locale);
christian@3908:
gernotbelger@9123: List textAnnos = new ArrayList<>();
christian@3438:
teichmann@4050: for (int[] idxs: annoIdxMap.values()) {
teichmann@4050:
christian@3438: double x = tsc.getXValue(idxs[0], idxs[1]);
christian@3908:
christian@3438: XYTextAnnotation anno = new CollisionFreeXYTextAnnotation(
christian@3908: nf.format(qwd.getQ()) + " m\u00B3/s",
christian@3746: x,
christian@3746: qwd.getDeltaW());
christian@3438: textAnnos.add(anno);
christian@3438: }
christian@3438:
teichmann@5864: RiverAnnotation flysAnno = new RiverAnnotation(null, null, null, theme);
christian@3438: flysAnno.setTextAnnotations(textAnnos);
christian@3438: addAnnotations(flysAnno);
christian@3438: }
christian@3438:
christian@3438:
christian@3438: protected void doReferenceEventsOut(
teichmann@6905: D4EArtifact artifact,
teichmann@6905: Object data,
teichmann@6905: String desc,
teichmann@6905: ThemeDocument theme,
teichmann@6905: boolean visible
christian@3746: ) {
teichmann@8202: log.debug("doReferenceEventsOut: desc = " + desc);
christian@3438:
raimund@3610: QWD qwd = (QWD) data;
raimund@3610: doQWDEventsOut(qwd, desc, theme, visible);
christian@3438: }
christian@3438:
christian@3438:
raimund@3131: protected void doDeviationOut(
teichmann@6905: D4EArtifact artifact,
teichmann@6905: Object data,
teichmann@6905: String desc,
teichmann@6905: ThemeDocument theme,
teichmann@6905: boolean visible
christian@3746: ) {
teichmann@8202: log.debug("doDeviationOut: desc = " + desc);
raimund@3131:
raimund@3131: if (data == null || !visible) {
teichmann@8202: log.debug("no standard deviation");
raimund@3131: return;
raimund@3131: }
raimund@3131: double[] value = (double[]) data;
tom@8856: StyledDomainMarker lower =
tom@8856: new StyledDomainMarker((value[0] * -1), 0, theme);
tom@8856: StyledDomainMarker upper =
tom@8856: new StyledDomainMarker(0, value[0], theme);
raimund@3131:
raimund@3131: valueMarker.add(lower);
raimund@3131: valueMarker.add(upper);
raimund@3131: }
raimund@3131:
raimund@3131:
raimund@3131: protected void doAnalysisPeriodsOut(
teichmann@5867: D4EArtifact artifact,
teichmann@6905: Object data,
teichmann@6905: String desc,
teichmann@6905: ThemeDocument theme,
teichmann@6905: boolean visible)
christian@3907: {
raimund@3131: DateRange[] ranges = (DateRange[]) data;
raimund@3131: if (ranges == null || !visible) {
raimund@3131: return;
raimund@3131: }
raimund@3131: for (int i = 0; i < ranges.length; i++) {
teichmann@8202: log.debug("creating domain marker");
aheinecke@6159: RegularTimePeriod start = new FixedMillisecond(ranges[i].getFrom());
aheinecke@6159: RegularTimePeriod end = new FixedMillisecond(ranges[i].getTo());
christian@3254: StyledDomainMarker marker =
christian@3746: new StyledDomainMarker(start.getMiddleMillisecond(),
christian@3746: end.getMiddleMillisecond(), theme);
christian@3254: marker.useSecondColor(i % 2 == 0);
raimund@3131: domainMarker.add(marker);
raimund@3131: }
teichmann@8202: log.debug("domainmarkers: " + domainMarker.size());
raimund@3131: }
raimund@3131:
raimund@3131:
raimund@3131: @Override
tom@8856: public void init(
tom@8856: String outName,
tom@8856: Document request,
tom@8856: OutputStream out,
tom@8856: CallContext context
tom@8856: ) {
teichmann@7077: super.init(outName, request, out, context);
raimund@3131:
sascha@3727: Double currentKm = FixChartGenerator.getCurrentKmFromRequest(request);
sascha@3404:
teichmann@8202: if (log.isDebugEnabled()) {
teichmann@8202: log.debug("currentKm = " + currentKm);
sascha@3404: }
sascha@3404:
rrenkert@8381: context.putContextValue(CURRENT_KM, currentKm);
raimund@3131:
teichmann@6905: // XXX: This looks hackish!
teichmann@6905: StyledValueMarker marker =
teichmann@6905: new StyledValueMarker(0, new ThemeDocument(request));
raimund@3131: valueMarker.add(marker);
raimund@3131: }
raimund@3131: }
raimund@3131: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :