package nl.tudelft.lifetiles.graph.view; import javafx.geometry.Bounds; import javafx.scene.Group; import javafx.scene.Node; import javafx.scene.shape.Circle; import javafx.scene.shape.Line; /** * An edge is visual line drawn from a starting vertex to an end vertex. The * default drawing style is to draw a line from the middle of both boxes, * however this can be changed. * */ public class EdgeLine extends Group { /** * Defines the radius of the head circle. */ private static final int HEAD_RADIUS = 2; /** * The line that this edge draws. */ private final Line line; /** * Create a new line from a vertex to another vertex. It tries to create a * straight line but if it fails then the line will be drawn from the middle * of the vertex to the middle of the other vertex. * * @param source * Vertex to draw from * @param destination * Vertex to draw to */ public EdgeLine(final Node source, final Node destination) { line = new Line(); line.getStyleClass().add("edgeline"); Bounds sourceBound = source.getBoundsInParent(); Bounds destinationBound = destination.getBoundsInParent(); if (outofboundsY(sourceBound, destinationBound)) { drawCrossLine(sourceBound, destinationBound); } else { drawStraightLine(sourceBound, destinationBound); } } /** * Draw a Crossed line between two Vertices. * * @param source * The Bounds of the start Vertex * @param destination * The Bounds of the end Vertex */ private void drawCrossLine(final Bounds source, final Bounds destination) { double fromX = source.getMaxX(); double fromY = source.getMinY() + (source.getHeight() / 2); double destX = destination.getMinX(); double destY = destination.getMinY() + (destination.getHeight() / 2); drawLine(fromX, fromY, destX, destY); } /** * Draw a straight line between two vertices. * * @param source * The Bounds of the start Vertex * @param destination * The Bounds of the end Vertex */ private void drawStraightLine(final Bounds source, final Bounds destination) { double startY = 0; // Decide from which bound the Y value should be taken from if (source.getMaxY() < destination.getMaxY() || source.getMinY() > destination.getMinY()) { startY = source.getMinY() + source.getHeight() / 2; } else { startY = destination.getMinY() + destination.getHeight() / 2; } drawLine(source.getMaxX(), startY, destination.getMinX(), startY); } /** * Draw a line given the start and end coordinates. * * @param startX * starting x coordinate * @param startY * starting y coordinate * @param endX * ending x coordinate * @param endY * ending y coordinate */ private void drawLine(final double startX, final double startY, final double endX, final double endY) { Circle head = new Circle(HEAD_RADIUS); Circle tail = new Circle(HEAD_RADIUS); head.getStyleClass().add("edgeHead"); tail.getStyleClass().add("edgeTail"); line.setStartX(startX); line.setStartY(startY); line.setEndX(endX); line.setEndY(endY); head.setCenterX(line.getStartX()); head.setCenterY(line.getStartY()); tail.setCenterX(line.getEndX()); tail.setCenterY(line.getEndY()); this.getChildren().addAll(line, head, tail); } /** * Returns the line that this edge draws. * * @return drawn line */ public Line getLine() { return line; } /** * Check if the y coordinates of the source lies completely above or below * the destination. * * @param source * the left bound * @param destination * the right bound * @return true if source lies indeed lies above or below */ private Boolean outofboundsY(final Bounds source, final Bounds destination) { // Check if source is completely below the destination if (source.getMinY() > destination.getMaxY() && source.getMaxY() > destination.getMinY() && source.getMinY() > destination.getMinY() && source.getMaxY() > destination.getMaxY()) { return true; } // Check if source is completely above the destination if (source.getMinY() < destination.getMaxY() && source.getMaxY() < destination.getMinY() && source.getMinY() < destination.getMinY() && source.getMaxY() < destination.getMaxY()) { return true; } return false; } }