changeset 422:f426f55d4f7a

Added Ingo Weinzierl's special JFreeChart classes. gnv-artifacts/trunk@470 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 21 Dec 2009 16:47:45 +0000
parents fd71ee76fa58
children 2402173a1490
files gnv-artifacts/ChangeLog gnv-artifacts/src/main/java/de/intevation/gnv/jfreechart/CompactXYItems.java gnv-artifacts/src/main/java/de/intevation/gnv/jfreechart/PolygonDataset.java gnv-artifacts/src/main/java/de/intevation/gnv/jfreechart/PolygonPlot.java gnv-artifacts/src/main/java/de/intevation/gnv/jfreechart/PolygonRenderer.java gnv-artifacts/src/main/java/de/intevation/gnv/jfreechart/PolygonSeries.java
diffstat 6 files changed, 949 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/gnv-artifacts/ChangeLog	Mon Dec 21 16:01:35 2009 +0000
+++ b/gnv-artifacts/ChangeLog	Mon Dec 21 16:47:45 2009 +0000
@@ -1,3 +1,25 @@
+2009-12-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Added Ingo Weinzierl's special JFreeChart classes.
+
+	* src/main/java/de/intevation/gnv/jfreechart: New package.
+	  Should contain general JFreeChart stuff.
+
+	* src/main/java/de/intevation/gnv/jfreechart/PolygonPlot.java: New.
+	  New type of plot to display multi-polygons with holes.
+
+	* src/main/java/de/intevation/gnv/jfreechart/CompactXYItems.java: New.
+	  Basic vertex data model: a ring of a polygon. ccw = shell, cw = hole.
+
+	* src/main/java/de/intevation/gnv/jfreechart/PolygonSeries.java: New.
+	  Attributes a set of rings with key/value pairs.
+
+	* src/main/java/de/intevation/gnv/jfreechart/PolygonDataset.java: New
+	  List of PolygonSeries which makes it a multi-polygon.
+
+	* src/main/java/de/intevation/gnv/jfreechart/PolygonRenderer.java: New
+	  A renderer to draw PolygonDatasets into a PolygonPlot.
+	
 2009-12-21  Ingo Weinzierl <ingo.weinzierl@intevation.de>
 
 	* doc/conf/products/verticalcrosssection/conf_mesh.xml: Prepared states and
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/jfreechart/CompactXYItems.java	Mon Dec 21 16:47:45 2009 +0000
@@ -0,0 +1,128 @@
+package de.intevation.gnv.jfreechart;
+
+import java.io.Serializable;
+
+/**
+ * @author Sascha Teichmann <sascha.teichmann@intevation.de>
+ * @author Ingo Weinzierl <ingo.weinzierl@intevation.de>
+ */
+public class CompactXYItems
+implements   Serializable
+{
+    protected double [] data;
+
+    public CompactXYItems(double [] data) {
+        this.data = data;
+    }
+
+    public double getX(int index) {
+        return data[index << 1];
+    }
+
+    public double getY(int index) {
+        return data[(index << 1)+1];
+    }
+
+    public void get(int index, double [] xy) {
+        xy[0] = data[index = (index << 1) + 1];
+        xy[1] = data[index + 1];
+    }
+
+    public double [] getData() {
+        return data;
+    }
+
+    public void setData(double [] data) {
+        this.data = data;
+    }
+
+    public int size() {
+        return data.length >> 1;
+    }
+
+    public double [] calculateBoundingBox(double [] bbox)  {
+        for (int i = 0; i < data.length;) {
+            double x = data[i++];
+            double y = data[i++];
+            if (x < bbox[0]) bbox[0] = x;
+            if (y < bbox[1]) bbox[1] = y;
+            if (x > bbox[2]) bbox[2] = x;
+            if (y > bbox[3]) bbox[3] = y;
+        }
+        return bbox;
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < data.length;) {
+            if (i > 0) sb.append("; ");
+            sb.append('(');
+            sb.append(data[i++]);
+            sb.append(", ");
+            sb.append(data[i++]);
+            sb.append(')');
+        }
+        return sb.toString();
+    }
+
+
+    public double getMinX() {
+        double lower = Double.POSITIVE_INFINITY;
+
+        for (int i = 0; i < data.length; i += 2) {
+            double x = data[i];
+
+            if (!Double.isNaN(x)) {
+                lower = Math.min(lower, x);
+            }
+        }
+
+        return lower;
+    }
+
+
+    public double getMaxX() {
+        double upper = Double.NEGATIVE_INFINITY;
+
+        for (int i = 0; i < data.length; i += 2) {
+            double x = data[i];
+
+            if (!Double.isNaN(x)) {
+                upper = Math.max(upper, x);
+            }
+        }
+
+        return upper;
+    }
+
+
+    public double getMinY() {
+        double lower = Double.POSITIVE_INFINITY;
+
+        for (int i = 1; i < data.length; i += 2) {
+            double y = data[i];
+
+            if (!Double.isNaN(y)) {
+                lower = Math.min(lower, y);
+            }
+        }
+
+        return lower;
+    }
+
+
+    public double getMaxY() {
+        double upper = Double.NEGATIVE_INFINITY;
+
+        for (int i = 1; i < data.length; i += 2) {
+            double y = data[i];
+
+            if (!Double.isNaN(y)) {
+                upper = Math.max(upper, y);
+            }
+        }
+
+        return upper;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/jfreechart/PolygonDataset.java	Mon Dec 21 16:47:45 2009 +0000
@@ -0,0 +1,103 @@
+package de.intevation.gnv.jfreechart;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import org.jfree.data.Range;
+import org.jfree.data.general.AbstractSeriesDataset;
+
+/**
+ * @author Ingo Weinzierl <ingo.weinzierl@intevation.de>
+ */
+public class PolygonDataset
+extends      AbstractSeriesDataset
+{
+    /** PolygonSeries included in this Dataset */
+    private List data;
+
+
+    public PolygonDataset() {
+        this(null);
+    }
+
+
+    public PolygonDataset(PolygonSeries series) {
+        data = new ArrayList();
+
+        if (series != null) {
+            data.add(series);
+        }
+    }
+
+
+    public void addSeries(PolygonSeries series) {
+        if (series == null)
+            throw new IllegalArgumentException("Null 'series' argument.");
+
+        data.add(series);
+    }
+
+
+    public Range getDomainBounds() {
+        double lower       = Double.POSITIVE_INFINITY;
+        double upper       = Double.NEGATIVE_INFINITY;
+        int    seriesCount = getSeriesCount();
+
+        for (int s = 0; s < seriesCount; s++) {
+            PolygonSeries series = getSeries(s);
+
+            Range domainRange = series.getDomainBounds();
+            double minX = domainRange.getLowerBound();
+            if (!Double.isNaN(minX)) {
+                lower = Math.min(lower, minX);
+            }
+
+            double maxX = domainRange.getUpperBound();
+            if (!Double.isNaN(maxX)) {
+                upper = Math.max(upper, maxX);
+            }
+        }
+
+        return new Range(lower, upper);
+    }
+
+
+    public Range getRangeBounds() {
+        double lower       = Double.POSITIVE_INFINITY;
+        double upper       = Double.NEGATIVE_INFINITY;
+        int    seriesCount = getSeriesCount();
+
+        for (int i = 0; i < seriesCount; i++) {
+            PolygonSeries series = getSeries(i);
+
+            Range range = series.getRangeBounds();
+            double minX = range.getLowerBound();
+            if (!Double.isNaN(minX)) {
+                lower = Math.min(lower, minX);
+            }
+
+            double maxX = range.getUpperBound();
+            if (!Double.isNaN(maxX)) {
+                upper = Math.max(upper, maxX);
+            }
+        }
+
+        return new Range(lower, upper);
+    }
+
+
+    public int getSeriesCount() {
+        return data.size();
+    }
+
+
+    public Comparable getSeriesKey(int series) {
+        return ((PolygonSeries)data.get(series)).getKey();
+    }
+
+
+    public PolygonSeries getSeries(int idx) {
+        return (PolygonSeries)data.get(idx);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/jfreechart/PolygonPlot.java	Mon Dec 21 16:47:45 2009 +0000
@@ -0,0 +1,416 @@
+package de.intevation.gnv.jfreechart;
+
+import java.awt.AlphaComposite;
+import java.awt.Composite;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.jfree.chart.axis.Axis;
+import org.jfree.chart.axis.AxisCollection;
+import org.jfree.chart.axis.AxisLocation;
+import org.jfree.chart.axis.AxisSpace;
+import org.jfree.chart.axis.AxisState;
+import org.jfree.chart.axis.ValueAxis;
+
+import org.jfree.chart.plot.Plot;
+import org.jfree.chart.plot.PlotRenderingInfo;
+import org.jfree.chart.plot.PlotState;
+import org.jfree.chart.plot.PlotOrientation;
+
+import org.jfree.data.Range;
+
+import org.jfree.ui.RectangleEdge;
+import org.jfree.ui.RectangleInsets;
+
+import org.jfree.util.ObjectList;
+
+/**
+ * @author Ingo Weinzierl <ingo.weinzierl@intevation.de>
+ */
+// TODO implement cloneable
+public class PolygonPlot
+extends      Plot
+{
+    public static final String PLOT_TYPE = "PolygonPlot";
+
+    public static final PlotOrientation DEFAULT_PLOT_ORIENTATION =
+        PlotOrientation.VERTICAL;
+
+    private PolygonDataset  dataset;
+    private transient PolygonRenderer renderer;
+
+    private PlotOrientation orientation;
+
+    private RectangleInsets axisOffset;
+
+    private ObjectList      domainAxisLocation;
+    private ObjectList      rangeAxisLocation;
+    private ObjectList      domainAxes;
+    private ObjectList      rangeAxes;
+
+
+    public PolygonPlot(PolygonDataset dataset, PolygonRenderer renderer) {
+        this(dataset, renderer, null, null, PlotOrientation.HORIZONTAL);
+    }
+
+
+    public PolygonPlot(
+        PolygonDataset  dataset,
+        PolygonRenderer renderer,
+        PlotOrientation orientation
+    ) {
+        this(dataset, renderer, null, null, orientation);
+    }
+
+
+    public PolygonPlot(
+        PolygonDataset  dataset,
+        PolygonRenderer renderer,
+        ValueAxis       domainAxis,
+        ValueAxis       rangeAxis,
+        PlotOrientation orientation
+    ) {
+        super();
+
+        this.dataset            = dataset;
+        this.renderer           = renderer;
+        this.domainAxes         = new ObjectList();
+        this.rangeAxes          = new ObjectList();
+        this.domainAxisLocation = new ObjectList();
+        this.rangeAxisLocation  = new ObjectList();
+        this.axisOffset         = RectangleInsets.ZERO_INSETS;
+
+        if (orientation != null)
+            this.orientation = orientation;
+        else
+            this.orientation = DEFAULT_PLOT_ORIENTATION;
+
+        if (domainAxis != null) {
+            this.domainAxes.set(0, domainAxis);
+            domainAxis.setPlot(this);
+        }
+        domainAxisLocation.set(0, AxisLocation.BOTTOM_OR_LEFT);
+
+        if (rangeAxis != null) {
+            this.rangeAxes.set(0, rangeAxis);
+            rangeAxis.setPlot(this);
+        }
+        rangeAxisLocation.set(0, AxisLocation.BOTTOM_OR_LEFT);
+
+        configureDomainAxis();
+        configureRangeAxis();
+    }
+
+
+    public void configureDomainAxis() {
+        // we just have 1 dataset
+        Range domainAxisRange = getDataset().getDomainBounds();
+
+        for (int i = 0; i < domainAxes.size(); i++) {
+            ValueAxis axis = (ValueAxis) domainAxes.get(i);
+
+            if (axis != null) {
+                axis.configure();
+                axis.setRange(domainAxisRange);
+            }
+        }
+    }
+
+
+    public  void configureRangeAxis() {
+        // we just have 1 dataset
+        Range rangeAxisRange = getDataset().getRangeBounds();
+
+        for (int i = 0; i < rangeAxes.size(); i++) {
+            ValueAxis axis = (ValueAxis) rangeAxes.get(i);
+
+            if (axis != null) {
+                axis.configure();
+                axis.setRange(rangeAxisRange);
+            }
+        }
+    }
+
+
+    public PolygonDataset getDataset(){
+        return this.dataset;
+    }
+
+
+    public String getPlotType() {
+        return PLOT_TYPE;
+    }
+
+
+    public  void setDataset(PolygonDataset dataset) {
+        this.dataset = dataset;
+    }
+
+
+    public void draw(
+        Graphics2D        g2,
+        Rectangle2D       area,
+        Point2D           anchor,
+        PlotState         parentState,
+        PlotRenderingInfo info
+    ) {
+        System.out.println("Start drawing plot.");
+
+        Graphics2D  savedG2       = g2;
+        Rectangle2D savedDataArea = area;
+
+        if (info != null) {
+            info.setPlotArea(area);
+            info.setDataArea(area);
+        }
+
+        AxisSpace space      = calculateAxisSpace(g2, area);
+        Rectangle2D dataArea = space.shrink(area, null);
+
+        // draw background and outline
+        drawBackground(g2, area);
+        drawOutline(g2, area);
+
+        Shape savedClip = g2.getClip();
+        g2.clip(area);
+
+        Composite originalComposite = g2.getComposite();
+        g2.setComposite(AlphaComposite.getInstance(
+            AlphaComposite.SRC_OVER,
+            getForegroundAlpha()
+        ));
+            
+        // draw axis
+        drawAxes(g2, area, dataArea, info);
+
+        if (!isEmptyOrNull(dataset)) {
+            // draw data
+            drawPolygons(savedG2, dataArea, info);
+        }
+
+        g2.setClip(savedClip);
+        g2.setComposite(originalComposite);
+
+        System.out.println("Finished drawing plot.");
+    }
+
+
+    private void drawAxes(
+        Graphics2D        g2,
+        Rectangle2D       plotArea,
+        Rectangle2D       dataArea,
+        PlotRenderingInfo plotState
+    ) {
+        AxisCollection axisCollection = new AxisCollection();
+
+        for (int i = 0; i < domainAxes.size(); i++) {
+            ValueAxis axis = (ValueAxis) domainAxes.get(i);
+            if (axis != null)
+                axisCollection.add(axis, getDomainAxisEdge(i));
+        }
+
+        for (int i = 0; i < rangeAxes.size(); i++) {
+            ValueAxis axis = (ValueAxis) rangeAxes.get(i);
+            if (axis != null)
+                axisCollection.add(axis, getRangeAxisEdge(i));
+        }
+
+        Map axisStateMap = new HashMap();
+
+        // draw the top axes
+        double cursor = dataArea.getMinY() - this.axisOffset.calculateTopOutset(
+                dataArea.getHeight());
+        Iterator iterator = axisCollection.getAxesAtTop().iterator();
+        while (iterator.hasNext()) {
+            ValueAxis axis = (ValueAxis) iterator.next();
+            AxisState info = axis.draw(g2, cursor, plotArea, dataArea,
+                    RectangleEdge.TOP, plotState);
+            cursor = info.getCursor();
+            axisStateMap.put(axis, info);
+        }
+
+        // draw the bottom axes
+        cursor = dataArea.getMaxY()
+                 + this.axisOffset.calculateBottomOutset(dataArea.getHeight());
+        iterator = axisCollection.getAxesAtBottom().iterator();
+        while (iterator.hasNext()) {
+            ValueAxis axis = (ValueAxis) iterator.next();
+            AxisState info = axis.draw(g2, cursor, plotArea, dataArea,
+                    RectangleEdge.BOTTOM, plotState);
+            cursor = info.getCursor();
+            axisStateMap.put(axis, info);
+        }
+
+        // draw the left axes
+        cursor = dataArea.getMinX()
+                 - this.axisOffset.calculateLeftOutset(dataArea.getWidth());
+        iterator = axisCollection.getAxesAtLeft().iterator();
+        while (iterator.hasNext()) {
+            ValueAxis axis = (ValueAxis) iterator.next();
+            AxisState info = axis.draw(g2, cursor, plotArea, dataArea,
+                    RectangleEdge.LEFT, plotState);
+            cursor = info.getCursor();
+            axisStateMap.put(axis, info);
+        }
+
+        // draw the right axes
+        cursor = dataArea.getMaxX()
+                 + this.axisOffset.calculateRightOutset(dataArea.getWidth());
+        iterator = axisCollection.getAxesAtRight().iterator();
+        while (iterator.hasNext()) {
+            ValueAxis axis = (ValueAxis) iterator.next();
+            AxisState info = axis.draw(g2, cursor, plotArea, dataArea,
+                    RectangleEdge.RIGHT, plotState);
+            cursor = info.getCursor();
+            axisStateMap.put(axis, info);
+        }
+    }
+
+
+    private void drawPolygons(
+        Graphics2D        g2,
+        Rectangle2D       area,
+        PlotRenderingInfo info
+    ) {
+        renderer.draw(g2, area, dataset);
+    }
+
+
+    private AxisSpace calculateAxisSpace(Graphics2D  g2, Rectangle2D plotArea) {
+        AxisSpace space         = new AxisSpace();
+        space                   = calculateRangeAxisSpace(g2, plotArea, space);
+        Rectangle2D tmpPlotArea = space.shrink(plotArea, null);
+        space                   = calculateDomainAxisSpace(g2, plotArea, space);
+
+        return space;
+    }
+
+
+    private AxisSpace calculateDomainAxisSpace(
+        Graphics2D  g2,
+        Rectangle2D plotArea,
+        AxisSpace   space
+    ) {
+        if (space == null)
+            space = new AxisSpace();
+
+        for (int i = 0; i < domainAxes.size(); i++) {
+            Axis axis = (Axis) domainAxes.get(i);
+
+            if (axis != null) {
+                RectangleEdge edge = getDomainAxisEdge(i);
+                space = axis.reserveSpace(g2, this, plotArea, edge, space);
+            }
+        }
+
+        return space;
+    }
+
+
+    private AxisSpace calculateRangeAxisSpace(
+        Graphics2D  g2,
+        Rectangle2D plotArea,
+        AxisSpace   space
+    ) {
+        if (space == null)
+            space = new AxisSpace();
+
+        for (int i = 0; i < rangeAxes.size(); i++) {
+            Axis axis = (Axis) rangeAxes.get(i);
+
+            if (axis != null) {
+                RectangleEdge edge = getRangeAxisEdge(i);
+                space = axis.reserveSpace(g2, this, plotArea, edge, space);
+            }
+        }
+
+        return space;
+    }
+
+    private RectangleEdge getDomainAxisEdge() {
+        return Plot.resolveDomainAxisLocation(
+            getDomainAxisLocation(), orientation
+        );
+    }
+
+
+    private RectangleEdge getDomainAxisEdge(int idx) {
+        AxisLocation  location = getDomainAxisLocation(idx);
+        RectangleEdge result   = Plot.resolveDomainAxisLocation(
+            location, orientation
+        );
+
+        if (result == null)
+            result = RectangleEdge.opposite(getDomainAxisEdge());
+
+        return result;
+    }
+
+
+    private RectangleEdge getRangeAxisEdge() {
+        return Plot.resolveRangeAxisLocation(
+            getRangeAxisLocation(), orientation
+        );
+    }
+
+
+    private RectangleEdge getRangeAxisEdge(int idx) {
+        AxisLocation  location = getRangeAxisLocation(idx);
+        RectangleEdge result   = Plot.resolveRangeAxisLocation(
+            location,
+            orientation
+        );
+
+        if (result == null)
+            result = RectangleEdge.opposite(getRangeAxisEdge());
+
+        return result;
+    }
+
+
+    public AxisLocation getDomainAxisLocation() {
+        return (AxisLocation) domainAxisLocation.get(0);
+    }
+
+
+    public AxisLocation getDomainAxisLocation(int idx) {
+        if (idx < domainAxisLocation.size())
+            return (AxisLocation) domainAxisLocation.get(idx);
+
+        return null;
+    }
+
+
+    public AxisLocation getRangeAxisLocation() {
+        return (AxisLocation) rangeAxisLocation.get(0);
+    }
+
+
+    public AxisLocation getRangeAxisLocation(int idx) {
+        if (idx < rangeAxisLocation.size())
+            return (AxisLocation) rangeAxisLocation.get(idx);
+
+        return null;
+    }
+
+
+    private boolean isEmptyOrNull(PolygonDataset dataset) {
+        if (dataset != null) {
+            int seriesCount = dataset.getSeriesCount();
+            for (int s = 0; s < seriesCount; s++) {
+                PolygonSeries series = dataset.getSeries(s);
+                if (series.getItemCount() > 0) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/jfreechart/PolygonRenderer.java	Mon Dec 21 16:47:45 2009 +0000
@@ -0,0 +1,129 @@
+package de.intevation.gnv.jfreechart;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.Shape;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.Rectangle2D.Double;
+
+import org.jfree.data.Range;
+
+/**
+ * @author Ingo Weinzierl <ingo.weinzierl@intevation.de>
+ */
+public class PolygonRenderer
+{
+    public static final int AREA           = 1;
+    public static final int LINES          = 2;
+    public static final int AREA_AND_LINES = AREA | LINES;
+
+    public interface PaintLookup {
+
+        Paint getPaint(int index);
+
+    } // interface PaintLookup
+
+    protected int type;
+
+    protected PaintLookup lookup;
+
+    protected PolygonPlot plot;
+
+
+    public PolygonRenderer(PaintLookup lookup) {
+        this(lookup, AREA);
+    }
+
+    public PolygonRenderer(PaintLookup lookup, int type) {
+        this.lookup = lookup;
+        this.type   = type;
+    }
+
+    public void draw(
+        Graphics2D     graphics,
+        Rectangle2D    rectangle,
+        PolygonDataset dataset
+    ) {
+        Rectangle2D bbox = getBoundingBox(dataset);
+
+        double sx = (double)rectangle.getWidth()/bbox.getWidth();
+        double sy = (double)rectangle.getHeight()/bbox.getHeight();
+        double tx = rectangle.getMinX();
+        double ty = rectangle.getMinY();
+
+        graphics.translate(tx, ty);
+        graphics.scale(sx, sy);
+
+        int seriesCount = dataset.getSeriesCount();
+        for (int i = 0; i < seriesCount; i++) {
+            PolygonSeries series   = dataset.getSeries(i);
+            Integer       colorIdx = (Integer)series.getAttribute("fill");
+
+            if (colorIdx != null) {
+                Paint paint = lookup.getPaint(colorIdx.intValue());
+                graphics.setPaint(paint != null ? paint : Color.black);
+                graphics.fill(constructShape(series));
+            }
+            else {
+                graphics.setPaint(Color.black);
+                graphics.draw(constructShape(series));
+            }
+        }
+    }
+
+    protected Shape constructShape(PolygonSeries series) {
+        CompactXYItems [] rings = series.getRings();
+        GeneralPath path = new GeneralPath();
+        for (int i = 0; i < rings.length; ++i) {
+            CompactXYItems ring = rings[i];
+            double [] data = ring.getData();
+            if (data.length >= 2) {
+                path.moveTo((float)data[0], (float)data[1]);
+            }
+            for (int j = 2; j < data.length;) {
+                float x = (float)data[j++];
+                float y = (float)data[j++];
+                path.lineTo(x, y);
+            }
+            path.closePath();
+        }
+        return path;
+    }
+
+    public Rectangle2D getBoundingBox(PolygonDataset dataset) {
+        Rectangle2D bbox = null;
+
+        for (int i = 0, N = dataset.getSeriesCount(); i < N; i++) {
+            Range domain = dataset.getSeries(i).getDomainBounds();
+            Range range  = dataset.getSeries(i).getRangeBounds();
+
+            double x = domain.getLowerBound();
+            double y = range.getLowerBound();
+            double w = Math.abs(domain.getUpperBound() - x);
+            double h = Math.abs(range.getUpperBound() - y);
+
+            if (bbox == null) {
+                bbox = new Rectangle2D.Double(x, y, w, h);
+            }
+            else {
+                bbox.add(new Rectangle2D.Double(x, y, w, h));
+            }
+        }
+
+        return bbox;
+    }
+
+    public Rectangle2D getBounds(PolygonSeries series) {
+
+        Range domain = series.getDomainBounds();
+        Range range  = series.getRangeBounds();
+
+        return new Rectangle2D.Double(
+            domain.getLowerBound(), range.getLowerBound(),
+            domain.getUpperBound(), range.getUpperBound()
+        );
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/jfreechart/PolygonSeries.java	Mon Dec 21 16:47:45 2009 +0000
@@ -0,0 +1,151 @@
+package de.intevation.gnv.jfreechart;
+
+import java.util.Map;
+import java.util.HashMap;
+
+import org.jfree.data.Range;
+import org.jfree.data.general.Series;
+
+/**
+ * @author Sascha Teichmann <sascha.teichmann@intevation.de>
+ * @author Ingo Weinzierl <ingo.weinzierl@intevation.de>
+ */
+public class PolygonSeries
+extends      Series
+{
+    protected CompactXYItems []  rings;
+    protected Map                attributes;
+
+
+    public PolygonSeries(Comparable key, CompactXYItems [] rings) {
+        this(key, null, rings, new HashMap());
+    }
+
+    public PolygonSeries(
+        Comparable       key,
+        String           description,
+        CompactXYItems[] rings
+    ) {
+        this(key, description, rings, new HashMap());
+    }
+
+    public PolygonSeries(
+        Comparable        key,
+        String            description,
+        CompactXYItems [] rings,
+        Map               attributes
+    ) {
+        super(key, description);
+        this.rings      = rings;
+        this.attributes = attributes;
+    }
+
+
+    public void setRings(CompactXYItems [] rings) {
+        this.rings = rings;
+    }
+
+    public CompactXYItems [] getRings() {
+        return rings;
+    }
+
+    public void addRings(CompactXYItems [] newRings) {
+        if (newRings == null || newRings.length == 0) {
+            return;
+        }
+        if (rings == null || rings.length == 0) {
+            rings = newRings;
+        }
+        else {
+            CompactXYItems [] both =
+                new CompactXYItems[rings.length + newRings.length];
+            System.arraycopy(rings, 0, both, 0, rings.length);
+            System.arraycopy(newRings, 0, both, rings.length, newRings.length);
+            rings = both;
+        }
+    }
+
+    public Object getAttribute(Object key) {
+        return attributes.get(key);
+    }
+
+
+    public Object setAttribute(Object key, Object value) {
+        return attributes.put(key, value);
+    }
+
+
+    public int getItemCount() {
+        return rings.length;
+    }
+
+
+    public CompactXYItems getItem(int idx) {
+        return rings[idx];
+    }
+
+
+    public Object removeAttribute(Object key) {
+        return attributes.remove(key);
+    }
+
+
+    public boolean hasAttribute(Object key) {
+        return attributes.containsKey(key);
+    }
+
+
+    public Range getDomainBounds() {
+        double upper = Double.NEGATIVE_INFINITY;
+        double lower = Double.POSITIVE_INFINITY;
+        int    count = getItemCount();
+
+        for (int i = 0; i < count; i++) {
+            CompactXYItems  items = getItem(i);
+            double          minX  = items.getMinX();
+            double          maxX  = items.getMaxX();
+
+            if (!Double.isNaN(minX)) {
+                lower = Math.min(lower, minX);
+            }
+
+            if (!Double.isNaN(maxX)) {
+                upper = Math.max(upper, maxX);
+            }
+        }
+
+        if (lower > upper) {
+            return null;
+        }
+
+        return new Range(lower, upper);
+    }
+
+
+    public Range getRangeBounds() {
+        double upper = Double.NEGATIVE_INFINITY;
+        double lower = Double.POSITIVE_INFINITY;
+        int    count = getItemCount();
+
+        for (int i = 0; i < count; i++) {
+            CompactXYItems  items = getItem(i);
+            double          minY  = items.getMinY();
+            double          maxY  = items.getMaxY();
+
+            if (!Double.isNaN(minY)) {
+                lower = Math.min(lower, minY);
+            }
+
+            if (!Double.isNaN(maxY)) {
+                upper = Math.max(upper, maxY);
+            }
+        }
+
+        if (lower > upper) {
+            return null;
+        }
+
+        return new Range(lower, upper);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :

http://dive4elements.wald.intevation.org