Is it possible to force edge lines to be drawn from the node's four cardinal border midpoints? i.e. the twelve o'clock, three o'clock, six o'clock, and nine o'clock locations on the node border, akin to connectors in Visio or PowerPoint.

Sketch of desired output

1

There are 1 answers

1
amonroejj On BEST ANSWER

I emailed the primary MSAGL author Lev Nachmanson, and he was kind enough to reply. He confirmed that as of January 2022, MSAGL currently has no such feature.

EDIT 1: MSAGL has FloatingPort objects that seem like they would lend themselves to manually positioning the endpoints of edge lines: Edge objects have SourcePort and TargetPort properties. I have yet to find any documentation or tutorials on how to make practical use of these. Any pointers appreciated.

EDIT 2: It can be done by calculating the layout once, then post-layout, forcing an EdgeRouter to reroute all the edges in a foreach loop.

I took a heavy dose of inspiration from Routing only edges with MSAGL and https://github.com/microsoft/automatic-graph-layout/issues/250 and a lot of trial and error.

private void Button1_Click(object sender, EventArgs e)
{
    //gViewer1.Invalidate();
    gViewer1.CalculateLayout(_visgraph);
    
    Microsoft.Msagl.Routing.InteractiveEdgeRouter edgeRouter = new Microsoft.Msagl.Routing.InteractiveEdgeRouter(_visgraph.GeometryGraph.Nodes.Select(n => n.BoundaryCurve), 3, 0.65 * 3, 0);
    edgeRouter.Run();

    Microsoft.Msagl.Core.Geometry.SmoothedPolyline ignore;
    foreach (var edge in _visgraph.GeometryGraph.Edges)
    {
        Microsoft.Msagl.Core.Layout.FloatingPort p1 = 
            new Microsoft.Msagl.Core.Layout.FloatingPort(edge.Source.BoundaryCurve
                                                        , new Microsoft.Msagl.Core.Geometry.Point(edge.Source.BoundingBox.Right
                                                                                                 ,edge.Source.BoundingBox.Center.Y));
        Microsoft.Msagl.Core.Layout.FloatingPort p2 = 
            new Microsoft.Msagl.Core.Layout.FloatingPort(edge.Target.BoundaryCurve
                                                        , new Microsoft.Msagl.Core.Geometry.Point(edge.Target.BoundingBox.Left
                                                                                                 ,edge.Target.BoundingBox.Center.Y));

        edge.SourcePort = p1;
        edge.TargetPort = p2;
        edge.Curve = edgeRouter.RouteSplineFromPortToPortWhenTheWholeGraphIsReady(edge.SourcePort, edge.TargetPort, true, out ignore);

        Microsoft.Msagl.Core.Layout.Arrowheads.TrimSplineAndCalculateArrowheads(edge
                                                                               ,edge.Curve
                                                                               ,true
                                                                               ,true);
    }
}

enter image description here