Hi. I've found some code for simulating the growth of a tree which I have altered a little. However, I could really do with some help.
The code draws a line and then when that line reaches a certain distance it divides and new lines are drawn. However, each new line is currently the same length as the one that came before. I would like to have each new line 2/3rds the size of the one that came before. I'm sure I'm missing something really obvious but I've been scratching my brain and can't seem to work it out.
Any help would be much appreciated! Thanks, Michael.
import toxi.geom.*;
import peasy.*;
import peasy.org.apache.commons.math.*;
import peasy.org.apache.commons.math.geometry.*;
PeasyCam cam; //use PeasyCam
Branch tree;
void setup() {
cam = new PeasyCam (this, width/2);
cam.setMinimumDistance(20);
cam.setDistance(200);
cam.setMaximumDistance(10000);
size(1000, 700, P3D);
stroke(255, 50);
tree = new Branch(new Vec3D(0, -1, 0), 5);
tree.start = new Vec3D(0, 0, 0);
}
void draw() {
background(0);
tree.update();
tree.draw();
}
class Branch {
float spltLength = 20;
int numChildren = 4;
float maxAngle = PI/1.5;
float energy;
Vec3D start;
Vec3D end;
Vec3D direction;
Branch[] children;
Branch( Vec3D direction, float energy) {
this.direction = direction;
this.energy = 5;
}
void update() {
// grow
float factor = 1 + energy/(5*sq(direction.magnitude()));
direction = direction.scale(factor);
end = start.add(direction);
// if splitLength is reached, create children and update them
if (direction.magnitude() >= spltLength) {
energy = 0;
// direction = direction.scale(0);
// create child-branches if they don't exist
if (children == null) {
createChildren();
}
for (int i =0; i<children.length; i++) {
children[i].start = end;
children[i].update();
}
}
}
void createChildren() {
children = new Branch[numChildren];
for (int i = 0; i<numChildren; i++) {
// this is not so elegant, there may be slick solution for it
Vec3D axis = new Vec3D();
boolean isPerpendicular = false;
// find a perpendicular vector
while (!isPerpendicular) {
axis = Vec3D.randomVector() ;
if (direction.dot(axis)!=0) {
isPerpendicular = true;
}
}
axis.cross(direction);
//rotate vector
Vec3D dir = direction.copy().rotateAroundAxis(axis, random(-maxAngle, maxAngle));
dir.normalize();
// calculate energy
float en = map(abs(dir.angleBetween(direction, true)), 0, maxAngle, energy, 0);
children[i] = new Branch(dir, en);
}
}
void draw() {
pushMatrix();
translate(end.x, end.y, end.z);
sphere(1);
popMatrix();
line(start.x, start.y, start.z, end.x, end.y, end.z);
if (children == null) {
point(end.x, end.y, end.z);
}
else {
for (int i = 0; i<children.length; i++) {
children[i].draw();
}
}
}
}