Space around disconnected nodes in MSAGL (WinForms)

297 views Asked by At

I'm trying to enforce a minimum distance between un-connected nodes in MSAGL (WinForms), version 1.1.3. The user creates a graph from scratch. This involves creating nodes, and dragging between nodes to create edges. But all nodes that don't have any edges stick to others like polystyrene balls to a wool jumper.

un-connected nodes - no distance from other nodes

I want all nodes, with or without edges, to have a minimum spacing. There's probably a simple answer to this, which so far eludes me. After searching for relevant material on GitHub, here and on Google, I've tried without success:

LayoutAlgorithmSettings.NodeSeparation = 200; //works well between nodes that have edges between
LayoutAlgorithmSettings.ClusterMargin = 200;
LayoutAlgorithmSettings.PackingMethod = Microsoft.Msagl.Core.Layout.PackingMethod.Columns;
LayoutAlgorithmSettings.PackingAspectRatio = 2;
LayoutAlgorithmSettings.EdgeRoutingSettings.Padding = 100;

Here is the graph generating code (some declarations and other details omitted). I'm using MDS layout:

Graph graph = new Microsoft.Msagl.Drawing.Graph("graph");

graph.LayoutAlgorithmSettings = new Microsoft.Msagl.Layout.MDS.MdsLayoutSettings();
            
//add steps
foreach (Step step in config.Steps)
{
    Node node = new Node(step.Name);
    node.UserData = step;
    UpdateNodeColour(node);
    graph.AddNode(node);
}
                
//add transitions (edges)
foreach(Transition t in config.Transitions)
    graph.AddEdge(t.FromStep.Name, t.Name, t.ToStep.Name);

gViewer.Graph = graph;

BTW - MSAGL is fantastic! Such a great tool for visualizing and editing state machines.

1

There are 1 answers

0
PushPeekPop On

I had the same overlap issue. I solved the problem using the below.

Once you have populated your graph, add the node separation using GeometryGraph via Microsoft.Msagl.Core.Layout.GraphConnectedComponents.CreateComponents():

if (graph.NodeCount > 1)
{
    GeometryGraph geomGraph = graph.GeometryGraph;
    IEnumerable< GeometryGraph> geomGraphComponents =
        GraphConnectedComponents.CreateComponents(geomGraph.Nodes, geomGraph.Edges);

    SugiyamaLayoutSettings settings = new SugiyamaLayoutSettings();
    foreach (GeometryGraph subgraph in geomGraphComponents)
    {
        LayeredLayout layout = new LayeredLayout(subgraph, settings);
        subgraph.Margins = settings.NodeSeparation / 2;
        layout.Run();
    }
    
    MdsGraphLayout.PackGraphs(geomGraphComponents, settings);
    geomGraph.UpdateBoundingBox();
}

See Example #1 in LayeredLayout.Run Examples:

https://csharp.hotexamples.com/examples/Microsoft.Msagl.Layout.Layered/LayeredLayout/Run/php-layeredlayout-run-method-examples.html

Note: From the source example don't set 'gViewer1.NeedToCalculateLayout = false;' if you intend to refresh your graph.