|
@@ -1,6 +1,7 @@
|
|
|
package bk;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
+import java.util.Stack;
|
|
|
|
|
|
import javax.swing.JTree;
|
|
|
|
|
@@ -8,134 +9,258 @@ import animation.AlgorithmStage;
|
|
|
import animation.BackwardAction;
|
|
|
import animation.PseudoCodeNode;
|
|
|
import animation.PseudoCodeNode.CodeAction;
|
|
|
+import bk.ExtremalLayoutCalc.LayoutType;
|
|
|
import graph.LayeredGraphEdge;
|
|
|
import graph.LayeredGraphNode;
|
|
|
+import lib.TextLayoutHelper;
|
|
|
|
|
|
+/**
|
|
|
+ * the preprocessing stage of the bk node placement algorithm
|
|
|
+ *
|
|
|
+ * @author kolja and eren
|
|
|
+ *
|
|
|
+ */
|
|
|
public class ConflictDetection implements AlgorithmStage {
|
|
|
|
|
|
private LayeredGraphNode graph;
|
|
|
- private ArrayList< BackwardAction > actions;
|
|
|
-
|
|
|
+ private Stack<BackwardAction> actions;
|
|
|
+
|
|
|
private int i;
|
|
|
private int l1;
|
|
|
+ private int k0;
|
|
|
+ private int k1;
|
|
|
+ private int l;
|
|
|
+ private int k;
|
|
|
+ private int hidden_k;
|
|
|
+ /**
|
|
|
+ * line number in Carstens' pseudocode listing 3.1
|
|
|
+ */
|
|
|
+ private int pseudo_line;
|
|
|
private PseudoCodeNode markNode;
|
|
|
-
|
|
|
- public ConflictDetection( LayeredGraphNode graph )
|
|
|
- {
|
|
|
+
|
|
|
+ public ConflictDetection(LayeredGraphNode graph) {
|
|
|
this.graph = graph;
|
|
|
- actions = new ArrayList<>();
|
|
|
- i = 1;
|
|
|
- l1 = 0;
|
|
|
+ actions = new Stack<>();
|
|
|
+ i = 0; // will be increased before first iteration
|
|
|
+ l1 = -1; // will be increased before first iteration
|
|
|
+ k0 = 0;
|
|
|
+ k1 = 0;
|
|
|
+ l = 0;
|
|
|
+ k = 0;
|
|
|
+ hidden_k = 0;
|
|
|
+ pseudo_line = 1;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
@Override
|
|
|
public StageStatus forwardStep() {
|
|
|
- int oldI = i;
|
|
|
- int oldL1 = l1;
|
|
|
- ((PseudoCodeNode)markNode.getParent()).setSelected( true );
|
|
|
- CodeAction action = markNode.setSelected( true );
|
|
|
- boolean breakPoint = action == CodeAction.STOP;
|
|
|
- if( i + 1 >= graph.getContainedLayers().size() - 1 )
|
|
|
- {
|
|
|
- ((PseudoCodeNode)markNode.getParent()).setSelected( false );
|
|
|
- markNode.setSelected( false );
|
|
|
- return StageStatus.FINISHED;
|
|
|
- }
|
|
|
- LayeredGraphNode curr = graph.getContainedLayers().get( i + 1 ).get( l1 );
|
|
|
- curr.setSelected( null );
|
|
|
- ArrayList< LayeredGraphEdge > edges = curr.getIncomingEdges();
|
|
|
- LayeredGraphEdge dummyEdge = null;
|
|
|
- for( LayeredGraphEdge e : edges )
|
|
|
- {
|
|
|
- if( e.isDummyEdge() )
|
|
|
- {
|
|
|
- dummyEdge = e;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- ArrayList< LayeredGraphEdge > conflicts = new ArrayList<>();
|
|
|
- if( dummyEdge != null )
|
|
|
- {
|
|
|
- for( LayeredGraphEdge e : edges )
|
|
|
- {
|
|
|
- if( e.isDummyEdge() )
|
|
|
- {
|
|
|
- ArrayList< LayeredGraphEdge > conf = e.calcEdgeCrossings();
|
|
|
- for( LayeredGraphEdge ce : conf )
|
|
|
- {
|
|
|
- if( !ce.isDummyEdge() )
|
|
|
- conflicts.add( ce );
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- for( LayeredGraphEdge c : conflicts )
|
|
|
- c.setConflicted( true, null );
|
|
|
- StageStatus status = calcNextStatus();
|
|
|
- actions.add( 0, ()->{
|
|
|
- i = oldI;
|
|
|
- l1 = oldL1;
|
|
|
- if( i + 1 < graph.getContainedLayers().size() - 1 && l1 > 0 )
|
|
|
- {
|
|
|
- LayeredGraphNode layde = graph.getContainedLayers().get( i + 1 ).get( l1 - 1 );
|
|
|
- layde.setSelected( null );
|
|
|
- }
|
|
|
- for( LayeredGraphEdge c : conflicts )
|
|
|
- c.setConflicted( false, null );
|
|
|
- });
|
|
|
- if( status != StageStatus.FINISHED && breakPoint )
|
|
|
- return StageStatus.BREAKPOINT;
|
|
|
- if( action == CodeAction.SKIP && status != StageStatus.FINISHED )
|
|
|
- return forwardStep();
|
|
|
- return status;
|
|
|
- }
|
|
|
-
|
|
|
- private StageStatus calcNextStatus()
|
|
|
- {
|
|
|
- l1++;
|
|
|
- if( l1 >= graph.getContainedLayers().get( i + 1 ).size() )
|
|
|
- {
|
|
|
+ int old_line = pseudo_line;
|
|
|
+ int old_k = k;
|
|
|
+ int old_k0 = k0;
|
|
|
+ int old_k1 = k1;
|
|
|
+ int old_l = l;
|
|
|
+ int old_l1 = l1;
|
|
|
+ int old_hidden_k = hidden_k;
|
|
|
+
|
|
|
+ switch (pseudo_line) {
|
|
|
+ case 1:
|
|
|
i++;
|
|
|
- if( i >= graph.getContainedLayers().size() - 2 )
|
|
|
- {
|
|
|
+ actions.push(() -> {
|
|
|
i--;
|
|
|
- l1--;
|
|
|
- ((PseudoCodeNode)markNode.getParent()).setSelected( false );
|
|
|
- markNode.setSelected( false );
|
|
|
+ pseudo_line = old_line;
|
|
|
+ selectNodes(pseudo_line);
|
|
|
+ });
|
|
|
+ if (i <= graph.getContainedLayers().size() - 2) {
|
|
|
+ pseudo_line++;
|
|
|
+ } else {
|
|
|
return StageStatus.FINISHED;
|
|
|
}
|
|
|
- l1 = 0;
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ k0 = 0;
|
|
|
+ l = 0;
|
|
|
+ l1 = -1; // will be increased before first iteration
|
|
|
+ pseudo_line++;
|
|
|
+ actions.push(() -> {
|
|
|
+ pseudo_line = old_line;
|
|
|
+ k0 = old_k0;
|
|
|
+ l = old_l;
|
|
|
+ l1 = old_l1;
|
|
|
+ selectNodes(pseudo_line);
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ l1++;
|
|
|
+ actions.push(() -> {
|
|
|
+ l1--;
|
|
|
+ pseudo_line = old_line;
|
|
|
+ selectNodes(pseudo_line);
|
|
|
+ });
|
|
|
+ if (l1 < graph.getContainedLayers().get(i + 1).size()) {
|
|
|
+ pseudo_line += 1;
|
|
|
+ } else {
|
|
|
+ pseudo_line = 1;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 4:
|
|
|
+ actions.push(() -> {
|
|
|
+ pseudo_line = old_line;
|
|
|
+ selectNodes(pseudo_line);
|
|
|
+ });
|
|
|
+ if (graph.getContainedLayers().get(i + 1).size() == l1 || incidentToInnerSegmentBetweenLiPlusOneAndLi()) {
|
|
|
+ pseudo_line++;
|
|
|
+ } else {
|
|
|
+ pseudo_line = 3;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 5:
|
|
|
+ actions.push(() -> {
|
|
|
+ k1 = old_k1;
|
|
|
+ pseudo_line = old_line;
|
|
|
+ selectNodes(pseudo_line);
|
|
|
+ });
|
|
|
+ k1 = graph.getContainedLayers().get(i).size() - 1;
|
|
|
+ pseudo_line++;
|
|
|
+ break;
|
|
|
+ case 6:
|
|
|
+ actions.push(() -> {
|
|
|
+ pseudo_line = old_line;
|
|
|
+ selectNodes(pseudo_line);
|
|
|
+ });
|
|
|
+ if (incidentToInnerSegmentBetweenLiPlusOneAndLi()) {
|
|
|
+ pseudo_line++;
|
|
|
+ } else {
|
|
|
+ pseudo_line = 9;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 7:
|
|
|
+ actions.push(() -> {
|
|
|
+ k1 = old_k1;
|
|
|
+ pseudo_line = old_line;
|
|
|
+ selectNodes(pseudo_line);
|
|
|
+ });
|
|
|
+ k1 = graph.getContainedLayers().get(i).indexOf(
|
|
|
+ graph.getContainedLayers().get(i + 1).get(l1).getSortedIncomingEdges().get(0).getSources().get(0));
|
|
|
+ pseudo_line = 9;
|
|
|
+ break;
|
|
|
+ case 9:
|
|
|
+ actions.push(() -> {
|
|
|
+ hidden_k = old_hidden_k;
|
|
|
+ pseudo_line = old_line;
|
|
|
+ selectNodes(pseudo_line);
|
|
|
+ });
|
|
|
+ if (l <= l1) {
|
|
|
+ pseudo_line++;
|
|
|
+ hidden_k = 0; // will not be increased before first iteration
|
|
|
+ k = graph.getContainedLayers().get(i).indexOf(graph.getContainedLayers().get(i + 1).get(l)
|
|
|
+ .getSortedIncomingEdges().get(hidden_k).getSources().get(0));
|
|
|
+ } else {
|
|
|
+ pseudo_line = 15;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 10:
|
|
|
+ actions.push(() -> {
|
|
|
+ k = old_k;
|
|
|
+ pseudo_line = old_line;
|
|
|
+ selectNodes(pseudo_line);
|
|
|
+ });
|
|
|
+ if (hidden_k < graph.getContainedLayers().get(i + 1).get(l).getSortedIncomingEdges().size()) {
|
|
|
+ k = graph.getContainedLayers().get(i).indexOf(graph.getContainedLayers().get(i + 1).get(l)
|
|
|
+ .getSortedIncomingEdges().get(hidden_k).getSources().get(0));
|
|
|
+ pseudo_line++;
|
|
|
+ } else {
|
|
|
+ pseudo_line = 13;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 11:
|
|
|
+ actions.push(() -> {
|
|
|
+ hidden_k--;
|
|
|
+ graph.getContainedLayers().get(i + 1).get(l).getSortedIncomingEdges().get(hidden_k).setConflicted(false,
|
|
|
+ null);
|
|
|
+ pseudo_line = old_line;
|
|
|
+ selectNodes(pseudo_line);
|
|
|
+ });
|
|
|
+ if (k < k0 || k > k1) {
|
|
|
+ graph.getContainedLayers().get(i + 1).get(l).getSortedIncomingEdges().get(hidden_k).setConflicted(true,
|
|
|
+ null);
|
|
|
+ }
|
|
|
+ hidden_k++;
|
|
|
+ pseudo_line = 10;
|
|
|
+ break;
|
|
|
+ case 13:
|
|
|
+ actions.push(() -> {
|
|
|
+ l--;
|
|
|
+ pseudo_line = old_line;
|
|
|
+ selectNodes(pseudo_line);
|
|
|
+ });
|
|
|
+ l++;
|
|
|
+ pseudo_line = 9;
|
|
|
+ break;
|
|
|
+ case 15:
|
|
|
+ actions.push(() -> {
|
|
|
+ k0 = old_k0;
|
|
|
+ pseudo_line = old_line;
|
|
|
+ selectNodes(pseudo_line);
|
|
|
+ });
|
|
|
+ k0 = k1;
|
|
|
+ pseudo_line = 3;
|
|
|
+ break;
|
|
|
}
|
|
|
+
|
|
|
+ selectNodes(pseudo_line);
|
|
|
+
|
|
|
return StageStatus.UNFINISHED;
|
|
|
}
|
|
|
|
|
|
+ private void selectNodes(int next_line) {
|
|
|
+ if (next_line >= 3 && l < graph.getContainedLayers().get(i + 1).size()) {
|
|
|
+ graph.getContainedLayers().get(i + 1).get(l).setSelected(null);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (next_line >= 4) {
|
|
|
+ graph.getContainedLayers().get(i + 1).get(l1).setSelected(null);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (next_line >= 3) {
|
|
|
+ graph.getContainedLayers().get(i).get(k0).setSelected(null);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (next_line >= 6) {
|
|
|
+ graph.getContainedLayers().get(i).get(k1).setSelected(null);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (next_line == 10 || next_line == 11) {
|
|
|
+ graph.getContainedLayers().get(i).get(k).setSelected(null);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public StageStatus backwardStep() {
|
|
|
- ((PseudoCodeNode)markNode.getParent()).setSelected( true );
|
|
|
- CodeAction action = markNode.setSelected( true );
|
|
|
+ ((PseudoCodeNode) markNode.getParent()).setSelected(true);
|
|
|
+ CodeAction action = markNode.setSelected(true);
|
|
|
boolean breakPoint = action == CodeAction.STOP;
|
|
|
- if( actions.size() == 0 )
|
|
|
- {
|
|
|
- ((PseudoCodeNode)markNode.getParent()).setSelected( false );
|
|
|
- markNode.setSelected( false );
|
|
|
+ if (actions.size() == 0) {
|
|
|
+ ((PseudoCodeNode) markNode.getParent()).setSelected(false);
|
|
|
+ markNode.setSelected(false);
|
|
|
return StageStatus.FINISHED;
|
|
|
}
|
|
|
- actions.get( 0 ).reverse();
|
|
|
- actions.remove( 0 );
|
|
|
- if( breakPoint )
|
|
|
+ actions.pop().reverse();
|
|
|
+ if (breakPoint)
|
|
|
return StageStatus.BREAKPOINT;
|
|
|
- if( action == CodeAction.SKIP )
|
|
|
+ if (action == CodeAction.SKIP)
|
|
|
return backwardStep();
|
|
|
return StageStatus.UNFINISHED;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public PseudoCodeNode createPseudocodeTree( JTree tree ) {
|
|
|
- PseudoCodeNode root = new PseudoCodeNode( "Preprocessing (mark type 1 conflicts)", tree );
|
|
|
- PseudoCodeNode loopNode = new PseudoCodeNode( "Loop through all nodes...", tree );
|
|
|
- markNode = new PseudoCodeNode( "If non-inner segment crosses an inner segment whose target is this node, mark the non-inner segment as conflicted", tree );
|
|
|
- loopNode.add( markNode );
|
|
|
- root.add( loopNode );
|
|
|
+ public PseudoCodeNode createPseudocodeTree(JTree tree) {
|
|
|
+ PseudoCodeNode root = new PseudoCodeNode("Preprocessing (mark type 1 conflicts)", tree);
|
|
|
+ PseudoCodeNode loopNode = new PseudoCodeNode("Loop through all nodes...", tree);
|
|
|
+ markNode = new PseudoCodeNode(
|
|
|
+ "If non-inner segment crosses an inner segment whose target is this node, mark the non-inner segment as conflicted",
|
|
|
+ tree);
|
|
|
+ loopNode.add(markNode);
|
|
|
+ root.add(loopNode);
|
|
|
return root;
|
|
|
}
|
|
|
|
|
@@ -147,7 +272,7 @@ public class ConflictDetection implements AlgorithmStage {
|
|
|
@Override
|
|
|
public StageStatus forwardStepOut() {
|
|
|
StageStatus status = StageStatus.UNFINISHED;
|
|
|
- while( status == StageStatus.UNFINISHED )
|
|
|
+ while (status == StageStatus.UNFINISHED)
|
|
|
status = forwardStep();
|
|
|
return status;
|
|
|
}
|
|
@@ -160,14 +285,43 @@ public class ConflictDetection implements AlgorithmStage {
|
|
|
@Override
|
|
|
public StageStatus backwardStepOut() {
|
|
|
StageStatus status = StageStatus.UNFINISHED;
|
|
|
- while( status == StageStatus.UNFINISHED )
|
|
|
+ while (status == StageStatus.UNFINISHED)
|
|
|
status = backwardStep();
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public String getDebugString()
|
|
|
- {
|
|
|
- return "";
|
|
|
+ public String getDebugString() {
|
|
|
+ String info = "| i | l | l1 | k0 | k1 | k |\n";
|
|
|
+ info += "|----|----|----|----|----|----|\n";
|
|
|
+ info += "|" + TextLayoutHelper.strToLen( "" + i, 4 ) +
|
|
|
+ "|" + TextLayoutHelper.strToLen( "" + l, 4 ) +
|
|
|
+ "|" + TextLayoutHelper.strToLen( "" + l1, 4 ) +
|
|
|
+ "|" + TextLayoutHelper.strToLen( "" + k0, 4 ) +
|
|
|
+ "|" + TextLayoutHelper.strToLen( "" + k1, 4 ) +
|
|
|
+ "|" + TextLayoutHelper.strToLen( "" + k, 4 ) + "|\n";
|
|
|
+// if( insideSubgraph && vIndex < graph.getContainedNodes().size() )
|
|
|
+// {
|
|
|
+// info += "Subgraph of " + graph.getContainedNodes().get( vIndex ).getName() + ":\n";
|
|
|
+// String tmp = subgraphAlgs.get( vIndex ).getDebugString();
|
|
|
+// info += tmp;
|
|
|
+// return info;
|
|
|
+// }
|
|
|
+ return info;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * part of line 4 and 6 in the pseudocode
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private boolean incidentToInnerSegmentBetweenLiPlusOneAndLi() {
|
|
|
+ LayeredGraphNode curr = graph.getContainedLayers().get(i + 1).get(l1);
|
|
|
+ for (LayeredGraphEdge e : curr.getIncomingEdges()) {
|
|
|
+ if (e.isDummyEdge()) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
}
|
|
|
}
|