View Javadoc
1   package edu.uci.ics.jung.visualization.renderers;
2   
3   import java.awt.Dimension;
4   import java.awt.Paint;
5   import java.awt.Rectangle;
6   import java.awt.Shape;
7   import java.awt.Stroke;
8   import java.awt.geom.AffineTransform;
9   import java.util.HashMap;
10  import java.util.HashSet;
11  import java.util.Map;
12  import java.util.Set;
13  
14  import javax.swing.JComponent;
15  import javax.swing.event.ChangeEvent;
16  import javax.swing.event.ChangeListener;
17  
18  import edu.uci.ics.jung.algorithms.layout.Layout;
19  import edu.uci.ics.jung.graph.Graph;
20  import edu.uci.ics.jung.graph.util.Context;
21  import edu.uci.ics.jung.graph.util.EdgeType;
22  import edu.uci.ics.jung.visualization.BasicVisualizationServer;
23  import edu.uci.ics.jung.visualization.Layer;
24  import edu.uci.ics.jung.visualization.RenderContext;
25  import edu.uci.ics.jung.visualization.layout.LayoutChangeListener;
26  import edu.uci.ics.jung.visualization.layout.LayoutEvent;
27  import edu.uci.ics.jung.visualization.layout.LayoutEventSupport;
28  import edu.uci.ics.jung.visualization.transform.LensTransformer;
29  import edu.uci.ics.jung.visualization.transform.MutableTransformer;
30  import edu.uci.ics.jung.visualization.transform.shape.GraphicsDecorator;
31  
32  public class CachingEdgeRenderer<V, E> extends BasicEdgeRenderer<V, E>  
33  	implements ChangeListener, LayoutChangeListener<V,E> {
34  	
35  	protected Map<E,Shape> edgeShapeMap = new HashMap<E,Shape>();
36  	protected Set<E> dirtyEdges = new HashSet<E>();
37  	
38  	@SuppressWarnings({ "rawtypes", "unchecked" })
39  	public CachingEdgeRenderer(BasicVisualizationServer<V,E> vv) {
40  		vv.getRenderContext().getMultiLayerTransformer().addChangeListener(this);
41  		Layout<V,E> layout = vv.getGraphLayout();
42  		if(layout instanceof LayoutEventSupport) {
43  			((LayoutEventSupport)layout).addLayoutChangeListener(this);
44  		}
45  	}
46  	/**
47       * Draws the edge <code>e</code>, whose endpoints are at <code>(x1,y1)</code>
48       * and <code>(x2,y2)</code>, on the graphics context <code>g</code>.
49       * The <code>Shape</code> provided by the <code>EdgeShapeFunction</code> instance
50       * is scaled in the x-direction so that its width is equal to the distance between
51       * <code>(x1,y1)</code> and <code>(x2,y2)</code>.
52       */
53      protected void drawSimpleEdge(RenderContext<V,E> rc, Layout<V,E> layout, E e) {
54      	
55      	int[] coords = new int[4];
56      	boolean[] loop = new boolean[1];
57      	
58      	Shape edgeShape = edgeShapeMap.get(e);
59      	if(edgeShape == null || dirtyEdges.contains(e)) {
60      		edgeShape = prepareFinalEdgeShape(rc, layout, e, coords, loop);
61      		edgeShapeMap.put(e, edgeShape);
62      		dirtyEdges.remove(e);
63      	}
64      	
65      	int x1 = coords[0];
66      	int y1 = coords[1];
67      	int x2 = coords[2];
68      	int y2 = coords[3];
69      	boolean isLoop = loop[0];
70          
71          GraphicsDecorator g = rc.getGraphicsContext();
72          Graph<V,E> graph = layout.getGraph();
73          boolean edgeHit = true;
74          boolean arrowHit = true;
75          Rectangle deviceRectangle = null;
76          JComponent vv = rc.getScreenDevice();
77          if(vv != null) {
78              Dimension d = vv.getSize();
79              deviceRectangle = new Rectangle(0,0,d.width,d.height);
80          }
81          MutableTransformer vt = rc.getMultiLayerTransformer().getTransformer(Layer.VIEW);
82          if(vt instanceof LensTransformer) {
83          	vt = ((LensTransformer)vt).getDelegate();
84          }
85          edgeHit = vt.transform(edgeShape).intersects(deviceRectangle);
86  
87          if(edgeHit == true) {
88              
89              Paint oldPaint = g.getPaint();
90              
91              // get Paints for filling and drawing
92              // (filling is done first so that drawing and label use same Paint)
93              Paint fill_paint = rc.getEdgeFillPaintTransformer().apply(e); 
94              if (fill_paint != null)
95              {
96                  g.setPaint(fill_paint);
97                  g.fill(edgeShape);
98              }
99              Paint draw_paint = rc.getEdgeDrawPaintTransformer().apply(e);
100             if (draw_paint != null)
101             {
102                 g.setPaint(draw_paint);
103                 g.draw(edgeShape);
104             }
105             
106             float scalex = (float)g.getTransform().getScaleX();
107             float scaley = (float)g.getTransform().getScaleY();
108             // see if arrows are too small to bother drawing
109             if(scalex < .3 || scaley < .3) return;
110             
111             if (rc.getEdgeArrowPredicate().apply(Context.<Graph<V,E>,E>getInstance(graph, e))) {
112             	
113                 Stroke new_stroke = rc.getEdgeArrowStrokeTransformer().apply(e);
114                 Stroke old_stroke = g.getStroke();
115                 if (new_stroke != null)
116                     g.setStroke(new_stroke);
117 
118                 
119                 Shape destVertexShape = 
120                     rc.getVertexShapeTransformer().apply(graph.getEndpoints(e).getSecond());
121 
122                 AffineTransform xf = AffineTransform.getTranslateInstance(x2, y2);
123                 destVertexShape = xf.createTransformedShape(destVertexShape);
124                 
125                 arrowHit = rc.getMultiLayerTransformer().getTransformer(Layer.VIEW).transform(destVertexShape).intersects(deviceRectangle);
126                 if(arrowHit) {
127                     
128                     AffineTransform at = 
129                         edgeArrowRenderingSupport.getArrowTransform(rc, edgeShape, destVertexShape);
130                     if(at == null) return;
131                     Shape arrow = rc.getEdgeArrowTransformer().apply(Context.<Graph<V,E>,E>getInstance(graph, e));
132                     arrow = at.createTransformedShape(arrow);
133                     g.setPaint(rc.getArrowFillPaintTransformer().apply(e));
134                     g.fill(arrow);
135                     g.setPaint(rc.getArrowDrawPaintTransformer().apply(e));
136                     g.draw(arrow);
137                 }
138                 if (graph.getEdgeType(e) == EdgeType.UNDIRECTED) {
139                     Shape vertexShape = 
140                         rc.getVertexShapeTransformer().apply(graph.getEndpoints(e).getFirst());
141                     xf = AffineTransform.getTranslateInstance(x1, y1);
142                     vertexShape = xf.createTransformedShape(vertexShape);
143                     
144                     arrowHit = rc.getMultiLayerTransformer().getTransformer(Layer.VIEW).transform(vertexShape).intersects(deviceRectangle);
145                     
146                     if(arrowHit) {
147                         AffineTransform at = edgeArrowRenderingSupport.getReverseArrowTransform(rc, edgeShape, vertexShape, !isLoop);
148                         if(at == null) return;
149                         Shape arrow = rc.getEdgeArrowTransformer().apply(Context.<Graph<V,E>,E>getInstance(graph, e));
150                         arrow = at.createTransformedShape(arrow);
151                         g.setPaint(rc.getArrowFillPaintTransformer().apply(e));
152                         g.fill(arrow);
153                         g.setPaint(rc.getArrowDrawPaintTransformer().apply(e));
154                         g.draw(arrow);
155                     }
156                 }
157                 // restore paint and stroke
158                 if (new_stroke != null)
159                     g.setStroke(old_stroke);
160 
161             }
162             
163             // restore old paint
164             g.setPaint(oldPaint);
165         }
166     }
167 
168 //	@Override
169 	public void stateChanged(ChangeEvent evt) {
170 		System.err.println("got change event "+evt);
171 		edgeShapeMap.clear();
172 		
173 	}
174 //	@Override
175 	public void layoutChanged(LayoutEvent<V, E> evt) {
176 		V v = evt.getVertex();
177 		Graph<V,E> graph = evt.getGraph();
178 		dirtyEdges.addAll(graph.getIncidentEdges(v));
179 	}
180 }