package de.tu_darmstadt.informatik.tk.scopviz.main; import java.util.Iterator; import org.graphstream.ui.geom.Point3; import org.graphstream.ui.graphicGraph.GraphPosLengthUtils; import org.graphstream.ui.view.Camera; import de.tu_darmstadt.informatik.tk.scopviz.graphs.GraphManager; import de.tu_darmstadt.informatik.tk.scopviz.graphs.MyEdge; import de.tu_darmstadt.informatik.tk.scopviz.graphs.MyNode; /** * This class contains helpful static functions. * * @author Matthias Wilhelm * @version 1.0 */ public final class EdgeSelectionHelper { /** * Private Constructor to prevent instantiation. private * EdgeSelectionHelper(){} * * /** Width in pixels for which the edge selection triggers. */ private static final int EDGE_SELECTION_WIDTH = 5; /** * Precalculates pi / 2. */ private static final double HALF_PI = Math.PI / 2; private EdgeSelectionHelper() { } // TODO optional: only update if view has changed /** * Returns the closest Edge in the current Graph to a given position. It * allows for an inaccuracy of around {@value #EDGE_SELECTION_WIDTH}px * * @param pos * The position. Expects a Point3, but only uses the x and * y coordinates * @return the closest Edge if a valid Edge exists, returns null * otherwise */ public static MyEdge getClosestEdge(Point3 pos) { Camera cam = Main.getInstance().getGraphManager().getView().getCamera(); // gets to points within a fixed distance of each other and calculates // the gu of those points Point3 min = cam.transformPxToGu(0, 0); Point3 max = cam.transformPxToGu(EDGE_SELECTION_WIDTH, EDGE_SELECTION_WIDTH); // calculates the approximate distance by taken the maximum of the // absolute Distances of the x's or y's double dist = Math.max(Math.abs(max.x - min.x), Math.abs(max.y - min.y)); // calls the actual calculation return getClosestEdge(pos, dist); } /** * Returns the closest Edge in the current Graph to a given position within * the given maxDistance. * * @param pos * The position. Expects a Point3, but only uses the x and * y coordinates * @param maxDistance * the maximum distance (in gu) the edge may be away from the * position to be considered as a valid edge * @return the closest Edge if a valid Edge exists, returns null * otherwise */ public static MyEdge getClosestEdge(Point3 pos, double maxDistance) { double x0 = pos.x; double y0 = pos.y; // keeps track of the current smallest distance to an edge; // initializes to the given maxDistance double dist = maxDistance; // keeps track of the current closest edge MyEdge result = null; GraphManager gm = Main.getInstance().getGraphManager(); // Iterates over every edge, calculates the distance and updates the // best edge and corresponding distance for (Iterator iterator = gm.getGraph().getEdgeIterator(); iterator.hasNext();) { MyEdge edge = iterator.next(); // Get the positions of the nodes of the currently selected edge. double[] n1 = GraphPosLengthUtils.nodePosition(edge.getNode0()); double[] n2 = GraphPosLengthUtils.nodePosition(edge.getNode1()); // Extract the x and y values of the positions of the nodes double x1 = n1[0]; double y1 = n1[1]; double x2 = n2[0]; double y2 = n2[1]; // Calculate the distance between the nodes // Naming convention is view node 0 as A, node 1 as B and the point // as C in a triangle double c = distance(x1, y1, x2, y2); // Distance Node0 Node1 // Calculate the distance between the edge and the point double cdist = Math.abs((y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1) / c; // Check if the edge is closer than the currently stored one if (cdist < dist) { // Calculate the distances from each node to the point double a = distance(x0, y0, x2, y2); // Distance Point Node0 double b = distance(x0, y0, x1, y1); // Distance Point Node1 // Precalculate the squares of the distances for later use double b2 = b * b; double a2 = a * a; double c2 = c * c; // Calculates the inner angles off the triangle double alpha = Math.acos((b2 + c2 - a2) / (2 * b * c)); double beta = Math.acos((a2 + c2 - b2) / (2 * a * c)); // Check if the point is actually visually next to the edge by // checking if both inner angles are less than 90° if (alpha <= HALF_PI && beta <= HALF_PI) { dist = cdist; result = edge; } } } return result; } /** * Calculates the distance between two given Nodes. * * @param a * Node 1 * @param b * Node 2 * @return the distance between the two Nodes as a double */ public static double distance(MyNode a, MyNode b) { double[] n1 = GraphPosLengthUtils.nodePosition(a); double[] n2 = GraphPosLengthUtils.nodePosition(b); return distance(n1[0], n1[1], n2[0], n2[1]); } /** * Calculates the distance between a x,y position and a Node. * * @param x0 * x cord of the position * @param y0 * y cord of the position * @param a * the Node * @return the distance between the position and the Node as a double */ public static double distance(double x0, double y0, MyNode a) { double[] n1 = GraphPosLengthUtils.nodePosition(a); return distance(x0, y0, n1[0], n1[1]); } /** * Calculates the distance between two x,y positions. * * @param x0 * x cord of the first position * @param y0 * y cord of the first position * @param x1 * x cord of the second position * @param y1 * y cord of the second position * @return the distance between the two positions as a double */ public static double distance(double x0, double y0, double x1, double y1) { return Math.sqrt(Math.pow(y0 - y1, 2) + Math.pow(x0 - x1, 2)); } }