You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

290 lines
8.5 KiB

paper.install(window);
function gen_tree(pos, maxheight) {
var baum = new Branch();
baum.length = 0.15 * maxheight + 0.15 * maxheight * Math.random();
var shapernd = Math.random() * 3;
if(shapernd < 1) {
baum.crown = new KiteCrown(
0.49 * maxheight + 0.21 * maxheight * Math.random(),
0.4 + Math.random() * 0.2,
{bisect: 0.2 + Math.random() * 0.2},
);
} else if(shapernd < 2) {
baum.crown = new TriangleCrown(
0.49 * maxheight + 0.21 * maxheight * Math.random(),
0.4 + Math.random() * 0.2,
);
} else {
baum.crown = new EllipseCrown(
0.49 * maxheight + 0.21 * maxheight * Math.random(),
0.4 + Math.random() * 0.2,
{bisect: 0.1 + Math.random() * 0.4},
);
}
baum.angle = Math.PI / 2;
if(Math.random() < 0.3) {
baum.angle += Math.random() * 0.2 - 0.1;
}
if((baum.crown.shape != "triangle") && (Math.random() < 0.5)) {
var b = {
length: baum.length * 0.4,
angle: Math.PI / 2,
crown: baum.crown.clone()
};
b.crown.length *= 0.4;
b.crown.width = 0.8;
baum.forks = [{
pos: 0.2 + Math.random() * 0.4,
branch: new Branch(b),
}];
baum.draw(pos);
var step = (Math.random() < 0.5) ? -0.1 : 0.1;
while(baum.collides_crown(baum.forks[0].branch)) {
baum.forks[0].branch.angle += step;
baum.draw(pos);
}
var range = 4*Math.PI/9 - Math.abs(Math.PI/2 - baum.forks[0].branch.angle);
if(step > 0) {
baum.forks[0].branch.angle += range * (0.1 + 0.9 * Math.random());
} else {
baum.forks[0].branch.angle -= range * (0.1 + 0.9 * Math.random());
}
baum.draw(pos);
}
baum.draw(pos);
return baum;
}
class Crown {
constructor(length, width, shape) {
this.width = width;
this.length = length;
this.shape = shape;
}
undraw() {
if(typeof this._path !== "undefined") {
this._path.removeSegments();
delete this._path;
}
}
collides(other) {
return this._path.intersects(other._path);
}
get bounds() {
return this._path.bounds;
}
}
class KiteCrown extends Crown {
constructor(length, width, {bisect = 0.3}={}) {
super(length, width, 'kite');
this.bisect = bisect;
}
clone() {
return new KiteCrown(this.length, this.width, {bisect: this.bisect});
}
draw(branch, bvec, cpos) {
this.undraw();
var cvec = bvec.multiply(1/bvec.length * this.length);
var bswidth = this.length * this.width;
var bsvec = new Point(Math.sin(branch.angle) * bswidth / 2,
Math.cos(branch.angle) * bswidth / 2);
this._path = new Path();
this._path.strokeColor = 'black';
this._path.fillColor = 'white';
this._path.strokeWidth = 2;
this._path.closed = true;
this._path.add(cpos);
this._path.add(cpos.add(cvec.multiply(this.bisect)).add(bsvec));
this._path.add(cpos.add(cvec));
this._path.add(cpos.add(cvec.multiply(this.bisect)).subtract(bsvec));
}
}
class TriangleCrown extends Crown {
constructor(length, width) {
super(length, width, 'triangle');
}
clone() {
return new TriangleCrown(this.length, this.width);
}
draw(branch, bvec, cpos) {
this.undraw();
var cvec = bvec.multiply(1/bvec.length * this.length);
var bswidth = this.length * this.width;
var bsvec = new Point(Math.sin(branch.angle) * bswidth / 2,
Math.cos(branch.angle) * bswidth / 2);
this._path = new Path();
this._path.strokeColor = 'black';
this._path.fillColor = 'white';
this._path.strokeWidth = 2;
this._path.closed = true;
this._path.add(cpos.add(bsvec));
this._path.add(cpos.add(cvec));
this._path.add(cpos.subtract(bsvec));
}
}
class EllipseCrown extends Crown {
constructor(length, width, {bisect = 0.5}={}) {
super(length, width, 'ellipse');
this.bisect = bisect;
}
clone() {
return new EllipseCrown(this.length, this.width, {bisect: this.bisect});
}
draw(branch, bvec, cpos) {
this.undraw();
var cvec = bvec.multiply(1/bvec.length * this.length);
var bswidth = this.length * this.width;
var bsvec = new Point(Math.sin(branch.angle) * bswidth / 2,
Math.cos(branch.angle) * bswidth / 2);
this._path = new Path();
this._path.strokeColor = 'black';
this._path.fillColor = 'white';
this._path.strokeWidth = 2;
this._path.closed = true;
var cmid = cpos.add(cvec.multiply(this.bisect));
this._path.add(new Segment(cpos,
bsvec.multiply(0.5),
bsvec.multiply(-0.5),
));
this._path.add(new Segment(cmid.subtract(bsvec),
bvec.multiply(-0.5),
bvec.multiply(0.5),
));
this._path.add(new Segment(cpos.add(cvec),
bsvec.multiply(-0.5),
bsvec.multiply(0.5),
));
this._path.add(new Segment(cmid.add(bsvec),
bvec.multiply(0.5),
bvec.multiply(-0.5),
));
}
}
class Branch {
constructor(data) {
Object.assign(this, data);
if(typeof this.forks !== "undefined") {
for (let fork of this.forks) {
fork.branch = new Branch(fork.branch, this);
}
}
}
draw(pos) {
if(typeof this._branch !== "undefined") {
this._branch.removeSegments();
delete this._branch;
}
this._branch = new Path();
var bvec = new Point(Math.cos(this.angle) * this.length,
-1 * Math.sin(this.angle) * this.length);
var end = pos.add(bvec);
this._branch.strokeColor = 'black';
this._branch.strokeWidth = 2;
this._branch.add(pos);
this._branch.add(end);
if(typeof this.crown !== "undefined") {
this.crown.draw(this, bvec, end);
}
if(typeof this.forks !== "undefined") {
for (let fork of this.forks) {
fork.branch.draw(pos.add(bvec.multiply(fork.pos)));
}
}
}
collides_crown(other) {
return this.crown.collides(other.crown);
}
get bounds() {
var b = this._branch.bounds;
b = b.unite(this.crown.bounds);
if(typeof this.forks !== "undefined") {
for (let fork of this.forks) {
b = b.unite(fork.branch.bounds);
/*
var r = new Path.Rectangle({
point: fork.branch.bounds.point,
size: fork.branch.bounds.size,
strokeWidth: 1,
strokeColor: 'green'});
*/
}
}
return b;
}
}
function draw() {
var canvas = document.getElementById('canvas');
paper.setup(canvas);
var width = 148 * 5;
var height = 105 * 5;
var rows = 3;
var rowspace = 20;
var inspace = 30;
var outspace = 10;
var maxh = (height - (rows-1)*rowspace - 2*outspace - 2*inspace) / rows;
var outline = new Path.Rectangle({
point: new Point(outspace, outspace),
size: new Size(width - 2*outspace, height - 2*outspace),
strokeWidth: 2,
strokeColor: 'black'
});
for(var row=0; row<rows; row++) {
var y = outspace + inspace + maxh * (row + 1) + rowspace * row;
var x = outspace + inspace + 20; // TODO approx width
var prev;
while(x < width - outspace - inspace - 60) { // TODO approx width
var yy = y + Math.random() * 40 - 20;
x += Math.random() * 10; // TODO approx width
var t = gen_tree(new Point(x, yy), maxh);
if(typeof prev !== 'undefined') {
while(prev.bounds.intersects(t.bounds)) {
x += 15;
t.draw(new Point(x, y));
console.log('intersects');
}
}
prev = t;
}
}
}