Recursive javascript function will not return to parent call data?

359 views Asked by At

I'm working on an HTML5/JS project to draw a binary fractal tree on a canvas.

HTML5::

<!DOCTYPE html>
<html>
  <body>
    <canvas id="canvas1" width="500" height="500"></canvas>
    <br />
    <script src="tree.js"></script>
    <button id="button1" type="button" onclick="main()">Start</button>
  </body>
</html>

Javascript::

var scale = 0.5;
var min_len = 1;
//setup canvas
var c = document.getElementById("canvas1");
var ctx = c.getContext("2d");
ctx.moveTo(250, 500);

//returns length of branch
function len(branch) {

    return Math.sqrt( Math.pow(branch.len_x, 2) + Math.pow(branch.len_y, 2) );
}

//draws from start to length of branch
function drawBranch(start, branch) {

    ctx.moveTo(start.x, start.y);
    ctx.lineTo(start.x + branch.len_x, start.y - branch.len_y);
    ctx.stroke();
}

//recursively builds binary fractal tree
function makeChildren(start, theta, parent) {

    if(len(parent) >= min_len) {
        drawBranch(start, parent);

        //linear transformation applied to parent branch which rotates and scales to produce child branch
        child = {len_x: ( parent.len_x * Math.cos(theta) - parent.len_y * Math.sin(theta) ) * scale,
                 len_y: ( parent.len_x * Math.sin(theta) + parent.len_y * Math.cos(theta) ) * scale};

        //recursively build left and right branches of tree
        makeChildren( {x: start.x + parent.len_x, y: start.y - parent.len_y}, theta, child);
        makeChildren( {x: start.x + parent.len_x, y: start.y - parent.len_y}, theta * (-1), child);
    }
}

function main() {

    //initialize tree
    makeChildren( {x: 250, y: 500}, Math.PI / 4, {len_x: 0, len_y: 100} );
}

When I run my code it produces a left-ward facing spiral kind of structure (sorry can't post images yet).

The problem is with the length check in the makeChildren function, once the if statement is not longer true i.e. when the branch is too small, the program gets caught in a recursive loop where the size remains too small. Here's the console log of the branch lengths::

[Log] 100 (tree.js, line 24)

[Log] 49.99999999999999 (tree.js, line 24)

[Log] 25 (tree.js, line 24)

[Log] 12.5 (tree.js, line 24)

[Log] 6.25 (tree.js, line 24)

[Log] 3.125 (tree.js, line 24)

[Log] 1.5624999999999998 (tree.js, line 24)

[Log] 0.7812499999999999 (tree.js, line 24)

[Log] 0.7812499999999999 (tree.js, line 24)

[Log] 0.7812499999999999 (tree.js, line 24)

[Log] 0.7812499999999999 (tree.js, line 24)

[Log] 0.7812499999999999 (tree.js, line 24)

[Log] 0.7812499999999999 (tree.js, line 24)

[Log] 0.7812499999999999 (tree.js, line 24)

[Log] 0.7812499999999999 (tree.js, line 24)

It should reach the base case for the recursive loop (branch length too small) and return to the previous recursive loop, but it looks like it just keeps checking the same length, 0.78125, over and over again. I can't figure out why, please help!

2

There are 2 answers

2
guest On BEST ANSWER

checking the same length, 0.78125, over and over again

Each level of recursion doubles the number of calls. It's going to reach that base case like ... 128 (?) times.

it produces a left-ward facing spiral kind of structure

As it is, there's a single global child variable. When the first sub-makeChild runs, it reassigns this global child variable, and the second sub-makeChild starts with this modified one.

You probably wanted

var child = {len_x: ...

http://jsfiddle.net/hLxe4fx1/

0
Jaime Agudo On

I reached the same conclusion but guest was faster than me :) To know why this happens remember that Objects are Passed by Reference and as child was undefined it was on the global scope.

Another jsfiddle http://jsfiddle.net/6pjduncg/