package prefuse.action.animate;
import java.awt.geom.Point2D;
import prefuse.Display;
import prefuse.action.ItemAction;
import prefuse.util.MathLib;
import prefuse.visual.VisualItem;
/**
* Animator that interpolates between starting and ending display locations
* by linearly interpolating between polar coordinates.
*
* @author <a href="http://jheer.org">jeffrey heer</a>
*/
public class PolarLocationAnimator extends ItemAction {
private Point2D m_anchor = new Point2D.Double();
private String m_linear = null;
// temp variables
private double ax, ay, sx, sy, ex, ey, x, y;
private double dt1, dt2, sr, st, er, et, r, t, stt, ett;
/**
* Creates a PolarLocationAnimator that operates on all VisualItems
* within a Visualization.
*/
public PolarLocationAnimator() {
super();
}
/**
* Creates a PolarLocationAnimator that operates on VisualItems
* within the specified group.
* @param group the data group to process
*/
public PolarLocationAnimator(String group) {
super(group);
}
/**
* Creates a PolarLocationAnimator that operates on VisualItems
* within the specified group, while using regular linear interpolation
* (in Cartesian (x,y) coordinates rather than polar coordinates) for
* items also contained within the specified linearGroup.
* @param group the data group to process
* @param linearGroup the group of items that should be interpolated
* in Cartesian (standard x,y) coordinates rather than polar coordinates.
* Note that this animator will not process any items in
* <code>linearGroup</code> that are not also in <code>group</code>.
*/
public PolarLocationAnimator(String group, String linearGroup) {
super(group);
m_linear = linearGroup;
}
private void setAnchor() {
Display d = getVisualization().getDisplay(0);
m_anchor.setLocation(d.getWidth()/2,d.getHeight()/2);
d.getAbsoluteCoordinate(m_anchor, m_anchor);
ax = m_anchor.getX();
ay = m_anchor.getY();
}
/**
* @see prefuse.action.Action#run(double)
*/
public void run(double frac) {
setAnchor();
super.run(frac);
}
/**
* @see prefuse.action.ItemAction#process(prefuse.visual.VisualItem, double)
*/
public void process(VisualItem item, double frac) {
if ( m_linear != null && item.isInGroup(m_linear) ) {
// perform linear interpolation instead
double s = item.getStartX();
item.setX(s + frac*(item.getEndX()-s));
s = item.getStartY();
item.setY(s + frac*(item.getEndY()-s));
return;
}
// otherwise, interpolate in polar coordinates
sx = item.getStartX() - ax;
sy = item.getStartY() - ay;
ex = item.getEndX() - ax;
ey = item.getEndY() - ay;
sr = Math.sqrt(sx*sx + sy*sy);
st = Math.atan2(sy,sx);
er = Math.sqrt(ex*ex + ey*ey);
et = Math.atan2(ey,ex);
stt = st < 0 ? st+MathLib.TWO_PI : st;
ett = et < 0 ? et+MathLib.TWO_PI : et;
dt1 = et - st;
dt2 = ett - stt;
if ( Math.abs(dt1) < Math.abs(dt2) ) {
t = st + frac * dt1;
} else {
t = stt + frac * dt2;
}
r = sr + frac * (er - sr);
x = Math.round(ax + r*Math.cos(t));
y = Math.round(ay + r*Math.sin(t));
item.setX(x);
item.setY(y);
}
} // end of class PolarLocationAnimator