1
2
3
4
5
6
7
8
9
10
11 package edu.uci.ics.jung.algorithms.layout;
12 import java.awt.Dimension;
13 import java.awt.geom.Point2D;
14 import java.util.ArrayList;
15 import java.util.HashMap;
16 import java.util.List;
17 import java.util.Map;
18
19 import com.google.common.cache.CacheBuilder;
20 import com.google.common.cache.CacheLoader;
21 import com.google.common.cache.LoadingCache;
22
23 import edu.uci.ics.jung.graph.Forest;
24 import edu.uci.ics.jung.graph.util.TreeUtils;
25
26
27
28
29
30
31
32
33
34
35 public class BalloonLayout<V,E> extends TreeLayout<V,E> {
36
37 protected LoadingCache<V, PolarPoint> polarLocations
38 = CacheBuilder.newBuilder().build(new CacheLoader<V, PolarPoint>() {
39 public PolarPoint load(V vertex) {
40 return new PolarPoint();
41 }
42 });
43
44 protected Map<V,Double> radii = new HashMap<V,Double>();
45
46
47
48
49
50 public BalloonLayout(Forest<V,E> g)
51 {
52 super(g);
53 }
54
55 protected void setRootPolars()
56 {
57 List<V> roots = TreeUtils.getRoots(graph);
58 if(roots.size() == 1) {
59
60 V root = roots.get(0);
61 setRootPolar(root);
62 setPolars(new ArrayList<V>(graph.getChildren(root)),
63 getCenter(), getSize().width/2);
64 } else if (roots.size() > 1) {
65
66 setPolars(roots, getCenter(), getSize().width/2);
67 }
68 }
69
70 protected void setRootPolar(V root) {
71 PolarPoint pp = new PolarPoint(0,0);
72 Point2D p = getCenter();
73 polarLocations.put(root, pp);
74 locations.put(root, p);
75 }
76
77
78 protected void setPolars(List<V> kids, Point2D parentLocation, double parentRadius) {
79
80 int childCount = kids.size();
81 if(childCount == 0) return;
82
83 double angle = Math.max(0, Math.PI / 2 * (1 - 2.0/childCount));
84 double childRadius = parentRadius*Math.cos(angle) / (1 + Math.cos(angle));
85 double radius = parentRadius - childRadius;
86
87 double rand = Math.random();
88
89 for(int i=0; i< childCount; i++) {
90 V child = kids.get(i);
91 double theta = i* 2*Math.PI/childCount + rand;
92 radii.put(child, childRadius);
93
94 PolarPoint pp = new PolarPoint(theta, radius);
95 polarLocations.put(child, pp);
96
97 Point2D p = PolarPoint.polarToCartesian(pp);
98 p.setLocation(p.getX()+parentLocation.getX(), p.getY()+parentLocation.getY());
99 locations.put(child, p);
100 setPolars(new ArrayList<V>(graph.getChildren(child)), p, childRadius);
101 }
102 }
103
104 @Override
105 public void setSize(Dimension size) {
106 this.size = size;
107 setRootPolars();
108 }
109
110
111
112
113
114 public Point2D getCenter(V v) {
115 V parent = graph.getParent(v);
116 if(parent == null) {
117 return getCenter();
118 }
119 return locations.getUnchecked(parent);
120 }
121
122 @Override
123 public void setLocation(V v, Point2D location) {
124 Point2D c = getCenter(v);
125 Point2D pv = new Point2D.Double(location.getX()-c.getX(),location.getY()-c.getY());
126 PolarPoint newLocation = PolarPoint.cartesianToPolar(pv);
127 polarLocations.getUnchecked(v).setLocation(newLocation);
128
129 Point2D center = getCenter(v);
130 pv.setLocation(pv.getX()+center.getX(), pv.getY()+center.getY());
131 locations.put(v, pv);
132 }
133
134 @Override
135 public Point2D apply(V v) {
136 return locations.getUnchecked(v);
137 }
138
139
140
141
142 public Map<V, Double> getRadii() {
143 return radii;
144 }
145 }