ingo@359: package de.intevation.flys.exports;
ingo@359:
ingo@1690: import java.awt.Font;
ingo@1991: import java.util.ArrayList;
ingo@1991: import java.util.List;
ingo@1690:
ingo@359: import org.apache.log4j.Logger;
ingo@359:
ingo@375: import org.jfree.chart.JFreeChart;
ingo@375: import org.jfree.chart.axis.NumberAxis;
felix@1719: import org.jfree.chart.title.TextTitle;
ingo@422: import org.jfree.chart.axis.ValueAxis;
ingo@375: import org.jfree.chart.plot.XYPlot;
ingo@369: import org.jfree.data.xy.XYSeries;
ingo@364:
ingo@359: import org.w3c.dom.Document;
ingo@359:
felix@1953: import de.intevation.artifactdatabase.state.ArtifactAndFacet;
ingo@1991: import de.intevation.artifactdatabase.state.Section;
ingo@695: import de.intevation.artifactdatabase.state.Facet;
ingo@695:
ingo@422: import de.intevation.flys.artifacts.FLYSArtifact;
sascha@706:
ingo@696: import de.intevation.flys.artifacts.model.FacetTypes;
felix@1769: import de.intevation.flys.artifacts.model.WKms;
ingo@364: import de.intevation.flys.artifacts.model.WQKms;
ingo@364:
ingo@1677: import de.intevation.flys.jfree.FLYSAnnotation;
sascha@1688:
ingo@1667: import de.intevation.flys.utils.FLYSUtils;
sascha@1688: import de.intevation.flys.utils.DataUtil;
ingo@359:
felix@1035:
felix@1035: /**
ingo@359: * An OutGenerator that generates discharge curves.
ingo@359: *
ingo@359: * @author Ingo Weinzierl
ingo@359: */
ingo@696: public class LongitudinalSectionGenerator
ingo@696: extends XYChartGenerator
ingo@696: implements FacetTypes
ingo@696: {
felix@1953: public enum YAXIS {
felix@1931: W(0),
felix@1931: Q(1),
felix@1931: D(2);
felix@1931: protected int idx;
felix@1931: private YAXIS(int c) {
felix@1931: idx = c;
felix@1931: }
felix@1931: }
felix@1931:
felix@1037: /** The logger that is used in this generator. */
ingo@359: private static Logger logger =
ingo@359: Logger.getLogger(LongitudinalSectionGenerator.class);
ingo@359:
felix@1700: /** Key to look up internationalized String for annotations label. */
felix@1041: public static final String I18N_ANNOTATIONS_LABEL =
felix@1041: "chart.longitudinal.annotations.label";
felix@1041:
felix@1701: /**
felix@1701: * Key to look up internationalized String for LongitudinalSection diagrams
felix@1701: * titles.
felix@1701: */
felix@1701: public static final String I18N_CHART_TITLE =
felix@1701: "chart.longitudinal.section.title";
felix@1701:
felix@1701: /**
felix@1701: * Key to look up internationalized String for LongitudinalSection diagrams
felix@1701: * subtitles.
felix@1701: */
felix@1701: public static final String I18N_CHART_SUBTITLE =
felix@1701: "chart.longitudinal.section.subtitle";
felix@1701:
felix@1701: public static final String I18N_XAXIS_LABEL =
felix@1701: "chart.longitudinal.section.xaxis.label";
felix@1701:
felix@1701: public static final String I18N_YAXIS_LABEL =
felix@1701: "chart.longitudinal.section.yaxis.label";
felix@1701:
felix@1701: public static final String I18N_2YAXIS_LABEL =
felix@1701: "chart.longitudinal.section.yaxis.second.label";
felix@1701:
felix@1701: public static final String I18N_CHART_TITLE_DEFAULT = "W-L\u00e4ngsschnitt";
felix@1701: public static final String I18N_XAXIS_LABEL_DEFAULT = "km";
felix@1701: public static final String I18N_YAXIS_LABEL_DEFAULT = "W [NN + m]";
felix@1701: public static final String I18N_2YAXIS_LABEL_DEFAULT = "Q [m\u00b3/s]";
felix@1701:
felix@1953: public final static String I18N_WDIFF_YAXIS_LABEL =
felix@1953: "chart.w_differences.yaxis.label";
felix@1953:
felix@1953: public final static String I18N_WDIFF_YAXIS_LABEL_DEFAULT = "m";
felix@1953:
felix@1700: /** Whether or not the plot is inverted (left-right). */
sascha@745: protected boolean inverted;
sascha@745:
felix@1041:
ingo@359: public LongitudinalSectionGenerator() {
ingo@359: super();
ingo@369: }
ingo@369:
ingo@369:
sascha@745: public boolean isInverted() {
sascha@745: return inverted;
sascha@745: }
sascha@745:
felix@1700:
sascha@745: public void setInverted(boolean inverted) {
sascha@745: this.inverted = inverted;
sascha@745: }
ingo@369:
felix@1700:
felix@1700: /**
felix@1700: * Get internationalized title for chart.
felix@1700: */
felix@1700: public String getChartTitle() {
felix@1701: return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT);
felix@1700: }
felix@1700:
felix@1700:
ingo@1989: @Override
ingo@1989: protected String getChartSubtitle() {
ingo@1989: double[] dist = getRange();
ingo@1989:
ingo@1989: Object[] args = new Object[] {
ingo@1989: getRiverName(),
ingo@1989:
ingo@1989: dist[0],
ingo@1989:
ingo@1989: dist[1]
ingo@1989: };
ingo@1989:
ingo@1989: return msg(getChartSubtitleKey(), "", args);
ingo@1989: }
ingo@1989:
ingo@1989:
felix@1700: /**
felix@1700: * Gets key to look up internationalized String for the charts subtitle.
felix@1700: * @return key to look up translated subtitle.
felix@1700: */
felix@1700: protected String getChartSubtitleKey() {
felix@1701: return I18N_CHART_SUBTITLE;
felix@1700: }
felix@1700:
felix@1700:
felix@1700: /**
felix@1700: * Add (internationalized) subtitle to chart.
felix@1700: * @see getChartSubtitleKey
felix@1700: */
ingo@414: @Override
ingo@414: protected void addSubtitles(JFreeChart chart) {
ingo@1989: String subtitle = getChartSubtitle();
ingo@414: chart.addSubtitle(new TextTitle(subtitle));
ingo@414: }
ingo@414:
ingo@414:
felix@1700: /**
felix@1700: * Get internationalized label for the x axis.
felix@1700: */
ingo@369: protected String getXAxisLabel() {
ingo@1667: FLYSArtifact flys = (FLYSArtifact) master;
ingo@1667:
ingo@1667: return msg(
felix@1701: I18N_XAXIS_LABEL,
felix@1701: I18N_XAXIS_LABEL_DEFAULT,
ingo@1667: new Object[] { FLYSUtils.getRiver(flys).getName() });
ingo@369: }
ingo@369:
ingo@369:
felix@1953: @Override
felix@1953: protected String getYAxisLabel() {
felix@1953: return getWAxisLabel();
felix@1953: }
felix@1953:
felix@1700: /**
felix@1700: * Get internationalized label for the y axis.
felix@1700: */
felix@1953: protected String getWAxisLabel() {
ingo@1667: FLYSArtifact flys = (FLYSArtifact) master;
ingo@1667:
ingo@1673: String unit = FLYSUtils.getRiver(flys).getWstUnit().getName();
ingo@1667:
ingo@1667: return msg(
felix@1701: I18N_YAXIS_LABEL,
felix@1701: I18N_YAXIS_LABEL_DEFAULT,
ingo@1667: new Object[] { unit });
ingo@369: }
ingo@369:
ingo@369:
felix@1700: /**
felix@1931: * Create Axis for given index.
felix@1931: * @return axis with according internationalized label.
felix@1931: */
felix@1931: @Override
felix@1931: protected NumberAxis createYAxis(int index) {
felix@1931: Font labelFont = new Font("Tahoma", Font.BOLD, 14);
ingo@1991: String label = getYAxisLabel(index);
ingo@1991:
felix@1931: NumberAxis axis = new NumberAxis(label);
felix@1941: // "Q" Axis shall include 0.
felix@1941: if (index == YAXIS.Q.idx) {
felix@1941: axis.setAutoRangeIncludesZero(true);
felix@1941: }
felix@1941: else {
felix@1941: axis.setAutoRangeIncludesZero(false);
felix@1941: }
felix@1931: axis.setLabelFont(labelFont);
felix@1931: return axis;
felix@1931: }
felix@1931:
ingo@1991:
ingo@1991: protected String getYAxisLabel(int index) {
ingo@1991: String label = "default";
ingo@1991:
ingo@1991: if (index == YAXIS.W.idx) {
ingo@1991: label = getWAxisLabel();
ingo@1991: }
ingo@1991: else if (index == YAXIS.Q.idx) {
ingo@1991: label = msg(getQAxisLabelKey(), getQAxisDefaultLabel());
ingo@1991: }
ingo@1991: else if (index == YAXIS.D.idx) {
ingo@1991: label = msg(I18N_WDIFF_YAXIS_LABEL, I18N_WDIFF_YAXIS_LABEL_DEFAULT);
ingo@1991: }
ingo@1991:
ingo@1991: return label;
ingo@1991: }
ingo@1991:
ingo@1991:
felix@1931: /**
felix@1700: * Get default value for the second Y-Axis' label (if no translation was
felix@1700: * found).
felix@1700: */
felix@1953: protected String getQAxisDefaultLabel() {
felix@1701: return I18N_2YAXIS_LABEL_DEFAULT;
felix@1700: }
felix@1700:
felix@1700:
felix@1700: /**
felix@1700: * Get key for internationalization of the second Y-Axis' label.
felix@1700: */
felix@1953: protected String getQAxisLabelKey() {
felix@1701: return I18N_2YAXIS_LABEL;
felix@1700: }
felix@1700:
felix@1700:
felix@1700: /**
felix@1931: * Trigger inversion.
felix@1700: */
felix@1700: @Override
ingo@375: protected void adjustAxes(XYPlot plot) {
ingo@375: super.adjustAxes(plot);
ingo@422: invertXAxis(plot.getDomainAxis());
ingo@422: }
ingo@422:
ingo@422:
ingo@422: /**
ingo@422: * This method inverts the x-axis based on the kilometer information of the
ingo@422: * selected river. If the head of the river is at kilometer 0, the axis is
ingo@422: * not inverted, otherwise it is.
ingo@422: *
ingo@422: * @param xaxis The domain axis.
ingo@422: */
ingo@422: protected void invertXAxis(ValueAxis xaxis) {
ingo@422:
sascha@745: if (inverted) {
ingo@1692: logger.debug("X-Axis.setInverted(true)");
ingo@422: xaxis.setInverted(true);
ingo@422: }
ingo@359: }
ingo@359:
ingo@359:
felix@1769: /**
felix@1769: * Produce output.
felix@1769: * @param facet current facet.
felix@1769: * @param attr theme for facet
felix@1769: */
ingo@1684: public void doOut(
felix@1944: ArtifactAndFacet artifactAndFacet,
felix@1944: Document attr,
felix@1944: boolean visible
ingo@1684: ) {
felix@1944: String name = artifactAndFacet.getFacetName();
ingo@359:
ingo@695: logger.debug("LongitudinalSectionGenerator.doOut: " + name);
ingo@695:
ingo@695: if (name == null) {
ingo@369: logger.error("No facet name for doOut(). No output generated!");
ingo@369: return;
ingo@369: }
ingo@369:
felix@1944: Facet facet = artifactAndFacet.getFacet();
ingo@696:
felix@1944: if (facet == null) {
ingo@696: return;
ingo@369: }
ingo@696:
ingo@696: if (name.equals(LONGITUDINAL_W)) {
felix@1944: doWOut((WQKms) artifactAndFacet.getData(context), facet, attr, visible);
ingo@696: }
ingo@696: else if (name.equals(LONGITUDINAL_Q)) {
felix@1944: doQOut((WQKms) artifactAndFacet.getData(context), facet, attr, visible);
ingo@369: }
felix@1028: else if (name.equals(LONGITUDINAL_ANNOTATION)) {
felix@1944: doAnnotations((FLYSAnnotation) artifactAndFacet.getData(context),
felix@1861: facet, attr, visible);
felix@1028: }
felix@1861: else if (name.equals(STATIC_WKMS)
felix@1861: || name.equals(HEIGHTMARKS_POINTS)
felix@1861: || name.equals(STATIC_WQKMS)) {
felix@1944: doWOut((WKms) artifactAndFacet.getData(context), facet, attr, visible);
felix@1769: }
felix@1769: else if (name.equals(W_DIFFERENCES)) {
felix@1769: doWDifferencesOut(
felix@1944: (WKms) artifactAndFacet.getData(context),
felix@1769: facet,
felix@1769: attr,
felix@1769: visible);
felix@1769: }
ingo@369: else {
ingo@695: logger.warn("Unknown facet name: " + name);
ingo@369: return;
ingo@369: }
ingo@369: }
ingo@369:
ingo@369:
felix@1037: /**
ingo@369: * Process the output for W facets in a longitudinal section curve.
ingo@369: *
ingo@369: * @param wqkms An array of WQKms values.
ingo@1712: * @param facet The facet. This facet does NOT support any data objects. Use
ingo@1712: * FLYSArtifact.getNativeFacet() instead to retrieve a Facet which supports
ingo@1712: * data.
ingo@924: * @param theme The theme that contains styling information.
ingo@1712: * @param visible The visibility of the curve.
ingo@369: */
ingo@1712: protected void doWOut(
felix@1769: WKms wkms,
ingo@1712: Facet facet,
ingo@1712: Document theme,
ingo@1712: boolean visible
ingo@1712: ) {
ingo@369: logger.debug("LongitudinalSectionGenerator.doWOut");
ingo@359:
ingo@1712: XYSeries series = new StyledXYSeries(facet.getDescription(), theme);
ingo@369:
felix@1791: StyledSeriesBuilder.addPoints(series, wkms);
ingo@696:
felix@1931: addAxisSeries(series, YAXIS.W.idx, visible);
sascha@745:
felix@1769: if (wkms instanceof WQKms) {
felix@1769: if (needInvertAxis((WQKms) wkms)) {
felix@1769: setInverted(true);
felix@1769: }
felix@1769: }
felix@1769: }
felix@1769:
felix@1769:
felix@1769: /**
felix@1769: * Add items to dataseries which describes the differences.
felix@1769: */
felix@1769: protected void doWDifferencesOut(
felix@1769: WKms wkms,
felix@1769: Facet facet,
felix@1769: Document theme,
felix@1769: boolean visible
felix@1769: ) {
felix@1769: logger.debug("WDifferencesCurveGenerator.doWDifferencesOut");
felix@1769: if (wkms == null) {
felix@1769: logger.warn("No data to add to WDifferencesChart.");
felix@1769: return;
felix@1769: }
felix@1769:
felix@1769: XYSeries series = new StyledXYSeries(facet.getDescription(), theme);
felix@1769:
felix@1769: if (logger.isDebugEnabled()) {
felix@1769: if (wkms.size() > 0) {
felix@1769: logger.debug("Generate series: " + series.getKey());
felix@1769: logger.debug("Start km: " + wkms.getKm(0));
felix@1791: logger.debug("End km: " + wkms.getKm(wkms.size() - 1));
felix@1791: logger.debug("Values : " + wkms.size());
felix@1769: }
felix@1769: }
felix@1769:
felix@1791: StyledSeriesBuilder.addPoints(series, wkms);
felix@1769:
felix@1931: addAxisSeries(series, YAXIS.D.idx, visible);
felix@1769: if (DataUtil.guessWaterIncreasing(wkms.allWs())) {
sascha@745: setInverted(true);
sascha@745: }
ingo@369: }
ingo@369:
ingo@369:
felix@1769:
ingo@369: /**
ingo@369: * Process the output for Q facets in a longitudinal section curve.
ingo@369: *
ingo@369: * @param wqkms An array of WQKms values.
ingo@1712: * @param facet The facet. This facet does NOT support any data objects. Use
ingo@1712: * FLYSArtifact.getNativeFacet() instead to retrieve a Facet which supports
ingo@1712: * data.
ingo@924: * @param theme The theme that contains styling information.
ingo@1712: * @param visible The visibility of the curve.
ingo@369: */
ingo@1712: protected void doQOut(
ingo@1712: WQKms wqkms,
ingo@1712: Facet facet,
ingo@1712: Document theme,
ingo@1712: boolean visible
ingo@1712: ) {
ingo@369: logger.debug("LongitudinalSectionGenerator.doQOut");
ingo@369:
ingo@1712: XYSeries series = new StyledXYSeries(facet.getDescription(), theme);
ingo@369:
felix@1936: StyledSeriesBuilder.addPointsKmQ(series, wqkms);
ingo@696:
felix@1931: addAxisSeries(series, YAXIS.Q.idx, visible);
sascha@745:
ingo@1692: if (needInvertAxis(wqkms)) {
ingo@1692: setInverted(true);
ingo@1692: }
ingo@1692: }
ingo@1692:
ingo@1692:
ingo@1692: /**
ingo@1692: * This method determines - taking JFreeCharts auto x value ordering into
ingo@1692: * account - if the x axis need to be inverted. Waterlines in these charts
ingo@1692: * should decrease.
ingo@1692: *
ingo@1692: * @param wqkms The data object that stores the x and y values used for this
ingo@1692: * chart.
ingo@1692: */
ingo@1692: public boolean needInvertAxis(WQKms wqkms) {
ingo@1692: boolean wsUp = wqkms.guessWaterIncreasing();
ingo@1692: boolean kmUp = DataUtil.guessWaterIncreasing(wqkms.allKms());
ingo@1692: boolean inv = (wsUp && kmUp) || (!wsUp && !kmUp);
ingo@1692:
ingo@1692: int size = wqkms.size();
ingo@1692:
ingo@1692: if (logger.isDebugEnabled()) {
ingo@1692: logger.debug("Values : " + size);
ingo@1692: if (size > 0) {
ingo@1692: logger.debug("Start km: " + wqkms.getKm(0));
ingo@1692: logger.debug("End km: " + wqkms.getKm(size-1));
ingo@1692: }
ingo@1692: logger.debug("wsUp: " + wsUp);
ingo@1692: logger.debug("kmUp: " + kmUp);
ingo@1692: logger.debug("inv: " + inv);
ingo@1692: }
ingo@1692:
ingo@1692: return inv;
ingo@369: }
ingo@369:
ingo@369:
felix@1041: /**
felix@1041: * Get name of series (displayed in legend).
felix@1041: * @return name of the series.
felix@1041: */
ingo@448: protected String getSeriesName(WQKms wqkms, String mode) {
ingo@448: String name = wqkms.getName();
ingo@448: String prefix = name != null && name.indexOf(mode) >= 0 ? null : mode;
ingo@448:
ingo@448: return prefix != null && prefix.length() > 0
ingo@448: ? prefix + "(" + name +")"
ingo@448: : name;
ingo@359: }
ingo@1991:
ingo@1991:
ingo@1991: @Override
ingo@1991: protected List buildAxisSections() {
ingo@1991: List axisSections = new ArrayList();
ingo@1991:
ingo@1991: for (YAXIS axis: YAXIS.values()) {
ingo@1991: String identifier = axis.toString();
ingo@1991:
ingo@1991: AxisSection axisSection = new AxisSection();
ingo@1991: axisSection.setIdentifier(identifier);
ingo@1991: axisSection.setLabel(getYAxisLabel(axis.idx));
ingo@1991:
ingo@1991: // TODO font-size
ingo@1991: // TODO fixation
ingo@1991: // TODO lower
ingo@1991: // TODO upper
ingo@1991:
ingo@1991: axisSections.add(axisSection);
ingo@1991: }
ingo@1991:
ingo@1991: return axisSections;
ingo@1991: }
ingo@359: }
ingo@359: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :