view flys-artifacts/src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java @ 659:ab43f36f4af6

The ChartInfoGenerator appends axes range information to the document now. flys-artifacts/trunk@2065 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Tue, 07 Jun 2011 13:15:02 +0000
parents ac1399d325e9
children 51172d56e8bc
line wrap: on
line source
package de.intevation.flys.exports;

import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Rectangle2D;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import org.apache.log4j.Logger;

import org.jfree.chart.ChartRenderingInfo;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.Range;

import de.intevation.artifacts.common.ArtifactNamespaceContext;
import de.intevation.artifacts.common.utils.XMLUtils;
import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;


/**
 * This class helps generating chart info documents.
 *
 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
 */
public class InfoGeneratorHelper {

    private static final Logger logger =
        Logger.getLogger(InfoGeneratorHelper.class);


    private InfoGeneratorHelper() {
    }


    /**
     * Triggers the creation of the chart info document.
     *
     * @param chart The JFreeChart chart.
     * @param info An info object that has been created while chart creation.
     *
     * @return the info document.
     */
    public static Document createInfoDocument(
        JFreeChart         chart,
        ChartRenderingInfo info)
    {
        logger.debug("InfoGeneratorHelper.createInfoDocument");

        Document doc = XMLUtils.newDocument();

        ElementCreator cr = new ElementCreator(
            doc,
            ArtifactNamespaceContext.NAMESPACE_URI,
            ArtifactNamespaceContext.NAMESPACE_PREFIX);

        Element chartinfo = cr.create("chartinfo");

        chartinfo.appendChild(createAxesElements(cr, chart));
        chartinfo.appendChild(createTransformationElement(cr, chart, info));

        doc.appendChild(chartinfo);

        return doc;
    }


    /**
     * This method create a axes element that contains all domain and range
     * axes of the given chart.
     *
     * @param cr The ElementCreator.
     * @param chart The chart that provides range information of its axes.
     *
     * @return an element with axes information.
     */
    protected static Element createAxesElements(
        ElementCreator     cr,
        JFreeChart         chart)
    {
        logger.debug("InfoGeneratorHelper.createRangeElements");

        Element axes = cr.create("axes");

        XYPlot plot = (XYPlot) chart.getPlot();

        int dAxisCount = plot.getDomainAxisCount();
        for (int i = 0; i < dAxisCount; i++) {
            Element e = createAxisElement(
                cr, plot.getDomainAxis(i), "domain", i);

            if (e != null) {
                axes.appendChild(e);
            }
        }

        int rAxisCount = plot.getRangeAxisCount();
        for (int i = 0; i < rAxisCount; i++) {
            Element e = createAxisElement(
                cr, plot.getRangeAxis(i), "range", i);

            if (e != null) {
                axes.appendChild(e);
            }
        }

        return axes;
    }


    /**
     * This method create a axis element for a given <i>axis</i> and
     * <i>type</i>. Type can be one of 'domain' or 'range'.
     *
     * @param cr The ElementCreator
     * @param axis The axis that provides range information.
     * @param type The axis type ('domain' or 'range').
     * @param pos The position in the chart.
     *
     * @return An element that contains range information of a given axis.
     */
    protected static Element createAxisElement(
        ElementCreator cr,
        ValueAxis      axis,
        String         type,
        int            pos)
    {
        Range range = axis.getRange();

        Element e = cr.create(type);
        cr.addAttr(e, "pos", String.valueOf(pos), true);
        cr.addAttr(e, "from", String.valueOf(range.getLowerBound()), true);
        cr.addAttr(e, "to", String.valueOf(range.getUpperBound()), true);

        return e;
    }


    /**
     * This method appends the values of a transformation matrix to transform
     * image pixel coordinates into chart coordinates.
     *
     * @param cr The ElementCreator.
     * @param chart The chart object.
     * @param info The ChartRenderingInfo that is filled while chart creation.
     *
     * @return an element that contains one or more transformation matrix.
     */
    protected static Element createTransformationElement(
        ElementCreator     cr,
        JFreeChart         chart,
        ChartRenderingInfo info)
    {
        logger.debug("InfoGeneratorHelper.createTransformationElement");

        Element tf = cr.create("transformation-matrix");

        Rectangle2D dataArea = info.getPlotInfo().getDataArea();

        XYPlot    plot  = (XYPlot) chart.getPlot();
        ValueAxis xAxis = plot.getDomainAxis();
        ValueAxis yAxis = plot.getRangeAxis();

        double[] tm = createTransformationMatrix(dataArea, xAxis, yAxis);

        cr.addAttr(tf, "sx", String.valueOf(tm[0]), true);
        cr.addAttr(tf, "sy", String.valueOf(tm[1]), true);
        cr.addAttr(tf, "tx", String.valueOf(tm[2]), true);
        cr.addAttr(tf, "ty", String.valueOf(tm[3]), true);

        return tf;
    }


    /**
     * This method determines a transformation matrix to transform pixel
     * coordinates of the chart image into chart coordinates.
     *
     * @param dataArea The rectangle that contains the data points of the chart.
     * @param xRange The x axis range.
     * @param yRange The y axis range.
     *
     * @return a double array as follows: [sx, sy, tx, ty].
     */
    protected static double[] createTransformationMatrix(
        Rectangle2D dataArea,
        ValueAxis   xAxis,
        ValueAxis   yAxis)
    {
        logger.debug("InfoGeneratorHelper.createTransformationMatrix");

        double offsetX = dataArea.getX();
        double width   = dataArea.getWidth();
        double offsetY = dataArea.getY();
        double height  = dataArea.getHeight();

        Range xRange = xAxis.getRange();
        Range yRange = yAxis.getRange();

        double lowerX  = xRange.getLowerBound();
        double upperX  = xRange.getUpperBound();
        double lowerY  = yRange.getLowerBound();
        double upperY  = yRange.getUpperBound();

        if (xAxis.isInverted()) {
            logger.info("X-Axis is inverted!");

            double tmp = upperX;
            upperX = lowerX;
            lowerX = tmp;
        }

        double dMoveX = upperX - lowerX;
        double fMoveX = width * lowerX;
        double dMoveY = lowerY - upperY;
        double fMoveY = height * upperY;

        AffineTransform t1 = AffineTransform.getTranslateInstance(
                offsetX - ( fMoveX / dMoveX ),
                offsetY - ( fMoveY / dMoveY ) );

        AffineTransform t2 = AffineTransform.getScaleInstance(
                width / (upperX - lowerX),
                height / (lowerY - upperY));

        t1.concatenate(t2);

        try {
            t1.invert();

            double[] c = new double[6];
            t1.getMatrix(c);

            return new double[] { c[0], c[3], c[4], c[5] };
        }
        catch (NoninvertibleTransformException e) {
            // do nothing
            logger.warn("Matrix is not invertible.");
        }

        return new double[] { 1d, 1d, 0d, 0d };
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org