# HG changeset patch # User Felix Wolfsteller # Date 1324363628 0 # Node ID 4f7f781e44819076c9ad38525c9a09ea85ee4c52 # Parent aa3e7ed1fa46645a8450b9b418c314d7d7095d5b Improved area rendering workflow. flys-artifacts/trunk@3475 c6561f87-3c4e-4783-a992-168aeb5c3f6f diff -r aa3e7ed1fa46 -r 4f7f781e4481 flys-artifacts/ChangeLog --- a/flys-artifacts/ChangeLog Tue Dec 20 06:39:20 2011 +0000 +++ b/flys-artifacts/ChangeLog Tue Dec 20 06:47:08 2011 +0000 @@ -1,3 +1,30 @@ +2011-12-20 Felix Wolfsteller + + Added further 'area' infrastructure. + + * src/main/java/de/intevation/flys/exports/StyledAreaSeriesCollection.java: + New, "area dataset". + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java + (doOut): Use helper to decide if facet is an 'area' facet. + (doArea): Construct StyledAreaSeriesCollection instead of two + dataseries. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + (AxisDataset.isArea): Distinguish area datasets with instanceof. + (AxisDataset.addArea): New. Replaces addAreaDataset. + (addAreaSeries): Simplified with new custom SeriesCollection. + (applyTheme): Register and style StableXYDifferenceRenderer for + StyledAreaSeriesCollections. + Added various TODOs and debug output to stabilize development. + +2011-12-20 Felix Wolfsteller + + * doc/conf/artifacts/winfo.xml: Added facets to compatibility + matrices. + + * doc/conf/themes.xml: Added Area theme defaults. + 2011-12-20 Felix Wolfsteller Lay ground for having areas in longitudinal section diagrams, too. diff -r aa3e7ed1fa46 -r 4f7f781e4481 flys-artifacts/src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java --- a/flys-artifacts/src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java Tue Dec 20 06:39:20 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java Tue Dec 20 06:47:08 2011 +0000 @@ -148,7 +148,7 @@ attr, visible); } - else if (name.equals(AREA)) { + else if (FacetTypes.IS.AREA(name)) { doArea(artifactFacet.getData(context), artifactFacet.getFacetDescription(), attr, @@ -160,6 +160,7 @@ } } + /** * Do Area out. */ @@ -170,16 +171,43 @@ boolean visible ) { logger.debug("CrossSectionGenerator.doArea"); + StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(theme); // TODO make this more stable. Object[] doubles = (Object[]) o; - XYSeries up = new StyledXYSeries("up", false, theme); - XYSeries down = new StyledXYSeries("down", false, theme); - StyledSeriesBuilder.addPoints(up, (double [][]) doubles[0]); - StyledSeriesBuilder.addPoints(down, (double [][]) doubles[1]); - addAreaSeries(up, down, 0, visible); + XYSeries up = null; + XYSeries down = null; + + if (doubles[1] != null) { + up = new StyledXYSeries(seriesName, false, theme); + StyledSeriesBuilder.addPoints(up, (double [][]) doubles[1]); + } + + if (doubles[0] != null) { + // TODO: Sort this out: when the two series have the same name, + // the renderer (or anything in between) will not work correctly. + down = new StyledXYSeries(seriesName + " ", false, theme); + StyledSeriesBuilder.addPoints(down, (double [][]) doubles[0]); + } + + if (up == null && down != null) { + area.setMode(StyledAreaSeriesCollection.FILL_MODE.ABOVE); + down.setKey(seriesName); + area.addSeries(down); + } + else if (up != null && down == null) { + area.setMode(StyledAreaSeriesCollection.FILL_MODE.UNDER); + area.addSeries(up); + } + else if (up != null && down != null) { + area.setMode(StyledAreaSeriesCollection.FILL_MODE.BETWEEN); + area.addSeries(up); + area.addSeries(down); + } + addAreaSeries(area, 0, visible); } + /** * Do cross sections waterline out. * diff -r aa3e7ed1fa46 -r 4f7f781e4481 flys-artifacts/src/main/java/de/intevation/flys/exports/StyledAreaSeriesCollection.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/StyledAreaSeriesCollection.java Tue Dec 20 06:47:08 2011 +0000 @@ -0,0 +1,96 @@ +package de.intevation.flys.exports; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Paint; +import java.awt.geom.Ellipse2D; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +import org.jfree.data.xy.XYSeriesCollection; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.data.Range; +import org.jfree.data.xy.XYSeries; + +import de.intevation.flys.utils.ThemeUtil; +import de.intevation.flys.jfree.StableXYDifferenceRenderer; + + +/** + * One or more dataseries to draw a polygon (either "open up/downwards", or + * the area between two curves), a theme-document and further display options. + * The theme-document will later "style" the graphical representation. + * The display options can be used to control the z-order and the axis of the + * dataset. + */ +public class StyledAreaSeriesCollection extends XYSeriesCollection { + /** Mode, how to draw/which areas to fill. */ + public enum FILL_MODE {UNDER, ABOVE, BETWEEN}; + + /** MODE in use. */ + protected FILL_MODE mode; + + /** The theme-document with attributes about actual visual representation. */ + protected Document theme; + + /** Own logger. */ + private static final Logger logger = + Logger.getLogger(StyledAreaSeriesCollection.class); + + + /** + * @param theme the theme-document. + */ + public StyledAreaSeriesCollection(Document theme) { + this.theme = theme; + this.mode = FILL_MODE.BETWEEN; + } + + + /** Gets the Fill mode. */ + public FILL_MODE getMode() { + return this.mode; + } + + + /** Sets the Fill mode. */ + public void setMode(FILL_MODE fMode) { + this.mode = fMode; + } + + + /** + * Applies line color, size and type attributes to renderer, also + * whether to draw lines and/or points. + */ + public StableXYDifferenceRenderer applyTheme( + StableXYDifferenceRenderer renderer + ) { + applyFillColor(renderer); + applyShowShape(renderer); + + return renderer; + } + + + /** + * Blindly (for now) apply the postiviepaint of renderer. + */ + protected void applyFillColor(StableXYDifferenceRenderer renderer) { + Paint paint = ThemeUtil.parseFillColorField(theme); + if (paint != null) + renderer.setPositivePaint(paint); + // TODO set negativepaint? Dependend on the over/under/between settings + } + + /** + * Blindly (for now) apply the postiviepaint of renderer. + */ + protected void applyShowShape(StableXYDifferenceRenderer renderer) { + boolean show = ThemeUtil.parseShowBorder(theme); + renderer.setShapesVisible(show); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r aa3e7ed1fa46 -r 4f7f781e4481 flys-artifacts/src/main/java/de/intevation/flys/exports/XYChartGenerator.java --- a/flys-artifacts/src/main/java/de/intevation/flys/exports/XYChartGenerator.java Tue Dec 20 06:39:20 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/XYChartGenerator.java Tue Dec 20 06:47:08 2011 +0000 @@ -2,7 +2,13 @@ import java.awt.BasicStroke; import java.awt.Color; +import java.awt.Paint; import java.awt.Stroke; +import java.awt.TexturePaint; + +import java.awt.geom.Rectangle2D; + +import java.awt.image.BufferedImage; import java.io.IOException; @@ -66,6 +72,7 @@ */ public abstract class XYChartGenerator extends ChartGenerator { + // TODO Consider storing the renderer here. private class AxisDataset { /** Symbolic integer, but also coding the priority (0 goes first). */ protected int axisSymbol; @@ -73,15 +80,11 @@ protected List datasets; /** Range to use to include all given datasets. */ protected Range range; - /** List of datasets that are "area datasets" (these will be also - * present in the datasets list). */ - List areaDatasets; /** Create AxisDataset. */ public AxisDataset(int symb) { this.axisSymbol = symb; datasets = new ArrayList(); - areaDatasets = new ArrayList(); } /** Merge (or create given range with range so far (if any). */ @@ -105,19 +108,13 @@ includeYRange(dataset); } - /** Add an area dataset. */ - public void addAreaDataset(XYSeries series1, XYSeries series2) { - XYSeriesCollection collection = new XYSeriesCollection(); - collection.addSeries(series1); - collection.addSeries(series2); - this.datasets.add(collection); - this.areaDatasets.add(collection); - // TODO include Range ... + public void addArea(StyledAreaSeriesCollection series) { + this.datasets.add(series); } /** True if to be renedered as area. */ public boolean isArea(XYSeriesCollection series) { - return areaDatasets.contains(series); + return (series instanceof StyledAreaSeriesCollection); } /** Adjust range to include given dataset. */ @@ -142,13 +139,16 @@ } + /** Override to make axis information available. */ protected YAxisWalker getYAxisWalker() { return new YAxisWalker() { + /** Get number of items. */ @Override public int length() { return 0; } + /** Get identifier for this index. */ @Override public String getId(int idx) { return null; @@ -436,8 +436,8 @@ * @param lower the lower curve to draw the area from. * @param upper the upper curve to draw the ara from. */ - public void addAreaSeries(Object lower, Object upper, int index, boolean visible) { - if (lower == null && upper == null) { + public void addAreaSeries(StyledAreaSeriesCollection area, int index, boolean visible) { + if (area == null) { logger.warn("Cannot yet render above/under curve."); return; } @@ -448,14 +448,16 @@ datasets.put(index, axisDataset); } - if (visible) - axisDataset.addAreaDataset((XYSeries) lower, (XYSeries) upper); + if (visible) { + axisDataset.addArea(area); + } else { // TODO only range merging. } //TODO range merging. } + /** * Add given series if visible, if not visible adjust ranges (such that * all points in data would be plotted once visible). @@ -786,6 +788,7 @@ } + /** Override to handle subtitle adding. */ protected void addSubtitles(JFreeChart chart) { // override this method in subclasses that need subtitles } @@ -863,17 +866,37 @@ LegendItemCollection lic = new LegendItemCollection(); LegendItemCollection anno = plot.getFixedLegendItems(); - XYLineAndShapeRenderer renderer = getRenderer(plot, idx); int retidx = idx; if (isArea) { - logger.debug("Registering an 'area'renderer."); - plot.setRenderer(retidx, new StableXYDifferenceRenderer()); - // TODO to legend entry - // TODO to styling - return retidx +1; + logger.debug("Registering an 'area'renderer at idx: " + idx); + StyledAreaSeriesCollection area = (StyledAreaSeriesCollection) series; + + StableXYDifferenceRenderer dRenderer = new StableXYDifferenceRenderer(); + if (area.getMode() == StyledAreaSeriesCollection.FILL_MODE.UNDER) { + dRenderer.setPositivePaint(createTransparentPaint()); + } + plot.setRenderer(idx, dRenderer); + + area.applyTheme(dRenderer); + + LegendItem legendItem = dRenderer.getLegendItem(idx, 0); + if (legendItem != null) { + lic.add(legendItem); + } + else { + logger.warn("Could not get LegentItem for renderer: " + + idx + ", series-idx " + 0); + } + if (anno != null) { + lic.addAll(anno); + } + plot.setFixedLegendItems(lic); + return retidx + 1; } + XYLineAndShapeRenderer renderer = getRenderer(plot, idx); + for (int s = 0, num = series.getSeriesCount(); s < num; s++) { XYSeries serie = series.getSeries(s); @@ -888,14 +911,15 @@ renderer.setSeriesShapesVisible(s, true); } - LegendItem li = renderer.getLegendItem(idx, s); - if (li != null) { - lic.add(li); + LegendItem legendItem = renderer.getLegendItem(idx, s); + if (legendItem != null) { + lic.add(legendItem); } else { logger.warn("Could not get LegentItem for renderer: " - + idx + ", series-idx " + s); + + idx + ", series-idx " + s); } + // TODO: why that? isnt renderer set per dataset not per series? retidx++; } @@ -911,10 +935,23 @@ } + /** Returns a transparently textured paint. */ + // TODO why not use a transparent color? + protected static Paint createTransparentPaint() { + BufferedImage texture = new BufferedImage( + 1, 1, BufferedImage.TYPE_4BYTE_ABGR); + + return new TexturePaint( + texture, new Rectangle2D.Double(0d, 0d, 0d, 0d)); + } + + /** * Get renderer, from plot or cloned default renderer otherwise. */ protected XYLineAndShapeRenderer getRenderer(XYPlot plot, int idx) { + // !TODO what if its a differencerenderer?! + logger.debug("getRenderer: " + idx); XYLineAndShapeRenderer r = (XYLineAndShapeRenderer) plot.getRenderer(idx);