package prefuse.action.distortion; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; /** * <p> * Computes a bifocal distortion of space, magnifying a focus region of space * and uniformly demagnifying the rest of the space. The affect is akin to * passing a magnifying glass over the data. * </p> * * <p> * For more details on this form of transformation, see Y. K. Leung and * M. D. Apperley, "A Review and Taxonomy of Distortion-Oriented Presentation * Techniques", in Transactions of Computer-Human Interaction (TOCHI), * 1(2): 126-160 (1994). Available online at * <a href="portal.acm.org/citation.cfm?id=180173&dl=ACM"> * portal.acm.org/citation.cfm?id=180173&dl=ACM</a>. * </p> * * @author <a href="http://jheer.org">jeffrey heer</a> */ public class BifocalDistortion extends Distortion { private double rx, ry; // magnification ranges private double mx, my; // magnification factor /** * Create a new BifocalDistortion with default range and magnification. */ public BifocalDistortion() { this(0.1,3); } /** * <p>Create a new BifocalDistortion with the specified range and * magnification. The same range and magnification is used for both * axes.</p> * * <p><strong>NOTE:</strong>if the range value times the magnification * value is greater than 1, the resulting distortion can exceed the * display bounds.</p> * * @param range the range around the focus that should be magnified. This * specifies the size of the magnified focus region, and should be in the * range of 0 to 1, 0 being no magnification range and 1 being the whole * display. * @param mag how much magnification should be used in the focal area */ public BifocalDistortion(double range, double mag) { this(range,mag,range,mag); } // /** * <p>Create a new BifocalDistortion with the specified range and * magnification along both axes.</p> * * <p><strong>NOTE:</strong>if the range value times the magnification * value is greater than 1, the resulting distortion can exceed the * display bounds.</p> * * @param xrange the range around the focus that should be magnified along * the x direction. This specifies the horizontal size of the magnified * focus region, and should be a value between 0 and 1, 0 indicating no * focus region and 1 indicating the whole display. * @param xmag how much magnification along the x direction should be used * in the focal area * @param yrange the range around the focus that should be magnified along * the y direction. This specifies the vertical size of the magnified * focus region, and should be a value between 0 and 1, 0 indicating no * focus region and 1 indicating the whole display. * @param ymag how much magnification along the y direction should be used * in the focal area */ public BifocalDistortion(double xrange, double xmag, double yrange, double ymag) { rx = xrange; mx = xmag; ry = yrange; my = ymag; m_distortX = !(rx == 0 || mx == 1.0); m_distortY = !(ry == 0 || my == 1.0); } /** * @see prefuse.action.distortion.Distortion#distortX(double, java.awt.geom.Point2D, java.awt.geom.Rectangle2D) */ protected double distortX(double x, Point2D a, Rectangle2D b) { return bifocal(x, a.getX(), rx, mx, b.getMinX(), b.getMaxX()); } /** * @see prefuse.action.distortion.Distortion#distortY(double, java.awt.geom.Point2D, java.awt.geom.Rectangle2D) */ protected double distortY(double y, Point2D a, Rectangle2D b) { return bifocal(y, a.getY(), ry, my, b.getMinY(), b.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) { boolean xmag = false, ymag = false; double m; if ( m_distortX ) { double cx = bbox.getCenterX(), ax = anchor.getX(); double minX = bounds.getMinX(), maxX = bounds.getMaxX(); m = (cx<ax ? ax-minX : maxX-ax); if ( m == 0 ) m = maxX-minX; if ( Math.abs(cx-ax) <= rx*m ) xmag = true; } if ( m_distortY ) { double cy = bbox.getCenterY(), ay = anchor.getY(); double minY = bounds.getMinY(), maxY = bounds.getMaxY(); m = (cy<ay ? ay-minY : maxY-ay); if ( m == 0 ) m = maxY-minY; if ( Math.abs(cy-ay) <= ry*m ) ymag = true; } if ( xmag && !m_distortY ) { return mx; } else if ( ymag && !m_distortX ) { return my; } else if ( xmag && ymag ) { return Math.min(mx,my); } else { return Math.min((1-rx*mx)/(1-rx), (1-ry*my)/(1-ry)); } } private double bifocal(double x, double a, double r, double mag, double min, double max) { double m = (x<a ? a-min : max-a); if ( m == 0 ) m = max-min; double v = x - a, s = m*r; if ( Math.abs(v) <= s ) { // in focus return x = v*mag + a; } else { // out of focus double bx = r*mag; x = ((Math.abs(v)-s) / m) * ((1-bx)/(1-r)); return (v<0?-1:1)*m*(x + bx) + a; } } /** * Returns the magnification factor for the x-axis. * @return Returns the magnification factor for the x-axis. */ public double getXMagnification() { return mx; } /** * Sets the magnification factor for the x-axis. * @param mx The magnification factor for the x-axis. */ public void setXMagnification(double mx) { this.mx = mx; } /** * Returns the magnification factor for the y-axis. * @return Returns the magnification factor for the y-axis. */ public double getYMagnification() { return my; } /** * Sets the magnification factor for the y-axis. * @param my The magnification factor for the y-axis. */ public void setYMagnification(double my) { this.my = my; } /** * Returns the range of the focal area along the x-axis. * @return Returns the range of the focal area along the x-axis. */ public double getXRange() { return rx; } /** * Sets the range of the focal area along the x-axis. * @param rx The focal range for the x-axis, a value between 0 and 1. */ public void setXRange(double rx) { this.rx = rx; } /** * Returns the range of the focal area along the y-axis. * @return Returns the range of the focal area along the y-axis. */ public double getYRange() { return ry; } /** * Sets the range of the focal area along the y-axis. * @param ry The focal range for the y-axis, a value between 0 and 1. */ public void setYRange(double ry) { this.ry = ry; } } // end of class BifocalDistortion