//
// Supawat Vitoorapakorn
// Svitoora@andrew.cmu.edu
// Section E
//
// Cherry Blossoms: Recusively generate a forest of Sakura.
// Using a Lindenmayer system, each plant grows towards the sun.
var w = 400;
var h = 400;
// Global Variable
var PLANT;
var segment_l = h * .1;
var r = h * .05 * .5;
var common_ratio = .618033 //Golden Ratio
var food;
// Recursively generates a plant model
var max_i = 7; // Max iteration depth
var cur_i = 0;
var DRAW_i = 0; // DRAW's iteration depth
///// MODEL /////
// Creates the sun for plants to grow towards
function food_create(x = w / 2, y = -h * 2) {
this.x = x;
this.y = y;
}
// Creates plants node. Nodes that have .child are branches,
// and nodes without .child are leaves.
function create_plant_node(x, y) {
this.x = x;
this.y = y;
this.x0 = this.x;
this.y0 = this.y;
this.child = [];
this.x1 = null;
this.y1 = null;
}
// Grows plant by making plant seek sunlight
function grow(plant, cur_i) {
// Using the golden ratio, plant's branch size is a geometric sequence
l = segment_l * (common_ratio ** (cur_i))
// Randomly generate the next node via reducing
// distance from plant ro sun
do {
angleMode(DEGREES);
if (cur_i == 0) {
angle = 5;
theta = random(-90 - angle, -90 + angle);
} else {
theta = random(0, 360);
}
plant.x1 = plant.x0 + (l * cos(theta));
plant.y1 = plant.y0 + (l * sin(theta));
d_new = dist(plant.x1, plant.y1, food.x, food.y)
d_old = dist(plant.x0, plant.y0, food.x, food.y)
}
// Keep generating until the new distance is less than the current one
while (d_new > d_old)
plant.child = [];
// Randomly decide how many children(branches) a node should have
for (var x = 0; x < random(1, 4); x++) {
plant.child.push(new create_plant_node(plant.x1, plant.y1));
}
}
// Recursively generates plant
function generate_plant(PLANT, cur_i, max_i) {
// Break Base
if (cur_i == max_i) {
return
// Continue case
} else {
grow(PLANT, cur_i);
cur_i++;
for (i in PLANT.child) {
generate_plant(PLANT.child[i], cur_i, max_i)
}
}
}
///// DRAW /////
// Recursively draws plant
function draw_PLANT(plant, DRAW_i) {
DRAW_i++; // Increases DRAW's Depth counter
stroke(255 * .3);
strokeCap(SQUARE);
strokeWeight((h * .0125) * (common_ratio ** DRAW_i))
// Break case: Flowers
// If node has no children; draw leaf.
if (plant.child.length == 0) {
fill(255, 255, 255);
ellipse(plant.x, plant.y, (2 / 600) * w, (2 / 600) * w);
return
} // If node has chldren; draw branches
else {
r = r ** common_ratio;
for (i in plant.child) {
line(plant.x, plant.y,
plant.child[i].x, plant.child[i].y)
draw_PLANT(plant.child[i], DRAW_i);
}
}
}
///// SETUP /////
function setup() {
createCanvas(w, h);
background("#a5d3e5");
food = new food_create();
// Row Cols Controller
num_tree = 3;
num_row = 3;
y_pos = 0;
// Translates Row and Col of Trees
push();
translate((w / num_tree) * .5, (h / num_row)*.825);
// Rows
for (var x = 0; x < num_row; x++) {
y_pos = x * (h / num_row);
// Cols
for (var i = 0; i < num_tree; i++) {
PLANT = new create_plant_node(i * (w / num_tree), y_pos);
generate_plant(PLANT, cur_i, max_i);
draw_PLANT(PLANT, DRAW_i);
}
}
pop();
textAlign(RIGHT);
textSize(10);
fill(255 * .3);
text("Please click to regnerate",w*.975,h*.985)
print("Final:", PLANT);
}
function mouseClicked() {
setup()
}
Using a Lindenmayer system, each plant grows towards the sun. Every plant starts with a seed, and randomly generates branches to reduce its distance towards the sun at (width/2, -height*2) for a maximum recursion depth of 7. A number of sub-branches (children) each branch (node) generates is random between 1-4.