001: package prefuse.action.distortion;
002:
003: import java.awt.geom.Point2D;
004: import java.awt.geom.Rectangle2D;
005: import java.util.Iterator;
006:
007: import prefuse.action.layout.Layout;
008: import prefuse.visual.VisualItem;
009:
010: /**
011: * Abstract base class providing a structure for space-distortion techniques.
012: *
013: * @version 1.0
014: * @author <a href="http://jheer.org">jeffrey heer</a>
015: */
016: public abstract class Distortion extends Layout {
017:
018: private Point2D m_tmp = new Point2D.Double();
019: protected boolean m_distortSize = true;
020: protected boolean m_distortX = true;
021: protected boolean m_distortY = true;
022:
023: // ------------------------------------------------------------------------
024:
025: /**
026: * Create a new Distortion instance.
027: */
028: public Distortion() {
029: super ();
030: }
031:
032: /**
033: * Create a new Distortion instance that processes the given data group.
034: * @param group the data group processed by this Distortion instance
035: */
036: public Distortion(String group) {
037: super (group);
038: }
039:
040: // ------------------------------------------------------------------------
041:
042: /**
043: * Controls whether item sizes are distorted along with the item locations.
044: * @param s true to distort size, false to distort positions only
045: */
046: public void setSizeDistorted(boolean s) {
047: m_distortSize = s;
048: }
049:
050: /**
051: * Indicates whether the item sizes are distorted along with the item
052: * locations.
053: * @return true if item sizes are distorted by this action, false otherwise
054: */
055: public boolean isSizeDistorted() {
056: return m_distortSize;
057: }
058:
059: // ------------------------------------------------------------------------
060:
061: /**
062: * @see prefuse.action.Action#run(double)
063: */
064: public void run(double frac) {
065: Rectangle2D bounds = getLayoutBounds();
066: Point2D anchor = correct(m_anchor, bounds);
067:
068: final Iterator iter = getVisualization().visibleItems(m_group);
069:
070: while (iter.hasNext()) {
071: VisualItem item = (VisualItem) iter.next();
072: if (item.isFixed())
073: continue;
074:
075: // reset distorted values
076: // TODO - make this play nice with animation?
077: item.setX(item.getEndX());
078: item.setY(item.getEndY());
079: item.setSize(item.getEndSize());
080:
081: // compute distortion if we have a distortion focus
082: if (anchor != null) {
083: Rectangle2D bbox = item.getBounds();
084: double x = item.getX();
085: double y = item.getY();
086:
087: // position distortion
088: if (m_distortX)
089: item.setX(x = distortX(x, anchor, bounds));
090: if (m_distortY)
091: item.setY(y = distortY(y, anchor, bounds));
092:
093: // size distortion
094: if (m_distortSize) {
095: double sz = distortSize(bbox, x, y, anchor, bounds);
096: item.setSize(sz * item.getSize());
097: }
098: }
099: }
100: }
101:
102: /**
103: * Corrects the anchor position, such that if the anchor is outside the
104: * layout bounds, the anchor is adjusted to be the nearest point on the
105: * edge of the bounds.
106: * @param anchor the un-corrected anchor point
107: * @param bounds the layout bounds
108: * @return the corrected anchor point
109: */
110: protected Point2D correct(Point2D anchor, Rectangle2D bounds) {
111: if (anchor == null)
112: return anchor;
113: double x = anchor.getX(), y = anchor.getY();
114: double x1 = bounds.getMinX(), y1 = bounds.getMinY();
115: double x2 = bounds.getMaxX(), y2 = bounds.getMaxY();
116: x = (x < x1 ? x1 : (x > x2 ? x2 : x));
117: y = (y < y1 ? y1 : (y > y2 ? y2 : y));
118:
119: m_tmp.setLocation(x, y);
120: return m_tmp;
121: }
122:
123: /**
124: * Distorts an item's x-coordinate.
125: * @param x the undistorted x coordinate
126: * @param anchor the anchor or focus point of the display
127: * @param bounds the layout bounds
128: * @return the distorted x-coordinate
129: */
130: protected abstract double distortX(double x, Point2D anchor,
131: Rectangle2D bounds);
132:
133: /**
134: * Distorts an item's y-coordinate.
135: * @param y the undistorted y coordinate
136: * @param anchor the anchor or focus point of the display
137: * @param bounds the layout bounds
138: * @return the distorted y-coordinate
139: */
140: protected abstract double distortY(double y, Point2D anchor,
141: Rectangle2D bounds);
142:
143: /**
144: * Returns the scaling factor by which to transform the size of an item.
145: * @param bbox the bounding box of the undistorted item
146: * @param x the x-coordinate of the distorted item
147: * @param y the y-coordinate of the distorted item
148: * @param anchor the anchor or focus point of the display
149: * @param bounds the layout bounds
150: * @return the scaling factor by which to change the size
151: */
152: protected abstract double distortSize(Rectangle2D bbox, double x,
153: double y, Point2D anchor, Rectangle2D bounds);
154:
155: } // end of abstract class Distortion
|