package graph; import java.awt.Point; import java.util.ArrayList; import org.eclipse.elk.graph.ElkEdge; import bk.LayoutType; import view.NodeView; /** * Die Implementation einer Kante aus einem Layered Graphen. * Implementiert {@link LayeredGraphEdge}. * * @author kolja * */ public class LayeredEdge implements LayeredGraphEdge { private ElkEdge original; private ArrayList< LayeredGraphNode > sources; private ArrayList< LayeredGraphNode > targets; private LayeredGraphNode graph; private boolean reversed; private boolean dummy; private ArrayList< Point >[] bindPoints; private boolean[] conflicted; /** * creates a {@link LayeredEdge} from an {@link ElkEdge}. * @param original the original {@link ElkEdge}. * @param sources the sources of the edge. * @param targets the targets of the edge. * @param graph the graph containing the edge. */ @SuppressWarnings("unchecked") public LayeredEdge( ElkEdge original, ArrayList< LayeredGraphNode > sources, ArrayList< LayeredGraphNode > targets, LayeredGraphNode graph ) { this.original = original; this.sources = sources; this.targets = targets; this.graph = graph; reversed = false; dummy = false; bindPoints = new ArrayList[ 5 ]; conflicted = new boolean[ 5 ]; for( int i = 0; i < 5; i++ ) { conflicted[ i ] = false; bindPoints[ i ] = new ArrayList<>(); } for( ArrayList bps : bindPoints ) { bps.add( null ); bps.add( null ); } } @Override public boolean isConflicted( LayoutType layout ) { // see javadoc for better understanding of what this does if( layout == LayoutType.LEFTMOST_UPPER ) return conflicted[ 0 ]; if( layout == LayoutType.RIGHTMOST_UPPER ) return conflicted[ 1 ]; if( layout == LayoutType.LEFTMOST_LOWER ) return conflicted[ 2 ]; if( layout == LayoutType.RIGHTMOST_LOWER ) return conflicted[ 3 ]; if( layout == LayoutType.COMBINED ) return conflicted[ 4 ]; return false; } @Override public void setConflicted( boolean conflicted, LayoutType layout ) { // see javadoc for better understanding of what this does if( layout == null ) { this.conflicted[ 0 ] = conflicted; this.conflicted[ 1 ] = conflicted; this.conflicted[ 2 ] = conflicted; this.conflicted[ 3 ] = conflicted; this.conflicted[ 4 ] = conflicted; } if( layout == LayoutType.LEFTMOST_UPPER ) this.conflicted[ 0 ] = conflicted; if( layout == LayoutType.RIGHTMOST_UPPER ) this.conflicted[ 1 ] = conflicted; if( layout == LayoutType.LEFTMOST_LOWER ) this.conflicted[ 2 ] = conflicted; if( layout == LayoutType.RIGHTMOST_LOWER ) this.conflicted[ 3 ] = conflicted; if( layout == LayoutType.COMBINED ) this.conflicted[ 4 ] = conflicted; } @Override public void setStartPoint( int x, int y, LayoutType layout ) { // see javadoc for better understanding of what this does if( layout == null ) { bindPoints[ 0 ].set( 0, new Point( x, y ) ); bindPoints[ 1 ].set( 0, new Point( x, y ) ); bindPoints[ 2 ].set( 0, new Point( x, y ) ); bindPoints[ 3 ].set( 0, new Point( x, y ) ); bindPoints[ 4 ].set( 0, new Point( x, y ) ); } if( layout == LayoutType.LEFTMOST_UPPER ) bindPoints[ 0 ].set( 0, new Point( x, y ) ); if( layout == LayoutType.RIGHTMOST_UPPER ) bindPoints[ 1 ].set( 0, new Point( x, y ) ); if( layout == LayoutType.LEFTMOST_LOWER ) bindPoints[ 2 ].set( 0, new Point( x, y ) ); if( layout == LayoutType.RIGHTMOST_LOWER ) bindPoints[ 3 ].set( 0, new Point( x, y ) ); if( layout == LayoutType.COMBINED ) bindPoints[ 4 ].set( 0, new Point( x, y ) ); } @Override public void addBindPoint( int x, int y, LayoutType layout ) { // see javadoc for better understanding of what this does if( layout == null ) { bindPoints[ 0 ].add( bindPoints[ 0 ].size() - 1, new Point( x, y ) ); bindPoints[ 1 ].add( bindPoints[ 1 ].size() - 1, new Point( x, y ) ); bindPoints[ 2 ].add( bindPoints[ 2 ].size() - 1, new Point( x, y ) ); bindPoints[ 3 ].add( bindPoints[ 3 ].size() - 1, new Point( x, y ) ); bindPoints[ 4 ].add( bindPoints[ 4 ].size() - 1, new Point( x, y ) ); } if( layout == LayoutType.LEFTMOST_UPPER ) bindPoints[ 0 ].add( bindPoints[ 0 ].size() - 1, new Point( x, y ) ); if( layout == LayoutType.RIGHTMOST_UPPER ) bindPoints[ 1 ].add( bindPoints[ 1 ].size() - 1, new Point( x, y ) ); if( layout == LayoutType.LEFTMOST_LOWER ) bindPoints[ 2 ].add( bindPoints[ 2 ].size() - 1, new Point( x, y ) ); if( layout == LayoutType.RIGHTMOST_LOWER ) bindPoints[ 3 ].add( bindPoints[ 3 ].size() - 1, new Point( x, y ) ); if( layout == LayoutType.COMBINED ) bindPoints[ 4 ].add( bindPoints[ 4 ].size() - 1, new Point( x, y ) ); } @Override public void setEndPoint( int x, int y, LayoutType layout ) { // see javadoc for better understanding of what this does if( layout == null ) { bindPoints[ 0 ].set( bindPoints[ 0 ].size() - 1, new Point( x, y ) ); bindPoints[ 1 ].set( bindPoints[ 1 ].size() - 1, new Point( x, y ) ); bindPoints[ 2 ].set( bindPoints[ 2 ].size() - 1, new Point( x, y ) ); bindPoints[ 3 ].set( bindPoints[ 3 ].size() - 1, new Point( x, y ) ); bindPoints[ 4 ].set( bindPoints[ 4 ].size() - 1, new Point( x, y ) ); } if( layout == LayoutType.LEFTMOST_UPPER ) bindPoints[ 0 ].set( bindPoints[ 0 ].size() - 1, new Point( x, y ) ); if( layout == LayoutType.RIGHTMOST_UPPER ) bindPoints[ 1 ].set( bindPoints[ 1 ].size() - 1, new Point( x, y ) ); if( layout == LayoutType.LEFTMOST_LOWER ) bindPoints[ 2 ].set( bindPoints[ 2 ].size() - 1, new Point( x, y ) ); if( layout == LayoutType.RIGHTMOST_LOWER ) bindPoints[ 3 ].set( bindPoints[ 3 ].size() - 1, new Point( x, y ) ); if( layout == LayoutType.COMBINED ) bindPoints[ 4 ].set( bindPoints[ 4 ].size() - 1, new Point( x, y ) ); } @Override public ArrayList getLinePoints( LayoutType layout ) { // see javadoc for better understanding of what this does NodeView sourceView = ((LayeredNode)sources.get( 0 )).getView( layout ); NodeView targetView = ((LayeredNode)targets.get( 0 )).getView( layout ); setStartPoint( sourceView.getVirtualX() + sourceView.getVirtualWidth() / 2, sourceView.getVirtualY() + sourceView.getVirtualHeight(), layout ); setEndPoint( targetView.getVirtualX() + targetView.getVirtualWidth() / 2, targetView.getVirtualY(), layout ); if( layout == LayoutType.LEFTMOST_UPPER ) return bindPoints[ 0 ]; if( layout == LayoutType.RIGHTMOST_UPPER ) return bindPoints[ 1 ]; if( layout == LayoutType.LEFTMOST_LOWER ) return bindPoints[ 2 ]; if( layout == LayoutType.RIGHTMOST_LOWER ) return bindPoints[ 3 ]; if( layout == LayoutType.COMBINED ) return bindPoints[ 4 ]; return null; } @Override public ElkEdge getOriginalEdge() { return original; } @Override public void remove() { graph.removeEdge( this ); } @Override public ArrayList getSources() { return sources; } @Override public ArrayList getTargets() { return targets; } @Override public boolean isCrossLayerEdge() { // check source int sl = sources.get( 0 ).getLayer(); for( LayeredGraphNode s : sources ) { if( sl != s.getLayer() ) return true; } // check target int tl = targets.get( 0 ).getLayer(); if( Math.abs( tl - sl ) != 1 ) return true; for( LayeredGraphNode t : targets ) { if( tl != t.getLayer() ) return true; } return false; } @Override public void replaceByDummyNodes() { if( isCrossLayerEdge() ) // cross layer edge? { remove(); // remove this edge if( sources.size() == 1 && targets.size() == 1 ) { LayeredGraphNode last = sources.get( 0 ); int sl = last.getLayer(); int tl = targets.get( 0 ).getLayer(); for( int i = sl + 1; i < tl; i++ ) // for each layer { // add a dummy edge and a dummy node LayeredGraphNode n = graph.createNode( null ); n.setLayer( i ); LayeredGraphEdge e = graph.createSimpleEdge( original, last, n ); e.setDummyEdge(); if( reversed ) e.setReversedEdge(); last = n; } // create last dummy edge LayeredGraphEdge e = graph.createSimpleEdge( original, last, targets.get( 0 ) ); e.setDummyEdge(); if( reversed ) e.setReversedEdge(); } } } @Override public void reverse() { reversed = !reversed; ArrayList< LayeredGraphNode > tmp = sources; sources = targets; targets = tmp; } @Override public boolean isDummyEdge() { return dummy; } @Override public void removeDummyNodes() { if( isDummyEdge() ) { // remove the dummy edge remove(); // remove the sources ArrayList< LayeredGraphNode > sours = sources; for( int i = 0; i < sours.size(); i++ ) { LayeredGraphNode n = sours.get( i ); if( n.getOriginalNode() == null ) { sours.remove( n ); for( LayeredGraphEdge e : n.getIncomingEdges() ) { if( e.isDummyEdge() && e.getOriginalEdge() == original ) sours.addAll( e.getSources() ); } } } // remove the targets ArrayList< LayeredGraphNode > targs = targets; for( int i = 0; i < targs.size(); i++ ) { LayeredGraphNode n = targs.get( i ); if( n.getOriginalNode() == null ) { targs.remove( n ); for( LayeredGraphEdge e : n.getOutgoingEdges() ) { if( e.isDummyEdge() && e.getOriginalEdge() == original ) targs.addAll( e.getTargets() ); } } } // add old edge again LayeredGraphEdge e = graph.createEdge( original, sours, targs ); if( reversed ) e.setReversedEdge(); } } @Override public void setDummyEdge() { dummy = true; } @Override public void setReversedEdge() { reversed = true; } @Override public void setGraph(LayeredGraphNode graph) { this.graph = graph; } @Override public boolean isReversedEdge() { return reversed; } @Override public String toString() { return "(" + sources.get( 0 ).toString() + "," + targets.get( 0 ).toString() + ")"; } }