1
2
3
4
5
6
7
8
9
10 package edu.uci.ics.jung.visualization.decorators;
11
12 import java.awt.Shape;
13 import java.awt.geom.AffineTransform;
14 import java.awt.geom.CubicCurve2D;
15 import java.awt.geom.Ellipse2D;
16 import java.awt.geom.GeneralPath;
17 import java.awt.geom.Line2D;
18 import java.awt.geom.QuadCurve2D;
19 import java.awt.geom.Rectangle2D;
20
21 import edu.uci.ics.jung.graph.Graph;
22 import edu.uci.ics.jung.graph.util.Context;
23 import edu.uci.ics.jung.graph.util.EdgeIndexFunction;
24 import edu.uci.ics.jung.graph.util.EdgeType;
25 import edu.uci.ics.jung.graph.util.Pair;
26 import edu.uci.ics.jung.visualization.util.ArrowFactory;
27
28
29
30
31
32
33
34
35
36
37
38
39
40 public class EdgeShape<V,E> {
41
42
43
44
45
46
47 @SuppressWarnings("unchecked")
48 protected static Loop loop = new Loop();
49
50
51
52
53
54
55 @SuppressWarnings("unchecked")
56 protected static SimpleLoop simpleLoop = new SimpleLoop();
57
58 @SuppressWarnings("unchecked")
59 protected static Box box = new Box();
60
61
62
63
64
65 public static class Line<V,E> extends AbstractEdgeShapeTransformer<V,E> {
66
67
68
69
70 private static Line2D instance = new Line2D.Float(0.0f, 0.0f, 1.0f, 0.0f);
71
72
73
74
75
76 @SuppressWarnings("unchecked")
77 public Shape transform(Context<Graph<V,E>,E> context) {
78 Graph<V,E> graph = context.graph;
79 E e = context.element;
80
81 Pair<V> endpoints = graph.getEndpoints(e);
82 if(endpoints != null) {
83 boolean isLoop = endpoints.getFirst().equals(endpoints.getSecond());
84 if (isLoop) {
85 return loop.transform(context);
86 }
87 }
88 return instance;
89 }
90 }
91
92
93
94
95
96 public static class BentLine<V,E>
97 extends AbstractEdgeShapeTransformer<V,E> implements IndexedRendering<V,E> {
98
99
100
101
102 private static GeneralPath instance = new GeneralPath();
103
104 protected EdgeIndexFunction<V,E> parallelEdgeIndexFunction;
105
106 @SuppressWarnings("unchecked")
107 public void setEdgeIndexFunction(EdgeIndexFunction<V,E> parallelEdgeIndexFunction) {
108 this.parallelEdgeIndexFunction = parallelEdgeIndexFunction;
109 loop.setEdgeIndexFunction(parallelEdgeIndexFunction);
110 }
111
112
113
114
115
116
117 public EdgeIndexFunction<V, E> getEdgeIndexFunction() {
118 return parallelEdgeIndexFunction;
119 }
120
121
122
123
124
125
126
127
128 @SuppressWarnings("unchecked")
129 public Shape transform(Context<Graph<V,E>,E> context) {
130 Graph<V,E> graph = context.graph;
131 E e = context.element;
132 Pair<V> endpoints = graph.getEndpoints(e);
133 if(endpoints != null) {
134 boolean isLoop = endpoints.getFirst().equals(endpoints.getSecond());
135 if (isLoop) {
136 return loop.transform(context);
137 }
138 }
139
140 int index = 1;
141 if(parallelEdgeIndexFunction != null) {
142 index = parallelEdgeIndexFunction.getIndex(graph, e);
143 }
144 float controlY = control_offset_increment + control_offset_increment*index;
145 instance.reset();
146 instance.moveTo(0.0f, 0.0f);
147 instance.lineTo(0.5f, controlY);
148 instance.lineTo(1.0f, 1.0f);
149 return instance;
150 }
151
152 }
153
154
155
156
157
158 public static class QuadCurve<V,E>
159 extends AbstractEdgeShapeTransformer<V,E> implements IndexedRendering<V,E> {
160
161
162
163
164 private static QuadCurve2D instance = new QuadCurve2D.Float();
165
166 protected EdgeIndexFunction<V,E> parallelEdgeIndexFunction;
167
168 @SuppressWarnings("unchecked")
169 public void setEdgeIndexFunction(EdgeIndexFunction<V,E> parallelEdgeIndexFunction) {
170 this.parallelEdgeIndexFunction = parallelEdgeIndexFunction;
171 loop.setEdgeIndexFunction(parallelEdgeIndexFunction);
172 }
173
174
175
176
177 public EdgeIndexFunction<V, E> getEdgeIndexFunction() {
178 return parallelEdgeIndexFunction;
179 }
180
181
182
183
184
185
186 @SuppressWarnings("unchecked")
187 public Shape transform(Context<Graph<V,E>,E> context) {
188 Graph<V,E> graph = context.graph;
189 E e = context.element;
190 Pair<V> endpoints = graph.getEndpoints(e);
191 if(endpoints != null) {
192 boolean isLoop = endpoints.getFirst().equals(endpoints.getSecond());
193 if (isLoop) {
194 return loop.transform(context);
195 }
196 }
197
198 int index = 1;
199 if(parallelEdgeIndexFunction != null) {
200 index = parallelEdgeIndexFunction.getIndex(graph, e);
201 }
202
203 float controlY = control_offset_increment +
204 control_offset_increment * index;
205 instance.setCurve(0.0f, 0.0f, 0.5f, controlY, 1.0f, 0.0f);
206 return instance;
207 }
208 }
209
210
211
212
213
214
215
216 public static class CubicCurve<V,E>
217 extends AbstractEdgeShapeTransformer<V,E> implements IndexedRendering<V,E> {
218
219
220
221
222 private static CubicCurve2D instance = new CubicCurve2D.Float();
223
224 protected EdgeIndexFunction<V,E> parallelEdgeIndexFunction;
225
226 @SuppressWarnings("unchecked")
227 public void setEdgeIndexFunction(EdgeIndexFunction<V,E> parallelEdgeIndexFunction) {
228 this.parallelEdgeIndexFunction = parallelEdgeIndexFunction;
229 loop.setEdgeIndexFunction(parallelEdgeIndexFunction);
230 }
231
232
233
234
235 public EdgeIndexFunction<V, E> getEdgeIndexFunction() {
236 return parallelEdgeIndexFunction;
237 }
238
239
240
241
242
243
244 @SuppressWarnings("unchecked")
245 public Shape transform(Context<Graph<V,E>,E> context) {
246 Graph<V,E> graph = context.graph;
247 E e = context.element;
248 Pair<V> endpoints = graph.getEndpoints(e);
249 if(endpoints != null) {
250 boolean isLoop = endpoints.getFirst().equals(endpoints.getSecond());
251 if (isLoop) {
252 return loop.transform(context);
253 }
254 }
255
256 int index = 1;
257 if(parallelEdgeIndexFunction != null) {
258 index = parallelEdgeIndexFunction.getIndex(graph, e);
259 }
260
261 float controlY = control_offset_increment
262 + control_offset_increment * index;
263 instance.setCurve(0.0f, 0.0f, 0.33f, 2 * controlY, .66f, -controlY,
264 1.0f, 0.0f);
265 return instance;
266 }
267 }
268
269
270
271
272
273
274
275 public static class SimpleLoop<V,E> extends AbstractEdgeShapeTransformer<V,E> {
276
277
278
279
280 private static Ellipse2D instance = new Ellipse2D.Float(-.5f, -.5f, 1, 1);
281
282
283
284
285
286 public Shape transform(Context<Graph<V,E>,E> context) {
287 return instance;
288 }
289 }
290
291
292
293
294
295 public static class Loop<V,E>
296 extends AbstractEdgeShapeTransformer<V,E> implements IndexedRendering<V,E> {
297
298
299
300
301 private static Ellipse2D instance = new Ellipse2D.Float();
302
303 protected EdgeIndexFunction<V,E> parallelEdgeIndexFunction;
304
305 public void setEdgeIndexFunction(EdgeIndexFunction<V,E> parallelEdgeIndexFunction) {
306 this.parallelEdgeIndexFunction = parallelEdgeIndexFunction;
307 }
308
309
310
311
312
313 public EdgeIndexFunction<V, E> getEdgeIndexFunction() {
314 return parallelEdgeIndexFunction;
315 }
316
317
318
319
320
321
322 public Shape transform(Context<Graph<V,E>,E> context) {
323 Graph<V,E> graph = context.graph;
324 E e = context.element;
325 int count = 1;
326 if(parallelEdgeIndexFunction != null) {
327 count = parallelEdgeIndexFunction.getIndex(graph, e);
328 }
329
330 float x = -.5f;
331 float y = -.5f;
332 float diam = 1.f;
333 diam += diam*count/2;
334 x += x*count/2;
335 y += y*count/2;
336 instance.setFrame(x,y,diam,diam);
337 return instance;
338 }
339 }
340
341
342
343
344
345
346
347 public static class Wedge<V,E> extends AbstractEdgeShapeTransformer<V,E> {
348 private static GeneralPath triangle;
349 private static GeneralPath bowtie;
350
351 public Wedge(int width) {
352 triangle = ArrowFactory.getWedgeArrow(width, 1);
353 triangle.transform(AffineTransform.getTranslateInstance(1,0));
354 bowtie = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
355 bowtie.moveTo(0, width/2);
356 bowtie.lineTo(1, -width/2);
357 bowtie.lineTo(1, width/2);
358 bowtie.lineTo(0, -width/2);
359 bowtie.closePath();
360 }
361
362 public Shape transform(Context<Graph<V,E>,E> context) {
363 Graph<V,E> graph = context.graph;
364 E e = context.element;
365
366 Pair<V> endpoints = graph.getEndpoints(e);
367 if(endpoints != null) {
368 boolean isLoop = endpoints.getFirst().equals(endpoints.getSecond());
369 if (isLoop) {
370 return Loop.instance;
371 }
372 }
373 if (graph.getEdgeType(e) == EdgeType.DIRECTED)
374 return triangle;
375 else
376 return bowtie;
377 }
378 }
379
380
381
382
383
384 public static class Box<V,E>
385 extends AbstractEdgeShapeTransformer<V,E> implements IndexedRendering<V,E> {
386
387
388
389
390 private static Rectangle2D instance = new Rectangle2D.Float();
391
392 protected EdgeIndexFunction<V,E> parallelEdgeIndexFunction;
393
394 public void setEdgeIndexFunction(EdgeIndexFunction<V,E> parallelEdgeIndexFunction) {
395 this.parallelEdgeIndexFunction = parallelEdgeIndexFunction;
396 }
397
398
399
400
401 public EdgeIndexFunction<V, E> getEdgeIndexFunction() {
402 return parallelEdgeIndexFunction;
403 }
404
405
406
407
408
409 public Shape transform(Context<Graph<V,E>,E> context) {
410 Graph<V,E> graph = context.graph;
411 E e = context.element;
412 int count = 1;
413 if(parallelEdgeIndexFunction != null) {
414 count = parallelEdgeIndexFunction.getIndex(graph, e);
415 }
416
417 float x = -.5f;
418 float y = -.5f;
419 float diam = 1.f;
420 diam += diam*count/2;
421 x += x*count/2;
422 y += y*count/2;
423 instance.setFrame(x,y,diam,diam);
424 return instance;
425 }
426 }
427
428
429
430
431
432
433 public static class Orthogonal<V,E>
434 extends AbstractEdgeShapeTransformer<V,E> implements IndexedRendering<V,E> {
435
436
437
438
439 private static Line2D instance = new Line2D.Float(0.0f, 0.0f, 1.0f, 0.0f);
440
441 protected EdgeIndexFunction<V,E> edgeIndexFunction;
442
443 @SuppressWarnings("unchecked")
444 public void setEdgeIndexFunction(EdgeIndexFunction<V,E> edgeIndexFunction) {
445 this.edgeIndexFunction = edgeIndexFunction;
446 box.setEdgeIndexFunction(edgeIndexFunction);
447 }
448
449
450
451
452 public EdgeIndexFunction<V, E> getEdgeIndexFunction() {
453 return edgeIndexFunction;
454 }
455
456
457
458
459
460
461 @SuppressWarnings("unchecked")
462 public Shape transform(Context<Graph<V,E>,E> context) {
463 Graph<V,E> graph = context.graph;
464 E e = context.element;
465 Pair<V> endpoints = graph.getEndpoints(e);
466 if(endpoints != null) {
467 boolean isLoop = endpoints.getFirst().equals(endpoints.getSecond());
468 if (isLoop) {
469 return box.transform(context);
470 }
471 }
472 return instance;
473 }
474 }
475
476 public static interface IndexedRendering<V,E> {
477 void setEdgeIndexFunction(EdgeIndexFunction<V,E> peif);
478 EdgeIndexFunction<V,E> getEdgeIndexFunction();
479 }
480 }
481
482