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 }