拓扑排序无法在有环图上进行,因此如果输入的图不是已经没有环的有向图,则需要找到一组可删除(或可能翻转)的边,以创建无环图(稍后将把它们添加到分层图中,但这将破坏分层并使图形不太美观 :)。由于找到可以删除的最小边集是NP完全问题(非常困难),我认为您必须在这里做一些快捷方式,并不一定要找到最小的边集,而是在合理的时间内完成。
将图形分成层,这里可以进行许多优化,但我建议您保持简单。遍历所有图形的顶点,并每次将没有入边的顶点收集到一个层中。这可能会在某些简单情况下产生类似线条的图形,但它非常适合UML图的情况。
好的图形是具有最小交叉边数的图形(交叉边数),这听起来并不重要,但这个事实对整体图形的外观有很大贡献。决定交叉数量的是每层中边的排列顺序。但同样地,找到最小交叉数或找到最大无交叉边集是NP完全的 :( "因此,通常会采用启发式方法,例如将每个顶点放置在一个位置上,该位置由其前一级邻居的位置的平均值或中位数确定,然后交换相邻对,只要这改善了交叉数量。"
算法的第一步中删除(或翻转)的边将返回到其原始位置。
这样就完成了!您的UML图现在有了漂亮的分层图。
希望我的评论对您有所帮助。
重要更新: 由于您表示您希望“寻求可信和/或官方来源的答案。” 我附上了此处 来自graphviz(dot算法的正式文档),其中“描述了一种用于绘制有向图的四遍算法。第一遍使用网络单纯形算法找到最佳排名分配。第二遍通过迭代启发式方法将顶点顺序设置在等级内,该方法包括一种新颖的权重函数和局部置换以减少交叉。第三遍通过构建和排名辅助图找到节点的最佳坐标。第四遍制作样条线以绘制边缘。该算法能够产生良好的绘图效果并且运行速度快。” http://www.graphviz.org/Documentation/TSE93.pdf
我不是Python程序员,但从功能上来说,我可以给您建议。
您必须知道每个类别中将要包含的行数。
保留类别的级别编号,这将帮助您根据级别号组织类别。
如果您想按顺序显示类(父类在上,子类在下),则应跟踪每个类的“权重”。我所说的权重是指“父级”的数量。
例如,如果B继承自A,则B.weight = 1,A.weight = 0。如果C继承自B,则C.weight = 2。如果将此表示为一行,则类A将打印在第0行,B将打印在第1行,C将打印在第2行。一般来说,所有相同“权重”的类都将打印在同一虚拟行上。
当然,这只是基本思想,如果要支持复杂对象(多重继承等),则定位元素将更加困难。
使用UML-first未开发的真实项目,很可能无法得到良好的结果。这是我们10年前使用第一个java-uml往返工具(TogetherJ)学到的教训。在文本模式下,很容易逃脱代码,使其无法漂亮地绘制。Smalltalk系统的动态基于浏览器的视图比UML工具更有效,可以提供深入了解代码的方式。
对于布局,只需查看电子CAD中完成的所有工作,特别是印刷电路板(PCB)。那里有很好的放置和布线算法。我从未见过自动化的UML工具正确处理大量子类的事情,其中您希望将布局从父代下面的单行类更改为双行,并将低节点移动半个节点。