1
2
3
4
5
6
7
8
9
10 package edu.uci.ics.jung.visualization.renderers;
11
12 import java.awt.Dimension;
13 import java.awt.Paint;
14 import java.awt.Rectangle;
15 import java.awt.Shape;
16 import java.awt.Stroke;
17 import java.awt.geom.AffineTransform;
18 import java.awt.geom.GeneralPath;
19 import java.awt.geom.Point2D;
20 import java.awt.geom.Rectangle2D;
21
22 import javax.swing.JComponent;
23
24 import edu.uci.ics.jung.algorithms.layout.Layout;
25 import edu.uci.ics.jung.graph.Graph;
26 import edu.uci.ics.jung.graph.util.Context;
27 import edu.uci.ics.jung.graph.util.EdgeIndexFunction;
28 import edu.uci.ics.jung.graph.util.EdgeType;
29 import edu.uci.ics.jung.graph.util.Pair;
30 import edu.uci.ics.jung.visualization.Layer;
31 import edu.uci.ics.jung.visualization.RenderContext;
32 import edu.uci.ics.jung.visualization.decorators.EdgeShape;
33 import edu.uci.ics.jung.visualization.decorators.ParallelEdgeShapeTransformer;
34 import edu.uci.ics.jung.visualization.transform.LensTransformer;
35 import edu.uci.ics.jung.visualization.transform.MutableTransformer;
36 import edu.uci.ics.jung.visualization.transform.shape.GraphicsDecorator;
37
38 public class BasicEdgeRenderer<V,E> implements Renderer.Edge<V,E> {
39
40 protected EdgeArrowRenderingSupport<V,E> edgeArrowRenderingSupport =
41 new BasicEdgeArrowRenderingSupport<V,E>();
42
43 public void paintEdge(RenderContext<V,E> rc, Layout<V, E> layout, E e) {
44 GraphicsDecorator g2d = rc.getGraphicsContext();
45 Graph<V,E> graph = layout.getGraph();
46 if (!rc.getEdgeIncludePredicate().apply(Context.<Graph<V,E>,E>getInstance(graph,e)))
47 return;
48
49
50 Pair<V> endpoints = graph.getEndpoints(e);
51 V v1 = endpoints.getFirst();
52 V v2 = endpoints.getSecond();
53 if (!rc.getVertexIncludePredicate().apply(Context.<Graph<V,E>,V>getInstance(graph,v1)) ||
54 !rc.getVertexIncludePredicate().apply(Context.<Graph<V,E>,V>getInstance(graph,v2)))
55 return;
56
57 Stroke new_stroke = rc.getEdgeStrokeTransformer().apply(e);
58 Stroke old_stroke = g2d.getStroke();
59 if (new_stroke != null)
60 g2d.setStroke(new_stroke);
61
62 drawSimpleEdge(rc, layout, e);
63
64
65 if (new_stroke != null)
66 g2d.setStroke(old_stroke);
67
68 }
69
70 protected Shape prepareFinalEdgeShape(RenderContext<V,E> rc, Layout<V, E> layout, E e, int[] coords, boolean[] loop) {
71 Graph<V,E> graph = layout.getGraph();
72 Pair<V> endpoints = graph.getEndpoints(e);
73 V v1 = endpoints.getFirst();
74 V v2 = endpoints.getSecond();
75
76 Point2D p1 = layout.apply(v1);
77 Point2D p2 = layout.apply(v2);
78 p1 = rc.getMultiLayerTransformer().transform(Layer.LAYOUT, p1);
79 p2 = rc.getMultiLayerTransformer().transform(Layer.LAYOUT, p2);
80 float x1 = (float) p1.getX();
81 float y1 = (float) p1.getY();
82 float x2 = (float) p2.getX();
83 float y2 = (float) p2.getY();
84 coords[0] = (int)x1;
85 coords[1] = (int)y1;
86 coords[2] = (int)x2;
87 coords[3] = (int)y2;
88
89 boolean isLoop = loop[0] = v1.equals(v2);
90 Shape s2 = rc.getVertexShapeTransformer().apply(v2);
91 Shape edgeShape = rc.getEdgeShapeTransformer().apply(e);
92
93 AffineTransform xform = AffineTransform.getTranslateInstance(x1, y1);
94
95 if(isLoop) {
96
97
98
99 Rectangle2D s2Bounds = s2.getBounds2D();
100 xform.scale(s2Bounds.getWidth(),s2Bounds.getHeight());
101 xform.translate(0, -edgeShape.getBounds2D().getWidth()/2);
102 } else if(rc.getEdgeShapeTransformer() instanceof EdgeShape.Orthogonal) {
103 float dx = x2-x1;
104 float dy = y2-y1;
105 int index = 0;
106 if(rc.getEdgeShapeTransformer() instanceof ParallelEdgeShapeTransformer) {
107 @SuppressWarnings("unchecked")
108 EdgeIndexFunction<V,E> peif =
109 ((ParallelEdgeShapeTransformer<V,E>)rc.getEdgeShapeTransformer())
110 .getEdgeIndexFunction();
111 index = peif.getIndex(null, e);
112 index *= 20;
113 }
114 GeneralPath gp = new GeneralPath();
115 gp.moveTo(0,0);
116 if(x1 > x2) {
117 if(y1 > y2) {
118 gp.lineTo(0, index);
119 gp.lineTo(dx-index, index);
120 gp.lineTo(dx-index, dy);
121 gp.lineTo(dx, dy);
122 } else {
123 gp.lineTo(0, -index);
124 gp.lineTo(dx-index, -index);
125 gp.lineTo(dx-index, dy);
126 gp.lineTo(dx, dy);
127 }
128
129 } else {
130 if(y1 > y2) {
131 gp.lineTo(0, index);
132 gp.lineTo(dx+index, index);
133 gp.lineTo(dx+index, dy);
134 gp.lineTo(dx, dy);
135
136 } else {
137 gp.lineTo(0, -index);
138 gp.lineTo(dx+index, -index);
139 gp.lineTo(dx+index, dy);
140 gp.lineTo(dx, dy);
141
142 }
143
144 }
145
146 edgeShape = gp;
147
148 } else {
149
150
151
152 float dx = x2-x1;
153 float dy = y2-y1;
154 float thetaRadians = (float) Math.atan2(dy, dx);
155 xform.rotate(thetaRadians);
156 float dist = (float) Math.sqrt(dx*dx + dy*dy);
157 xform.scale(dist, 1.0);
158 }
159
160 edgeShape = xform.createTransformedShape(edgeShape);
161
162 return edgeShape;
163 }
164
165
166
167
168
169
170
171
172
173
174
175 protected void drawSimpleEdge(RenderContext<V,E> rc, Layout<V,E> layout, E e) {
176
177 int[] coords = new int[4];
178 boolean[] loop = new boolean[1];
179 Shape edgeShape = prepareFinalEdgeShape(rc, layout, e, coords, loop);
180
181 int x1 = coords[0];
182 int y1 = coords[1];
183 int x2 = coords[2];
184 int y2 = coords[3];
185 boolean isLoop = loop[0];
186
187 GraphicsDecorator g = rc.getGraphicsContext();
188 Graph<V,E> graph = layout.getGraph();
189 boolean edgeHit = true;
190 boolean arrowHit = true;
191 Rectangle deviceRectangle = null;
192 JComponent vv = rc.getScreenDevice();
193 if(vv != null) {
194 Dimension d = vv.getSize();
195 deviceRectangle = new Rectangle(0,0,d.width,d.height);
196 }
197
198 MutableTransformer vt = rc.getMultiLayerTransformer().getTransformer(Layer.VIEW);
199 if(vt instanceof LensTransformer) {
200 vt = ((LensTransformer)vt).getDelegate();
201 }
202 edgeHit = vt.transform(edgeShape).intersects(deviceRectangle);
203
204 if(edgeHit == true) {
205
206 Paint oldPaint = g.getPaint();
207
208
209
210 Paint fill_paint = rc.getEdgeFillPaintTransformer().apply(e);
211 if (fill_paint != null)
212 {
213 g.setPaint(fill_paint);
214 g.fill(edgeShape);
215 }
216 Paint draw_paint = rc.getEdgeDrawPaintTransformer().apply(e);
217 if (draw_paint != null)
218 {
219 g.setPaint(draw_paint);
220 g.draw(edgeShape);
221 }
222
223 float scalex = (float)g.getTransform().getScaleX();
224 float scaley = (float)g.getTransform().getScaleY();
225
226 if(scalex < .3 || scaley < .3) return;
227
228 if (rc.getEdgeArrowPredicate().apply(Context.<Graph<V,E>,E>getInstance(graph, e))) {
229
230 Stroke new_stroke = rc.getEdgeArrowStrokeTransformer().apply(e);
231 Stroke old_stroke = g.getStroke();
232 if (new_stroke != null)
233 g.setStroke(new_stroke);
234
235
236 Shape destVertexShape =
237 rc.getVertexShapeTransformer().apply(graph.getEndpoints(e).getSecond());
238
239 AffineTransform xf = AffineTransform.getTranslateInstance(x2, y2);
240 destVertexShape = xf.createTransformedShape(destVertexShape);
241
242 arrowHit = rc.getMultiLayerTransformer().getTransformer(Layer.VIEW).transform(destVertexShape).intersects(deviceRectangle);
243 if(arrowHit) {
244
245 AffineTransform at =
246 edgeArrowRenderingSupport.getArrowTransform(rc, edgeShape, destVertexShape);
247 if(at == null) return;
248 Shape arrow = rc.getEdgeArrowTransformer().apply(Context.<Graph<V,E>,E>getInstance(graph, e));
249 arrow = at.createTransformedShape(arrow);
250 g.setPaint(rc.getArrowFillPaintTransformer().apply(e));
251 g.fill(arrow);
252 g.setPaint(rc.getArrowDrawPaintTransformer().apply(e));
253 g.draw(arrow);
254 }
255 if (graph.getEdgeType(e) == EdgeType.UNDIRECTED) {
256 Shape vertexShape =
257 rc.getVertexShapeTransformer().apply(graph.getEndpoints(e).getFirst());
258 xf = AffineTransform.getTranslateInstance(x1, y1);
259 vertexShape = xf.createTransformedShape(vertexShape);
260
261 arrowHit = rc.getMultiLayerTransformer().getTransformer(Layer.VIEW).transform(vertexShape).intersects(deviceRectangle);
262
263 if(arrowHit) {
264 AffineTransform at = edgeArrowRenderingSupport.getReverseArrowTransform(rc, edgeShape, vertexShape, !isLoop);
265 if(at == null) return;
266 Shape arrow = rc.getEdgeArrowTransformer().apply(Context.<Graph<V,E>,E>getInstance(graph, e));
267 arrow = at.createTransformedShape(arrow);
268 g.setPaint(rc.getArrowFillPaintTransformer().apply(e));
269 g.fill(arrow);
270 g.setPaint(rc.getArrowDrawPaintTransformer().apply(e));
271 g.draw(arrow);
272 }
273 }
274
275 if (new_stroke != null)
276 g.setStroke(old_stroke);
277
278 }
279
280
281 g.setPaint(oldPaint);
282 }
283 }
284
285 public EdgeArrowRenderingSupport<V, E> getEdgeArrowRenderingSupport() {
286 return edgeArrowRenderingSupport;
287 }
288
289 public void setEdgeArrowRenderingSupport(
290 EdgeArrowRenderingSupport<V, E> edgeArrowRenderingSupport) {
291 this.edgeArrowRenderingSupport = edgeArrowRenderingSupport;
292 }
293 }