1 /**
2 * Copyright (c) 2008, the JUNG Project and the Regents of the University
3 * of California
4 * All rights reserved.
5 *
6 * This software is open-source under the BSD license; see either
7 * "license.txt" or
8 * http://jung.sourceforge.net/license.txt for a description.
9 * Created on Apr 24, 2008
10 *
11 */
12 package edu.uci.ics.jung.visualization.picking;
13
14 import java.awt.Shape;
15 import java.awt.geom.Point2D;
16 import java.util.Collection;
17 import java.util.ConcurrentModificationException;
18
19 import edu.uci.ics.jung.algorithms.layout.GraphElementAccessor;
20 import edu.uci.ics.jung.algorithms.layout.Layout;
21 import edu.uci.ics.jung.visualization.Layer;
22 import edu.uci.ics.jung.visualization.VisualizationServer;
23
24 /**
25 * A <code>GraphElementAccessor</code> that finds the closest element to
26 * the pick point, and returns it if it is within the element's shape.
27 * This is best suited to elements with convex shapes that do not overlap.
28 * It differs from <code>ShapePickSupport</code> in that it only checks
29 * the closest element to see whether it contains the pick point.
30 * Possible unexpected odd behaviors:
31 * <ul>
32 * <li/>If the elements overlap, this mechanism may pick another element than the one that's
33 * "on top" (rendered last) if the pick point is closer to the center of an obscured vertex.
34 * <li/>If element shapes are not convex, then this mechanism may return <code>null</code>
35 * even if the pick point is inside some element's shape, if the pick point is closer
36 * to the center of another element.
37 * </ul>
38 * Users who want to avoid either of these should use <code>ShapePickSupport</code>
39 * instead, which is slower but more flexible. If neither of the above conditions
40 * (overlapping elements or non-convex shapes) is true, then <code>ShapePickSupport</code>
41 * and this class should have the same behavior.
42 */
43 public class ClosestShapePickSupport<V,E> implements GraphElementAccessor<V,E> {
44
45 protected VisualizationServer<V,E> vv;
46 protected float pickSize;
47
48 /**
49 * Creates a <code>ShapePickSupport</code> for the <code>vv</code>
50 * VisualizationServer, with the specified pick footprint.
51 * The <code>VisualizationServer</code> is used to fetch the current
52 * <code>Layout</code>.
53 * @param vv source of the current <code>Layout</code>.
54 * @param pickSize the size of the pick footprint for line edges
55 */
56 public ClosestShapePickSupport(VisualizationServer<V,E> vv, float pickSize)
57 {
58 this.vv = vv;
59 this.pickSize = pickSize;
60 }
61
62 /**
63 * Create a <code>ShapePickSupport</code> with the <code>vv</code>
64 * VisualizationServer and default pick footprint.
65 * The footprint defaults to 2.
66 */
67 public ClosestShapePickSupport(VisualizationServer<V,E> vv)
68 {
69 this.vv = vv;
70 }
71
72 /**
73 * @see edu.uci.ics.jung.algorithms.layout.GraphElementAccessor#getEdge(edu.uci.ics.jung.algorithms.layout.Layout, double, double)
74 */
75 public E getEdge(Layout<V,E> layout, double x, double y)
76 {
77 return null;
78 }
79
80 /**
81 * @see edu.uci.ics.jung.algorithms.layout.GraphElementAccessor#getVertex(edu.uci.ics.jung.algorithms.layout.Layout, double, double)
82 */
83 public V getVertex(Layout<V,E> layout, double x, double y)
84 {
85 // first, find the closest vertex to (x,y)
86 double minDistance = Double.MAX_VALUE;
87 V closest = null;
88 while(true)
89 {
90 try
91 {
92 for(V v : layout.getGraph().getVertices())
93 {
94 Point2D p = layout.transform(v);
95 double dx = p.getX() - x;
96 double dy = p.getY() - y;
97 double dist = dx * dx + dy * dy;
98 if (dist < minDistance)
99 {
100 minDistance = dist;
101 closest = v;
102 }
103 }
104 break;
105 }
106 catch(ConcurrentModificationException cme) {}
107 }
108
109 // now check to see whether (x,y) is in the shape for this vertex.
110
111 // get the vertex shape
112 Shape shape = vv.getRenderContext().getVertexShapeTransformer().transform(closest);
113 // get the vertex location
114 Point2D p = layout.transform(closest);
115 // transform the vertex location to screen coords
116 p = vv.getRenderContext().getMultiLayerTransformer().transform(Layer.LAYOUT, p);
117
118 double ox = x - p.getX();
119 double oy = y - p.getY();
120
121 if (shape.contains(ox, oy))
122 return closest;
123 else
124 return null;
125 }
126
127 /**
128 * @see edu.uci.ics.jung.algorithms.layout.GraphElementAccessor#getVertices(edu.uci.ics.jung.algorithms.layout.Layout, java.awt.Shape)
129 */
130 public Collection<V> getVertices(Layout<V,E> layout, Shape rectangle)
131 {
132 // FIXME: RadiusPickSupport and ShapePickSupport are not using the same mechanism!
133 // talk to Tom and make sure I understand which should be used.
134 // in particular, there are some transformations that the latter uses; the latter is also
135 // doing a couple of kinds of filtering. (well, only one--just predicate-based.)
136 // looks to me like the VV could (should) be doing this filtering. (maybe.)
137 //
138 return null;
139 }
140 }