From e43de9c902a1d84744509592d9380c4bd9335751 Mon Sep 17 00:00:00 2001 From: Markus Alexander Kuppe Date: Wed, 18 Dec 2024 16:56:42 -0800 Subject: [PATCH] Decouple loading the JUngraph dependency from loading the SVG class. 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 --- modules/tlc2/overrides/SVG.java | 130 +++++++++++++++----------------- 1 file changed, 62 insertions(+), 68 deletions(-) diff --git a/modules/tlc2/overrides/SVG.java b/modules/tlc2/overrides/SVG.java index a0f8d3c..8fad665 100644 --- a/modules/tlc2/overrides/SVG.java +++ b/modules/tlc2/overrides/SVG.java @@ -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; @@ -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 graph = GraphTypeBuilder - .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 layoutModel = LayoutModel.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 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 graph = org.jgrapht.graph.builder.GraphTypeBuilder + .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 layoutModel = org.jungrapht.visualization.layout.model.LayoutModel.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 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 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.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.edgeAwareBuilder() - .layering(Layering.valueOf(l)).vertexBoundsFunction(v -> Rectangle.of(-5, -5, nodeW.val, nodeH.val)).threaded(false) - .build(); - default: - return TreeLayoutAlgorithm.builder() - .vertexBoundsFunction(v -> Rectangle.of(-5, -5, nodeW.val, nodeH.val)).build(); + private static org.jungrapht.visualization.layout.algorithms.LayoutAlgorithm 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.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.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.builder() + .vertexBoundsFunction(v -> org.jungrapht.visualization.layout.model.Rectangle.of(-5, -5, nodeW.val, nodeH.val)).build(); + } } }