view gnv-artifacts/src/main/java/de/intevation/gnv/jfreechart/PolygonRenderer.java @ 605:e8ebdbc7f1e3

First step of removing the cache blob. The static part of the describe document will be created by using the input data stored at each state. Some TODOs left (see ChangeLog). gnv-artifacts/trunk@671 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Tue, 09 Feb 2010 14:27:55 +0000
parents bc5901bb4525
children 9a828e5a2390
line wrap: on
line source
package de.intevation.gnv.jfreechart;

import java.util.ArrayList;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Shape;
import java.awt.BasicStroke;
import java.awt.FontMetrics;
import java.awt.Font;

import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Rectangle2D.Double;

import org.jfree.data.Range;

import org.jfree.chart.axis.ValueAxis;

import org.jfree.ui.RectangleEdge;

import org.apache.log4j.Logger;

import org.jfree.text.TextUtilities;


/**
 * @author Ingo Weinzierl      (ingo.weinzierl@intevation.de)
 * @author Sascha L. Teichmann (sascha.teichmann@intevation.de)
 */
public class PolygonRenderer
{
	private static Logger log = Logger.getLogger(
		PolygonRenderer.class);

    public interface PaintLookup {

        Paint getPaint(int index);

    } // interface PaintLookup

    public static class DefaultLabelGenerator
    implements          PolygonSeriesLabelGenerator
    {
        public DefaultLabelGenerator() {
        }

        public String generateLabel(PolygonSeries series) {
            Object label = series.getAttribute("label");
            return label != null
                ? toString(label)
                : null;
        }

        protected String toString(Object label) {
            return label.toString();
        }
    } // class DefaultLabelGenerator

    public static final PolygonSeriesLabelGenerator 
        DEFAULT_LABEL_GENERATOR_INSTANCE = new DefaultLabelGenerator();

    protected PaintLookup                 lookup;
    protected PolygonSeriesLabelGenerator labelGenerator;

    public PolygonRenderer(PaintLookup lookup) {
        this(lookup, null);
    }

    public PolygonRenderer(
        PaintLookup                 lookup, 
        PolygonSeriesLabelGenerator labelGenerator
    ) {
        this.lookup         = lookup;
        this.labelGenerator = labelGenerator;
    }

    public void drawPolygons(
        Graphics2D     graphics,
        PolygonPlot    plot,
        Rectangle2D    area,
        PolygonDataset dataset
    ) {
        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(plot, area, series, true));
            }
            else {
                Number lineWidth = (Number)series.getAttribute("line.width");
                BasicStroke stroke = new BasicStroke(
                    lineWidth != null ? lineWidth.floatValue() : 1f);
                graphics.setStroke(stroke);
                graphics.setPaint(Color.black);
                graphics.draw(constructShape(plot, area, series, false));
            }
        }
    }

    public void drawLabels(
        final Graphics2D  graphics,
        final PolygonPlot plot,
        final Rectangle2D area,
        PolygonDataset    dataset
    ) {
        if (labelGenerator == null) {
            return;
        }

        final ArrayList<Rectangle2D> bboxes = new ArrayList<Rectangle2D>();

        Font font = graphics.getFont();
        font = font.deriveFont(Font.PLAIN, Math.max(8, font.getSize()-3));
        graphics.setFont(font);
        FontMetrics metrics = graphics.getFontMetrics(font);

        for (int i = dataset.getSeriesCount()-1; i >= 0; --i) {
            PolygonSeries series = dataset.getSeries(i);

            String label = labelGenerator.generateLabel(series);
            if (label == null) {
                continue;
            }

            final Rectangle2D box = TextUtilities.getTextBounds(
                label, graphics, metrics);

            for (int j = series.getItemCount()-1; j >= 0; --j) {
                final CompactXYItems ring = series.getItem(j);
                LevelOrderIndices loi = new LevelOrderIndices(ring.size()-1);
                Rectangle2D r = (Rectangle2D)loi.visit(
                    new LevelOrderIndices.Visitor() 
                {
                    ValueAxis          da = plot.getDomainAxis();
                    ValueAxis          ra = plot.getRangeAxis();
                    RectangleEdge      de = plot.getDomainAxisEdge();
                    RectangleEdge      re = plot.getRangeAxisEdge();
                    Rectangle2D.Double r  = new Rectangle2D.Double(
                        0d, 0d, box.getWidth(), box.getHeight());

                    public Object visit(int index) {
                        r.x = da.valueToJava2D(ring.getX(index), area, de) 
                            - 0.5*box.getWidth();
                        r.y = ra.valueToJava2D(ring.getY(index), area, re)
                            + 0.5*box.getHeight();

                        for (Rectangle2D b: bboxes) {
                            if (b.intersects(r)) {
                                return null;
                            }
                        }
                        return r;
                    }
                });

                if (r != null) {
                    bboxes.add(r);
                    graphics.drawString(
                        label, (float)r.getX(), (float)r.getY());
                }
            } // for all items in series
        } // for all series
    }

    protected Shape constructShape(
        PolygonPlot   plot,
        Rectangle2D   area,
        PolygonSeries series, 
        boolean       close
    ) {
        ValueAxis     da = plot.getDomainAxis();
        ValueAxis     ra = plot.getRangeAxis();
        RectangleEdge de = plot.getDomainAxisEdge();
        RectangleEdge re = plot.getRangeAxisEdge();

        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)da.valueToJava2D(data[0], area, de),
                    (float)ra.valueToJava2D(data[1], area, re));
            }
            for (int j = 2; j < data.length;) {
                path.lineTo(
                    (float)da.valueToJava2D(data[j++], area, de),
                    (float)ra.valueToJava2D(data[j++], area, re));
            }
            if (close) {
                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 :

http://dive4elements.wald.intevation.org