BlockCalc.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. package bk;
  2. import java.awt.Color;
  3. import java.util.ArrayList;
  4. import java.util.Collections;
  5. import javax.swing.JTree;
  6. import animation.AlgorithmStage;
  7. import animation.BackwardAction;
  8. import animation.PseudoCodeNode;
  9. import bk.ExtremalLayoutCalc.LayoutType;
  10. import graph.LayeredGraphEdge;
  11. import graph.LayeredGraphNode;
  12. /**
  13. * The stage of the BK node placement algorithm where the blocks are computed.
  14. * @author kolja
  15. *
  16. */
  17. public class BlockCalc implements AlgorithmStage {
  18. private int layerIndex;
  19. private int nodeIndex;
  20. private int r;
  21. private LayeredGraphNode graph;
  22. private ArrayList< ArrayList< PseudoCodeNode > > subgraphNodes;
  23. private ArrayList< ArrayList< ExtremalLayoutCalc > > subgraphAlgs;
  24. private ArrayList< BackwardAction > backwards; // TODO: evtl richtigen "Stack" benutzen
  25. private LayoutType layout;
  26. private PseudoCodeNode loopNode;
  27. private boolean inside;
  28. int step;
  29. public BlockCalc( LayeredGraphNode graph, LayoutType layout )
  30. {
  31. this.layout = layout;
  32. step = 0;
  33. this.graph = graph;
  34. layerIndex = 0;
  35. nodeIndex = 0;
  36. r = 0;
  37. subgraphNodes = new ArrayList<>();
  38. subgraphAlgs = new ArrayList<>();
  39. for( ArrayList<LayeredGraphNode> l : graph.getContainedLayers() )
  40. {
  41. ArrayList< PseudoCodeNode > nodes = new ArrayList<>();
  42. ArrayList< ExtremalLayoutCalc > algs = new ArrayList<>();
  43. for( int i = 0; i < l.size(); i++ )
  44. {
  45. nodes.add( null );
  46. algs.add( null );
  47. }
  48. subgraphAlgs.add( algs );
  49. subgraphNodes.add( nodes );
  50. }
  51. inside = false;
  52. backwards = new ArrayList<>();
  53. }
  54. private int calcLayerIndex()
  55. {
  56. if( layout == LayoutType.TOP_BOTTOM_LEFT || layout == LayoutType.TOP_BOTTOM_RIGHT )
  57. return layerIndex;
  58. if( layout == LayoutType.BOTTOM_TOP_LEFT || layout == LayoutType.BOTTOM_TOP_RIGHT )
  59. return graph.getContainedLayers().size() - layerIndex - 1;
  60. return -1;
  61. }
  62. private int calcBeforeLayerIndex()
  63. {
  64. if( layout == LayoutType.TOP_BOTTOM_LEFT || layout == LayoutType.TOP_BOTTOM_RIGHT )
  65. return layerIndex - 1;
  66. if( layout == LayoutType.BOTTOM_TOP_LEFT || layout == LayoutType.BOTTOM_TOP_RIGHT )
  67. return graph.getContainedLayers().size() - layerIndex;
  68. return -1;
  69. }
  70. private int calcNodeIndex( int index )
  71. {
  72. if( layout == LayoutType.TOP_BOTTOM_LEFT || layout == LayoutType.BOTTOM_TOP_LEFT )
  73. return index;
  74. if( layout == LayoutType.TOP_BOTTOM_RIGHT || layout == LayoutType.BOTTOM_TOP_RIGHT )
  75. return graph.getContainedLayers().get( calcLayerIndex() ).size() - index - 1;
  76. return index;
  77. }
  78. private int calcBeforeLayerNodeIndex( int index )
  79. {
  80. if( layout == LayoutType.TOP_BOTTOM_LEFT || layout == LayoutType.BOTTOM_TOP_LEFT )
  81. return index;
  82. if( layout == LayoutType.TOP_BOTTOM_RIGHT || layout == LayoutType.BOTTOM_TOP_RIGHT )
  83. return graph.getContainedLayers().get( calcBeforeLayerIndex() ).size() - index - 1;
  84. return index;
  85. }
  86. @Override
  87. public StageStatus forwardStep() {
  88. LayeredGraphNode current = graph.getContainedLayers().get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) );
  89. current.setSelected( layout );
  90. if( current.getContainedNodes().size() > 0 )
  91. {
  92. inside = true;
  93. boolean breakpoint = false;
  94. if( !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).isSelected() )
  95. breakpoint |= !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( true );
  96. switch( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).forwardStep() )
  97. {
  98. case BREAKPOINT:
  99. return StageStatus.BREAKPOINT;
  100. case UNFINISHED:
  101. if( breakpoint )
  102. return StageStatus.BREAKPOINT;
  103. return StageStatus.UNFINISHED;
  104. case FINISHED:
  105. inside = false;
  106. subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( false );
  107. break;
  108. }
  109. }
  110. ArrayList< LayeredGraphEdge > incommingEdges = null;
  111. if( layout == LayoutType.TOP_BOTTOM_LEFT || layout == LayoutType.TOP_BOTTOM_RIGHT )
  112. incommingEdges = current.getSortedIncomingEdges();
  113. if( layout == LayoutType.BOTTOM_TOP_LEFT || layout == LayoutType.BOTTOM_TOP_RIGHT )
  114. incommingEdges = current.getSortedOutgoingEdges();
  115. if( layout == LayoutType.TOP_BOTTOM_RIGHT || layout == LayoutType.BOTTOM_TOP_RIGHT )
  116. Collections.reverse( incommingEdges );
  117. if( incommingEdges.size() == 0 )
  118. {
  119. backwards.add( 0, () -> {
  120. System.out.println( "Performing Empty Backwards Step..." );
  121. });
  122. return calcNextState();
  123. }
  124. int[] ms = {(incommingEdges.size() + 1) / 2, (int)( (incommingEdges.size() + 1) / 2.0 + 0.5 )};
  125. boolean backwardsAdded = false;
  126. for( int m : ms )
  127. {
  128. if( current.getAlign( layout ) == current )
  129. {
  130. LayeredGraphNode u = null;
  131. if( layout == LayoutType.TOP_BOTTOM_LEFT || layout == LayoutType.TOP_BOTTOM_RIGHT )
  132. u = incommingEdges.get( m - 1 ).getSources().get( 0 );
  133. if( layout == LayoutType.BOTTOM_TOP_LEFT || layout == LayoutType.BOTTOM_TOP_RIGHT )
  134. u = incommingEdges.get( m - 1 ).getTargets().get( 0 );
  135. ArrayList<LayeredGraphEdge> conflicts = incommingEdges.get( m - 1 ).calcEdgeCrossings();
  136. if( !incommingEdges.get( m - 1 ).isConflicted( layout ) && r < calcBeforeLayerNodeIndex( graph.getContainedLayers().get( calcBeforeLayerIndex() ).indexOf( u ) ) + 1 )
  137. {
  138. System.out.println( "" );
  139. ArrayList< Boolean > oldConflicts = new ArrayList<>();
  140. for( LayeredGraphEdge e : conflicts )
  141. {
  142. oldConflicts.add( e.isConflicted( layout ) );
  143. e.setConflicted( true, layout );
  144. }
  145. LayeredGraphNode oldAlignU = u.getAlign( layout );
  146. Color oldColorCurrent = current.getColor( layout );
  147. LayeredGraphNode oldRootCurrent = current.getRoot( layout );
  148. LayeredGraphNode oldAlignCurrent = current.getAlign( layout );
  149. int oldR = r;
  150. u.setAlign( current, layout );
  151. current.setColor( u.getRoot( layout ).getColor( layout ), layout );
  152. current.setRoot( u.getRoot( layout ), layout );
  153. current.setAlign( current.getRoot( layout ), layout );
  154. r = calcBeforeLayerNodeIndex( graph.getContainedLayers().get( calcBeforeLayerIndex() ).indexOf( u ) ) + 1;
  155. int oldStep = step++;
  156. final LayeredGraphNode uf = u;
  157. backwards.add( 0, () -> {
  158. System.out.println( "Stepping Backwards... (Step " + oldStep + ")" );
  159. for( int i = 0; i < conflicts.size(); i++ )
  160. conflicts.get( i ).setConflicted( oldConflicts.get( i ), layout );
  161. uf.setAlign( oldAlignU, layout );
  162. current.setColor( oldColorCurrent, layout );
  163. current.setRoot( oldRootCurrent, layout );
  164. current.setAlign( oldAlignCurrent, layout );
  165. r = oldR;
  166. });
  167. backwardsAdded = true;
  168. }
  169. }
  170. }
  171. if( !backwardsAdded )
  172. {
  173. backwards.add( 0, () -> {
  174. System.out.println( "Performing Empty Backwards Step..." );
  175. });
  176. }
  177. //current.update();
  178. return calcNextState();
  179. }
  180. private StageStatus calcNextState()
  181. {
  182. boolean breakpoint = !loopNode.setSelected( true );
  183. if( layerIndex >= graph.getContainedLayers().size() - 1 )
  184. {
  185. if( nodeIndex >= graph.getContainedLayers().get( calcLayerIndex() ).size() -1 )
  186. {
  187. loopNode.setSelected( false );
  188. return StageStatus.FINISHED;
  189. }
  190. }
  191. nodeIndex++;
  192. if( nodeIndex >= graph.getContainedLayers().get( calcLayerIndex() ).size() )
  193. {
  194. layerIndex++;
  195. nodeIndex = 0;
  196. int oldR = r;
  197. r = 0;
  198. backwards.add(0, ()->{
  199. this.r = oldR;
  200. });
  201. }
  202. if( breakpoint )
  203. return StageStatus.BREAKPOINT;
  204. return StageStatus.UNFINISHED;
  205. }
  206. @Override
  207. public StageStatus backwardStep() {
  208. if( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ) != null )
  209. {
  210. inside = true;
  211. boolean breakpoint = false;
  212. if( !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).isSelected() )
  213. breakpoint |= !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( true );
  214. switch( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).backwardStep() )
  215. {
  216. case BREAKPOINT:
  217. return StageStatus.BREAKPOINT;
  218. case UNFINISHED:
  219. LayeredGraphNode current = graph.getContainedLayers().get( calcLayerIndex() ).get( nodeIndex );
  220. current.setSelected( layout );
  221. if( breakpoint )
  222. return StageStatus.BREAKPOINT;
  223. return StageStatus.UNFINISHED;
  224. case FINISHED:
  225. inside = false;
  226. subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( false );
  227. break;
  228. }
  229. }
  230. StageStatus status = calcBeforeState();
  231. if( status == StageStatus.FINISHED )
  232. return status;
  233. LayeredGraphNode current = graph.getContainedLayers().get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) );
  234. current.setSelected( layout );
  235. //current.update();
  236. if( !backwards.isEmpty() )
  237. {
  238. backwards.get( 0 ).reverse();
  239. backwards.remove( 0 );
  240. }
  241. return status;
  242. }
  243. private StageStatus calcBeforeState()
  244. {
  245. boolean breakpoint = !loopNode.setSelected( true );
  246. if( layerIndex == 0 )
  247. {
  248. if( nodeIndex == 0 )
  249. {
  250. loopNode.setSelected( false );
  251. return StageStatus.FINISHED;
  252. }
  253. }
  254. nodeIndex--;
  255. if( nodeIndex < 0 )
  256. {
  257. layerIndex--;
  258. backwards.get( 0 ).reverse();
  259. backwards.remove( 0 );
  260. nodeIndex = graph.getContainedLayers().get( calcLayerIndex() ).size() - 1;
  261. }
  262. if( breakpoint )
  263. return StageStatus.BREAKPOINT;
  264. return StageStatus.UNFINISHED;
  265. }
  266. @Override
  267. public PseudoCodeNode createPseudocodeTree( JTree tree ) {
  268. PseudoCodeNode root = new PseudoCodeNode( "Vertical alignment", tree );
  269. loopNode = new PseudoCodeNode( "Loop through all nodes...", tree );
  270. do {
  271. LayeredGraphNode current = graph.getContainedLayers().get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) );
  272. if( current.getContainedNodes().size() > 0 )
  273. {
  274. ExtremalLayoutCalc extcalc = new ExtremalLayoutCalc( layout, current );
  275. PseudoCodeNode subNode = extcalc.createPseudocodeTree( loopNode.getTree() );
  276. loopNode.add( subNode );
  277. subgraphAlgs.get( calcLayerIndex() ).set( calcNodeIndex( nodeIndex ), extcalc );
  278. subgraphNodes.get( calcLayerIndex() ).set( calcNodeIndex( nodeIndex ), subNode );
  279. }
  280. } while( calcNextState() != StageStatus.FINISHED );
  281. layerIndex = 0;
  282. nodeIndex = 0;
  283. backwards.clear();
  284. root.add( loopNode );
  285. return root;
  286. }
  287. @Override
  288. public StageStatus forwardStepOver() {
  289. if( !inside )
  290. return forwardStep();
  291. else
  292. {
  293. boolean breakpoint = false;
  294. if( !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).isSelected() )
  295. breakpoint |= !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( true );
  296. switch( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).forwardStepOver() )
  297. {
  298. case BREAKPOINT:
  299. return StageStatus.BREAKPOINT;
  300. case UNFINISHED:
  301. if( breakpoint )
  302. return StageStatus.BREAKPOINT;
  303. return StageStatus.UNFINISHED;
  304. case FINISHED:
  305. inside = false;
  306. subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( false );
  307. break;
  308. }
  309. return StageStatus.UNFINISHED;
  310. }
  311. }
  312. @Override
  313. public StageStatus forwardStepOut() {
  314. if( !inside )
  315. {
  316. StageStatus status = StageStatus.UNFINISHED;
  317. while( status == StageStatus.UNFINISHED )
  318. status = forwardStep();
  319. return status;
  320. }
  321. else
  322. {
  323. boolean breakpoint = false;
  324. if( !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).isSelected() )
  325. breakpoint |= !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( true );
  326. switch( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).forwardStepOut() )
  327. {
  328. case BREAKPOINT:
  329. return StageStatus.BREAKPOINT;
  330. case UNFINISHED:
  331. if( breakpoint )
  332. return StageStatus.BREAKPOINT;
  333. return StageStatus.UNFINISHED;
  334. case FINISHED:
  335. inside = false;
  336. subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( false );
  337. break;
  338. }
  339. return StageStatus.UNFINISHED;
  340. }
  341. }
  342. @Override
  343. public StageStatus backwardStepOver() {
  344. if( !inside )
  345. return backwardStep();
  346. else
  347. {
  348. boolean breakpoint = false;
  349. if( !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).isSelected() )
  350. breakpoint |= !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( true );
  351. switch( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).backwardStepOver() )
  352. {
  353. case BREAKPOINT:
  354. return StageStatus.BREAKPOINT;
  355. case UNFINISHED:
  356. LayeredGraphNode current = graph.getContainedLayers().get( calcLayerIndex() ).get( nodeIndex );
  357. current.setSelected( layout );
  358. if( breakpoint )
  359. return StageStatus.BREAKPOINT;
  360. return StageStatus.UNFINISHED;
  361. case FINISHED:
  362. inside = false;
  363. subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( false );
  364. break;
  365. }
  366. return StageStatus.UNFINISHED;
  367. }
  368. }
  369. @Override
  370. public StageStatus backwardStepOut() {
  371. if( !inside )
  372. {
  373. StageStatus status = StageStatus.UNFINISHED;
  374. while( status == StageStatus.UNFINISHED )
  375. status = backwardStep();
  376. return status;
  377. }
  378. else
  379. {
  380. boolean breakpoint = false;
  381. if( !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).isSelected() )
  382. breakpoint |= !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( true );
  383. switch( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).backwardStepOut() )
  384. {
  385. case BREAKPOINT:
  386. return StageStatus.BREAKPOINT;
  387. case UNFINISHED:
  388. LayeredGraphNode current = graph.getContainedLayers().get( calcLayerIndex() ).get( nodeIndex );
  389. current.setSelected( layout );
  390. if( breakpoint )
  391. return StageStatus.BREAKPOINT;
  392. return StageStatus.UNFINISHED;
  393. case FINISHED:
  394. inside = false;
  395. subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( false );
  396. break;
  397. }
  398. return StageStatus.UNFINISHED;
  399. }
  400. }
  401. }