I found the articles listed in jwpat7's answer to be very useful, although it took me a while to figure out the exact logic needed for this algorithm, so I wrote my own blog post to simplify the explanation.
Here's the plain-text logic of how you determine the X node positions:
Start with a post-order traversal of the tree
Assign an initial X value to each node of 0 if it's the first in a set, or previousSibling + 1
if it's not.
If a node has children, find the desired X value that would center it over its children.
If the node is the left-most node, set its X to that value
If the node is not the left-most node, set a Mod
property on the node to (X - centeredX)
in order to shift all children so they're centered under this node. The last traversal of the tree will use this Mod
property to determine the final X value of each node.
Determine if any of this node's children would overlap any children of siblings to the left of this node. Basically for each Y, get the largest and smallest X from the two nodes, and compare them.
If any collisions occur, shift the node over by however much needed. Shifting a subtree just requires adding to the X
and Mod
properties of the node.
If node was shifted, also shift any nodes between the two subtrees that were overlapping so they are equally spaced out
Do a check to ensure that when the final X is calculated, there is no negative X values. If any are found, add the largest one to the Root Node's X
and Mod
properites to shift the entire tree over
Do a second traversal of the tree using pre-order traversal and add the sum of the Mod
values from each of a node's parents to it's X
property
The final X values of the tree above would look like this:
I have some more details and some sample code in my blog post, but it's too long to include everything here, and I wanted to focus on the logic of the algorithm instead of code specifics.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…