1 package edu.uci.ics.jung.visualization.spatial;
2
3 import java.awt.Shape;
4 import java.awt.geom.AffineTransform;
5 import java.awt.geom.GeneralPath;
6 import java.awt.geom.Point2D;
7 import java.awt.geom.Rectangle2D;
8 import java.util.Collection;
9 import java.util.HashSet;
10 import java.util.Set;
11
12 import edu.uci.ics.jung.algorithms.layout.Layout;
13 import edu.uci.ics.jung.graph.Graph;
14 import edu.uci.ics.jung.graph.util.EdgeIndexFunction;
15 import edu.uci.ics.jung.graph.util.EdgeType;
16 import edu.uci.ics.jung.graph.util.Pair;
17 import edu.uci.ics.jung.visualization.BasicVisualizationServer;
18 import edu.uci.ics.jung.visualization.Layer;
19 import edu.uci.ics.jung.visualization.RenderContext;
20 import edu.uci.ics.jung.visualization.decorators.EdgeShape;
21 import edu.uci.ics.jung.visualization.decorators.ParallelEdgeShapeTransformer;
22
23
24
25
26
27
28
29
30
31
32 public class FastRenderingGraph<V, E> implements Graph<V, E> {
33
34 protected Graph<V,E> graph;
35 protected Set<V> vertices = new HashSet<V>();
36 protected Set<E> edges = new HashSet<E>();
37 protected boolean dirty;
38 protected Set<Rectangle2D> bounds;
39 protected RenderContext<V,E> rc;
40 protected BasicVisualizationServer<V,E> vv;
41 protected Layout<V,E> layout;
42
43 public FastRenderingGraph(Graph<V,E> graph, Set<Rectangle2D> bounds, BasicVisualizationServer<V,E> vv) {
44 this.graph = graph;
45 this.bounds = bounds;
46 this.vv = vv;
47 this.rc = vv.getRenderContext();
48 }
49
50 private void cleanUp() {
51 vertices.clear();
52 edges.clear();
53 for(V v : graph.getVertices()) {
54 checkVertex(v);
55 }
56 for(E e : graph.getEdges()) {
57 checkEdge(e);
58 }
59 }
60
61 private void checkVertex(V v) {
62
63 Shape shape = rc.getVertexShapeTransformer().apply(v);
64 Point2D p = layout.apply(v);
65 p = rc.getMultiLayerTransformer().transform(Layer.LAYOUT, p);
66 float x = (float)p.getX();
67 float y = (float)p.getY();
68
69
70 AffineTransform xform = AffineTransform.getTranslateInstance(x,y);
71
72 shape = xform.createTransformedShape(shape);
73 for(Rectangle2D r : bounds) {
74 if(shape.intersects(r)) {
75 vertices.add(v);
76 }
77 }
78 }
79
80 private void checkEdge(E e) {
81 Pair<V> endpoints = graph.getEndpoints(e);
82 V v1 = endpoints.getFirst();
83 V v2 = endpoints.getSecond();
84
85 Point2D p1 = layout.apply(v1);
86 Point2D p2 = layout.apply(v2);
87 p1 = rc.getMultiLayerTransformer().transform(Layer.LAYOUT, p1);
88 p2 = rc.getMultiLayerTransformer().transform(Layer.LAYOUT, p2);
89 float x1 = (float) p1.getX();
90 float y1 = (float) p1.getY();
91 float x2 = (float) p2.getX();
92 float y2 = (float) p2.getY();
93
94 boolean isLoop = v1.equals(v2);
95 Shape s2 = rc.getVertexShapeTransformer().apply(v2);
96 Shape edgeShape = rc.getEdgeShapeTransformer().apply(e);
97
98 AffineTransform xform = AffineTransform.getTranslateInstance(x1, y1);
99
100 if(isLoop) {
101
102
103
104 Rectangle2D s2Bounds = s2.getBounds2D();
105 xform.scale(s2Bounds.getWidth(),s2Bounds.getHeight());
106 xform.translate(0, -edgeShape.getBounds2D().getWidth()/2);
107 } else if(rc.getEdgeShapeTransformer() instanceof EdgeShape.Orthogonal) {
108 float dx = x2-x1;
109 float dy = y2-y1;
110 int index = 0;
111 if(rc.getEdgeShapeTransformer() instanceof ParallelEdgeShapeTransformer) {
112 @SuppressWarnings("unchecked")
113 EdgeIndexFunction<V,E> peif =
114 ((ParallelEdgeShapeTransformer<V,E>)rc.getEdgeShapeTransformer())
115 .getEdgeIndexFunction();
116 index = peif.getIndex(null, e);
117 index *= 20;
118 }
119 GeneralPath gp = new GeneralPath();
120 gp.moveTo(0,0);
121 if(x1 > x2) {
122 if(y1 > y2) {
123 gp.lineTo(0, index);
124 gp.lineTo(dx-index, index);
125 gp.lineTo(dx-index, dy);
126 gp.lineTo(dx, dy);
127 } else {
128 gp.lineTo(0, -index);
129 gp.lineTo(dx-index, -index);
130 gp.lineTo(dx-index, dy);
131 gp.lineTo(dx, dy);
132 }
133
134 } else {
135 if(y1 > y2) {
136 gp.lineTo(0, index);
137 gp.lineTo(dx+index, index);
138 gp.lineTo(dx+index, dy);
139 gp.lineTo(dx, dy);
140
141 } else {
142 gp.lineTo(0, -index);
143 gp.lineTo(dx+index, -index);
144 gp.lineTo(dx+index, dy);
145 gp.lineTo(dx, dy);
146
147 }
148
149 }
150
151 edgeShape = gp;
152
153 } else {
154
155
156
157 float dx = x2-x1;
158 float dy = y2-y1;
159 float thetaRadians = (float) Math.atan2(dy, dx);
160 xform.rotate(thetaRadians);
161 float dist = (float) Math.sqrt(dx*dx + dy*dy);
162 xform.scale(dist, 1.0);
163 }
164
165 edgeShape = xform.createTransformedShape(edgeShape);
166 for(Rectangle2D r : bounds) {
167 if(edgeShape.intersects(r)) {
168 edges.add(e);
169 }
170 }
171 }
172
173 public Set<Rectangle2D> getBounds() {
174 return bounds;
175 }
176
177 public void setBounds(Set<Rectangle2D> bounds) {
178 this.bounds = bounds;
179 }
180
181 public boolean addEdge(E edge, Collection<? extends V> vertices,
182 EdgeType edgeType) {
183 return graph.addEdge(edge, vertices, edgeType);
184 }
185 public boolean addEdge(E edge, Collection<? extends V> vertices) {
186 return graph.addEdge(edge, vertices);
187 }
188 public boolean addEdge(E e, V v1, V v2, EdgeType edgeType) {
189 return graph.addEdge(e, v1, v2, edgeType);
190 }
191 public boolean addEdge(E e, V v1, V v2) {
192 return graph.addEdge(e, v1, v2);
193 }
194 public boolean addVertex(V vertex) {
195 return graph.addVertex(vertex);
196 }
197 public boolean containsEdge(E edge) {
198 return graph.containsEdge(edge);
199 }
200 public boolean containsVertex(V vertex) {
201 return graph.containsVertex(vertex);
202 }
203 public int degree(V vertex) {
204 return graph.degree(vertex);
205 }
206 public E findEdge(V v1, V v2) {
207 return graph.findEdge(v1, v2);
208 }
209 public Collection<E> findEdgeSet(V v1, V v2) {
210 return graph.findEdgeSet(v1, v2);
211 }
212 public EdgeType getDefaultEdgeType() {
213 return graph.getDefaultEdgeType();
214 }
215 public V getDest(E directedEdge) {
216 return graph.getDest(directedEdge);
217 }
218 public int getEdgeCount() {
219 return graph.getEdgeCount();
220 }
221 public int getEdgeCount(EdgeType edgeType) {
222 return graph.getEdgeCount(edgeType);
223 }
224 public Collection<E> getEdges() {
225 if(dirty) {
226 cleanUp();
227 }
228 return edges;
229 }
230 public Collection<E> getEdges(EdgeType edgeType) {
231 return graph.getEdges(edgeType);
232 }
233 public EdgeType getEdgeType(E edge) {
234 return graph.getEdgeType(edge);
235 }
236 public Pair<V> getEndpoints(E edge) {
237 return graph.getEndpoints(edge);
238 }
239 public int getIncidentCount(E edge) {
240 return graph.getIncidentCount(edge);
241 }
242 public Collection<E> getIncidentEdges(V vertex) {
243 return graph.getIncidentEdges(vertex);
244 }
245 public Collection<V> getIncidentVertices(E edge) {
246 return graph.getIncidentVertices(edge);
247 }
248 public Collection<E> getInEdges(V vertex) {
249 return graph.getInEdges(vertex);
250 }
251 public int getNeighborCount(V vertex) {
252 return graph.getNeighborCount(vertex);
253 }
254 public Collection<V> getNeighbors(V vertex) {
255 return graph.getNeighbors(vertex);
256 }
257 public V getOpposite(V vertex, E edge) {
258 return graph.getOpposite(vertex, edge);
259 }
260 public Collection<E> getOutEdges(V vertex) {
261 return graph.getOutEdges(vertex);
262 }
263 public int getPredecessorCount(V vertex) {
264 return graph.getPredecessorCount(vertex);
265 }
266 public Collection<V> getPredecessors(V vertex) {
267 return graph.getPredecessors(vertex);
268 }
269 public V getSource(E directedEdge) {
270 return graph.getSource(directedEdge);
271 }
272 public int getSuccessorCount(V vertex) {
273 return graph.getSuccessorCount(vertex);
274 }
275 public Collection<V> getSuccessors(V vertex) {
276 return graph.getSuccessors(vertex);
277 }
278 public int getVertexCount() {
279 return graph.getVertexCount();
280 }
281 public Collection<V> getVertices() {
282 if(dirty) cleanUp();
283 return vertices;
284 }
285 public int inDegree(V vertex) {
286 return graph.inDegree(vertex);
287 }
288 public boolean isDest(V vertex, E edge) {
289 return graph.isDest(vertex, edge);
290 }
291 public boolean isIncident(V vertex, E edge) {
292 return graph.isIncident(vertex, edge);
293 }
294 public boolean isNeighbor(V v1, V v2) {
295 return graph.isNeighbor(v1, v2);
296 }
297 public boolean isPredecessor(V v1, V v2) {
298 return graph.isPredecessor(v1, v2);
299 }
300 public boolean isSource(V vertex, E edge) {
301 return graph.isSource(vertex, edge);
302 }
303 public boolean isSuccessor(V v1, V v2) {
304 return graph.isSuccessor(v1, v2);
305 }
306 public int outDegree(V vertex) {
307 return graph.outDegree(vertex);
308 }
309 public boolean removeEdge(E edge) {
310 return graph.removeEdge(edge);
311 }
312 public boolean removeVertex(V vertex) {
313 return graph.removeVertex(vertex);
314 }
315 }