package bk; import java.awt.Color; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.swing.JTree; import animation.CodeLine; import animation.ControlFlow; import animation.Memory; import animation.Memory.MemoryType; import animation.Memory.ReadOnlyMemory; import animation.PseudoCodeNode; import codelines.DeclareVariable; import codelines.ForEachLoop; import codelines.FunctionDefinition; import codelines.SetVariable; import graph.LayeredGraphNode; /** * The stage of the combination of the four extremal layouts. * @author kolja * */ public class Combine { public static PseudoCodeNode combine( JTree tree ) { String[] vars = { "graph", "l", "l_min", "v", "positions" }; @SuppressWarnings("serial") PseudoCodeNode root = new PseudoCodeNode( "function combine( graph )", vars, tree, new FunctionDefinition( new String[]{ "graph" } ) ){ @Override public String getDebugOutput( Memory m ) { if( m.isSomewhereDefined( "v", MemoryType.LOCAL ) ) m.read( "v", MemoryType.LOCAL).setSelected( null ); return super.getDebugOutput( m ); } }; root.add( new PseudoCodeNode( "-- Align all Layouts to the one with the smallest width --", vars, tree, new CodeLine() { @Override public ControlFlow runForward(Memory m) { LayeredGraphNode graph = m.read( "graph", MemoryType.LOCAL ); if( graph.parent() == null ) graph.setColor( Color.BLACK, null ); actions.add( (Memory mem) -> { if( graph.parent() == null ) graph.setColor( null, null ); }); return new ControlFlow( ControlFlow.STEP_OVER ); } })); PseudoCodeNode firstLoop = new PseudoCodeNode( "foreach l in ['DOWN_RIGHT', 'DOWN_LEFT', 'UP_RIGHT', 'UP_LEFT'] do", vars, tree, new ForEachLoop( "l" ) { @Override protected List list(ReadOnlyMemory m) { ArrayList< String > list = new ArrayList(); list.add( "DOWN_RIGHT" ); list.add( "DOWN_LEFT" ); list.add( "UP_RIGHT" ); list.add( "UP_LEFT" ); return list; } }); root.add( firstLoop ); firstLoop.add( new PseudoCodeNode( "min[l] = minimum x coordinate in l;", vars, tree, new CodeLine() { @Override public ControlFlow runForward(Memory m) { String layout = m.read( "l", MemoryType.LOCAL ); m.declare( "min[" + layout + "]", calcMinX( m.read( "graph", MemoryType.LOCAL ), LayoutType.fromString( layout ) ), MemoryType.GLOBAL ); actions.add( (Memory mem) -> { mem.undeclare( "min[" + layout + "]", MemoryType.GLOBAL ); }); return new ControlFlow( ControlFlow.STEP_OVER ); } })); firstLoop.add( new PseudoCodeNode( "max[l] = maximum x coordinate in l;", vars, tree, new CodeLine() { @Override public ControlFlow runForward(Memory m) { String layout = m.read( "l", MemoryType.LOCAL ); m.declare( "max[" + layout + "]", calcMaxX( m.read( "graph", MemoryType.LOCAL ), LayoutType.fromString( layout ) ), MemoryType.GLOBAL ); actions.add( (Memory mem) -> { mem.undeclare( "max[" + layout + "]", MemoryType.GLOBAL ); }); return new ControlFlow( ControlFlow.STEP_OVER ); } })); firstLoop.add( new PseudoCodeNode( "width[l] = max[l] - min[l];", vars, tree, new CodeLine() { @Override public ControlFlow runForward(Memory m) { String layout = m.read( "l", MemoryType.LOCAL ); m.declare( "width[" + layout + "]", m.read( "max[" + layout + "]", MemoryType.GLOBAL ) - m.read( "min[" + layout + "]", MemoryType.GLOBAL ), MemoryType.GLOBAL ); actions.add( (Memory mem) -> { mem.undeclare( "width[" + layout + "]", MemoryType.GLOBAL ); }); return new ControlFlow( ControlFlow.STEP_OVER ); } })); root.add( new PseudoCodeNode( "l_min = l with width[l] == min(width);", vars, tree, new DeclareVariable( "l_min" ) { @Override protected String value(ReadOnlyMemory m) { String min = "DOWN_RIGHT"; int minW = m.read( "width[DOWN_RIGHT]", MemoryType.GLOBAL ); for( String l : new String[]{ "DOWN_LEFT", "UP_RIGHT", "UP_LEFT" } ) { if( minW > m.read( "width[" + l + "]", MemoryType.GLOBAL ) ) { minW = m.read( "width[" + l + "]", MemoryType.GLOBAL ); min = l; } } return min; } })); PseudoCodeNode secondLoop = new PseudoCodeNode( "foreach l in ['DOWN_RIGHT', 'DOWN_LEFT', 'UP_RIGHT', 'UP_LEFT'] do", vars, tree, new ForEachLoop( "l" ) { @Override protected List list(ReadOnlyMemory m) { ArrayList< String > list = new ArrayList(); list.add( "DOWN_RIGHT" ); list.add( "DOWN_LEFT" ); list.add( "UP_RIGHT" ); list.add( "UP_LEFT" ); return list; } }); root.add( secondLoop ); secondLoop.add( new PseudoCodeNode( "shift[l] = l.contains('RIGHT') ? min[l_min] - min[l] : max[l_min] - max[l];", vars, tree, new CodeLine() { @Override public ControlFlow runForward(Memory m) { String layout = m.read( "l", MemoryType.LOCAL ); String lMin = m.read( "l_min", MemoryType.LOCAL ); if( layout.contains( "RIGHT" ) ) m.declare( "shift[" + layout + "]", m.read( "min[" + lMin + "]", MemoryType.GLOBAL ) - m.read( "min[" + layout + "]", MemoryType.GLOBAL ), MemoryType.GLOBAL ); else m.declare( "shift[" + layout + "]", m.read( "max[" + lMin + "]", MemoryType.GLOBAL ) - m.read( "max[" + layout + "]", MemoryType.GLOBAL ), MemoryType.GLOBAL ); actions.add( (Memory mem) -> { mem.undeclare( "shift[" + layout + "]", MemoryType.GLOBAL ); }); return new ControlFlow( ControlFlow.STEP_OVER ); } })); PseudoCodeNode thirdLoop = new PseudoCodeNode( "foreach v in graph do", vars, tree, new ForEachLoop( "v" ) { @Override protected List list(ReadOnlyMemory m) { return m.read( "graph", MemoryType.LOCAL ).getContainedNodes(); } }); root.add( thirdLoop ); thirdLoop.add( new PseudoCodeNode( "positions = [];", vars, tree, new DeclareVariable>( "positions") { @Override protected ArrayList value(ReadOnlyMemory m) { return new ArrayList(); } })); PseudoCodeNode innerLoop = new PseudoCodeNode( "foreach l in ['DOWN_RIGHT', 'DOWN_LEFT', 'UP_RIGHT', 'UP_LEFT'] do", vars, tree, new ForEachLoop( "l" ) { @Override protected List list(ReadOnlyMemory m) { ArrayList< String > list = new ArrayList(); list.add( "DOWN_RIGHT" ); list.add( "DOWN_LEFT" ); list.add( "UP_RIGHT" ); list.add( "UP_LEFT" ); return list; } }); innerLoop.add( new PseudoCodeNode( "positions.add(x[v] in l);", vars, tree, new CodeLine() { @Override public ControlFlow runForward(Memory m) { String layout = m.read( "l", MemoryType.LOCAL ); ArrayList positions = m.read( "positions", MemoryType.LOCAL ); positions.add( (int)m.read( "v", MemoryType.LOCAL ).getX( LayoutType.fromString( layout ) ) + m.read( "shift[" + layout + "]", MemoryType.GLOBAL ) ); actions.add( (Memory mem) -> { positions.remove( positions.size() - 1 ); }); return new ControlFlow( ControlFlow.STEP_OVER ); } })); thirdLoop.add( innerLoop ); thirdLoop.add( new PseudoCodeNode( "positions = sort( positions );", vars, tree, new SetVariable>( "positions" ) { @Override public ArrayList value(ReadOnlyMemory m) { ArrayList positions = m.read( "positions", MemoryType.LOCAL ); ArrayList neu = new ArrayList(); for( int p : positions ) neu.add( p ); Collections.sort( neu ); return neu; } })); thirdLoop.add( new PseudoCodeNode( "x[v] = (positions[1]+positions[2]) / 2;", vars, tree, new CodeLine() { @Override public ControlFlow runForward(Memory m) { ArrayList positions = m.read( "positions", MemoryType.LOCAL ); LayeredGraphNode v = m.read( "v", MemoryType.LOCAL ); double old = v.getX( LayoutType.COMBINED ); v.setX( (positions.get( 1 ) + positions.get( 2 )) / 2.0, true, LayoutType.COMBINED ); actions.add( (Memory mem) -> { v.setX( old, false, LayoutType.COMBINED ); }); return new ControlFlow( ControlFlow.STEP_OVER ); } })); return root; } private static int calcMinX( LayeredGraphNode graph, LayoutType layout ) { int minX = 0; if( graph.getContainedNodes().size() > 0 ) minX = (int)graph.getContainedNodes().get( 0 ).getX( layout ); for( LayeredGraphNode n : graph.getContainedNodes() ) minX = Math.min( minX, (int)n.getX( layout ) ); return minX; } private static int calcMaxX( LayeredGraphNode graph, LayoutType layout ) { int maxX = 0; if( graph.getContainedNodes().size() > 0 ) maxX = (int)graph.getContainedNodes().get( 0 ).getX( layout ); for( LayeredGraphNode n : graph.getContainedNodes() ) maxX = Math.max( maxX, (int)n.getX( layout ) ); return maxX; } }