Compaction.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. package bk;
  2. import java.util.ArrayList;
  3. import animation.AlgorithmStage;
  4. import animation.BackwardAction;
  5. import animation.PseudoCodeNode;
  6. import bk.ExtremalLayoutCalc.LayoutType;
  7. import graph.LayeredGraphNode;
  8. /**
  9. * The stage of compacting the layout.
  10. * @author kolja
  11. *
  12. */
  13. public class Compaction implements AlgorithmStage{
  14. private enum CompactionState
  15. {
  16. PLACE_BLOCKS,
  17. APPLY_SHIFT
  18. }
  19. private class StackFrame
  20. {
  21. public LayeredGraphNode v;
  22. public LayeredGraphNode u;
  23. public LayeredGraphNode w;
  24. }
  25. private CompactionState state;
  26. private LayeredGraphNode graph;
  27. private int vIndex;
  28. private ArrayList< StackFrame > stack; // TODO: evtl richtigen "Stack" benutzen
  29. private ArrayList< BackwardAction > actions; // TODO: evtl richtigen "Stack" benutzen
  30. private LayoutType layout;
  31. private PseudoCodeNode placeNode;
  32. private PseudoCodeNode placeLoopNode;
  33. private PseudoCodeNode applyNode;
  34. private PseudoCodeNode applyLoopNode;
  35. private boolean inside;
  36. public Compaction( LayeredGraphNode graph, LayoutType layout )
  37. {
  38. this.layout = layout;
  39. this.graph = graph;
  40. state = CompactionState.PLACE_BLOCKS;
  41. stack = new ArrayList<>(); // der call-stack des rekursiven algorithmus
  42. vIndex = 0;
  43. actions = new ArrayList<>();
  44. inside = false;
  45. }
  46. /**
  47. * calculates the minimum spacing needed between two left borders of nodes.
  48. * @return the spacing
  49. */
  50. public double calcSpacing()
  51. {
  52. double max = 0;
  53. for( LayeredGraphNode n : graph.getContainedNodes() )
  54. max = Math.max( max, n.getWidth( layout ) );
  55. //return max + 25;
  56. return max;
  57. }
  58. private LayeredGraphNode getNodeFromIndex( int index )
  59. {
  60. for( ArrayList< LayeredGraphNode > l : graph.getContainedLayers() )
  61. {
  62. if( index >= l.size() )
  63. index -= l.size();
  64. else
  65. return l.get( index );
  66. }
  67. return null;
  68. }
  69. @Override
  70. public StageStatus forwardStep() {
  71. int acSize = actions.size();
  72. if( state == CompactionState.PLACE_BLOCKS ) // blöcke platzieren
  73. {
  74. inside = true;
  75. placeNode.setSelected( true );
  76. placeLoopNode.setSelected( true );
  77. if( stack.size() == 0 ) // äußere schleife, placeblocks bisher nicht aufgerufen
  78. {
  79. ArrayList< LayeredGraphNode > nodes = graph.getContainedNodes();
  80. boolean found = false; // knoten mit v = root[v] gefunden?
  81. int oldVIndex = vIndex; // nötig für "undo"
  82. // suche knoten mit v = root[v] und undefiniertem x-Wert
  83. for( ; vIndex < nodes.size(); vIndex++ )
  84. {
  85. if( getNodeFromIndex( vIndex ).isXUndefined( layout ) && getNodeFromIndex( vIndex ) == getNodeFromIndex( vIndex ).getRoot( layout ) )
  86. {
  87. found = true;
  88. break;
  89. }
  90. }
  91. // kein knoten gefunden
  92. if( !found )
  93. {
  94. // wechsele in die phase des Blöckeshiftens
  95. placeNode.setSelected( false );
  96. placeLoopNode.setSelected( false );
  97. applyNode.setSelected( true );
  98. applyLoopNode.setSelected( true );
  99. state = CompactionState.APPLY_SHIFT;
  100. inside = false;
  101. vIndex = 0;
  102. actions.add( 0, ()-> {
  103. applyNode.setSelected( false );
  104. applyLoopNode.setSelected( false );
  105. placeNode.setSelected( true );
  106. placeLoopNode.setSelected( true );
  107. vIndex = oldVIndex;
  108. inside = false;
  109. state = CompactionState.PLACE_BLOCKS;
  110. } );
  111. }
  112. else // Knoten gefunden
  113. {
  114. StackFrame f = new StackFrame(); // enthält lokale variablen
  115. f.v = getNodeFromIndex( vIndex );
  116. double oldX = f.v.getX( layout ); // nötig für "undo"
  117. f.v.setX( 0, true, layout );
  118. f.w = f.v;
  119. f.w.setSelected( layout ); // zeige knoten als aktiven knoten an
  120. System.out.println( "call place_block( " + f.v + " )" );
  121. stack.add( 0, f );
  122. // die "undo"-action
  123. actions.add( 0, ()-> {
  124. inside = true;
  125. stack.get( 0 ).v.setX( oldX, false, layout );
  126. stack.get( 0 ).v.setSelected( layout );
  127. stack.remove( 0 );
  128. vIndex = oldVIndex;
  129. state = CompactionState.PLACE_BLOCKS;
  130. });
  131. }
  132. }
  133. else // zurzeit innerhalb einer placeblock methode
  134. {
  135. StackFrame sf = stack.get( 0 );
  136. if( sf.u == null ) // zu beginn der placeblock methode
  137. {
  138. int posW = graph.getContainedLayers().get( sf.w.getLayer() ).indexOf( sf.w );
  139. 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"
  140. {
  141. int offset = -1;
  142. if( layout == LayoutType.BOTTOM_TOP_RIGHT || layout == LayoutType.TOP_BOTTOM_RIGHT )
  143. offset = 1;
  144. sf.u = graph.getContainedLayers().get( sf.w.getLayer() ).get( posW + offset ).getRoot( layout );
  145. if( sf.u.isXUndefined( layout ) ) // nötig placeblock aufzurufen?
  146. {// ja
  147. StackFrame nsf = new StackFrame(); // enthält lokale variablen
  148. nsf.v = sf.u;
  149. double oldX = nsf.v.getX( layout ); // nötig für "undo"
  150. nsf.v.setX( 0, true, layout );
  151. nsf.w = nsf.v;
  152. nsf.w.setSelected( layout ); // zeige knoten als aktiven knoten an
  153. System.out.println( "call place_block( " + nsf.v + " )" );
  154. stack.add( 0, nsf );
  155. // die "undo"-action
  156. actions.add( 0, ()-> {
  157. inside = true;
  158. stack.get( 0 ).v.setX( oldX, false, layout );
  159. stack.get( 0 ).v.setSelected( layout );
  160. stack.remove( 0 );
  161. stack.get( 0 ).u = null;
  162. });
  163. }
  164. else // nein
  165. {
  166. // tue nix
  167. sf.w.setSelected( layout );
  168. actions.add( 0, ()-> {
  169. inside = true;
  170. stack.get( 0 ).u = null;
  171. });
  172. }
  173. }
  174. else
  175. { // w = align[w]
  176. LayeredGraphNode oldW = sf.w;
  177. sf.w = sf.w.getAlignedTo( layout );
  178. sf.w.setSelected( layout );
  179. if( sf.w == sf.v ) // schleifenabbruchbedingung
  180. { //abbrechen, placeblock beendet
  181. System.out.println( "return place_block( " + sf.v + " )" );
  182. stack.remove( 0 );
  183. actions.add( 0, ()-> {
  184. inside = true;
  185. stack.add( 0, sf );
  186. sf.w = oldW;
  187. sf.w.setSelected( layout );
  188. });
  189. }
  190. else
  191. { //nur "undo aktion" hinzufügen
  192. actions.add( 0, ()-> {
  193. inside = true;
  194. sf.w = oldW;
  195. sf.w.setSelected( layout );
  196. });
  197. }
  198. }
  199. }
  200. else // ein "placeBlock(u)" aufruf hat gerade returned
  201. {
  202. // alte Werte merken für undo
  203. LayeredGraphNode oldSink = sf.v.getSink( layout );
  204. LayeredGraphNode sinkOfU = sf.u.getSink( layout );
  205. double oldShift = sinkOfU.getShift( layout );
  206. double oldX = sf.v.getX( layout );
  207. boolean oldDef = !sf.v.isXUndefined( layout );
  208. // v für visualisierung markieren
  209. sf.w.setSelected( layout );
  210. if( sf.v.getSink( layout ) == sf.v ) // sink[v] = v?
  211. sf.v.setSink( sf.u.getSink( layout ), layout ); // sink[v] := sink[u]
  212. int multiplyer = 1;
  213. if( layout == LayoutType.BOTTOM_TOP_RIGHT || layout == LayoutType.TOP_BOTTOM_RIGHT )
  214. multiplyer = -1;
  215. if( sf.v.getSink( layout ) != sf.u.getSink( layout ) ) // sink[v] != sink [u]?
  216. sf.u.getSink( layout ).setShift( // shift[sink[u]] =
  217. Math.min( sf.u.getSink( layout ).getShift( layout ), // min(shift[sink[u]]
  218. multiplyer * (Math.abs(sf.v.getX( layout )) - Math.abs(sf.u.getX( layout )) - calcSpacing()) ), layout ); // y_v - y_u - s
  219. else
  220. // y_v = max {y_v, y_u + s}
  221. sf.v.setX( multiplyer * Math.max( Math.abs( sf.v.getX( layout ) ), Math.abs( sf.u.getX( layout ) ) + calcSpacing() ), true, layout );
  222. // alte Werte merken für undo
  223. LayeredGraphNode oldW = sf.w;
  224. LayeredGraphNode oldU = sf.u;
  225. sf.w = sf.w.getAlignedTo( layout ); // w = align[w]
  226. sf.u = null; // u wird nächsten schleifendurchlauf neu gesetzt
  227. if( sf.w == sf.v ) // schleifenabbruchbedingung
  228. { //abbrechen, placeblock beendet
  229. System.out.println( "return place_block( " + sf.v + " )" );
  230. stack.remove( 0 );
  231. actions.add( 0, ()-> {
  232. inside = true;
  233. stack.add( 0, sf );
  234. stack.get( 0 ).v.setSink( oldSink, layout );
  235. sinkOfU.setShift( oldShift, layout );
  236. sf.u = oldU;
  237. sf.v.setX( oldX, oldDef, layout );
  238. sf.w = oldW;
  239. sf.w.setSelected( layout );
  240. });
  241. }
  242. else
  243. { //nur "undo aktion" hinzufügen
  244. actions.add( 0, ()-> {
  245. inside = true;
  246. stack.get( 0 ).v.setSink( oldSink, layout );
  247. sinkOfU.setShift( oldShift, layout );
  248. sf.u = oldU;
  249. sf.v.setX( oldX, oldDef, layout );
  250. sf.w = oldW;
  251. sf.w.setSelected( layout );
  252. });
  253. }
  254. }
  255. }
  256. }
  257. else if( state == CompactionState.APPLY_SHIFT )// "Compute absolute coordinates"
  258. {
  259. inside = true;
  260. if( vIndex >= graph.getContainedNodes().size() )
  261. {
  262. inside = false;
  263. applyNode.setSelected( false );
  264. applyLoopNode.setSelected( false );
  265. return StageStatus.FINISHED;
  266. }
  267. LayeredGraphNode v = graph.getContainedNodes().get( vIndex );
  268. double oldX = v.getX( layout );
  269. boolean oldDef = !v.isXUndefined( layout );
  270. v.setSelected( layout );
  271. v.setX( v.getRoot( layout ).getX( layout ), true, layout ); // y_v = y_root[v]
  272. if( v == v.getRoot( layout ) && v.getSink( layout ).getShift( layout ) < Double.POSITIVE_INFINITY )
  273. v.setX( v.getX( layout ) + v.getSink( layout ).getShift( layout ), true, layout );
  274. actions.add( 0, ()-> {
  275. inside = true;
  276. applyNode.setSelected( true );
  277. applyLoopNode.setSelected( true );
  278. v.setX( oldX, oldDef, layout );
  279. v.setSelected( layout );
  280. vIndex--;
  281. } );
  282. vIndex++;
  283. if( vIndex >= graph.getContainedNodes().size() )
  284. {
  285. applyNode.setSelected( false );
  286. applyLoopNode.setSelected( false );
  287. return StageStatus.FINISHED;
  288. }
  289. }
  290. if( actions.size() != acSize + 1 )
  291. System.out.println( "ERROR" );
  292. return StageStatus.UNFINISHED;
  293. }
  294. @Override
  295. public StageStatus backwardStep() {
  296. if( actions.size() == 0 )
  297. {
  298. inside = false;
  299. placeNode.setSelected( false );
  300. placeLoopNode.setSelected( false );
  301. return StageStatus.FINISHED;
  302. }
  303. actions.get( 0 ).reverse();
  304. actions.remove( 0 );
  305. return StageStatus.UNFINISHED;
  306. }
  307. @Override
  308. public PseudoCodeNode createPseudocodeTree() {
  309. PseudoCodeNode root = new PseudoCodeNode( "Horizontal compaction" );
  310. placeNode = new PseudoCodeNode( "Root coordinates relative to sink" );
  311. placeLoopNode = new PseudoCodeNode( "Loop through root nodes..." );
  312. placeNode.add( placeLoopNode );
  313. applyNode = new PseudoCodeNode( "Absolute coordinates" );
  314. applyLoopNode = new PseudoCodeNode( "Loop through all nodes..." );
  315. applyNode.add( applyLoopNode );
  316. root.add( placeNode );
  317. root.add( applyNode );
  318. return root;
  319. }
  320. @Override
  321. public StageStatus forwardStepOver() {
  322. if( !inside )
  323. {
  324. CompactionState oldState = state;
  325. StageStatus stage = StageStatus.UNFINISHED;
  326. while( state == oldState && stage != StageStatus.FINISHED )
  327. stage = forwardStep();
  328. return stage;
  329. }
  330. else
  331. return forwardStep();
  332. }
  333. @Override
  334. public StageStatus forwardStepOut() {
  335. if( !inside )
  336. {
  337. StageStatus status = StageStatus.UNFINISHED;
  338. while( status != StageStatus.FINISHED )
  339. status = forwardStep();
  340. return status;
  341. }
  342. else
  343. {
  344. CompactionState oldState = state;
  345. StageStatus stage = StageStatus.UNFINISHED;
  346. while( state == oldState && stage != StageStatus.FINISHED )
  347. stage = forwardStep();
  348. return stage;
  349. }
  350. }
  351. @Override
  352. public StageStatus backwardStepOver() {
  353. if( !inside )
  354. {
  355. CompactionState oldState = state;
  356. StageStatus stage = StageStatus.UNFINISHED;
  357. while( state == oldState && stage != StageStatus.FINISHED )
  358. stage = backwardStep();
  359. return stage;
  360. }
  361. else
  362. return backwardStep();
  363. }
  364. @Override
  365. public StageStatus backwardStepOut() {
  366. if( !inside )
  367. {
  368. StageStatus status = StageStatus.UNFINISHED;
  369. while( status != StageStatus.FINISHED )
  370. status = backwardStep();
  371. return status;
  372. }
  373. else
  374. {
  375. CompactionState oldState = state;
  376. StageStatus stage = StageStatus.UNFINISHED;
  377. while( state == oldState && stage != StageStatus.FINISHED )
  378. stage = backwardStep();
  379. return stage;
  380. }
  381. }
  382. }