001 /* 002 * Copyright (C) 2008-2010 by Holger Arndt 003 * 004 * This file is part of the Universal Java Matrix Package (UJMP). 005 * See the NOTICE file distributed with this work for additional 006 * information regarding copyright ownership and licensing. 007 * 008 * UJMP is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Lesser General Public License as 010 * published by the Free Software Foundation; either version 2 011 * of the License, or (at your option) any later version. 012 * 013 * UJMP is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU Lesser General Public License for more details. 017 * 018 * You should have received a copy of the GNU Lesser General Public 019 * License along with UJMP; if not, write to the 020 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 021 * Boston, MA 02110-1301 USA 022 */ 023 024 package org.ujmp.jung; 025 026 import java.awt.Shape; 027 import java.awt.geom.AffineTransform; 028 import java.awt.geom.PathIterator; 029 import java.awt.geom.Point2D; 030 import java.awt.geom.Rectangle2D; 031 import java.util.ConcurrentModificationException; 032 import java.util.Iterator; 033 034 import edu.uci.ics.jung.graph.Edge; 035 import edu.uci.ics.jung.graph.Vertex; 036 import edu.uci.ics.jung.utils.Pair; 037 import edu.uci.ics.jung.visualization.Layout; 038 import edu.uci.ics.jung.visualization.ShapePickSupport; 039 040 public class DefaultShapePickSupport extends ShapePickSupport { 041 042 043 public Edge getEdge(double x, double y) { 044 Layout layout = hasGraphLayout.getGraphLayout(); 045 046 // as a Line has no area, we can't always use edgeshape.contains(point) 047 // so we 048 // make a small rectangular pickArea around the point and check if the 049 // edgeshape.intersects(pickArea) 050 Rectangle2D pickArea = new Rectangle2D.Float((float) x - pickSize / 2, 051 (float) y - pickSize / 2, pickSize, pickSize); 052 Edge closest = null; 053 double minDistance = Double.MAX_VALUE; 054 while (true) { 055 try { 056 for (Iterator<?> iter = layout.getGraph().getEdges().iterator(); iter 057 .hasNext();) { 058 059 if (hasShapeFunctions != null) { 060 Edge e = (Edge) iter.next(); 061 Pair pair = e.getEndpoints(); 062 Vertex v1 = (Vertex) pair.getFirst(); 063 Vertex v2 = (Vertex) pair.getSecond(); 064 boolean isLoop = v1.equals(v2); 065 Point2D p1 = layoutTransformer.layoutTransform(layout 066 .getLocation(v1)); 067 Point2D p2 = layoutTransformer.layoutTransform(layout 068 .getLocation(v2)); 069 if (p1 == null || p2 == null) 070 continue; 071 float x1 = (float) p1.getX(); 072 float y1 = (float) p1.getY(); 073 float x2 = (float) p2.getX(); 074 float y2 = (float) p2.getY(); 075 076 // translate the edge to the starting vertex 077 AffineTransform xform = AffineTransform 078 .getTranslateInstance(x1, y1); 079 080 Shape edgeShape = hasShapeFunctions 081 .getEdgeShapeFunction().getShape(e); 082 if (isLoop) { 083 // make the loops proportional to the size of the 084 // vertex 085 Shape s2 = hasShapeFunctions 086 .getVertexShapeFunction().getShape(v2); 087 Rectangle2D s2Bounds = s2.getBounds2D(); 088 xform.scale(s2Bounds.getWidth(), s2Bounds 089 .getHeight()); 090 // move the loop so that the nadir is centered in 091 // the vertex 092 xform.translate(0, -edgeShape.getBounds2D() 093 .getHeight() / 2); 094 } else { 095 float dx = x2 - x1; 096 float dy = y2 - y1; 097 // rotate the edge to the angle between the vertices 098 double theta = Math.atan2(dy, dx); 099 xform.rotate(theta); 100 // stretch the edge to span the distance between the 101 // vertices 102 float dist = (float) Math.sqrt(dx * dx + dy * dy); 103 xform.scale(dist, 1.0f); 104 } 105 106 // transform the edge to its location and dimensions 107 edgeShape = xform.createTransformedShape(edgeShape); 108 109 // because of the transform, the edgeShape is now a 110 // GeneralPath 111 // see if this edge is the closest of any that intersect 112 if (edgeShape.intersects(pickArea)) { 113 float cx = 0; 114 float cy = 0; 115 float[] f = new float[6]; 116 PathIterator pi = edgeShape.getPathIterator(null); 117 if (pi.isDone() == false) { 118 pi.next(); 119 pi.currentSegment(f); 120 cx = f[0]; 121 cy = f[1]; 122 if (pi.isDone() == false) { 123 pi.currentSegment(f); 124 cx = f[0]; 125 cy = f[1]; 126 } 127 } 128 float dx = (float) (cx - x); 129 float dy = (float) (cy - y); 130 float dist = dx * dx + dy * dy; 131 if (dist < minDistance) { 132 minDistance = dist; 133 closest = e; 134 } 135 } 136 } 137 } 138 break; 139 } catch (ConcurrentModificationException cme) { 140 } 141 } 142 return closest; 143 } 144 145 }