You are right that you are going to intersect. This is because you add / subtract a fixed value in xOffset when you cross the tree. In the example image, this is not actually a fixed offset: rather, it is logarithmic exponentially with respect to its vertical position. The farther you go, the smaller the offset should be.
Replace 30s with A * Math.Log(yOffset)
, where A is some scaling value that you will need to adjust until it looks right.
EDIT : or is it exponential? I can not imagine this stuff too well. Instead, you might want A * Math.Exp(-B * yOffset)
. (Negative is significant: this means that it will decrease as yOffset increases, which is what you want.)
A
will look like your master, a linear scale factor, and B
will control how quickly the bias decreases.
double A = some_number; double B = some_other_number; int offset = (int)(A * Math.Exp(-B * yOffset)); DrawNode(g, node.LeftNode, xOffset - offset , yOffset + 20); DrawNode(g, node.RightNode, xOffset + offset, yOffset + 20);
Update:
double A = 75f; double B = 0.05f; int offset = (int)(A * Math.Exp(-B * (yOffset - 10))); DrawNode(g, node.LeftNode, xOffset - offset, yOffset + 20); DrawNode(g, node.RightNode, xOffset + offset, yOffset + 20);
Called with
DrawNode(e.Graphics, head, this.ClientSize.Width / 2, 10f);
- 10
in Exp is significant: this is the initial yOffset of the head. It produces the following:
If you need precise control of margin / indentation, then be sure to use the dtb method, but I think that 3 extra lines with one formula are as elegant mathematical solutions that you are going to get.
Update 2:
One more thing that I forgot: I use base e = 2.7183
, but you need something closer to 2. Logically you would use exactly 2, but since the nodes have a nonzero width, you might need something a little more like 2.1 . You can change the base by multiplying B
by Math.Log(new_base)
:
double B = 0.05f * Math.Log(2.1);
I should also explain how I got the value 0.05f. Basically, you increase yOffset
by 20 for each level of the tree. If I subtract the initial yOffset
head (which in my case is 10), then my first few yOffset
are 0, 20, 40, 60, etc. I want the offset x to be cut in half for each row; i.e
2 ^ (-0B) = 1 2 ^ (-20B) = 0.5 2 ^ (-40B) = 0.25
Obviously, B should be 1/20 or 0.05. I get the value of Math.Log(2.1)
from the relation:
base ^ exponent == e ^ (ln(base) * exponent)
So, with base 2.1, it looks like this: