3232import org .jgrapht .graph .DefaultGraphType ;
3333import org .jgrapht .graph .builder .GraphTypeBuilder ;
3434import org .jgrapht .util .SupplierUtil ;
35+ import org .jungrapht .visualization .layout .algorithms .EiglspergerLayoutAlgorithm ;
36+ import org .jungrapht .visualization .layout .algorithms .LayoutAlgorithm ;
37+ import org .jungrapht .visualization .layout .algorithms .SugiyamaLayoutAlgorithm ;
3538import org .jungrapht .visualization .layout .algorithms .TreeLayoutAlgorithm ;
39+ import org .jungrapht .visualization .layout .algorithms .sugiyama .Layering ;
3640import org .jungrapht .visualization .layout .model .LayoutModel ;
3741import org .jungrapht .visualization .layout .model .Point ;
3842import org .jungrapht .visualization .layout .model .Rectangle ;
3943
44+ import tlc2 .tool .EvalControl ;
4045import tlc2 .value .impl .FcnRcdValue ;
4146import tlc2 .value .impl .IntValue ;
4247import tlc2 .value .impl .RecordValue ;
@@ -151,11 +156,13 @@ public static Value ringNetwork(IntValue cx, IntValue cy, IntValue r, IntValue n
151156 }
152157
153158 @ TLAPlusOperator (identifier = "NodesOfDirectedMultiGraph" , module = "SVG" , warn = false )
154- public static Value directedMultiGraph (final SetEnumValue nodes , final SetEnumValue edges , final IntValue width , final IntValue height ) throws Exception {
159+ public static Value directedMultiGraph (final SetEnumValue nodes , final SetEnumValue edges , final RecordValue opts )
160+ throws Exception {
155161 // https://jgrapht.org/guide/UserOverview#graph-structures
156- final Graph <Value , Integer > graph = GraphTypeBuilder .<Value , Integer >forGraphType (DefaultGraphType .directedMultigraph ())
162+ final Graph <Value , Integer > graph = GraphTypeBuilder
163+ .<Value , Integer >forGraphType (DefaultGraphType .directedMultigraph ())
157164 .edgeSupplier (SupplierUtil .createIntegerSupplier ()).allowingSelfLoops (false ).buildGraph ();
158-
165+
159166 ValueVec elems = nodes .elems ;
160167 for (int i = 0 ; i < elems .size (); i ++) {
161168 graph .addVertex (elems .elementAt (i ));
@@ -166,22 +173,50 @@ public static Value directedMultiGraph(final SetEnumValue nodes, final SetEnumVa
166173 graph .addEdge (tuple .elems [0 ], tuple .elems [1 ]);
167174 }
168175
169- final LayoutModel <Value > layoutModel = LayoutModel .<Value >builder ().size (1000 , 1000 ).graph (graph ).build ();
170- TreeLayoutAlgorithm <Value > layoutAlgo = TreeLayoutAlgorithm .<Value >builder ()
171- .vertexBoundsFunction (v -> Rectangle .of (-5 , -5 , width .val , height .val )).build ();
172- layoutAlgo .visit (layoutModel );
173- final Map <Value , Point > locations = layoutModel .getLocations ();
176+ // Layout
177+ final IntValue viewH = (IntValue ) opts .apply (new StringValue ("view_width" ), EvalControl .Clear );
178+ final IntValue viewW = (IntValue ) opts .apply (new StringValue ("view_height" ), EvalControl .Clear );
179+ final LayoutModel <Value > layoutModel = LayoutModel .<Value >builder ().size (viewW .val , viewH .val ).graph (graph )
180+ .build ();
181+
182+ // Algorithm
183+ final StringValue algo = (StringValue ) opts .apply (new StringValue ("algo" ), EvalControl .Clear );
184+ getAlgo (algo .val .toString (), opts ).visit (layoutModel );
185+
186+ // Get the node's coordinates from the algorithm.
187+ final Map <Value , Point > locations = layoutModel .getLocations ();
174188
189+ // convert to TLC values.
175190 return new FcnRcdValue (locations .entrySet ().stream ()
176- .collect (Collectors .toMap (
177- entry -> entry .getKey (),
178- entry -> point2Value (entry .getValue ()))));
191+ .collect (Collectors .toMap (entry -> entry .getKey (), entry -> point2Value (entry .getValue ()))));
179192 }
180-
193+
181194 private static Value point2Value (final Point p ) {
182195 final int x = ((Double ) p .x ).intValue ();
183196 final int y = ((Double ) p .y ).intValue ();
184197 return new RecordValue (new UniqueString [] { UniqueString .of ("x" ), UniqueString .of ("y" ) },
185198 new Value [] { IntValue .gen (x ), IntValue .gen (y ) }, false );
186199 }
200+
201+ private static LayoutAlgorithm <Value > getAlgo (final String algo , final RecordValue opts ) {
202+ final IntValue nodeH = (IntValue ) opts .apply (new StringValue ("node_width" ), EvalControl .Clear );
203+ final IntValue nodeW = (IntValue ) opts .apply (new StringValue ("node_height" ), EvalControl .Clear );
204+
205+ switch (algo ) {
206+ case "Sugiyama" :
207+ // https://github.com/tomnelson/jungrapht-visualization/blob/afd155bf0246e5185f054ba1429bbcfbd429292a/jungrapht-layout/src/main/java/org/jungrapht/visualization/layout/algorithms/sugiyama/Layering.java#L4-L7
208+ String l = ((StringValue ) opts .apply (new StringValue ("layering" ), EvalControl .Clear )).val .toString ();
209+ return SugiyamaLayoutAlgorithm .<Value , Integer >edgeAwareBuilder ()
210+ .layering (Layering .valueOf (l )).vertexBoundsFunction (v -> Rectangle .of (-5 , -5 , nodeW .val , nodeH .val )).threaded (false )
211+ .build ();
212+ case "Eiglsperger" :
213+ l = ((StringValue ) opts .apply (new StringValue ("layering" ), EvalControl .Clear )).val .toString ();
214+ return EiglspergerLayoutAlgorithm .<Value , Integer >edgeAwareBuilder ()
215+ .layering (Layering .valueOf (l )).vertexBoundsFunction (v -> Rectangle .of (-5 , -5 , nodeW .val , nodeH .val )).threaded (false )
216+ .build ();
217+ default :
218+ return TreeLayoutAlgorithm .<Value >builder ()
219+ .vertexBoundsFunction (v -> Rectangle .of (-5 , -5 , nodeW .val , nodeH .val )).build ();
220+ }
221+ }
187222}
0 commit comments