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    }