package prefuse.util.display;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Iterator;
import prefuse.Display;
import prefuse.visual.VisualItem;
/**
* Library routines pertaining to a prefuse Display.
*
* @author <a href="http://jheer.org">jeffrey heer</a>
*/
public class DisplayLib {
private DisplayLib() {
// don't instantiate
}
/**
* Get a bounding rectangle of the VisualItems in the input iterator.
* @param iter an iterator of VisualItems
* @param margin a margin to add on to the bounding rectangle
* @param b the Rectangle instance in which to store the result
* @return the bounding rectangle. This is the same object as the
* parameter <code>b</code>.
*/
public static Rectangle2D getBounds(
Iterator iter, double margin, Rectangle2D b)
{
b.setFrame(Double.NaN,Double.NaN,Double.NaN,Double.NaN);
// TODO: synchronization?
if ( iter.hasNext() ) {
VisualItem item = (VisualItem)iter.next();
Rectangle2D nb = item.getBounds();
b.setFrame(nb);
}
while ( iter.hasNext() ) {
VisualItem item = (VisualItem)iter.next();
Rectangle2D nb = item.getBounds();
double x1 = (nb.getMinX()<b.getMinX() ? nb.getMinX() : b.getMinX());
double x2 = (nb.getMaxX()>b.getMaxX() ? nb.getMaxX() : b.getMaxX());
double y1 = (nb.getMinY()<b.getMinY() ? nb.getMinY() : b.getMinY());
double y2 = (nb.getMaxY()>b.getMaxY() ? nb.getMaxY() : b.getMaxY());
b.setFrame(x1,y1,x2-x1,y2-y1);
}
b.setFrame(b.getMinX() - margin,
b.getMinY() - margin,
b.getWidth() + 2*margin,
b.getHeight() + 2*margin);
return b;
}
/**
* Get a bounding rectangle of the VisualItems in the input iterator.
* @param iter an iterator of VisualItems
* @param margin a margin to add on to the bounding rectangle
* @return the bounding rectangle. A new Rectangle2D instance is
* allocated and returned.
*/
public static Rectangle2D getBounds(Iterator iter, double margin)
{
Rectangle2D b = new Rectangle2D.Double();
return getBounds(iter, margin, b);
}
/**
* Return the centroid (averaged location) of a group of items.
* @param iter an iterator of VisualItems
* @param p a Point2D instance in which to store the result
* @return the centroid point. This is the same object as the
* parameter <code>p</code>.
*/
public static Point2D getCentroid(Iterator iter, Point2D p) {
double cx = 0, cy = 0;
int count = 0;
while ( iter.hasNext() ) {
VisualItem item = (VisualItem)iter.next();
double x = item.getX(), y = item.getY();
if ( !(Double.isInfinite(x) || Double.isNaN(x)) &&
!(Double.isInfinite(y) || Double.isNaN(y)) )
{
cx += x;
cy += y;
count++;
}
}
if ( count > 0 ) {
cx /= count;
cy /= count;
}
p.setLocation(cx, cy);
return p;
}
/**
* Return the centroid (averaged location) of a group of items.
* @param iter an iterator of VisualItems
* @return the centroid point. A new Point2D instance is allocated
* and returned.
*/
public static Point2D getCentroid(Iterator iter)
{
return getCentroid(iter, new Point2D.Double());
}
/**
* Set the display view such that the given bounds are within view.
* @param display the Display instance
* @param bounds the bounds that should be visible in the Display view
* @param duration the duration of an animated transition. A value of
* zero will result in an instantaneous change.
*/
public static void fitViewToBounds(Display display, Rectangle2D bounds,
long duration)
{
fitViewToBounds(display, bounds, null, duration);
}
/**
* Set the display view such that the given bounds are within view, subject
* to a given center point being maintained.
* @param display the Display instance
* @param bounds the bounds that should be visible in the Display view
* @param center the point that should be the center of the Display
* @param duration the duration of an animated transition. A value of
* zero will result in an instantaneous change.
*/
public static void fitViewToBounds(Display display, Rectangle2D bounds,
Point2D center, long duration)
{
// init variables
double w = display.getWidth(), h = display.getHeight();
double cx = (center==null? bounds.getCenterX() : center.getX());
double cy = (center==null? bounds.getCenterY() : center.getY());
// compute half-widths of final bounding box around
// the desired center point
double wb = Math.max(cx-bounds.getMinX(),
bounds.getMaxX()-cx);
double hb = Math.max(cy-bounds.getMinY(),
bounds.getMaxY()-cy);
// compute scale factor
// - figure out if z or y dimension takes priority
// - then balance against the current scale factor
double scale = Math.min(w/(2*wb),h/(2*hb)) / display.getScale();
// animate to new display settings
if ( center == null )
center = new Point2D.Double(cx,cy);
if ( duration > 0 ) {
display.animatePanAndZoomToAbs(center,scale,duration);
} else {
display.panToAbs(center);
display.zoomAbs(center, scale);
}
}
} // end of class DisplayLib