/**
* Copyright (c) 2008, the JUNG Project and the Regents of the University
* of California
* All rights reserved.
*
* This software is open-source under the BSD license; see either
* "license.txt" or
* http://jung.sourceforge.net/license.txt for a description.
* Created on Apr 24, 2008
*
*/
package edu.uci.ics.jung.visualization.picking;
import java.awt.Shape;
import java.awt.geom.Point2D;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import edu.uci.ics.jung.algorithms.layout.GraphElementAccessor;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.visualization.Layer;
import edu.uci.ics.jung.visualization.VisualizationServer;
/**
* A <code>GraphElementAccessor</code> that finds the closest element to
* the pick point, and returns it if it is within the element's shape.
* This is best suited to elements with convex shapes that do not overlap.
* It differs from <code>ShapePickSupport</code> in that it only checks
* the closest element to see whether it contains the pick point.
* Possible unexpected odd behaviors:
* <ul>
* <li/>If the elements overlap, this mechanism may pick another element than the one that's
* "on top" (rendered last) if the pick point is closer to the center of an obscured vertex.
* <li/>If element shapes are not convex, then this mechanism may return <code>null</code>
* even if the pick point is inside some element's shape, if the pick point is closer
* to the center of another element.
* </ul>
* Users who want to avoid either of these should use <code>ShapePickSupport</code>
* instead, which is slower but more flexible. If neither of the above conditions
* (overlapping elements or non-convex shapes) is true, then <code>ShapePickSupport</code>
* and this class should have the same behavior.
*/
public class ClosestShapePickSupport<V,E> implements GraphElementAccessor<V,E> {
protected VisualizationServer<V,E> vv;
protected float pickSize;
/**
* Creates a <code>ShapePickSupport</code> for the <code>vv</code>
* VisualizationServer, with the specified pick footprint.
* The <code>VisualizationServer</code> is used to fetch the current
* <code>Layout</code>.
* @param vv source of the current <code>Layout</code>.
* @param pickSize the size of the pick footprint for line edges
*/
public ClosestShapePickSupport(VisualizationServer<V,E> vv, float pickSize)
{
this.vv = vv;
this.pickSize = pickSize;
}
/**
* Create a <code>ShapePickSupport</code> with the <code>vv</code>
* VisualizationServer and default pick footprint.
* The footprint defaults to 2.
*/
public ClosestShapePickSupport(VisualizationServer<V,E> vv)
{
this.vv = vv;
}
/**
* @see edu.uci.ics.jung.algorithms.layout.GraphElementAccessor#getEdge(edu.uci.ics.jung.algorithms.layout.Layout, double, double)
*/
public E getEdge(Layout<V,E> layout, double x, double y)
{
return null;
}
/**
* @see edu.uci.ics.jung.algorithms.layout.GraphElementAccessor#getVertex(edu.uci.ics.jung.algorithms.layout.Layout, double, double)
*/
public V getVertex(Layout<V,E> layout, double x, double y)
{
// first, find the closest vertex to (x,y)
double minDistance = Double.MAX_VALUE;
V closest = null;
while(true)
{
try
{
for(V v : layout.getGraph().getVertices())
{
Point2D p = layout.transform(v);
double dx = p.getX() - x;
double dy = p.getY() - y;
double dist = dx * dx + dy * dy;
if (dist < minDistance)
{
minDistance = dist;
closest = v;
}
}
break;
}
catch(ConcurrentModificationException cme) {}
}
// now check to see whether (x,y) is in the shape for this vertex.
// get the vertex shape
Shape shape = vv.getRenderContext().getVertexShapeTransformer().transform(closest);
// get the vertex location
Point2D p = layout.transform(closest);
// transform the vertex location to screen coords
p = vv.getRenderContext().getMultiLayerTransformer().transform(Layer.LAYOUT, p);
double ox = x - p.getX();
double oy = y - p.getY();
if (shape.contains(ox, oy))
return closest;
else
return null;
}
/**
* @see edu.uci.ics.jung.algorithms.layout.GraphElementAccessor#getVertices(edu.uci.ics.jung.algorithms.layout.Layout, java.awt.Shape)
*/
public Collection<V> getVertices(Layout<V,E> layout, Shape rectangle)
{
// FIXME: RadiusPickSupport and ShapePickSupport are not using the same mechanism!
// talk to Tom and make sure I understand which should be used.
// in particular, there are some transformations that the latter uses; the latter is also
// doing a couple of kinds of filtering. (well, only one--just predicate-based.)
// looks to me like the VV could (should) be doing this filtering. (maybe.)
//
return null;
}
}