Public
Edited
Jun 11, 2023
Insert cell
Insert cell
{

const tree = new Tree(
MID,
0.9,
INIT_BRANCH,
-Math.PI*0.5,
ONE,
ONE,
BRANCH_SPLIT_ANGLE,
BRANCH_PROB_SCALE,
BRANCH_DIMINISH,
BRANCH_SPLIT_DIMINISH,
BRANCH_ANGLE_MAX,
BRANCH_ANGLE_EXP
)
const ctx = DOM.context2d(width, height);
let i = 1
while(tree.Q && i < 1000){

i += 1
tree.step()
}
tree.Q.forEach(d=>renderBranch(ctx, d))

console.log(tree)
return ctx.canvas;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
renderBranch = (ctx, branch) => {
const a = branch.a
const r = branch.r
const x = branch.x
const y = branch.y

const one = ONE

const x1 = x + Math.cos(a-0.5*Math.PI)*r
const x2 = x + Math.cos(a+0.5*Math.PI)*r
const y1 = y + Math.sin(a-0.5*Math.PI)*r
const y2 = y + Math.sin(a+0.5*Math.PI)*r
const dd = Math.sqrt((x-x2)**2 + (y-y2)**2)

//TRUNK STROKE
ctx.strokeStyle = "red";
ctx.moveTo(width*x1, height*y1);
ctx.lineTo(width*x2, height*y2);
ctx.stroke();
/*
for _ in xrange(10):
rx.move_to(x1,y1)
rx.line_to(x2,y2)
rx.stroke()*/
}
Insert cell
Tree = {class Tree{
constructor(root_x,
root_y,
root_r,
root_a,
one,
stepsize,
branch_split_angle,
branch_prob_scale,
branch_diminish,
branch_split_diminish,
branch_angle_max,
branch_angle_exp) {
this.root_x = root_x
this.root_y = root_y
this.root_r = root_r
this.root_a = root_a
this.stepsize = stepsize
this.one = one

this.branch_split_angle = branch_split_angle
this.branch_diminish = branch_diminish
this.branch_split_diminish = branch_split_diminish
this.branch_angle_max = branch_angle_max
this.branch_angle_exp = branch_angle_exp

this.branch_prob_scale = branch_prob_scale
this.init()
}

init(){
this.Q = []

const branch = new Branch(this,
this.root_x,
this.root_y,
this.root_r,
this.root_a,
0)
this.Q.push(branch)
}

step(){
const q_remove = []
const q_new = []
this.Q.forEach((b, i)=>{

b.step()

if(b.r<=this.one){
q_remove.push(i)
}

const branch_prob = (this.root_r-b.r+this.one)*this.branch_prob_scale;


if(Math.random()<branch_prob){

const x = b.x
const y = b.y
const a = b.a
const r = b.r
const g = b.g

const new_r = this.branch_split_diminish*r

const ra = ((-1)**Math.floor(Math.random()*2))*Math.random()*this.branch_split_angle

q_new.push(new Branch(this,
x,
y,
new_r,
a + ra,
g+1))

} else {
q_remove.push(i)
q_new.push(b)
}

});


this.Q = this.Q.filter((_, idx)=>!q_remove.includes(idx));

this.Q = [...this.Q, ...q_new];
}
};

return Tree;
}
Insert cell
Branch = {
class Branch {
constructor(tree,x,y,r,a,g){
this.tree = tree

this.x = x
this.y = y
this.r = r
this.a = a
this.shade = 0
this.i = 0
this.g = g

}

step(){
this.r = this.r - this.tree.branch_diminish
const random = d3.randomNormal(0, 0.1)()
//console.log(random)
const angle = random*this.tree.branch_angle_max;

const scale = this.tree.one+this.tree.root_r-this.r
const da = (1.+scale/this.tree.root_r)**this.tree.branch_angle_exp
this.a += da*angle

const dx = Math.cos(this.a)*this.tree.stepsize
const dy = Math.sin(this.a)*this.tree.stepsize

this.x += dx
this.y += dy
this.i += 1
}
}

return Branch;
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more