Ez-tree

Basic recursive tree. Plotter friendly by lifting the pen infrequently.

Log in to post a comment.

// LL 2021

Canvas.setpenopacity(.6);

const turtle = new Turtle();

const max_depth = 11;        // min=1,     max=20,   step=1
const split = 2;             // min = 1,   max = 10, step=1
const turn_factor = 0.69;    // min = 0.1, max = 1,  step=0.001
const scale = 3.3;           // min=1,     max=50,   step=0.1
const angleInc = 0.62;       // min=-3.14, max=3.14, step=0.01
const min_length = 0.1;      // min=0.01,  max=0.5,  step=0.001
const max_length = 1.214;    // min=0.01,  max=100,  step=0.001
const count = 3;             // min=1,     max=100,  step=1
const rdiff = 0.84;          // min=-6.3,  max=6.3,  step=0.001
const offset = 1;            // min=0,     max=1,    step=0.01
const startAngle = 0;        // min=-3.14, max=3.14, step=0.01

const seed = 0;              // min=0,     max=100,  step=1

const root_x = 0;
const root_y = 0;

const imprecision = 0.0;

var rdiff2;

function Branch(x, y, length, angle, depth)
{
    this.x = x;
    this.y = y;
    this.length = length;
    this.angle = angle;
    this.depth = depth;
    this.branches = [];
}

Branch.prototype.draw = function() 
{
    if (this.length < max_length)
    {
        const xi1 = imprecision * (Math.random() - 0.5) * 2;
        const yi1 = imprecision * (Math.random() - 0.5) * 2;
        const xi2 = imprecision * (Math.random() - 0.5) * 2;
        const yi2 = imprecision * (Math.random() - 0.5) * 2;
        
        const x2 = this.x + Math.cos(this.angle) * this.length;
        const y2 = this.y + Math.sin(this.angle) * this.length;

        turtle.goto(xi1 + root_x + this.x * scale, yi1 + root_y + this.y * scale);
        turtle.pendown();
        turtle.goto(xi2 + root_x + x2 * scale, yi2 + root_y + y2 * scale);
    }
    else
    {
        turtle.penup();
    }
    
    for (var c=0; c<this.branches.length; c++)
    {
        this.branches[c].draw();
    }
    
    if (this.length < max_length)
    {
        const xi1 = imprecision * (Math.random() - 0.5) * 2;
        const yi1 = imprecision * (Math.random() - 0.5) * 2;
        const xi2 = imprecision * (Math.random() - 0.5) * 2;
        const yi2 = imprecision * (Math.random() - 0.5) * 2;
        
        const x2 = this.x + Math.cos(this.angle) * this.length;
        const y2 = this.y + Math.sin(this.angle) * this.length;

        turtle.goto(xi2 + root_x + x2 * scale, yi2 + root_y + y2 * scale);
        turtle.pendown();
        turtle.goto(xi1 + root_x + this.x * scale, yi1 + root_y + this.y * scale);
    }
    else
    {
        turtle.penup();
    }
}

function create_branch(parent, offset, factor, angleChange)
{
    if (parent.depth > max_depth) return;

    var x = parent.x + Math.cos(parent.angle) * parent.length * offset;
    var y = parent.y + Math.sin(parent.angle) * parent.length * offset;
    var length = parent.length * factor;
    var angle = parent.angle + angleChange;
    var depth = parent.depth + 1;
    
    if (length < min_length) return;
    
    var branch = new Branch(x, y, length, angle, depth);
    parent.branches.push(branch);
    
    create_branches(branch);
}

function create_branches(parent)
{
    var offset2 = offset;  
    var factor = turn_factor;
    var angleChange = angleInc;
    for (var s=0; s<split; s++)
    {
        if ((s>0) && (!(s&1)))
        {
            offset2 *= 0.5;
            factor *= 0.5;
        }
        angleChange *= -1;
        
        var rangle = rdiff2;
        if (seed)
        {
            randomSeed(seed + (parent.depth+100) * ((Math.floor(parent.x) + 500) * 1000 + Math.floor(parent.y)) * 94568946);
            rangle = (random()-0.5) * 2 * rdiff2;
        }
        
        create_branch(parent, offset2, factor, angleChange + rangle);
    }
}

// The walk function will be called until it returns false.
function walk(i, t)
{
    rdiff2 = rdiff * (Math.cos(t * Math.PI * 2) + 1) * 0.5;
    //rdiff2 = rdiff + t * Math.PI * 2;
    
    if (i==0)
    {
        randomSeed(seed);
        turtle.penup();
    }

    const length = 10;
    const angle = -Math.PI * 0.5;
    var root = new Branch(0, 0, length, startAngle + angle + Math.PI * 2 * i / (count), 0);
    create_branches(root);
    root.draw();

    return (i+1)<count;
}

////////////////////////
// Utils
////////////////////////

function sleep(milliseconds) {
  const date = Date.now();
  let currentDate = null;
  do {
    currentDate = Date.now();
  } while (currentDate - date < milliseconds);
}

///////////////

var rseed = 0;
var r_a = 1664525; // a - 1 should be divisible by m's prime factors
var r_m = 4294967296; // c and m should be co-prime
var r_c = 1013904223;

function randomSeed(val)
{
    if (val == null) val = 0;
    rseed = (val == 0 ? Math.random() * r_m : val) >>> 0;
}

function random()
{
    rseed = (r_a * rseed + r_c) % r_m;
    var rand = rseed / r_m;

    return rand;
}