/*
* Copyright (c) 2003, 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.
*
*/
package edu.uci.ics.jung.visualization.transform;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Shape;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RectangularShape;
/**
* LensTransformer wraps a MutableAffineTransformer and modifies
* the transform and inverseTransform methods so that they create a
* projection of the graph points within an elliptical lens.
*
* LensTransformer uses an
* affine transform to cause translation, scaling, rotation, and shearing
* while applying a possibly non-affine filter in its transform and
* inverseTransform methods.
*
* @author Tom Nelson
*
*
*/
public abstract class LensTransformer extends MutableTransformerDecorator implements MutableTransformer {
/**
* the area affected by the transform
*/
protected RectangularShape lensShape = new Ellipse2D.Float();
protected float magnification = 0.7f;
/**
* create an instance with a possibly shared transform
* @param component
* @param delegate
*/
public LensTransformer(Component component, MutableTransformer delegate) {
super(delegate);
setComponent(component);
component.addComponentListener(new ComponentListenerImpl());
}
/**
* set values from the passed component.
* declared private so it can't be overridden
* @param component
*/
private void setComponent(Component component) {
Dimension d = component.getSize();
if(d.width <= 0 || d.height <= 0) {
d = component.getPreferredSize();
}
float ewidth = d.width/1.5f;
float eheight = d.height/1.5f;
lensShape.setFrame(d.width/2-ewidth/2, d.height/2-eheight/2, ewidth, eheight);
}
/**
* @return Returns the magnification.
*/
public float getMagnification() {
return magnification;
}
/**
* @param magnification The magnification to set.
*/
public void setMagnification(float magnification) {
this.magnification = magnification;
}
/**
* @return Returns the viewCenter.
*/
public Point2D getViewCenter() {
return new Point2D.Double(lensShape.getCenterX(), lensShape.getCenterY());
}
/**
* @param viewCenter The viewCenter to set.
*/
public void setViewCenter(Point2D viewCenter) {
double width = lensShape.getWidth();
double height = lensShape.getHeight();
lensShape.setFrame(viewCenter.getX()-width/2,
viewCenter.getY()-height/2,
width, height);
}
/**
* @return Returns the viewRadius.
*/
public double getViewRadius() {
return lensShape.getHeight()/2;
}
/**
* @param viewRadius The viewRadius to set.
*/
public void setViewRadius(double viewRadius) {
double x = lensShape.getCenterX();
double y = lensShape.getCenterY();
double viewRatio = getRatio();
lensShape.setFrame(x-viewRadius/viewRatio,
y-viewRadius,
2*viewRadius/viewRatio,
2*viewRadius);
}
/**
* @return Returns the ratio.
*/
public double getRatio() {
return lensShape.getHeight()/lensShape.getWidth();
}
public void setLensShape(RectangularShape ellipse) {
this.lensShape = ellipse;
}
public RectangularShape getLensShape() {
return lensShape;
}
public void setToIdentity() {
this.delegate.setToIdentity();
}
/**
* react to size changes on a component
*/
protected class ComponentListenerImpl extends ComponentAdapter {
public void componentResized(ComponentEvent e) {
setComponent(e.getComponent());
}
}
/**
* override base class transform to project the fisheye effect
*/
public abstract Point2D transform(Point2D graphPoint);
/**
* override base class to un-project the fisheye effect
*/
public abstract Point2D inverseTransform(Point2D viewPoint);
public double getDistanceFromCenter(Point2D p) {
double dx = lensShape.getCenterX()-p.getX();
double dy = lensShape.getCenterY()-p.getY();
dx *= getRatio();
return Math.sqrt(dx*dx + dy*dy);
}
/**
* return the supplied shape, translated to the coordinates
* that result from calling transform on its center
*/
public Shape transform(Shape shape) {
Rectangle2D bounds = shape.getBounds2D();
Point2D center = new Point2D.Double(bounds.getCenterX(),bounds.getCenterY());
Point2D newCenter = transform(center);
double dx = newCenter.getX()-center.getX();
double dy = newCenter.getY()-center.getY();
AffineTransform at = AffineTransform.getTranslateInstance(dx,dy);
return at.createTransformedShape(shape);
}
/**
* return the supplied shape, translated to the coordinates
* that result from calling inverseTransform on its center
*/
public Shape inverseTransform(Shape shape) {
Rectangle2D bounds = shape.getBounds2D();
Point2D center = new Point2D.Double(bounds.getCenterX(),bounds.getCenterY());
Point2D newCenter = inverseTransform(center);
double dx = newCenter.getX()-center.getX();
double dy = newCenter.getY()-center.getY();
AffineTransform at = AffineTransform.getTranslateInstance(dx,dy);
return at.createTransformedShape(shape);
}
}