Kinda sorta leaf vein pattern based on the algorithm described in the following paper:
cp.eng.chula.ac.th/~…per/2002/cmm2002.pdf
Log in to post a comment.
// You can find the Turtle API reference here: https://turtletoy.net/syntax Canvas.setpenopacity(0.35); // Define here a number of adjustable constants const NUM_PARTICLES = 500; // The number of random particles to generate const ROOT_POINT = [0, 120]; // The x,y coordinate of our goal point const JOIN_DISTANCE = 1; // How close particles have to be before they merge const MOVE_DISTANCE = 0.5; // Using the algorithm defined in: // https://www.cp.eng.chula.ac.th/~prabhas//paper/2002/cmm2002.pdf // Global code will be evaluated once. const turtle = new Turtle(); turtle.pendown(); var particles = []; // Simple implementation of distance formula function getDist(p0, p1){ var dx = p1[0] - p0[0]; var dy = p1[1] - p0[1]; return Math.sqrt(dx**2 + dy**2); } // Simple function to create a unit vector function normalize(vector, mag){ // Pass in the magnitude/distance just so we don't have to calculate it twice return [vector[0]/mag, vector[1]/mag] } function updateVectors(){ // For each particle: for (var i = 0; i < particles.length; i++) { var curr_particle = particles[i]; // Get the next closest particle var closest_neighbor = i; var closest_dist = 10000; // Set this to an arbitrarily high number for (var j = 0; j < particles.length; j++){ if (j == i) continue; var dist = getDist(curr_particle, particles[j]); // Ignore neighbors too close to us, so that they start to move in the same direction if (dist < JOIN_DISTANCE) continue; if (dist < closest_dist){ closest_dist = dist; closest_neighbor = j; } } // if (closest_neighbor == i) { // return; // } var n_particle = particles[closest_neighbor]; // Get a unit vector in that particle's direction var closest_vector = [n_particle[0] - curr_particle[0], n_particle[1] - curr_particle[1]]; closest_vector = normalize(closest_vector, closest_dist); // Get a unit vector in the direction of our root point var root_vector = [ROOT_POINT[0] - curr_particle[0], ROOT_POINT[1] - curr_particle[1]]; root_vector = normalize(root_vector, getDist(ROOT_POINT, curr_particle)); // Add these to get the particles new direction vector var new_dir_vector = [root_vector[0] + closest_vector[0], root_vector[1] + closest_vector[1]] // new_dir_vector = normalize(new_dir_vector, Math.sqrt(new_dir_vector[0]**2 + new_dir_vector[1]**2)) particles[i][2] = new_dir_vector; } } // Inital generation of our random field of particles for (var j = 0; j < NUM_PARTICLES; j++){ // For x an y, generate a random point on the visible canvas plane var x = ((Math.random() * 200) - 100) var y = ((Math.random() * 200) - 100) // Here we add a placeholder value where we will later store a vector particles.push([x, y, null]) } // The walk function will be called until it returns false. function walk(i) { updateVectors(); for (var j = 0; j < particles.length; j++){ var curr = particles[j]; turtle.up() if (Math.random() >= 0) turtle.down(); turtle.jump(curr[0], curr[1]); turtle.goto(curr[0] + (curr[2][0] * MOVE_DISTANCE), curr[1] + (curr[2][1] * MOVE_DISTANCE)); particles[j][0] = turtle.x(); particles[j][1] = turtle.y(); } return i < 300 // return particles.length > 1 || getDist(particles[0], ROOT_POINT) < JOIN_DISTANCE; }