ingo@647: package de.intevation.flys.exports; ingo@647: ingo@647: import java.awt.geom.AffineTransform; ingo@647: import java.awt.geom.NoninvertibleTransformException; ingo@647: import java.awt.geom.Rectangle2D; ingo@647: ingo@647: import org.w3c.dom.Document; ingo@647: import org.w3c.dom.Element; ingo@647: ingo@647: import org.apache.log4j.Logger; ingo@647: ingo@647: import org.jfree.chart.ChartRenderingInfo; ingo@647: import org.jfree.chart.JFreeChart; ingo@648: import org.jfree.chart.axis.ValueAxis; ingo@647: import org.jfree.chart.plot.XYPlot; ingo@647: import org.jfree.data.Range; ingo@647: ingo@647: import de.intevation.artifacts.common.ArtifactNamespaceContext; ingo@647: import de.intevation.artifacts.common.utils.XMLUtils; ingo@647: import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; ingo@647: ingo@647: ingo@647: /** ingo@647: * This class helps generating chart info documents. ingo@647: * ingo@647: * @author Ingo Weinzierl ingo@647: */ ingo@647: public class InfoGeneratorHelper { ingo@647: ingo@647: private static final Logger logger = ingo@647: Logger.getLogger(InfoGeneratorHelper.class); ingo@647: ingo@647: ingo@647: private InfoGeneratorHelper() { ingo@647: } ingo@647: ingo@647: ingo@647: /** ingo@647: * Triggers the creation of the chart info document. ingo@647: * ingo@647: * @param chart The JFreeChart chart. ingo@647: * @param info An info object that has been created while chart creation. ingo@647: * ingo@647: * @return the info document. ingo@647: */ ingo@647: public static Document createInfoDocument( ingo@647: JFreeChart chart, ingo@647: ChartRenderingInfo info) ingo@647: { ingo@647: logger.debug("InfoGeneratorHelper.createInfoDocument"); ingo@647: ingo@647: Document doc = XMLUtils.newDocument(); ingo@647: ingo@647: ElementCreator cr = new ElementCreator( ingo@647: doc, ingo@647: ArtifactNamespaceContext.NAMESPACE_URI, ingo@647: ArtifactNamespaceContext.NAMESPACE_PREFIX); ingo@647: ingo@647: Element chartinfo = cr.create("chartinfo"); ingo@647: ingo@647: chartinfo.appendChild(createTransformationElement(cr, chart, info)); ingo@647: ingo@647: doc.appendChild(chartinfo); ingo@647: ingo@647: return doc; ingo@647: } ingo@647: ingo@647: ingo@647: /** ingo@647: * This method appends the values of a transformation matrix to transform ingo@647: * image pixel coordinates into chart coordinates. ingo@647: * ingo@647: * @param cr The ElementCreator. ingo@647: * @param chart The chart object. ingo@647: * @param info The ChartRenderingInfo that is filled while chart creation. ingo@647: * ingo@647: * @return an element that contains one or more transformation matrix. ingo@647: */ ingo@647: protected static Element createTransformationElement( ingo@647: ElementCreator cr, ingo@647: JFreeChart chart, ingo@647: ChartRenderingInfo info) ingo@647: { ingo@647: logger.debug("InfoGeneratorHelper.createTransformationElement"); ingo@647: ingo@647: Element tf = cr.create("transformation-matrix"); ingo@647: ingo@647: Rectangle2D dataArea = info.getPlotInfo().getDataArea(); ingo@647: ingo@648: XYPlot plot = (XYPlot) chart.getPlot(); ingo@648: ValueAxis xAxis = plot.getDomainAxis(); ingo@648: ValueAxis yAxis = plot.getRangeAxis(); ingo@647: ingo@648: double[] tm = createTransformationMatrix(dataArea, xAxis, yAxis); ingo@647: ingo@647: cr.addAttr(tf, "sx", String.valueOf(tm[0]), true); ingo@647: cr.addAttr(tf, "sy", String.valueOf(tm[1]), true); ingo@647: cr.addAttr(tf, "tx", String.valueOf(tm[2]), true); ingo@647: cr.addAttr(tf, "ty", String.valueOf(tm[3]), true); ingo@647: ingo@647: return tf; ingo@647: } ingo@647: ingo@647: ingo@647: /** ingo@647: * This method determines a transformation matrix to transform pixel ingo@647: * coordinates of the chart image into chart coordinates. ingo@647: * ingo@647: * @param dataArea The rectangle that contains the data points of the chart. ingo@647: * @param xRange The x axis range. ingo@647: * @param yRange The y axis range. ingo@647: * ingo@647: * @return a double array as follows: [sx, sy, tx, ty]. ingo@647: */ ingo@647: protected static double[] createTransformationMatrix( ingo@647: Rectangle2D dataArea, ingo@648: ValueAxis xAxis, ingo@648: ValueAxis yAxis) ingo@647: { ingo@648: logger.debug("InfoGeneratorHelper.createTransformationMatrix"); ingo@648: ingo@647: double offsetX = dataArea.getX(); sascha@657: double width = dataArea.getWidth(); ingo@647: double offsetY = dataArea.getY(); ingo@647: double height = dataArea.getHeight(); ingo@647: ingo@648: Range xRange = xAxis.getRange(); ingo@648: Range yRange = yAxis.getRange(); ingo@648: ingo@647: double lowerX = xRange.getLowerBound(); ingo@647: double upperX = xRange.getUpperBound(); ingo@647: double lowerY = yRange.getLowerBound(); ingo@647: double upperY = yRange.getUpperBound(); ingo@647: ingo@648: if (xAxis.isInverted()) { ingo@648: logger.info("X-Axis is inverted!"); ingo@648: ingo@648: double tmp = upperX; ingo@648: upperX = lowerX; ingo@648: lowerX = tmp; ingo@648: } ingo@648: ingo@647: double dMoveX = upperX - lowerX; ingo@647: double fMoveX = width * lowerX; ingo@647: double dMoveY = lowerY - upperY; ingo@647: double fMoveY = height * upperY; ingo@647: ingo@647: AffineTransform t1 = AffineTransform.getTranslateInstance( ingo@647: offsetX - ( fMoveX / dMoveX ), ingo@647: offsetY - ( fMoveY / dMoveY ) ); ingo@647: ingo@647: AffineTransform t2 = AffineTransform.getScaleInstance( ingo@647: width / (upperX - lowerX), ingo@647: height / (lowerY - upperY)); ingo@647: ingo@647: t1.concatenate(t2); ingo@647: ingo@647: try { ingo@647: t1.invert(); ingo@647: ingo@647: double[] c = new double[6]; ingo@647: t1.getMatrix(c); ingo@647: ingo@647: return new double[] { c[0], c[3], c[4], c[5] }; ingo@647: } ingo@647: catch (NoninvertibleTransformException e) { ingo@647: // do nothing ingo@647: logger.warn("Matrix is not invertible."); ingo@647: } ingo@647: ingo@647: return new double[] { 1d, 1d, 0d, 0d }; ingo@647: } ingo@647: } ingo@647: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :