Pythagorean Tree

In high school, I thought that geometry was the most useless subject. It was mainly used to teach mathematical proofs that were supposed to be intuitive. They proved to be quite the opposite. If only my teachers would have shown that you need geometry to make fractals and games. I might have paid more attention. What follows is some simple high school level math which took me several hours to (re-)figure out. Of course, you can skip over the parts you already know.


A B C D E F P T
Post affine

First, we need Pythagoras' theorem: a^2+b^2=c^2. Which we can rewrite to find the length of the hypotenuse: c=\sqrt{a^2+b^2}. The visual interpretation theorem is nicely shown in the image below. The square at the root of the tree is attached to the hypotenuse of a triangle. Let's give the hypotenuse a length of c. The area of the square then becomes c^2. Similarly, the other squares of the triangle are given lengths of a and b. Pythagoras' theorem simply states that the area of the square attached to the hypotenuse is equal to the sum of the area of the squares attached to the rest of the right triangle.

The theorem is used to calculate the length of child squares. In this application, the lengths are calculated relative to a reference point (x,y). In the image above (x,y) is set a the point where the two smaller squares, which I'll call left and right, intersect. The length of the base square is set at 1. The lengths are thus given by:

    \[\text{left length}=\sqrt{x^2+y^2}\]

    \[\text{right length}=\sqrt{(1-x)^2 + y^2}\]

To calculate the angle of these child squares in relation to the parent squares we need the SOH-CAH-TOA (SOS-CAS-TOA in Dutch) formulas. These formulas can be rewritten so that they solve for \theta. Which will be useful for the purpose of constructing a Pythagorean fractal tree. Here's a quick recap:

    \[sin(\theta)=\frac{O}{H}\rightarrow \theta=sin^{-1}(\frac{O}{H})\]

    \[cos(\theta)=\frac{A}{H}\rightarrow\theta=cos^{-1}(\frac{A}{H})\]

    \[tan(\theta)=\frac{O}{A}\rightarrow\theta=tan^{-1}(\frac{O}{A})\]

The angles are calculated as if the squares are turned counter-clockwise. To turn the right square we thus need to apply a negative angle. The angles then become:

    \[\text{left angle}=tan^{-1}(\frac{y}{x}\]

    \[\text{right angle}=-tan^{-1}(\frac{y}{1-x})\]

Small digression into IFS formulas. In previous post I only used linear transformations. This means that the (x,y) coordinates remain unaltered after they undergo an affine transformation. The squares in the image are achieved by instead of returning the unaltered coordinates, returning coordinates that are uniformly sampled from a bi-unit square shifted 0.5 down and left.

    \[\text{linear}(x,y)=(x,y)\]

    \[\text{square}(x,y)=(r_0 - 0.5, r_1-0.5)\]

Now because the first square is shifted 0.5 down and left we need some additional offsets.

    \[\text{left x offset}= -\frac{1}{2} - \frac{1}{2}cos(180-45-\text{left angle})\sqrt{2\text{(left length)}^2}\]

    \[\text{left y offset}=-\frac{1}{2} - \frac{1}{2}sin(180-45-\text{left angle})\sqrt{2\text{(left length)}^2}\]

    \[\text{right x offset}=\frac{1}{2}cos(180-45-\text{right angle})\sqrt{2\text{(left length)}^2} + 1\]

    \[\text{right y offset}=-\frac{1}{2}sin(180-45-\text{right angle})\sqrt{2\text{(left length)}^2} - 1\]

Now all that is left is applying a scaling and rotation matrix. To chain operations simply matrix multiply the matrices.

    \[\text{left affine matrix}=\begin{bmatrix}\text{left length} & 0 \\ 0 & \text{left length}\end{bmatrix}\begin{bmatrix}cos(\text{left angle}) & -sin(\text{left angle}) \\ sin(\text{left angle}) & cos(\text{left angle})\end{bmatrix}\]

    \[\text{right affine matrix}=\begin{bmatrix}\text{right length} & 0 \\ 0 & \text{right length}\end{bmatrix}\begin{bmatrix}cos(\text{right angle}) & -sin(\text{right angle}) \\ sin(\text{right angle}) & cos(\text{right angle})\end{bmatrix}\]