001 package nl.cwi.sen1.gui.plugin;
002
003 import java.awt.Shape;
004 import java.awt.geom.AffineTransform;
005 import java.awt.geom.GeneralPath;
006 import java.awt.geom.Point2D;
007 import java.awt.geom.Rectangle2D;
008
009 import prefuse.Constants;
010 import prefuse.render.EdgeRenderer;
011 import prefuse.util.GraphicsLib;
012 import prefuse.visual.EdgeItem;
013 import prefuse.visual.VisualItem;
014
015 public class GraphEdgeRenderer extends EdgeRenderer {
016 private static Point2D start = new Point2D.Float();
017
018 private static Point2D end = new Point2D.Float();
019
020 public GraphEdgeRenderer(int edgeType, int arrowType) {
021 super(edgeType, arrowType);
022 }
023
024 private boolean onDotLocation(VisualItem item) {
025 return item.getX() == item.getInt(GraphDotLayout.DOT_X)
026 && item.getY() == item.getInt(GraphDotLayout.DOT_Y);
027 }
028
029 private Shape makeCurvedEdge(Point2D start, Point2D end, Point2D[] points) {
030 Point2D from = start;
031 Point2D to = from;
032
033 GeneralPath gp = new GeneralPath(GeneralPath.WIND_NON_ZERO);
034 gp.moveTo((float) from.getX(), (float) from.getY());
035
036 int i;
037 for (i = 1; i + 2 < points.length; i += 3) {
038 Point2D cp1 = points[i];
039 Point2D cp2 = points[i + 1];
040 Point2D cur = points[i + 2];
041
042 from = cp1;
043 to = cur;
044
045 gp.curveTo((float) cp1.getX(), (float) cp1.getY(), (float) cp2
046 .getX(), (float) cp2.getY(), (float) cur.getX(),
047 (float) cur.getY());
048 }
049
050 if (i < points.length) {
051 from = to;
052 to = points[points.length - 1];
053 gp.lineTo((float) to.getX(), (float) to.getY());
054 }
055
056 gp.lineTo((float) end.getX(), (float) end.getY());
057
058 // TODO: remove this hack that is used to retrieve the last direction of
059 // the edge
060 start.setLocation(from);
061 return gp;
062 }
063
064 protected Shape getArrowShape(Point2D start, Point2D end, VisualItem item) {
065 Rectangle2D r = item.getBounds();
066 int i = GraphicsLib.intersectLineRectangle(start, end, r, m_isctPoints);
067 if (i > 0) {
068 end = m_isctPoints[0];
069 }
070 AffineTransform at = getArrowTrans(start, end, 1);
071 return at.createTransformedShape(m_arrowHead);
072 }
073
074 protected Shape getRawShape(VisualItem item) {
075 EdgeItem edge = (EdgeItem) item;
076 VisualItem item1 = edge.getSourceItem();
077 VisualItem item2 = edge.getTargetItem();
078
079 // If the nodes are not on their original dot positions, the curved
080 // edge degenerates to a straight edge.
081 if (!onDotLocation(item1) || !onDotLocation(item2)) {
082 return super.getRawShape(item);
083 }
084
085 // Find the middle of the start and end nodes
086 getAlignedPoint(start, item1.getBounds(), Constants.CENTER, Constants.CENTER);
087 getAlignedPoint(end, item2.getBounds(), Constants.CENTER, Constants.CENTER);
088
089 // Retrieve the dot curve points data
090 Point2D[] points = (Point2D[]) item.get(GraphDotLayout.CURVE_POINTS);
091 if (points == null) {
092 return super.getRawShape(item);
093 }
094
095
096 // now construct the curved edge
097 Shape shape = makeCurvedEdge(start, end, points);
098 AffineTransform at = getTransform(item);
099 shape = (at == null) ? shape : at.createTransformedShape(shape);
100
101 // create the arrow head, if needed
102 Shape arrow = getArrowShape(start, end, item2);
103 setRenderType(RENDER_TYPE_DRAW_AND_FILL);
104 m_curArrow = arrow;
105
106 setRenderType(RENDER_TYPE_DRAW);
107 return shape;
108 }
109 }