Coverage details for edu.uci.ics.jung.visualization.ShapePickSupport

LineHitsSource
1 /*
2  * Copyright (c) 2005, 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 Mar 11, 2005
10  *
11  */
12 package edu.uci.ics.jung.visualization;
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.ConcurrentModificationException;
21 import java.util.Iterator;
22  
23 import edu.uci.ics.jung.graph.Edge;
24 import edu.uci.ics.jung.graph.Vertex;
25 import edu.uci.ics.jung.utils.Pair;
26 import edu.uci.ics.jung.visualization.transform.LayoutTransformer;
27 import edu.uci.ics.jung.visualization.transform.MutableAffineTransformer;
28 import edu.uci.ics.jung.visualization.transform.Transformer;
29  
30 /**
31  * ShapePickSupport provides access to Vertices and Edges based on
32  * their actual shapes.
33  *
34  * @author Tom Nelson - RABA Technologies
35  *
36  */
37 public class ShapePickSupport implements PickSupport {
38  
39     protected HasGraphLayout hasGraphLayout;
40     protected HasShapeFunctions hasShapeFunctions;
41     protected float pickSize;
42     protected LayoutTransformer layoutTransformer;
43     
44     /**
45      * Create an instance.
46      * The HasGraphLayout is used as the source of the current
47      * Graph Layout. The HasShapes
48      * is used to access the VertexShapes and the EdgeShapes
49      * @param hasGraphLayout source of the current layout.
50      * @param hasShapeFunctions source of Vertex and Edge shapes.
51      * @param pickSize how large to make the pick footprint for line edges
52      */
53     public ShapePickSupport(HasGraphLayout hasGraphLayout,
54             LayoutTransformer layoutTransformer, HasShapeFunctions hasShapeFunctions,
550            float pickSize) {
560        this.hasGraphLayout = hasGraphLayout;
570        this.hasShapeFunctions = hasShapeFunctions;
580        this.layoutTransformer = layoutTransformer;
590        this.pickSize = pickSize;
600    }
61     
620    public ShapePickSupport(float pickSize) {
630        this.pickSize = pickSize;
640    }
65             
66     /**
67      * Create an instance.
68      * The pickSize footprint defaults to 2.
69      */
70     public ShapePickSupport() {
710        this(2);
720    }
73     
74     /**
75      * called by a HasLayout impl (like VisualizationViewer) when this
76      * PickSupport impl is
77      * added to it. This allows the PickSupport to
78      * always get the current Layout and the current Renderer
79      * from thecomponent it supports picking on.
80      */
81     public void setHasGraphLayout(HasGraphLayout hasGraphLayout) {
820        this.hasGraphLayout = hasGraphLayout;
830    }
84  
85     /**
86      * @param hasShapes The hasShapes to set.
87      */
88     public void setHasShapes(HasShapeFunctions hasShapes) {
890        this.hasShapeFunctions = hasShapes;
900    }
91     /**
92      * @return Returns the layoutTransformer.
93      */
94     public LayoutTransformer getLayoutTransformer() {
950        return layoutTransformer;
96     }
97  
98     /**
99      * When this PickSupport is set on a VisualizationViewer,
100      * the VisualizationViewer calls this method to pass its
101      * layout transformer in
102      *
103      * @param layoutTransformer The layoutTransformer to set.
104      */
105     public void setLayoutTransformer(LayoutTransformer layoutTransformer) {
1060        this.layoutTransformer = layoutTransformer;
1070    }
108  
109     /**
110      * Iterates over Vertices, checking to see if x,y is contained in the
111      * Vertex's Shape. If (x,y) is contained in more than one vertex, use
112      * the vertex whose center is closest to the pick point.
113      * @see edu.uci.ics.jung.visualization.PickSupport#getVertex(double, double)
114      */
115     public Vertex getVertex(double x, double y) {
1160        Layout layout = hasGraphLayout.getGraphLayout();
117  
1180        Vertex closest = null;
1190        double minDistance = Double.MAX_VALUE;
120         while(true) {
121             try {
1220                for (Iterator iter=layout.getGraph().getVertices().iterator(); iter.hasNext(); ) {
1230                    if(hasShapeFunctions != null) {
1240                        Vertex v = (Vertex) iter.next();
1250                        Shape shape = hasShapeFunctions.getVertexShapeFunction().getShape(v);
126                         // transform the vertex location to screen coords
1270                        Point2D p = layoutTransformer.layoutTransform(layout.getLocation(v));
1280                        if(p == null) continue;
1290                        AffineTransform xform =
130                             AffineTransform.getTranslateInstance(p.getX(), p.getY());
1310                        shape = xform.createTransformedShape(shape);
132                         // see if this vertex center is closest to the pick point
133                         // among any other containing vertices
1340                        if(shape.contains(x, y)) {
135                             
1360                            Rectangle2D bounds = shape.getBounds2D();
1370                            double dx = bounds.getCenterX() - x;
1380                            double dy = bounds.getCenterY() - y;
1390                            double dist = dx * dx + dy * dy;
1400                            if (dist < minDistance) {
1410                                minDistance = dist;
1420                                closest = v;
143                             }
144                         }
145                     }
146                 }
1470                break;
1480            } catch(ConcurrentModificationException cme) {}
149         }
1500        return closest;
151     }
152  
153     /**
154      * return an edge whose shape intersects the 'pickArea' footprint of the passed
155      * x,y, coordinates.
156      */
157     public Edge getEdge(double x, double y) {
1580        Layout layout = hasGraphLayout.getGraphLayout();
159  
160         // as a Line has no area, we can't always use edgeshape.contains(point) so we
161         // make a small rectangular pickArea around the point and check if the
162         // edgeshape.intersects(pickArea)
1630        Rectangle2D pickArea =
164             new Rectangle2D.Float((float)x-pickSize/2,(float)y-pickSize/2,pickSize,pickSize);
1650        Edge closest = null;
1660        double minDistance = Double.MAX_VALUE;
167         while(true) {
168             try {
1690                for (Iterator iter=layout.getGraph().getEdges().iterator(); iter.hasNext(); ) {
170                     
1710                    if(hasShapeFunctions != null) {
1720                        Edge e = (Edge) iter.next();
1730                        Pair pair = e.getEndpoints();
1740                        Vertex v1 = (Vertex)pair.getFirst();
1750                        Vertex v2 = (Vertex)pair.getSecond();
1760                        boolean isLoop = v1.equals(v2);
1770                        Point2D p1 = layoutTransformer.layoutTransform(layout.getLocation(v1));
1780                        Point2D p2 = layoutTransformer.layoutTransform(layout.getLocation(v2));
1790                        if(p1 == null || p2 == null) continue;
1800                        float x1 = (float) p1.getX();
1810                        float y1 = (float) p1.getY();
1820                        float x2 = (float) p2.getX();
1830                        float y2 = (float) p2.getY();
184                         
185                         // translate the edge to the starting vertex
1860                        AffineTransform xform = AffineTransform.getTranslateInstance(x1, y1);
187                         
1880                        Shape edgeShape = hasShapeFunctions.getEdgeShapeFunction().getShape(e);
1890                        if(isLoop) {
190                             // make the loops proportional to the size of the vertex
1910                            Shape s2 = hasShapeFunctions.getVertexShapeFunction().getShape(v2);
1920                            Rectangle2D s2Bounds = s2.getBounds2D();
1930                            xform.scale(s2Bounds.getWidth(),s2Bounds.getHeight());
194                             // move the loop so that the nadir is centered in the vertex
1950                            xform.translate(0, -edgeShape.getBounds2D().getHeight()/2);
196                         } else {
1970                            float dx = x2 - x1;
1980                            float dy = y2 - y1;
199                             // rotate the edge to the angle between the vertices
2000                            double theta = Math.atan2(dy,dx);
2010                            xform.rotate(theta);
202                             // stretch the edge to span the distance between the vertices
2030                            float dist = (float) Math.sqrt(dx*dx + dy*dy);
2040                            xform.scale(dist, 1.0f);
205                         }
206                         
207                         // transform the edge to its location and dimensions
2080                        edgeShape = xform.createTransformedShape(edgeShape);
209                         
210                         // because of the transform, the edgeShape is now a GeneralPath
211                         // see if this edge is the closest of any that intersect
2120                        if(edgeShape.intersects(pickArea)) {
2130                            float cx=0;
2140                            float cy=0;
2150                            float[] f = new float[6];
2160                            PathIterator pi = ((GeneralPath)edgeShape).getPathIterator(null);
2170                            if(pi.isDone()==false) {
2180                                pi.next();
2190                                pi.currentSegment(f);
2200                                cx = f[0];
2210                                cy = f[1];
2220                                if(pi.isDone()==false) {
2230                                    pi.currentSegment(f);
2240                                    cx = f[0];
2250                                    cy = f[1];
226                                 }
227                             }
2280                            float dx = (float) (cx - x);
2290                            float dy = (float) (cy - y);
2300                            float dist = dx * dx + dy * dy;
2310                            if (dist < minDistance) {
2320                                minDistance = dist;
2330                                closest = e;
234                             }
235                         }
236                     }
237                 }
2380                break;
2390            } catch(ConcurrentModificationException cme) {}
240         }
2410        return closest;
242     }
243  
244     /**
245      * <code>ShapePickSupport</code> gets its layout from its VisualizationViewer, so this
246      * method currently does nothing.
247      * @see edu.uci.ics.jung.visualization.PickSupport#setLayout(edu.uci.ics.jung.visualization.Layout)
248      */
2490    public void setLayout(Layout layout) {}
250 }

this report was generated by version 1.0.5 of jcoverage.
visit www.jcoverage.com for updates.

copyright © 2003, jcoverage ltd. all rights reserved.
Java is a trademark of Sun Microsystems, Inc. in the United States and other countries.