Mercurial > dive4elements > river
diff artifacts/src/main/java/org/dive4elements/river/exports/CrossSectionGenerator.java @ 5838:5aa05a7a34b7
Rename modules to more fitting names.
author | Sascha L. Teichmann <teichmann@intevation.de> |
---|---|
date | Thu, 25 Apr 2013 15:23:37 +0200 |
parents | flys-artifacts/src/main/java/org/dive4elements/river/exports/CrossSectionGenerator.java@bd047b71ab37 |
children | 4897a58c8746 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/CrossSectionGenerator.java Thu Apr 25 15:23:37 2013 +0200 @@ -0,0 +1,445 @@ +package org.dive4elements.river.exports; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Paint; +import java.awt.Stroke; +import java.text.NumberFormat; +import java.util.List; + +import org.apache.log4j.Logger; +import org.jfree.chart.LegendItemCollection; +import org.jfree.chart.annotations.XYBoxAnnotation; +import org.jfree.chart.annotations.XYTextAnnotation; +import org.jfree.chart.plot.XYPlot; +import org.jfree.data.xy.XYSeries; +import org.w3c.dom.Document; + +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.DataProvider; +import org.dive4elements.river.artifacts.FLYSArtifact; +import org.dive4elements.river.artifacts.geom.Lines; +import org.dive4elements.river.artifacts.model.CrossSectionFacet; +import org.dive4elements.river.artifacts.model.FacetTypes; +import org.dive4elements.river.artifacts.model.HYKFactory; +import org.dive4elements.river.artifacts.resources.Resources; +import org.dive4elements.river.jfree.FLYSAnnotation; +import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.model.FastCrossSectionLine; +import org.dive4elements.river.themes.LineStyle; +import org.dive4elements.river.themes.TextStyle; +import org.dive4elements.river.themes.ThemeAccess; +import org.dive4elements.river.utils.FLYSUtils; +import org.dive4elements.river.utils.Formatter; +import org.dive4elements.river.utils.ThemeUtil; + + +/** + * An OutGenerator that generates cross section graphs. + */ +public class CrossSectionGenerator +extends LongitudinalSectionGenerator +implements FacetTypes +{ + /** The logger that is used in this generator. */ + private static Logger logger = + Logger.getLogger(CrossSectionGenerator.class); + + public static final String I18N_CHART_TITLE = + "chart.cross_section.title"; + + public static final String I18N_CHART_SUBTITLE = + "chart.cross_section.subtitle"; + + public static final String I18N_XAXIS_LABEL = + "chart.cross_section.xaxis.label"; + + public static final String I18N_YAXIS_LABEL = + "chart.cross_section.yaxis.label"; + + public static final String I18N_CHART_TITLE_DEFAULT = "Querprofildiagramm"; + public static final String I18N_XAXIS_LABEL_DEFAULT = "Abstand [m]"; + public static final String I18N_YAXIS_LABEL_DEFAULT = "W [NN + m]"; + + + /** Trivial Constructor. */ + public CrossSectionGenerator() { + super(); + } + + + @Override + protected YAxisWalker getYAxisWalker() { + return new YAxisWalker() { + @Override + public int length() { + return 1; + } + + /** Get identifier for this index. */ + @Override + public String getId(int idx) { + return "W"; + } + }; + } + + + /** + * Get localized chart title. + */ + @Override + public String getDefaultChartTitle() { + Object[] i18n_msg_args = new Object[] { + getRiverName() + }; + return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT, i18n_msg_args); + } + + + /** Always return default subtitle. */ + @Override + protected String getChartSubtitle() { + // XXX NOTE: overriding this method disables ChartSettings subtitle! + // The default implementation of this method in ChartGenerator returns + // the subtitle changed via the chart settings dialog. This method + // always returns the subtitle containing river and km, NEVER the + // ChartSettings subtitle! + return getDefaultChartSubtitle(); + } + + + /** Get Charts default subtitle. */ + @Override + protected String getDefaultChartSubtitle() { + List<DataProvider> providers = + context.getDataProvider(CrossSectionFacet.BLACKBOARD_CS_MASTER_DATA); + double km = 0d; + if (providers.size() > 0) { + FastCrossSectionLine csl = (FastCrossSectionLine) providers.get(0). + provideData(CrossSectionFacet.BLACKBOARD_CS_MASTER_DATA, + null, context); + km = csl == null ? -1 : csl.getKm(); + } + + Object[] args = new Object[] { + getRiverName(), + km + }; + + logger.debug("Locale: " + Resources.getLocale(context.getMeta())); + + return msg(I18N_CHART_SUBTITLE, "", args); + } + + + /** Get color for hyk zones by their type (which is the name). */ + protected Paint colorForHYKZone(String zoneName) { + if (zoneName.startsWith("R")) { + // Brownish. + return new Color(153, 60, 0); + } + else if (zoneName.startsWith("V")) { + // Greenish. + return new Color(0, 255, 0); + } + else if (zoneName.startsWith("B")) { + // Grayish. + return new Color(128, 128, 128); + } + else if (zoneName.startsWith("H")) { + // Blueish. + return new Color(0, 0, 255); + } + else { + // Default. + logger.debug("Unknown zone type found."); + return new Color(255, 0, 0); + } + } + + @Override + protected void addAnnotationsToRenderer(XYPlot plot) { + super.addAnnotationsToRenderer(plot); + + // Paints for the boxes/lines. + Stroke basicStroke = new BasicStroke(1.0f); + + // XXX: DEAD CODE // Paint linePaint = new Color(255, 0,0,60); + Paint fillPaint = new Color(0, 255,0,60); + Paint tranPaint = new Color(0, 0,0, 0); + + // OPTMIMIZE: Pre-calculate positions + ChartArea area = new ChartArea( + plot.getDomainAxis(0).getRange(), + plot.getRangeAxis().getRange()); + + for(FLYSAnnotation fa : this.annotations) { + + // Access text styling, if any. + Document theme = fa.getTheme(); + TextStyle textStyle = null; + // XXX: DEAD CODE // LineStyle lineStyle = null; + + // Get Themeing information and add legend item. + if (theme != null) { + ThemeAccess themeAccess = new ThemeAccess(theme); + textStyle = themeAccess.parseTextStyle(); + // XXX: DEAD CODE // lineStyle = themeAccess.parseLineStyle(); + if (fa.getLabel() != null) { + LegendItemCollection lic = new LegendItemCollection(); + LegendItemCollection old = plot.getFixedLegendItems(); + lic.add(createLegendItem(theme, fa.getLabel())); + // (Re-)Add prior legend entries. + if (old != null) { + old.addAll(lic); + } + else { + old = lic; + } + plot.setFixedLegendItems(old); + } + } + + // Hyks. + for (HYKFactory.Zone zone: fa.getBoxes()) { + // For each zone, create a box to fill with color, a box to draw + // the lines and a text to display the type. + fillPaint = colorForHYKZone(zone.getName()); + + XYBoxAnnotation boxA = new XYBoxAnnotation(zone.getFrom(), area.atGround(), + zone.getTo(), area.ofGround(0.03f), basicStroke, tranPaint, fillPaint); + XYBoxAnnotation boxB = new XYBoxAnnotation(zone.getFrom(), area.atGround(), + zone.getTo(), area.atTop(), basicStroke, fillPaint, tranPaint); + + XYTextAnnotation tex = new XYTextAnnotation(zone.getName(), + zone.getFrom() + (zone.getTo() - zone.getFrom()) / 2.0d, + area.ofGround(0.015f)); + if (textStyle != null) { + textStyle.apply(tex); + } + + plot.getRenderer().addAnnotation(boxA, org.jfree.ui.Layer.BACKGROUND); + plot.getRenderer().addAnnotation(boxB, org.jfree.ui.Layer.BACKGROUND); + plot.getRenderer().addAnnotation(tex, org.jfree.ui.Layer.BACKGROUND); + } + } + } + + @Override + protected String getDefaultXAxisLabel() { + return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT); + } + + + @Override + protected String getDefaultYAxisLabel(int pos) { + FLYSArtifact flys = (FLYSArtifact) master; + + String unit = FLYSUtils.getRiver(flys).getWstUnit().getName(); + + return msg(I18N_YAXIS_LABEL, + I18N_YAXIS_LABEL_DEFAULT, + new Object[] { unit }); + } + + + /** + * Let one facet do its job. + */ + @Override + public void doOut( + ArtifactAndFacet artifactFacet, + Document attr, + boolean visible + ) { + String name = artifactFacet.getFacetName(); + + logger.debug("CrossSectionGenerator.doOut: " + name); + + if (name == null) { + logger.error("No facet name for doOut(). No output generated!"); + return; + } + + if (name.equals(CROSS_SECTION)) { + doCrossSectionOut( + artifactFacet.getData(context), + artifactFacet.getFacetDescription(), + attr, + visible); + } + else if (name.equals(CROSS_SECTION_WATER_LINE)) { + doCrossSectionWaterLineOut( + artifactFacet.getData(context), + artifactFacet.getFacetDescription(), + attr, + visible); + } + else if (FacetTypes.IS.AREA(name)) { + doArea(artifactFacet.getData(context), + artifactFacet, + attr, + visible); + } + else if (name.equals(HYK)) { + doHyk(artifactFacet.getData(context), + artifactFacet.getFacetDescription(), + attr, + visible); + } + else if (FacetTypes.IS.MANUALLINE(name)) { + doCrossSectionWaterLineOut( + artifactFacet.getData(context), + artifactFacet.getFacetDescription(), + attr, + visible); + } + else if (FacetTypes.IS.MANUALPOINTS(name)) { + doPoints(artifactFacet.getData(context), + artifactFacet, + attr, visible, YAXIS.W.idx); + } + else { + logger.warn("CrossSection.doOut: Unknown facet name: " + name); + return; + } + } + + + /** Look up the axis identifier for a given facet type. */ + @Override + public int axisIdxForFacet(String facetName) { + // TODO Where to add thid axis too. + return 0; + } + + + /** + * Do cross sections waterline out. + * + * @param seriesName name of the data (line) to display in legend. + * @param theme Theme for the data series. + */ + protected void doCrossSectionWaterLineOut( + Object o, + String seriesName, + Document theme, + boolean visible + ) { + logger.debug("CrossSectionGenerator.doCrossSectionWaterLineOut"); + + Lines.LineData lines = (Lines.LineData) o; + // DO NOT SORT DATA! This destroys the gaps indicated by NaNs. + StyledXYSeries series = new StyledXYSeries(seriesName, false, theme); + + if (!ThemeUtil.parseShowLineLabel(theme)) { + series.setLabel(""); + } + if (ThemeUtil.parseShowWidth(theme)) { + NumberFormat nf = Formatter.getMeterFormat(this.context); + String labelAdd = "b=" + nf.format(lines.width) + "m"; + if (series.getLabel().length() == 0) { + series.setLabel(labelAdd); + } + else { + series.setLabel(series.getLabel() + ", " + labelAdd); + } + } + if (ThemeUtil.parseShowLevel(theme) && lines.points.length > 1 + && lines.points[1].length > 0) { + NumberFormat nf = Formatter.getMeterFormat(this.context); + FLYSArtifact flys = (FLYSArtifact) master; + + String unit = FLYSUtils.getRiver(flys).getWstUnit().getName(); + + String labelAdd = "W=" + nf.format(lines.points[1][0]) + unit; + if (series.getLabel().length() == 0) { + series.setLabel(labelAdd); + } + else { + series.setLabel(series.getLabel() + ", " + labelAdd); + } + } + if (ThemeUtil.parseShowMiddleHeight(theme) && lines.width != 0) { + NumberFormat nf = Formatter.getMeterFormat(this.context); + String labelAdd = "T=" + nf.format(lines.area / lines.width) + "m"; + // : " + lines.area + "/" + lines.width); + if (series.getLabel().length() == 0) { + series.setLabel(labelAdd); + } + else { + series.setLabel(series.getLabel() + ", " + labelAdd); + } + } + + StyledSeriesBuilder.addPoints(series, lines.points, false); + + addAxisSeries(series, 0, visible); + } + + + /** Add HYK-Annotations (colorize and label some areas, draw lines. */ + protected void doHyk( + Object o, + String seriesName, + Document theme, + boolean visible + ) { + logger.debug("CrossSectionGenerator.doHyk"); + + List<HYKFactory.Zone> zones = (List<HYKFactory.Zone>) o; + + if (zones == null || zones.isEmpty()) { + logger.warn("CrossSectionGenerator.doHYK: empty zone list received."); + return; + } + + // Actual Styling is done in XYChartGenerator. + if (visible) { + addAnnotations(new FLYSAnnotation(seriesName, null, zones, theme)); + } + } + + + /** + * Do cross sections out. + * + * @param seriesName name of the data (line) to display in legend. + * @param theme Theme for the data series. + */ + protected void doCrossSectionOut( + Object o, + String seriesName, + Document theme, + boolean visible + ) { + logger.debug("CrossSectionGenerator.doCrossSectionOut"); + + XYSeries series = new StyledXYSeries(seriesName, theme); + + StyledSeriesBuilder.addPoints(series, (double [][]) o, false); + + addAxisSeries(series, 0, visible); + } + + + /** + * Creates a new <i>ChartSection</i>. + * + * Overridden to prevent inclusion of subtitle. + * + * @return a new <i>ChartSection</i>. + */ + @Override + protected ChartSection buildChartSection() { + ChartSection chartSection = new ChartSection(); + chartSection.setTitle(getChartTitle()); + chartSection.setDisplayGrid(isGridVisible()); + chartSection.setDisplayLogo(showLogo()); + chartSection.setLogoVPlacement(logoVPlace()); + chartSection.setLogoHPlacement(logoHPlace()); + return chartSection; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :