svitoora – 05 – Recursive Sakura Wallpaper

sketch

// 
// 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.

Leave a Reply