I suggest drawing the tree linewise. You do this by using some kind of moving "drawing cursor".
You could store an attribute width
for each node which is calculated as follows:
- the
width
of a leave is 1
- the
width
of an inner node is the sum of all childrens' width
s
Then, you draw the root "in the first line" in the middle, which means, you just take root's width
's half.
Then, you generate a grid over the image such that each gridline corresponds to one line resp. one step from left to right and each intersection of grid lines can contain a node and each node has enough space.
Then, you iterate through the childs and while iterating, you accumulate the children's width
s and draw the children "in the next line". To draw currentChild
, you move your drawing cursor currentWidth/2
to the right, draw currentChild
, and move the drawing cursor the remaining currentWidth/2
to the right.
In order to get the nodes in a good order, you might consider a breadth first search.
I hope my explanation is clear, but I think it will be better, if I draw a little picture.
This is our tree (x
are nodes, everything else edges)
+-------x--+-------+
| | |
+-x-+ +-+x+-+ +-x-+
| | | | | | | | |
x x x x x x x x x
So, you calculate the leaf's width
s:
+-------x--+-------+
| | |
+-x-+ +-+x+-+ +-x-+
| | | | | | | | |
1 1 1 1 1 1 1 1 1
Then, bottom up, the width
s as sums of childrens' width
s:
+-------9--+-------+
| | |
+-2-+ +-+4+-+ +-3-+
| | | | | | | | |
1 1 1 1 1 1 1 1 1
So, you start at the root (width
9) and go 4.5 steps to the rigt in the first line.
Then, you move your "drawing cursor" to the second line, "column 0" (go to left).
The first child has width
2, so we go 2/2=1
grid lines to the right and draw the node and move the drawing cursor the remaining 1 grid lines to the right in order to finish the node. So, the next node has width
4, which means, that we go right 4/2=2 grid lines, draw, go the remaining 2 steps, and so on.
And so on with the next line. At the end (or in intermediate steps), connect the nodes.
This procedure ensures that there are no overlapping nodes (if grid lines are far enough from each other), but it might lead to quite large tree diagrams that could use the space more efficiently.
In order to detect unused space, one might just scan the lines after the above process and look if there are unused grid line intersections and then possibly realign some nodes in order to fill space.