001: package prefuse.render;
002:
003: import java.awt.BasicStroke;
004: import java.awt.Graphics2D;
005: import java.awt.Shape;
006: import java.awt.geom.AffineTransform;
007: import java.awt.geom.Point2D;
008:
009: import prefuse.util.GraphicsLib;
010: import prefuse.visual.VisualItem;
011:
012: /**
013: * <p>Abstract base class implementation of the Renderer interface for
014: * supporting the drawing of basic shapes. Subclasses should override the
015: * {@link #getRawShape(VisualItem) getRawShape} method,
016: * which returns the shape to draw. Optionally, subclasses can also override the
017: * {@link #getTransform(VisualItem) getTransform} method to apply a desired
018: * <code>AffineTransform</code> to the shape.</p>
019: *
020: * <p><b>NOTE:</b> For more efficient rendering, subclasses should use a
021: * single shape instance in memory, and update its parameters on each call
022: * to getRawShape, rather than allocating a new Shape object each time.
023: * Otherwise, a new object will be allocated every time something needs to
024: * be drawn, and then subsequently be arbage collected. This can significantly
025: * reduce performance, especially when there are many things to draw.
026: * </p>
027: *
028: * @version 1.0
029: * @author alan newberger
030: * @author <a href="http://jheer.org">jeffrey heer</a>
031: */
032: public abstract class AbstractShapeRenderer implements Renderer {
033:
034: public static final int RENDER_TYPE_NONE = 0;
035: public static final int RENDER_TYPE_DRAW = 1;
036: public static final int RENDER_TYPE_FILL = 2;
037: public static final int RENDER_TYPE_DRAW_AND_FILL = 3;
038:
039: private int m_renderType = RENDER_TYPE_DRAW_AND_FILL;
040: protected AffineTransform m_transform = new AffineTransform();
041: protected boolean m_manageBounds = true;
042:
043: public void setManageBounds(boolean b) {
044: m_manageBounds = b;
045: }
046:
047: /**
048: * @see prefuse.render.Renderer#render(java.awt.Graphics2D, prefuse.visual.VisualItem)
049: */
050: public void render(Graphics2D g, VisualItem item) {
051: Shape shape = getShape(item);
052: if (shape != null)
053: drawShape(g, item, shape);
054: }
055:
056: /**
057: * Draws the specified shape into the provided Graphics context, using
058: * stroke and fill color values from the specified VisualItem. This method
059: * can be called by subclasses in custom rendering routines.
060: */
061: protected void drawShape(Graphics2D g, VisualItem item, Shape shape) {
062: GraphicsLib.paint(g, item, shape, getStroke(item),
063: getRenderType(item));
064: }
065:
066: /**
067: * Returns the shape describing the boundary of an item. The shape's
068: * coordinates should be in abolute (item-space) coordinates.
069: * @param item the item for which to get the Shape
070: */
071: public Shape getShape(VisualItem item) {
072: AffineTransform at = getTransform(item);
073: Shape rawShape = getRawShape(item);
074: return (at == null || rawShape == null ? rawShape : at
075: .createTransformedShape(rawShape));
076: }
077:
078: /**
079: * Retursn the stroke to use for drawing lines and shape outlines. By
080: * default returns the value of {@link VisualItem#getStroke()}.
081: * Subclasses can override this method to implement custom stroke
082: * assignment, though changing the <code>VisualItem</code>'s stroke
083: * value is preferred.
084: * @param item the VisualItem
085: * @return the strok to use for drawing lines and shape outlines
086: */
087: protected BasicStroke getStroke(VisualItem item) {
088: return item.getStroke();
089: }
090:
091: /**
092: * Return a non-transformed shape for the visual representation of the
093: * item. Subclasses must implement this method.
094: * @param item the VisualItem being drawn
095: * @return the "raw", untransformed shape.
096: */
097: protected abstract Shape getRawShape(VisualItem item);
098:
099: /**
100: * Return the graphics space transform applied to this item's shape, if any.
101: * Subclasses can implement this method, otherwise it will return null
102: * to indicate no transformation is needed.
103: * @param item the VisualItem
104: * @return the graphics space transform, or null if none
105: */
106: protected AffineTransform getTransform(VisualItem item) {
107: return null;
108: }
109:
110: /**
111: * Returns a value indicating if a shape is drawn by its outline, by a
112: * fill, or both. The default is to draw both.
113: * @return the rendering type
114: */
115: public int getRenderType(VisualItem item) {
116: return m_renderType;
117: }
118:
119: /**
120: * Sets a value indicating if a shape is drawn by its outline, by a fill,
121: * or both. The default is to draw both.
122: * @param type the new rendering type. Should be one of
123: * {@link #RENDER_TYPE_NONE}, {@link #RENDER_TYPE_DRAW},
124: * {@link #RENDER_TYPE_FILL}, or {@link #RENDER_TYPE_DRAW_AND_FILL}.
125: */
126: public void setRenderType(int type) {
127: if (type < RENDER_TYPE_NONE || type > RENDER_TYPE_DRAW_AND_FILL) {
128: throw new IllegalArgumentException(
129: "Unrecognized render type.");
130: }
131: m_renderType = type;
132: }
133:
134: /**
135: * @see prefuse.render.Renderer#locatePoint(java.awt.geom.Point2D, prefuse.visual.VisualItem)
136: */
137: public boolean locatePoint(Point2D p, VisualItem item) {
138: if (item.getBounds().contains(p)) {
139: // if within bounds, check within shape outline
140: Shape s = getShape(item);
141: return (s != null ? s.contains(p) : false);
142: } else {
143: return false;
144: }
145: }
146:
147: /**
148: * @see prefuse.render.Renderer#setBounds(prefuse.visual.VisualItem)
149: */
150: public void setBounds(VisualItem item) {
151: if (!m_manageBounds)
152: return;
153: Shape shape = getShape(item);
154: if (shape == null) {
155: item.setBounds(item.getX(), item.getY(), 0, 0);
156: } else {
157: GraphicsLib.setBounds(item, shape, getStroke(item));
158: }
159: }
160:
161: } // end of abstract class AbstractShapeRenderer
|