/*
* Copyright (c) 2005, the JUNG Project and the Regents of the University of
* California All rights reserved.
*
* This software is open-source under the BSD license; see either "license.txt"
* or http://jung.sourceforge.net/license.txt for a description.
*
* Created on Jul 11, 2005
*/
package edu.uci.ics.jung.visualization.jai;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.ParameterBlock;
import java.util.ArrayList;
import java.util.List;
import javax.media.jai.InterpolationNearest;
import javax.media.jai.JAI;
import javax.media.jai.PerspectiveTransform;
import javax.media.jai.WarpPerspective;
import javax.media.jai.operator.WarpDescriptor;
import javax.swing.Icon;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.visualization.Layer;
import edu.uci.ics.jung.visualization.RenderContext;
import edu.uci.ics.jung.visualization.renderers.BasicVertexRenderer;
import edu.uci.ics.jung.visualization.transform.shape.GraphicsDecorator;
import edu.uci.ics.jung.visualization.transform.shape.ShapeTransformer;
import edu.uci.ics.jung.visualization.transform.shape.TransformingGraphics;
/**
* a subclass to apply a TransformingGraphics to certain operations
* @author Tom Nelson
*
*
*/
public class TransformingImageVertexIconRenderer<V,E> extends BasicVertexRenderer<V,E> {
WarpDescriptor warpDescriptor;
/**
* create an instance
*
*/
public TransformingImageVertexIconRenderer() {
this.warpDescriptor = new WarpDescriptor();
}
@Override
public void paintIconForVertex(RenderContext<V,E> rc, V v, Layout<V,E> layout) {
GraphicsDecorator g = rc.getGraphicsContext();
TransformingGraphics g2d = (TransformingGraphics)g;
boolean vertexHit = true;
// get the shape to be rendered
Shape shape = rc.getVertexShapeTransformer().transform(v);
Point2D p = layout.transform(v);
p = rc.getMultiLayerTransformer().transform(Layer.LAYOUT, p);
float x = (float)p.getX();
float y = (float)p.getY();
// create a transform that translates to the location of
// the vertex to be rendered
AffineTransform xform = AffineTransform.getTranslateInstance(x,y);
// transform the vertex shape with xtransform
shape = xform.createTransformedShape(shape);
vertexHit = vertexHit(rc, shape);
if (vertexHit) {
if(rc.getVertexIconTransformer() != null) {
Icon icon = rc.getVertexIconTransformer().transform(v);
if(icon != null) {
BufferedImage image = new BufferedImage(icon.getIconWidth(),
icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D ig = image.createGraphics();
icon.paintIcon(null, ig, 0, 0);
int imageWidth = image.getWidth(null);
int imageHeight = image.getHeight(null);
int xLoc = (int) (x - imageWidth / 2);
int yLoc = (int) (y - imageHeight / 2);
Rectangle2D imageRectangle = new Rectangle2D.Double(xLoc, yLoc,
imageWidth, imageHeight);
Shape perspectiveShape =
((ShapeTransformer) g2d.getTransformer()).transform(imageRectangle);
// see if the transformer will affect the imageRectangle,
if(imageRectangle.equals(perspectiveShape.getBounds2D()) == false) {
RenderedImage ri = getPerspectiveImage(image, imageRectangle,
perspectiveShape);
if (ri != null) {
Shape clip = g2d.getClip();
g2d.setClip(perspectiveShape);
g2d.drawRenderedImage(ri, AffineTransform
.getTranslateInstance(xLoc, yLoc));
g2d.setClip(clip);
}
} else {
g2d.drawImage(image, AffineTransform.getTranslateInstance(xLoc,
yLoc), null);
}
} else {
paintShapeForVertex(rc, v, shape);
}
} else {
paintShapeForVertex(rc, v, shape);
}
}
}
protected RenderedImage getPerspectiveImage(Image image, Shape imageShape, Shape perspectiveShape) {
Rectangle2D imageRectangle = imageShape.getBounds2D();
double imagex1 = imageRectangle.getX();
double imagey1 = imageRectangle.getY();
double imagex2 = imageRectangle.getMaxX();
double imagey2 = imageRectangle.getMaxY();
double width = imagex2 - imagex1;
double height = imagey2 - imagey1;
double quadx1 = 0;
double quady1 = 0;
double quadx2 = 0;
double quady2 = 0;
double quadx3 = 0;
double quady3 = 0;
double quadx4 = 0;
double quady4 = 0;
List<Point2D> quadList = new ArrayList<Point2D>();
for(PathIterator iterator=perspectiveShape.getPathIterator(null);
iterator.isDone() == false; iterator.next()) {
float[] coords = new float[6];
int type = iterator.currentSegment(coords);
switch(type) {
case PathIterator.SEG_MOVETO:
quadList.add(new Point2D.Float(coords[0], coords[1]));
break;
case PathIterator.SEG_LINETO:
quadList.add(new Point2D.Float(coords[0], coords[1]));
break;
}
}
Point2D pt1 = quadList.remove(0);
Point2D pt2 = quadList.remove(0);
Point2D pt3 = quadList.remove(0);
Point2D pt4 = quadList.remove(0);
quadx1 = pt1.getX()-imagex1;
quady1 = pt1.getY()-imagey1;
quadx2 = pt2.getX()-imagex1;
quady2 = pt2.getY()-imagey1;
quadx3 = pt3.getX()-imagex1;
quady3 = pt3.getY()-imagey1;
quadx4 = pt4.getX()-imagex1;
quady4 = pt4.getY()-imagey1;
RenderedImage srcImage = null;
if(image instanceof RenderedImage) {
srcImage = (RenderedImage)image;
} else {
srcImage = getBufferedImage(image);
}
PerspectiveTransform perspectiveTransform =
PerspectiveTransform.getQuadToQuad(
quadx1, quady1,
quadx2, quady2,
quadx3, quady3,
quadx4, quady4,
0, 0,
width, 0,
width, height,
0, height
);
double[][] matrix = new double[3][3];
perspectiveTransform.getMatrix(matrix);
if(matrix[2][2] == 0 || Double.isNaN(matrix[2][2])) {
System.err.println("matrix[2][2] = "+matrix[2][2]);
return null;
}
if(matrix[1][1] == 0 || Double.isNaN(matrix[1][1])) {
System.err.println("matrix[1][1] = "+matrix[1][1]);
return null;
}
if(matrix[0][0] == 0 || Double.isNaN(matrix[0][0])) {
System.err.println("matrix[0][0] = "+matrix[0][0]);
return null;
}
WarpPerspective warp = new WarpPerspective(perspectiveTransform);
ParameterBlock pm = new ParameterBlock();
pm.addSource(srcImage);
pm.add(warp);
pm.add(new InterpolationNearest());
RenderedImage dstImage = JAI.create("warp", pm);
return dstImage;
}
private BufferedImage getBufferedImage(Image image) {
int width = image.getWidth(null);
int height = image.getHeight(null);
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return bi;
}
}