changeset 2020:4f7f781e4481

Improved area rendering workflow. flys-artifacts/trunk@3475 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Felix Wolfsteller <felix.wolfsteller@intevation.de>
date Tue, 20 Dec 2011 06:47:08 +0000
parents aa3e7ed1fa46
children 1ae17b100973
files flys-artifacts/ChangeLog flys-artifacts/src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java flys-artifacts/src/main/java/de/intevation/flys/exports/StyledAreaSeriesCollection.java flys-artifacts/src/main/java/de/intevation/flys/exports/XYChartGenerator.java
diffstat 4 files changed, 221 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- 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	<felix.wolfsteller@intevation.de>
+
+	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	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Added facets to compatibility
+	  matrices.
+
+	* doc/conf/themes.xml: Added Area theme defaults.
+
 2011-12-20	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
 
 	Lay ground for having areas in longitudinal section diagrams, too.
--- 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.
      *
--- /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 :
--- 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<XYDataset> 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<XYDataset> areaDatasets;
 
         /** Create AxisDataset. */
         public AxisDataset(int symb) {
             this.axisSymbol = symb;
             datasets        = new ArrayList<XYDataset>();
-            areaDatasets    = new ArrayList<XYDataset>();
         }
 
         /** 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);
 

http://dive4elements.wald.intevation.org