/* * Copyright (C) 2010 Brockmann Consult GmbH (info@brockmann-consult.de) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at your option) * any later version. * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see http://www.gnu.org/licenses/ */ package org.esa.snap.rcp.statistics; import com.bc.ceres.core.Assert; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.plot.CrosshairState; import org.jfree.chart.plot.PlotRenderingInfo; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.data.xy.DefaultXYDataset; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; /** * An X/Y plot that uses a buffered image to display its data. * * @author Norman Fomferra */ public class XYImagePlot extends XYPlot { private BufferedImage image; private Rectangle2D imageDataBounds; private final Object imageLock = new Object(); public XYImagePlot() { super(null, new NumberAxis("X"), new NumberAxis("Y"), new XYLineAndShapeRenderer(false, false)); } public BufferedImage getImage() { synchronized (imageLock) { return image; } } public void setImage(BufferedImage image) { synchronized (imageLock) { this.image = image; if (image != null && imageDataBounds == null) { setImageDataBounds(new Rectangle(0, 0, image.getWidth(), image.getHeight())); } } } public Rectangle2D getImageDataBounds() { synchronized (imageLock) { return imageDataBounds != null ? (Rectangle2D) imageDataBounds.clone() : null; } } public void setImageDataBounds(Rectangle2D imageDataBounds) { synchronized (imageLock) { this.imageDataBounds = (Rectangle2D) imageDataBounds.clone(); DefaultXYDataset xyDataset = new DefaultXYDataset(); xyDataset.addSeries("Image Data Bounds", new double[][]{ {imageDataBounds.getMinX(), imageDataBounds.getMaxX()}, {imageDataBounds.getMinY(), imageDataBounds.getMaxY()} }); setDataset(xyDataset); getDomainAxis().setRange(imageDataBounds.getMinX(), imageDataBounds.getMaxX()); getRangeAxis().setRange(imageDataBounds.getMinY(), imageDataBounds.getMaxY()); } } @Override public boolean render(Graphics2D g2, Rectangle2D dataArea, int index, PlotRenderingInfo info, CrosshairState crosshairState) { final boolean foundData = super.render(g2, dataArea, index, info, crosshairState); if (image != null) { final int dx1 = (int) dataArea.getMinX(); final int dy1 = (int) dataArea.getMinY(); final int dx2 = (int) dataArea.getMaxX(); final int dy2 = (int) dataArea.getMaxY(); synchronized (imageLock) { final Rectangle rectangle = getImageSourceArea(); final int sx1 = rectangle.x; final int sy1 = rectangle.y; final int sx2 = sx1 + rectangle.width - 1; final int sy2 = sy1 + rectangle.height - 1; g2.drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null); } } return foundData; } final Rectangle getImageSourceArea() { Assert.notNull(image); Assert.notNull(imageDataBounds); final ValueAxis xAxis = getDomainAxis(); final ValueAxis yAxis = getRangeAxis(); final double scaleX = image.getWidth() / imageDataBounds.getWidth(); final double scaleY = image.getHeight() / imageDataBounds.getHeight(); final int x = crop(scaleX * (xAxis.getLowerBound() - imageDataBounds.getMinX()), 0, image.getWidth() - 1); final int y = crop(scaleY * (imageDataBounds.getMaxY() - yAxis.getUpperBound()), 0, image.getHeight() - 1); final int w = crop(scaleX * (xAxis.getUpperBound() - xAxis.getLowerBound()), 1, image.getWidth()); final int h = crop(scaleY * (yAxis.getUpperBound() - yAxis.getLowerBound()), 1, image.getHeight()); return new Rectangle(x, y, w, h); } private static int crop(double v, int i1, int i2) { int i = (int) Math.round(v); if (i < i1) { return i1; } if (i > i2) { return i2; } return i; } }