package prefuse.action.distortion;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Iterator;
import prefuse.action.layout.Layout;
import prefuse.visual.VisualItem;
/**
* Abstract base class providing a structure for space-distortion techniques.
*
* @version 1.0
* @author <a href="http://jheer.org">jeffrey heer</a>
*/
public abstract class Distortion extends Layout {
private Point2D m_tmp = new Point2D.Double();
protected boolean m_distortSize = true;
protected boolean m_distortX = true;
protected boolean m_distortY = true;
// ------------------------------------------------------------------------
/**
* Create a new Distortion instance.
*/
public Distortion() {
super();
}
/**
* Create a new Distortion instance that processes the given data group.
* @param group the data group processed by this Distortion instance
*/
public Distortion(String group) {
super(group);
}
// ------------------------------------------------------------------------
/**
* Controls whether item sizes are distorted along with the item locations.
* @param s true to distort size, false to distort positions only
*/
public void setSizeDistorted(boolean s) {
m_distortSize = s;
}
/**
* Indicates whether the item sizes are distorted along with the item
* locations.
* @return true if item sizes are distorted by this action, false otherwise
*/
public boolean isSizeDistorted() {
return m_distortSize;
}
// ------------------------------------------------------------------------
/**
* @see prefuse.action.Action#run(double)
*/
public void run(double frac) {
Rectangle2D bounds = getLayoutBounds();
Point2D anchor = correct(m_anchor, bounds);
final Iterator iter = getVisualization().visibleItems(m_group);
while ( iter.hasNext() ) {
VisualItem item = (VisualItem)iter.next();
if ( item.isFixed() ) continue;
// reset distorted values
// TODO - make this play nice with animation?
item.setX(item.getEndX());
item.setY(item.getEndY());
item.setSize(item.getEndSize());
// compute distortion if we have a distortion focus
if ( anchor != null ) {
Rectangle2D bbox = item.getBounds();
double x = item.getX();
double y = item.getY();
// position distortion
if ( m_distortX )
item.setX(x=distortX(x, anchor, bounds));
if ( m_distortY )
item.setY(y=distortY(y, anchor, bounds));
// size distortion
if ( m_distortSize ) {
double sz = distortSize(bbox, x, y, anchor, bounds);
item.setSize(sz*item.getSize());
}
}
}
}
/**
* Corrects the anchor position, such that if the anchor is outside the
* layout bounds, the anchor is adjusted to be the nearest point on the
* edge of the bounds.
* @param anchor the un-corrected anchor point
* @param bounds the layout bounds
* @return the corrected anchor point
*/
protected Point2D correct(Point2D anchor, Rectangle2D bounds) {
if ( anchor == null ) return anchor;
double x = anchor.getX(), y = anchor.getY();
double x1 = bounds.getMinX(), y1 = bounds.getMinY();
double x2 = bounds.getMaxX(), y2 = bounds.getMaxY();
x = (x < x1 ? x1 : (x > x2 ? x2 : x));
y = (y < y1 ? y1 : (y > y2 ? y2 : y));
m_tmp.setLocation(x,y);
return m_tmp;
}
/**
* Distorts an item's x-coordinate.
* @param x the undistorted x coordinate
* @param anchor the anchor or focus point of the display
* @param bounds the layout bounds
* @return the distorted x-coordinate
*/
protected abstract double distortX(double x, Point2D anchor, Rectangle2D bounds);
/**
* Distorts an item's y-coordinate.
* @param y the undistorted y coordinate
* @param anchor the anchor or focus point of the display
* @param bounds the layout bounds
* @return the distorted y-coordinate
*/
protected abstract double distortY(double y, Point2D anchor, Rectangle2D bounds);
/**
* Returns the scaling factor by which to transform the size of an item.
* @param bbox the bounding box of the undistorted item
* @param x the x-coordinate of the distorted item
* @param y the y-coordinate of the distorted item
* @param anchor the anchor or focus point of the display
* @param bounds the layout bounds
* @return the scaling factor by which to change the size
*/
protected abstract double distortSize(Rectangle2D bbox, double x, double y,
Point2D anchor, Rectangle2D bounds);
} // end of abstract class Distortion