Pythagorean Tree

Pythagorean Tree IFS.

Log in to post a comment.

const shape = 0; // min=0, max=4, step=1 (Square, Bubble, Blur, Linear, Circle)
const x_height = 0.1; // min=-1, max=1, step=0.01
const y_height = 0.5; // min=-1, max=1, step=0.01
const x_post = 0.5; // min=-100, max=100, step=1
const y_post = 0.5; // min=-100, max=100, step=1

Canvas.setpenopacity(-0.05);

const turtle = new Turtle();

let x = 0;
let y = 0;

function toRadians (angle) {
  return angle * (Math.PI / 180);
}

function toDegrees (angle) {
  return angle * (180 / Math.PI);
}

function matrix_multiplication(m0, m1){
    return [[m0[0][0]*m1[0][0] + m0[0][1]*m1[1][0], m0[0][0]*m1[0][1] + m0[0][1]*m1[1][1]], [m0[1][0]*m1[0][0] + m0[1][1]*m1[1][0], m0[1][0]*m1[0][1] + m0[1][1]*m1[1][1]]];
}

function rotation_matrix(theta){
    return [[Math.cos(toRadians(theta)), -Math.sin(toRadians(theta))], [Math.sin(toRadians(theta)), Math.cos(toRadians(theta))]];
}


var left_angle = toDegrees(Math.atan(y_height/x_height));
var right_angle = -toDegrees(Math.atan(y_height/(1.0-x_height)));

var left_length = Math.sqrt(Math.pow(x_height,2) + Math.pow(y_height, 2));
var right_length = Math.sqrt(Math.pow((1.0-x_height),2) + Math.pow(y_height, 2));

var left_x_offset = -0.5 - 0.5*Math.cos(toRadians(180 - 45 - left_angle))*Math.sqrt(2*Math.pow(left_length, 2));
var left_y_offset = -0.5 -0.5* Math.sin(toRadians(180 - 45 - left_angle))*Math.sqrt(2*Math.pow(left_length, 2));

var right_x_offset = 0.5 + Math.cos(toRadians(180 - 45 + right_angle))*0.5*Math.sqrt(2*Math.pow(right_length, 2));
var right_y_offset = -0.5 - Math.sin(toRadians(180 - 45 + right_angle))*0.5*Math.sqrt(2*Math.pow(right_length, 2));

var left_rotation_matrix = rotation_matrix(left_angle);
var right_rotation_matrix = rotation_matrix(right_angle);

var left_length_matrix = [[left_length, 0], [0, left_length]];
var right_length_matrix = [[right_length, 0], [0, right_length]];

var final_left_matrix = matrix_multiplication(left_rotation_matrix,left_length_matrix);
var final_right_matrix = matrix_multiplication(right_rotation_matrix,right_length_matrix);


let function_set = [[1.0, 0, 0, 1.0, 0, 0, 0.33],
                    [final_left_matrix[0][0], final_left_matrix[0][1], final_left_matrix[1][0], final_left_matrix[1][1], left_x_offset, -left_y_offset, 0.33],
                    [final_right_matrix[0][0], final_right_matrix[0][1], final_right_matrix[1][0], final_right_matrix[1][1], right_x_offset, -right_y_offset, 0.33]];

let shapes = ["Square", "Bubble", "Blur", "Linear", "Circle"];
let function_transforms = [shapes[shape], "Linear", "Linear"];

function linear(x,y){
    return [x, y];
}

function square(x, y){
    var r1 = Math.random();
    var r2 = Math.random();
    return [(r1 - 0.5), (r2 - 0.5)];
}

function bubble(x, y){
    var r = 1.0;
    var multiplier = 4.0/(Math.pow(r,2.0) + 4.0);
    return [multiplier*x, multiplier*y];
}

function blur(x, y){
    var r1 = Math.random();
    var r2 = Math.random();
    return [r1*Math.cos(2*Math.PI*r2), r1*Math.sin(2*Math.PI*r2)];
}

function circle(x, y){
    var t = 2*Math.PI*Math.random();
    var u = Math.random() + Math.random();
    var r = u;
    if(u>1.0){
        r = 2-u;
    }
    return [r*Math.cos(t), r*Math.sin(t)];
}

function walk(i) {
    turtle.jump(x * 20 + x_post, - y * 20 + y_post);
    turtle.circle(.1);

    let r = Math.random();
    let p_total = 0;

    for (let j = 0; j < function_set.length; j++) {
        let f = function_set[j];
        p_total += f[6];

        if (r < p_total) {
            // Use precomputed function lookup
            let next;
            switch (function_transforms[j]) {
                case "Square": next = square(x, y); break;
                case "Bubble": next = bubble(x, y); break;
                case "Blur": next = blur(x, y); break;
                case "Circle": next = circle(x, y); break;
                default: next = linear(x, y);
            }

            // Apply transformation matrix
            x = next[0] * f[0] + next[1] * f[1] + f[4];
            y = next[0] * f[2] + next[1] * f[3] + f[5];

            break;
        }
    }

    return i < 100000000;
}