c# - 绘制有向无环图 : Minimizing edge crossing?

标签 c# wpf algorithm graph graph-drawing

如果没有像 Efficient Sugiyama 这样的图形绘制算法,以树形式布置 DAG 中的顶点(即顶部没有内边的顶点,仅依赖于下一层的顶点等)是相当简单的。但是,是否有一种简单的算法可以最大限度地减少边缘交叉? (对于某些图,可能无法完全消除边缘交叉。)一张图说一千个字,那么有没有一种算法会建议 something without crossing edges . (compared to this)。

编辑:结果

我已经接受了 Senthil 的建议 graphviz/dot —— 快速浏览一下文档确认这很容易 use it as a library or external tool , 和 the output format is surprisingly easy to parse .但是,我最终选择使用 GraphSharp相反,因为我已经在使用 .NET 等(尽管它绝对不如点强大)。结果“足够好”,并且可以通过一些边缘路由和调整做得更好(模糊文本是因为 3.5 WPF )。

Automatically layed-out graph http://public.blu.livefilestore.com/y1pEY8I95GtlzcxZzhDMhhKoUyejT_sVVZ4jlsDK2fdl6XAR4WV4-yuSesY6chXokmAZxdJXZ4Bv674TqwpT1-fOg/dag3.gif

这是完整的 C# 代码(这是引用 QuickGraph 或 GraphSharp 的所有代码——是的;就这么简单):

internal static class LayoutManager
{
    private const string ALGORITHM_NAME = "EfficientSugiyama";
    private const bool MINIMIZE_EDGE_LENGTH = true;
    private const double VERTEX_DISTANCE = 25;
    private const double LAYER_DISTANCE = 25;
    private const double MIN_CANVAS_OFFSET = 20;

    public static void doLayout(GraphCanvas canvas)
    {
        // TODO use a background thread
        // TODO add comments
        canvas.IsEnabled = false;
        canvas.Cursor = Cursors.Wait;
        var graph = new BidirectionalGraph<GraphNode, LayoutEdge>();
        var positions = new Dictionary<GraphNode, Point>();
        var sizes = new Dictionary<GraphNode, Size>();
        foreach(var node in canvas.nodes)
        {
            var size = node.RenderSize;
            graph.AddVertex(node);
            positions.Add(node, new Point(node.left + size.Width / 2, node.top + size.Height / 2));
            sizes.Add(node, size);
        }
        foreach(var edge in canvas.edges)
        {
            graph.AddEdge(new LayoutEdge(edge));
        }

        var context = new LayoutContext<GraphNode, LayoutEdge, BidirectionalGraph<GraphNode, LayoutEdge>>(graph, positions, sizes, LayoutMode.Simple);
        var parameters = new EfficientSugiyamaLayoutParameters();
        parameters.VertexDistance = VERTEX_DISTANCE;
        parameters.MinimizeEdgeLength = MINIMIZE_EDGE_LENGTH;
        parameters.LayerDistance = LAYER_DISTANCE;
        var factory = new StandardLayoutAlgorithmFactory<GraphNode, LayoutEdge, BidirectionalGraph<GraphNode, LayoutEdge>>();
        var algorithm = factory.CreateAlgorithm(ALGORITHM_NAME, context, parameters);
        algorithm.Compute();
        canvas.deselectAll();

        var minx = algorithm.VertexPositions.Select(kvp => kvp.Value.X - (kvp.Key.RenderSize.Width / 2)).Aggregate(Math.Min);
        var miny = algorithm.VertexPositions.Select(kvp => kvp.Value.Y - (kvp.Key.RenderSize.Height / 2)).Aggregate(Math.Min);
        minx -= MIN_CANVAS_OFFSET;
        miny -= MIN_CANVAS_OFFSET;
        minx = minx < 0 ? -minx : 0;
        miny = miny < 0 ? -miny : 0;
        foreach(var kvp in algorithm.VertexPositions)
        {
            var node = kvp.Key;
            var pos = kvp.Value;
            node.left = (pos.X - (node.RenderSize.Width / 2)) + minx;
            node.top = (pos.Y - (node.RenderSize.Height / 2)) + miny;
        }
        canvas.Cursor = Cursors.Arrow;
        canvas.IsEnabled = true;
    }

    private sealed class LayoutEdge : IEdge<GraphNode>
    {
        private readonly ConnectingEdge _edge;
        public LayoutEdge(ConnectingEdge edge) { _edge = edge; }
        public GraphNode Source { get { return _edge.output.node; } }
        public GraphNode Target { get { return _edge.input.node; } }
    }

最佳答案

Dot 似乎符合要求:

dot - ``hierarchical'' or layered drawings of directed graphs. The layout algorithm aims edges in the same direction (top to bottom, or left to right) and then attempts to avoid edge crossings and reduce edge length.

https://docs.google.com/viewer?url=http://www.graphviz.org/pdf/dotguide.pdf

关于c# - 绘制有向无环图 : Minimizing edge crossing?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2853093/

相关文章:

c# - 在 C# 接口(interface)应用程序之间通信并注入(inject)到另一个进程 dll

WPF对角线拖放

c# - 样式化 WPF - 代码中的 Material Design GroupBox

c# - 动态创建点数组

c# - 当我尝试编译用 C# 代码编写的 wpf 应用程序时出现错误

algorithm - 通过连接的组件找到一条路径,其中每个顶点都被恰好访问一次

algorithm - 是否有生成心理随机数的算法?

algorithm - 使用指针 Next 的链表挑战

C# - 在 csproj 文件中使用通配符和添加新文件

c# - 在 SelectSingleNode : Retrieving individual element from XML if it's present 中使用 XPath