123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413 |
- package bk;
- import java.util.ArrayList;
- import animation.AlgorithmStage;
- import animation.BackwardAction;
- import animation.PseudoCodeNode;
- import bk.ExtremalLayoutCalc.LayoutType;
- import graph.LayeredGraphNode;
- /**
- * The stage of compacting the layout.
- * @author kolja
- *
- */
- public class Compaction implements AlgorithmStage{
- private enum CompactionState
- {
- PLACE_BLOCKS,
- APPLY_SHIFT
- }
-
- private class StackFrame
- {
- public LayeredGraphNode v;
- public LayeredGraphNode u;
- public LayeredGraphNode w;
- }
-
- private CompactionState state;
- private LayeredGraphNode graph;
- private int vIndex;
-
- private ArrayList< StackFrame > stack; // TODO: evtl richtigen "Stack" benutzen
- private ArrayList< BackwardAction > actions; // TODO: evtl richtigen "Stack" benutzen
- private LayoutType layout;
- private PseudoCodeNode placeNode;
- private PseudoCodeNode placeLoopNode;
- private PseudoCodeNode applyNode;
- private PseudoCodeNode applyLoopNode;
- private boolean inside;
-
-
- public Compaction( LayeredGraphNode graph, LayoutType layout )
- {
- this.layout = layout;
- this.graph = graph;
- state = CompactionState.PLACE_BLOCKS;
- stack = new ArrayList<>(); // der call-stack des rekursiven algorithmus
- vIndex = 0;
- actions = new ArrayList<>();
- inside = false;
- }
-
- /**
- * calculates the minimum spacing needed between two left borders of nodes.
- * @return the spacing
- */
- public double calcSpacing()
- {
- double max = 0;
- for( LayeredGraphNode n : graph.getContainedNodes() )
- max = Math.max( max, n.getWidth( layout ) );
- //return max + 25;
- return max;
- }
-
- private LayeredGraphNode getNodeFromIndex( int index )
- {
- for( ArrayList< LayeredGraphNode > l : graph.getContainedLayers() )
- {
- if( index >= l.size() )
- index -= l.size();
- else
- return l.get( index );
- }
- return null;
- }
-
- @Override
- public StageStatus forwardStep() {
- int acSize = actions.size();
- if( state == CompactionState.PLACE_BLOCKS ) // blöcke platzieren
- {
- inside = true;
- placeNode.setSelected( true );
- placeLoopNode.setSelected( true );
- if( stack.size() == 0 ) // äußere schleife, placeblocks bisher nicht aufgerufen
- {
- ArrayList< LayeredGraphNode > nodes = graph.getContainedNodes();
- boolean found = false; // knoten mit v = root[v] gefunden?
- int oldVIndex = vIndex; // nötig für "undo"
-
- // suche knoten mit v = root[v] und undefiniertem x-Wert
- for( ; vIndex < nodes.size(); vIndex++ )
- {
- if( getNodeFromIndex( vIndex ).isXUndefined( layout ) && getNodeFromIndex( vIndex ) == getNodeFromIndex( vIndex ).getRoot( layout ) )
- {
- found = true;
- break;
- }
- }
-
- // kein knoten gefunden
- if( !found )
- {
- // wechsele in die phase des Blöckeshiftens
- placeNode.setSelected( false );
- placeLoopNode.setSelected( false );
- applyNode.setSelected( true );
- applyLoopNode.setSelected( true );
- state = CompactionState.APPLY_SHIFT;
- inside = false;
- vIndex = 0;
- actions.add( 0, ()-> {
- applyNode.setSelected( false );
- applyLoopNode.setSelected( false );
- placeNode.setSelected( true );
- placeLoopNode.setSelected( true );
- vIndex = oldVIndex;
- inside = false;
- state = CompactionState.PLACE_BLOCKS;
- } );
- }
- else // Knoten gefunden
- {
- StackFrame f = new StackFrame(); // enthält lokale variablen
- f.v = getNodeFromIndex( vIndex );
- double oldX = f.v.getX( layout ); // nötig für "undo"
- f.v.setX( 0, true, layout );
- f.w = f.v;
- f.w.setSelected( layout ); // zeige knoten als aktiven knoten an
- System.out.println( "call place_block( " + f.v + " )" );
- stack.add( 0, f );
-
- // die "undo"-action
- actions.add( 0, ()-> {
- inside = true;
- stack.get( 0 ).v.setX( oldX, false, layout );
- stack.get( 0 ).v.setSelected( layout );
- stack.remove( 0 );
- vIndex = oldVIndex;
- state = CompactionState.PLACE_BLOCKS;
- });
- }
- }
- else // zurzeit innerhalb einer placeblock methode
- {
- StackFrame sf = stack.get( 0 );
- if( sf.u == null ) // zu beginn der placeblock methode
- {
- int posW = graph.getContainedLayers().get( sf.w.getLayer() ).indexOf( sf.w );
- if( (posW >= 1 && (layout == LayoutType.BOTTOM_TOP_LEFT || layout == LayoutType.TOP_BOTTOM_LEFT)) || (posW < graph.getContainedLayers().get( sf.w.getLayer() ).size() - 1 && (layout == LayoutType.BOTTOM_TOP_RIGHT || layout == LayoutType.TOP_BOTTOM_RIGHT)) ) // if pos[w] > 1"
- {
- int offset = -1;
- if( layout == LayoutType.BOTTOM_TOP_RIGHT || layout == LayoutType.TOP_BOTTOM_RIGHT )
- offset = 1;
- sf.u = graph.getContainedLayers().get( sf.w.getLayer() ).get( posW + offset ).getRoot( layout );
-
- if( sf.u.isXUndefined( layout ) ) // nötig placeblock aufzurufen?
- {// ja
- StackFrame nsf = new StackFrame(); // enthält lokale variablen
- nsf.v = sf.u;
- double oldX = nsf.v.getX( layout ); // nötig für "undo"
- nsf.v.setX( 0, true, layout );
- nsf.w = nsf.v;
- nsf.w.setSelected( layout ); // zeige knoten als aktiven knoten an
- System.out.println( "call place_block( " + nsf.v + " )" );
- stack.add( 0, nsf );
-
- // die "undo"-action
- actions.add( 0, ()-> {
- inside = true;
- stack.get( 0 ).v.setX( oldX, false, layout );
- stack.get( 0 ).v.setSelected( layout );
- stack.remove( 0 );
- stack.get( 0 ).u = null;
- });
- }
- else // nein
- {
- // tue nix
- sf.w.setSelected( layout );
- actions.add( 0, ()-> {
- inside = true;
- stack.get( 0 ).u = null;
- });
- }
- }
- else
- { // w = align[w]
- LayeredGraphNode oldW = sf.w;
- sf.w = sf.w.getAlignedTo( layout );
- sf.w.setSelected( layout );
- if( sf.w == sf.v ) // schleifenabbruchbedingung
- { //abbrechen, placeblock beendet
- System.out.println( "return place_block( " + sf.v + " )" );
- stack.remove( 0 );
- actions.add( 0, ()-> {
- inside = true;
- stack.add( 0, sf );
- sf.w = oldW;
- sf.w.setSelected( layout );
- });
- }
- else
- { //nur "undo aktion" hinzufügen
- actions.add( 0, ()-> {
- inside = true;
- sf.w = oldW;
- sf.w.setSelected( layout );
- });
- }
- }
- }
- else // ein "placeBlock(u)" aufruf hat gerade returned
- {
- // alte Werte merken für undo
- LayeredGraphNode oldSink = sf.v.getSink( layout );
- LayeredGraphNode sinkOfU = sf.u.getSink( layout );
- double oldShift = sinkOfU.getShift( layout );
- double oldX = sf.v.getX( layout );
- boolean oldDef = !sf.v.isXUndefined( layout );
-
- // v für visualisierung markieren
- sf.w.setSelected( layout );
-
- if( sf.v.getSink( layout ) == sf.v ) // sink[v] = v?
- sf.v.setSink( sf.u.getSink( layout ), layout ); // sink[v] := sink[u]
- int multiplyer = 1;
- if( layout == LayoutType.BOTTOM_TOP_RIGHT || layout == LayoutType.TOP_BOTTOM_RIGHT )
- multiplyer = -1;
-
- if( sf.v.getSink( layout ) != sf.u.getSink( layout ) ) // sink[v] != sink [u]?
- sf.u.getSink( layout ).setShift( // shift[sink[u]] =
- Math.min( sf.u.getSink( layout ).getShift( layout ), // min(shift[sink[u]]
- multiplyer * (Math.abs(sf.v.getX( layout )) - Math.abs(sf.u.getX( layout )) - calcSpacing()) ), layout ); // y_v - y_u - s
- else
- // y_v = max {y_v, y_u + s}
- sf.v.setX( multiplyer * Math.max( Math.abs( sf.v.getX( layout ) ), Math.abs( sf.u.getX( layout ) ) + calcSpacing() ), true, layout );
-
- // alte Werte merken für undo
- LayeredGraphNode oldW = sf.w;
- LayeredGraphNode oldU = sf.u;
-
- sf.w = sf.w.getAlignedTo( layout ); // w = align[w]
- sf.u = null; // u wird nächsten schleifendurchlauf neu gesetzt
-
- if( sf.w == sf.v ) // schleifenabbruchbedingung
- { //abbrechen, placeblock beendet
- System.out.println( "return place_block( " + sf.v + " )" );
- stack.remove( 0 );
- actions.add( 0, ()-> {
- inside = true;
- stack.add( 0, sf );
- stack.get( 0 ).v.setSink( oldSink, layout );
- sinkOfU.setShift( oldShift, layout );
- sf.u = oldU;
- sf.v.setX( oldX, oldDef, layout );
- sf.w = oldW;
- sf.w.setSelected( layout );
- });
- }
- else
- { //nur "undo aktion" hinzufügen
- actions.add( 0, ()-> {
- inside = true;
- stack.get( 0 ).v.setSink( oldSink, layout );
- sinkOfU.setShift( oldShift, layout );
- sf.u = oldU;
- sf.v.setX( oldX, oldDef, layout );
- sf.w = oldW;
- sf.w.setSelected( layout );
- });
- }
- }
- }
- }
- else if( state == CompactionState.APPLY_SHIFT )// "Compute absolute coordinates"
- {
- inside = true;
- if( vIndex >= graph.getContainedNodes().size() )
- {
- inside = false;
- applyNode.setSelected( false );
- applyLoopNode.setSelected( false );
- return StageStatus.FINISHED;
- }
- LayeredGraphNode v = graph.getContainedNodes().get( vIndex );
- double oldX = v.getX( layout );
- boolean oldDef = !v.isXUndefined( layout );
-
- v.setSelected( layout );
- v.setX( v.getRoot( layout ).getX( layout ), true, layout ); // y_v = y_root[v]
- if( v == v.getRoot( layout ) && v.getSink( layout ).getShift( layout ) < Double.POSITIVE_INFINITY )
- v.setX( v.getX( layout ) + v.getSink( layout ).getShift( layout ), true, layout );
- actions.add( 0, ()-> {
- inside = true;
- applyNode.setSelected( true );
- applyLoopNode.setSelected( true );
- v.setX( oldX, oldDef, layout );
- v.setSelected( layout );
- vIndex--;
- } );
- vIndex++;
- if( vIndex >= graph.getContainedNodes().size() )
- {
- applyNode.setSelected( false );
- applyLoopNode.setSelected( false );
- return StageStatus.FINISHED;
- }
- }
- if( actions.size() != acSize + 1 )
- System.out.println( "ERROR" );
- return StageStatus.UNFINISHED;
- }
- @Override
- public StageStatus backwardStep() {
- if( actions.size() == 0 )
- {
- inside = false;
- placeNode.setSelected( false );
- placeLoopNode.setSelected( false );
- return StageStatus.FINISHED;
- }
- actions.get( 0 ).reverse();
- actions.remove( 0 );
- return StageStatus.UNFINISHED;
- }
- @Override
- public PseudoCodeNode createPseudocodeTree() {
- PseudoCodeNode root = new PseudoCodeNode( "Horizontal compaction" );
- placeNode = new PseudoCodeNode( "Root coordinates relative to sink" );
- placeLoopNode = new PseudoCodeNode( "Loop through root nodes..." );
- placeNode.add( placeLoopNode );
- applyNode = new PseudoCodeNode( "Absolute coordinates" );
- applyLoopNode = new PseudoCodeNode( "Loop through all nodes..." );
- applyNode.add( applyLoopNode );
- root.add( placeNode );
- root.add( applyNode );
- return root;
- }
- @Override
- public StageStatus forwardStepOver() {
- if( !inside )
- {
- CompactionState oldState = state;
- StageStatus stage = StageStatus.UNFINISHED;
- while( state == oldState && stage != StageStatus.FINISHED )
- stage = forwardStep();
- return stage;
- }
- else
- return forwardStep();
- }
- @Override
- public StageStatus forwardStepOut() {
- if( !inside )
- {
- StageStatus status = StageStatus.UNFINISHED;
- while( status != StageStatus.FINISHED )
- status = forwardStep();
- return status;
- }
- else
- {
- CompactionState oldState = state;
- StageStatus stage = StageStatus.UNFINISHED;
- while( state == oldState && stage != StageStatus.FINISHED )
- stage = forwardStep();
- return stage;
- }
- }
- @Override
- public StageStatus backwardStepOver() {
- if( !inside )
- {
- CompactionState oldState = state;
- StageStatus stage = StageStatus.UNFINISHED;
- while( state == oldState && stage != StageStatus.FINISHED )
- stage = backwardStep();
- return stage;
- }
- else
- return backwardStep();
- }
- @Override
- public StageStatus backwardStepOut() {
- if( !inside )
- {
- StageStatus status = StageStatus.UNFINISHED;
- while( status != StageStatus.FINISHED )
- status = backwardStep();
- return status;
- }
- else
- {
- CompactionState oldState = state;
- StageStatus stage = StageStatus.UNFINISHED;
- while( state == oldState && stage != StageStatus.FINISHED )
- stage = backwardStep();
- return stage;
- }
- }
- }
|