View Javadoc

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 }