Skip to content

Commit

Permalink
Decouple loading the JUngraph dependency from loading the SVG class.
Browse files Browse the repository at this point in the history
Prevents a `NoClassDefFoundError` when referencing a `CommunityModules`
release that does *not* include its dependencies (i.e., the version
without the `-deps.jar` suffix).

[Refactor]

Signed-off-by: Markus Alexander Kuppe <[email protected]>
  • Loading branch information
lemmy committed Dec 19, 2024
1 parent 1531742 commit e43de9c
Showing 1 changed file with 62 additions and 68 deletions.
130 changes: 62 additions & 68 deletions modules/tlc2/overrides/SVG.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,6 @@
import java.util.Map;
import java.util.stream.Collectors;

import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultGraphType;
import org.jgrapht.graph.builder.GraphTypeBuilder;
import org.jgrapht.util.SupplierUtil;
import org.jungrapht.visualization.layout.algorithms.EiglspergerLayoutAlgorithm;
import org.jungrapht.visualization.layout.algorithms.LayoutAlgorithm;
import org.jungrapht.visualization.layout.algorithms.SugiyamaLayoutAlgorithm;
import org.jungrapht.visualization.layout.algorithms.TreeLayoutAlgorithm;
import org.jungrapht.visualization.layout.algorithms.sugiyama.Layering;
import org.jungrapht.visualization.layout.model.LayoutModel;
import org.jungrapht.visualization.layout.model.Point;
import org.jungrapht.visualization.layout.model.Rectangle;

import tlc2.tool.EvalControl;
import tlc2.value.impl.FcnLambdaValue;
import tlc2.value.impl.FcnRcdValue;
Expand Down Expand Up @@ -180,65 +167,72 @@ public static Value directedMultiGraph(final Value n, final Value e, final Value
final SetEnumValue edges = (SetEnumValue) e.toSetEnum();
final RecordValue opts = (RecordValue) o.toRcd();

// https://jgrapht.org/guide/UserOverview#graph-structures
final Graph<Value, Integer> graph = GraphTypeBuilder
.<Value, Integer>forGraphType(DefaultGraphType.directedMultigraph())
.edgeSupplier(SupplierUtil.createIntegerSupplier()).allowingSelfLoops(false).buildGraph();

ValueVec elems = nodes.elems;
for (int i = 0; i < elems.size(); i++) {
graph.addVertex(elems.elementAt(i));
}
elems = edges.elems;
for (int i = 0; i < elems.size(); i++) {
TupleValue tuple = (TupleValue) elems.elementAt(i);
graph.addEdge(tuple.elems[0], tuple.elems[1]);
}

// Layout
final IntValue viewH = (IntValue) opts.apply(new StringValue("view_width"), EvalControl.Clear);
final IntValue viewW = (IntValue) opts.apply(new StringValue("view_height"), EvalControl.Clear);
final LayoutModel<Value> layoutModel = LayoutModel.<Value>builder().size(viewW.val, viewH.val).graph(graph)
.build();

// Algorithm
final StringValue algo = (StringValue) opts.apply(new StringValue("algo"), EvalControl.Clear);
getAlgo(algo.val.toString(), opts).visit(layoutModel);

// Get the node's coordinates from the algorithm.
final Map <Value, Point> locations = layoutModel.getLocations();

// convert to TLC values.
return new FcnRcdValue(locations.entrySet().stream()
.collect(Collectors.toMap(entry -> entry.getKey(), entry -> point2Value(entry.getValue()))));
return JUngraph.toGraph(nodes, edges, opts);
}

private static class JUngraph {

private static Value toGraph(final SetEnumValue nodes, final SetEnumValue edges, final RecordValue opts) {
// https://jgrapht.org/guide/UserOverview#graph-structures
final org.jgrapht.Graph<Value, Integer> graph = org.jgrapht.graph.builder.GraphTypeBuilder
.<Value, Integer>forGraphType(org.jgrapht.graph.DefaultGraphType.directedMultigraph())
.edgeSupplier(org.jgrapht.util.SupplierUtil.createIntegerSupplier()).allowingSelfLoops(false).buildGraph();

ValueVec elems = nodes.elems;
for (int i = 0; i < elems.size(); i++) {
graph.addVertex(elems.elementAt(i));
}
elems = edges.elems;
for (int i = 0; i < elems.size(); i++) {
TupleValue tuple = (TupleValue) elems.elementAt(i);
graph.addEdge(tuple.elems[0], tuple.elems[1]);
}

// Layout
final IntValue viewH = (IntValue) opts.apply(new StringValue("view_width"), EvalControl.Clear);
final IntValue viewW = (IntValue) opts.apply(new StringValue("view_height"), EvalControl.Clear);
final org.jungrapht.visualization.layout.model.LayoutModel<Value> layoutModel = org.jungrapht.visualization.layout.model.LayoutModel.<Value>builder().size(viewW.val, viewH.val).graph(graph)
.build();

private static Value point2Value(final Point p) {
final int x = ((Double) p.x).intValue();
final int y = ((Double) p.y).intValue();
return new RecordValue(new UniqueString[] { UniqueString.of("x"), UniqueString.of("y") },
new Value[] { IntValue.gen(x), IntValue.gen(y) }, false);
}
// Algorithm
final StringValue algo = (StringValue) opts.apply(new StringValue("algo"), EvalControl.Clear);
JUngraph.getAlgo(algo.val.toString(), opts).visit(layoutModel);

// Get the node's coordinates from the algorithm.
final Map <Value, org.jungrapht.visualization.layout.model.Point> locations = layoutModel.getLocations();

// convert to TLC values.
return new FcnRcdValue(locations.entrySet().stream()
.collect(Collectors.toMap(entry -> entry.getKey(), entry -> JUngraph.point2Value(entry.getValue()))));
}

private static LayoutAlgorithm<Value> getAlgo(final String algo, final RecordValue opts) {
final IntValue nodeH = (IntValue) opts.apply(new StringValue("node_width"), EvalControl.Clear);
final IntValue nodeW = (IntValue) opts.apply(new StringValue("node_height"), EvalControl.Clear);
private static Value point2Value(final org.jungrapht.visualization.layout.model.Point p) {
final int x = ((Double) p.x).intValue();
final int y = ((Double) p.y).intValue();
return new RecordValue(new UniqueString[] { UniqueString.of("x"), UniqueString.of("y") },
new Value[] { IntValue.gen(x), IntValue.gen(y) }, false);
}

switch (algo) {
case "Sugiyama":
// https://github.com/tomnelson/jungrapht-visualization/blob/afd155bf0246e5185f054ba1429bbcfbd429292a/jungrapht-layout/src/main/java/org/jungrapht/visualization/layout/algorithms/sugiyama/Layering.java#L4-L7
String l = ((StringValue) opts.apply(new StringValue("layering"), EvalControl.Clear)).val.toString();
return SugiyamaLayoutAlgorithm.<Value, Integer>edgeAwareBuilder()
.layering(Layering.valueOf(l)).vertexBoundsFunction(v -> Rectangle.of(-5, -5, nodeW.val, nodeH.val)).threaded(false)
.build();
case "Eiglsperger":
l = ((StringValue) opts.apply(new StringValue("layering"), EvalControl.Clear)).val.toString();
return EiglspergerLayoutAlgorithm.<Value, Integer>edgeAwareBuilder()
.layering(Layering.valueOf(l)).vertexBoundsFunction(v -> Rectangle.of(-5, -5, nodeW.val, nodeH.val)).threaded(false)
.build();
default:
return TreeLayoutAlgorithm.<Value>builder()
.vertexBoundsFunction(v -> Rectangle.of(-5, -5, nodeW.val, nodeH.val)).build();
private static org.jungrapht.visualization.layout.algorithms.LayoutAlgorithm<Value> getAlgo(final String algo, final RecordValue opts) {
final IntValue nodeH = (IntValue) opts.apply(new StringValue("node_width"), EvalControl.Clear);
final IntValue nodeW = (IntValue) opts.apply(new StringValue("node_height"), EvalControl.Clear);

switch (algo) {
case "Sugiyama":
// https://github.com/tomnelson/jungrapht-visualization/blob/afd155bf0246e5185f054ba1429bbcfbd429292a/jungrapht-layout/src/main/java/org/jungrapht/visualization/layout/algorithms/sugiyama/Layering.java#L4-L7
String l = ((StringValue) opts.apply(new StringValue("layering"), EvalControl.Clear)).val.toString();
return org.jungrapht.visualization.layout.algorithms.SugiyamaLayoutAlgorithm.<Value, Integer>edgeAwareBuilder()
.layering(org.jungrapht.visualization.layout.algorithms.sugiyama.Layering.valueOf(l)).vertexBoundsFunction(v -> org.jungrapht.visualization.layout.model.Rectangle.of(-5, -5, nodeW.val, nodeH.val)).threaded(false)
.build();
case "Eiglsperger":
l = ((StringValue) opts.apply(new StringValue("layering"), EvalControl.Clear)).val.toString();
return org.jungrapht.visualization.layout.algorithms.EiglspergerLayoutAlgorithm.<Value, Integer>edgeAwareBuilder()
.layering(org.jungrapht.visualization.layout.algorithms.sugiyama.Layering.valueOf(l)).vertexBoundsFunction(v -> org.jungrapht.visualization.layout.model.Rectangle.of(-5, -5, nodeW.val, nodeH.val)).threaded(false)
.build();
default:
return org.jungrapht.visualization.layout.algorithms.TreeLayoutAlgorithm.<Value>builder()
.vertexBoundsFunction(v -> org.jungrapht.visualization.layout.model.Rectangle.of(-5, -5, nodeW.val, nodeH.val)).build();
}
}
}

Expand Down

0 comments on commit e43de9c

Please sign in to comment.