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