1
2
3
4
5
6
7
8
9
10
11
12 package edu.uci.ics.jung.visualization.picking;
13
14 import java.awt.Shape;
15 import java.awt.geom.AffineTransform;
16 import java.awt.geom.GeneralPath;
17 import java.awt.geom.PathIterator;
18 import java.awt.geom.Point2D;
19 import java.awt.geom.Rectangle2D;
20 import java.util.Collection;
21 import java.util.ConcurrentModificationException;
22 import java.util.HashSet;
23 import java.util.Set;
24
25 import edu.uci.ics.jung.algorithms.layout.GraphElementAccessor;
26 import edu.uci.ics.jung.algorithms.layout.Layout;
27 import edu.uci.ics.jung.graph.Graph;
28 import edu.uci.ics.jung.graph.util.Context;
29 import edu.uci.ics.jung.graph.util.Pair;
30 import edu.uci.ics.jung.visualization.Layer;
31 import edu.uci.ics.jung.visualization.VisualizationServer;
32
33
34
35
36
37
38
39
40 public class LayoutLensShapePickSupport<V, E> extends ShapePickSupport<V,E>
41 implements GraphElementAccessor<V,E> {
42
43
44
45
46
47
48
49
50
51
52 public LayoutLensShapePickSupport(VisualizationServer<V,E> vv, float pickSize) {
53 super(vv,pickSize);
54 }
55
56
57
58
59
60 public LayoutLensShapePickSupport(VisualizationServer<V,E> vv) {
61 this(vv,2);
62 }
63
64
65
66
67
68
69
70 public V getVertex(Layout<V, E> layout, double x, double y) {
71
72 V closest = null;
73 double minDistance = Double.MAX_VALUE;
74
75 while(true) {
76 try {
77 for(V v : getFilteredVertices(layout)) {
78
79 Shape shape = vv.getRenderContext().getVertexShapeTransformer().transform(v);
80
81 Point2D p = layout.transform(v);
82 if(p == null) continue;
83
84 p = vv.getRenderContext().getMultiLayerTransformer().transform(p);
85 AffineTransform xform =
86 AffineTransform.getTranslateInstance(p.getX(), p.getY());
87 shape = xform.createTransformedShape(shape);
88
89
90
91 if(shape.contains(x, y)) {
92
93 if(style == Style.LOWEST) {
94
95 return v;
96 } else if(style == Style.HIGHEST) {
97
98 closest = v;
99 } else {
100 Rectangle2D bounds = shape.getBounds2D();
101 double dx = bounds.getCenterX() - x;
102 double dy = bounds.getCenterY() - y;
103 double dist = dx * dx + dy * dy;
104 if (dist < minDistance) {
105 minDistance = dist;
106 closest = v;
107 }
108 }
109 }
110 }
111 break;
112 } catch(ConcurrentModificationException cme) {}
113 }
114 return closest;
115 }
116
117
118
119
120
121
122
123 public Collection<V> getVertices(Layout<V, E> layout, Shape rectangle) {
124 Set<V> pickedVertices = new HashSet<V>();
125
126 while(true) {
127 try {
128 for(V v : getFilteredVertices(layout)) {
129 Point2D p = layout.transform(v);
130 if(p == null) continue;
131
132 p = vv.getRenderContext().getMultiLayerTransformer().transform(p);
133 if(rectangle.contains(p)) {
134 pickedVertices.add(v);
135 }
136 }
137 break;
138 } catch(ConcurrentModificationException cme) {}
139 }
140 return pickedVertices;
141 }
142
143
144
145
146 public E getEdge(Layout<V, E> layout, double x, double y) {
147
148 Point2D ip = vv.getRenderContext().getMultiLayerTransformer().inverseTransform(Layer.VIEW, new Point2D.Double(x,y));
149 x = ip.getX();
150 y = ip.getY();
151
152
153
154
155 Rectangle2D pickArea =
156 new Rectangle2D.Float((float)x-pickSize/2,(float)y-pickSize/2,pickSize,pickSize);
157 E closest = null;
158 double minDistance = Double.MAX_VALUE;
159 while(true) {
160 try {
161 for(E e : getFilteredEdges(layout)) {
162
163 Pair<V> pair = layout.getGraph().getEndpoints(e);
164 V v1 = pair.getFirst();
165 V v2 = pair.getSecond();
166 boolean isLoop = v1.equals(v2);
167 Point2D p1 = vv.getRenderContext().getMultiLayerTransformer().transform(Layer.LAYOUT, layout.transform(v1));
168 Point2D p2 = vv.getRenderContext().getMultiLayerTransformer().transform(Layer.LAYOUT, layout.transform(v2));
169 if(p1 == null || p2 == null) continue;
170 float x1 = (float) p1.getX();
171 float y1 = (float) p1.getY();
172 float x2 = (float) p2.getX();
173 float y2 = (float) p2.getY();
174
175
176 AffineTransform xform = AffineTransform.getTranslateInstance(x1, y1);
177
178 Shape edgeShape =
179 vv.getRenderContext().getEdgeShapeTransformer().transform(Context.<Graph<V,E>,E>getInstance(vv.getGraphLayout().getGraph(),e));
180 if(isLoop) {
181
182 Shape s2 = vv.getRenderContext().getVertexShapeTransformer().transform(v2);
183 Rectangle2D s2Bounds = s2.getBounds2D();
184 xform.scale(s2Bounds.getWidth(),s2Bounds.getHeight());
185
186 xform.translate(0, -edgeShape.getBounds2D().getHeight()/2);
187 } else {
188 float dx = x2 - x1;
189 float dy = y2 - y1;
190
191 double theta = Math.atan2(dy,dx);
192 xform.rotate(theta);
193
194 float dist = (float) Math.sqrt(dx*dx + dy*dy);
195 xform.scale(dist, 1.0f);
196 }
197
198
199 edgeShape = xform.createTransformedShape(edgeShape);
200
201
202
203 if(edgeShape.intersects(pickArea)) {
204 float cx=0;
205 float cy=0;
206 float[] f = new float[6];
207 PathIterator pi = new GeneralPath(edgeShape).getPathIterator(null);
208 if(pi.isDone()==false) {
209 pi.next();
210 pi.currentSegment(f);
211 cx = f[0];
212 cy = f[1];
213 if(pi.isDone()==false) {
214 pi.currentSegment(f);
215 cx = f[0];
216 cy = f[1];
217 }
218 }
219 float dx = (float) (cx - x);
220 float dy = (float) (cy - y);
221 float dist = dx * dx + dy * dy;
222 if (dist < minDistance) {
223 minDistance = dist;
224 closest = e;
225 }
226 }
227 }
228 break;
229 } catch(ConcurrentModificationException cme) {}
230 }
231 return closest;
232 }
233 }