package prefuse.action.distortion;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
/**
* <p>
* Computes a graphical fisheye distortion of a graph view. This distortion
* allocates more space to items near the layout anchor and less space to
* items further away, magnifying space near the anchor and demagnifying
* distant space in a continuous fashion.
* </p>
*
* <p>
* For more details on this form of transformation, see Manojit Sarkar and
* Marc H. Brown, "Graphical Fisheye Views of Graphs", in Proceedings of
* CHI'92, Human Factors in Computing Systems, p. 83-91, 1992. Available
* online at <a href="http://citeseer.ist.psu.edu/sarkar92graphical.html">
* http://citeseer.ist.psu.edu/sarkar92graphical.html</a>.
* </p>
*
* @author <a href="http://jheer.org">jeffrey heer</a>
*/
public class FisheyeDistortion extends Distortion {
private double dx, dy; // distortion factors
private double sz = 3.0; // size factor
/**
* Create a new FisheyeDistortion with default distortion factor.
*/
public FisheyeDistortion() {
this(4);
}
/**
* Create a new FisheyeDistortion with the given distortion factor
* for use along both the x and y directions.
* @param dfactor the distortion factor (same for both axes)
*/
public FisheyeDistortion(double dfactor) {
this(dfactor, dfactor);
}
/**
* Create a new FisheyeDistortion with the given distortion factors
* along the x and y directions.
* @param xfactor the distortion factor along the x axis
* @param yfactor the distortion factor along the y axis
*/
public FisheyeDistortion(double xfactor, double yfactor) {
super();
dx = xfactor;
dy = yfactor;
m_distortX = dx > 0;
m_distortY = dy > 0;
}
/**
* Returns the distortion factor for the x-axis.
* @return returns the distortion factor for the x-axis.
*/
public double getXDistortionFactor() {
return dx;
}
/**
* Sets the distortion factor for the x-axis.
* @param d The distortion factor to set.
*/
public void setXDistortionFactor(double d) {
dx = d;
m_distortX = dx > 0;
}
/**
* Returns the distortion factor for the y-axis.
* @return returns the distortion factor for the y-axis.
*/
public double getYDistortionFactor() {
return dy;
}
/**
* Sets the distortion factor for the y-axis.
* @param d The distortion factor to set.
*/
public void setYDistortionFactor(double d) {
dy = d;
m_distortY = dy > 0;
}
/**
* @see prefuse.action.distortion.Distortion#distortX(double, java.awt.geom.Point2D, java.awt.geom.Rectangle2D)
*/
protected double distortX(double x, Point2D anchor, Rectangle2D bounds) {
return fisheye(x,anchor.getX(),dx,bounds.getMinX(),bounds.getMaxX());
}
/**
* @see prefuse.action.distortion.Distortion#distortY(double, java.awt.geom.Point2D, java.awt.geom.Rectangle2D)
*/
protected double distortY(double y, Point2D anchor, Rectangle2D bounds) {
return fisheye(y,anchor.getY(),dy,bounds.getMinY(),bounds.getMaxY());
}
/**
* @see prefuse.action.distortion.Distortion#distortSize(java.awt.geom.Rectangle2D, double, double, java.awt.geom.Point2D, java.awt.geom.Rectangle2D)
*/
protected double distortSize(Rectangle2D bbox, double x, double y,
Point2D anchor, Rectangle2D bounds)
{
if ( !m_distortX && !m_distortY ) return 1.;
double fx=1, fy=1;
if ( m_distortX ) {
double ax = anchor.getX();
double minX = bbox.getMinX(), maxX = bbox.getMaxX();
double xx = (Math.abs(minX-ax) > Math.abs(maxX-ax) ? minX : maxX);
if ( xx < bounds.getMinX() || xx > bounds.getMaxX() )
xx = (xx==minX ? maxX : minX);
fx = fisheye(xx,ax,dx,bounds.getMinX(),bounds.getMaxX());
fx = Math.abs(x-fx)/bbox.getWidth();
}
if ( m_distortY ) {
double ay = anchor.getY();
double minY = bbox.getMinY(), maxY = bbox.getMaxY();
double yy = (Math.abs(minY-ay) > Math.abs(maxY-ay) ? minY : maxY);
if ( yy < bounds.getMinY() || yy > bounds.getMaxY() )
yy = (yy==minY ? maxY : minY);
fy = fisheye(yy,ay,dy,bounds.getMinY(),bounds.getMaxY());
fy = Math.abs(y-fy)/bbox.getHeight();
}
double sf = (!m_distortY ? fx : (!m_distortX ? fy : Math.min(fx,fy)));
if (Double.isInfinite(sf) || Double.isNaN(sf)) {
return 1.;
} else {
return sz*sf;
}
}
private double fisheye(double x, double a, double d, double min, double max) {
if ( d != 0 ) {
boolean left = x<a;
double v, m = (left ? a-min : max-a);
if ( m == 0 ) m = max-min;
v = Math.abs(x - a) / m;
v = (d+1)/(d+(1/v));
return (left?-1:1)*m*v + a;
} else {
return x;
}
}
} // end of class FisheyeDistortion