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
48
49
50
51
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
92
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
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
158 if (new_stroke != null)
159 g.setStroke(old_stroke);
160
161 }
162
163
164 g.setPaint(oldPaint);
165 }
166 }
167
168
169 public void stateChanged(ChangeEvent evt) {
170 System.err.println("got change event "+evt);
171 edgeShapeMap.clear();
172
173 }
174
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 }