package de.tu_darmstadt.informatik.tk.scopviz.main;
import java.util.Iterator;
import org.graphstream.algorithm.Toolkit;
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));
}
}