xxxxxxxxxx
426
let world;
let dt = 0.05;
let N = 0;
let G = 9.81;
let grassN = 300;
let W_C = 35;
let id = 0;
let C = 10;
let img;
let colors;
function preload() {
img = loadImage('test3.jpg');
colors = loadJSON('test.json');
}
class World {
constructor() {
this.objects = [];
this.g_constraints = [];
this.constraints = [];
}
show() {
for(let el of this.objects) {
el.show();
}
}
show_c() {
for(let el of this.constraints) {
el.show();
}
for(let el of this.g_constraints) {
el.show();
}
}
add(el) {
this.objects.push(el);
}
add_gc(el) {
this.g_constraints.push(el);
}
add_c(c) {
this.constraints.push(c);
}
update() {
for(let el of this.objects) {
let f = createVector(W, G); // Wind and Gravity
el.update(f);
}
for(let i = 0; i < 2; ++i) {
// Global Constraints
// Local constraints
if (i != 0) shuffle(this.constraints);
for(let c of this.constraints) {
c.constraint();
}
for(let el of this.objects) {
if(el.fixed) continue;
// if(el.p.x < 0) el.p.x = 0 + random() * 5;
// if(el.p.x > 400) el.p.x = 400 - random()* 2;
// if(el.p.y < 0 ) el.p.y = 0 + random()*2 ;
// if(el.p.y > 400) el.p.y = 400 - random()*2;
for(let c of this.g_constraints) {
c.constraint(el);
}
}
}
}
}
class MassPoint {
constructor(x, y, r=8, m=1, fixed=false) {
this.p = createVector(x, y);
this.pp = this.p.copy();
this.m = 1.0;
this.r = r * 0.95;
this.r2 = r*r;
this.c = [0, 240, 0];
// this.getColor();
this.id = id;
this.fixed = fixed;
// this.c = colors[this.id]
id += 1;
}
getColor() {
let i = int(this.p.x);
let j = int(this.p.y);
this.c[0] = img.pixels[j*4*400 + i*4];
this.c[1] = img.pixels[j*4*400 + i*4 + 1];
this.c[2] = img.pixels[j*4*400 + i*4 + 2];
}
getPosition() {
return this.p;
}
setPosition(p) {
if(this.fixed) return;
this.p = p;
}
update(F) {
if(this.fixed) return;
F.mult(dt * dt / this.m);
let temp = this.p.copy()
this.p.sub(this.pp).mult(0.99).add(temp).add(F);
this.pp = temp;
}
show() {
// console.log(this.p)
// this.getColor();
noStroke();
fill(this.c[0], this.c[1], this.c[2])
circle(this.p.x, this.p.y, this.r * 1.5);
}
}
class WallC {
constructor(x1, y1, x2, y2) {
this.e1 = createVector(x1, y1);
this.e2 = createVector(x2, y2);
this.e = p5.Vector.sub(this.e2, this.e1);
this.l = this.e.mag();
this.dir = p5.Vector.normalize(this.e);
}
constraint(p) {
let proj = p5.Vector.mult(this.dir, p5.Vector.dot(p5.Vector.sub(p.p, this.e1), this.dir)).add(this.e1);
let d = p5.Vector.sub(p.p, proj);
// line(p.p.x, p.p.y, proj.x + this.e1.x, proj.y + this.e1.y);
if(d.mag() <= 10) {
let pp1 = p5.Vector.sub(this.e1, p.p);
let pp2 = p5.Vector.sub(this.e2, p.p);
if(p5.Vector.dot(pp1, pp2) < pp1.mag() * pp2.mag() / sqrt(2)) {
// stroke("blue")
// proj.add(this.e1)
// strokeWeight(1)
// line(p.p.x, p.p.y, p.p.x + d.x, p.p.y + d.y);
// point(proj.x + 5*d.x, proj.y + 5*d.y)
// p.setPosition(d.normalize().mult(5));
d.normalize().mult(10 + random() * 0.5);
proj.add(d)
p.setPosition(proj);
}
}
}
show() {
strokeWeight(8)
stroke("blue");
line(this.e1.x, this.e1.y, this.e2.x, this.e2.y);
}
}
class StickC {
constructor(p1, p2, l, s=false) {
this.p1 = p1;
this.p2 = p2;
this.l = l;
this.l2 = l*l;
this.s = s;
}
get_dir() {
return p5.Vector.sub(this.p2.p, this.p1.p).normalize();
}
show() {
if(!this.s) return;
strokeWeight(2);
stroke("purple")
line(this.p1.p.x, this.p1.p.y, this.p2.p.x, this.p2.p.y);
}
constraint() {
let delta = p5.Vector.sub(this.p2.p, this.p1.p);
delta.mult(this.l2 / (delta.magSq() + this.l2) - 0.5);
if(!this.p1.fixed) this.p1.p.sub(delta);
if(!this.p2.fixed) this.p2.p.add(delta);
}
}
class PointPointC {
constructor(p1, p2) {
this.p1 = p1;
this.p2 = p2;
}
constraint() {
let d = p5.Vector.sub(this.p2.p, this.p1.p);
if(this.p1.r2 + this.p2.r2 > d.magSq()) { // Intersection
// console.log("intersection")
d.div((this.p1.r2 + this.p2.r2));
if(!this.p1.fixed) this.p1.p.sub(d);
if(!this.p2.fixed) this.p2.p.add(d);
}
}
show(){}
}
class StickStickC {
constructor(s1, s2) {
this.s1 = s1;
this.s2 = s2;
}
constraint() {
// Compute projection vector for s1.p1 and s1.p2 to s2
let p1 = this.s1.p1.p;
let p2 = this.s1.p2.p;
let q1 = this.s2.p1.p;
let q2 = this.s2.p2.p
let dir = this.s2.get_dir();
// handle orthogonal case?
let proj1 = p5.Vector.mult(dir, p5.Vector.dot(p5.Vector.sub(p1, q1), dir));
let orth1 = p5.Vector.sub(p1, q1).sub(proj1)
let proj2 = p5.Vector.mult(dir, p5.Vector.dot(p5.Vector.sub(p2, q1), dir));
let orth2 = p5.Vector.sub(p2, q1).sub(proj2)
line(orth1.x + proj1.x + q1.x, orth1.y + proj1.y + q1.y, proj1.x + q1.x, proj1.y + q1.y)
line(orth2.x + proj2.x + q1.x, orth2.y + proj2.y + q1.y, proj2.x + q1.x, proj2.y + q1.y)
// console.log(proj1.heading(), proj2.heading())
if(abs(orth1.heading() - orth2.heading()) >= 0.0001) {
console.log("crossed")
if(orth1.magSq() < orth2.magSq()) {
orth1.normalize();
orth1.mult(0.4)
this.s1.p1.p.sub(orth1);
this.s1.p2.p.sub(orth1);
this.s2.p1.p.add(orth1);
this.s2.p2.p.add(orth1)
} else {
orth2.normalize();
orth2.mult(0.4)
this.s1.p1.p.sub(orth2);
this.s1.p2.p.sub(orth2);
this.s2.p1.p.add(orth2);
this.s2.p2.p.add(orth2)
}
}
strokeWeight(2);
stroke("blue")
// line(p1.x, p1.y, proj1.x + q1.x, proj1.y + q1.y)
// line(p2.x, p2.y, proj2.x + q1.x, proj2.y + q1.y)
}
show() {
}
}
class Plant {
constructor(world, gpoints, K, L, x0, y0) {
this.world = world;
this.gpoints = gpoints;
this.K = K;
this.L = L;
this.h = L / K;
this.p = createVector(x0, y0);
this.x0 = x0;
this.y0 = y0;
this.points = [];
this.c = random() * 100 + 100
this.create();
this.copyPoints();
}
create() {
let m1 = new MassPoint(this.x0, this.y0, 8, 1, true);
this.world.add(m1);
this.points.push(m1);
console.log(this.h)
for(let i = 1; i < this.K + 1; ++i) {
let m = new MassPoint(this.x0, this.y0 - i * this.h);
let s = new StickC(m, this.points[this.points.length-1], this.h)
this.world.add(m);
this.points.push(m);
this.world.add_c(s);
}
// Body
let first = this.points[0];
let last = this.points[this.points.length - 1];
this.world.add_c(new StickC(first, last, first.p.dist(last.p)));
for(let i = 0; i < this.K - 3 ; i += 2) {
let m1 = this.points[i];
let m2 = this.points[i+3];
this.world.add_c(new StickC(m1, m2, 3.5*this.h));
}
// Feet
let m2 = this.points[1];
let m3 = new MassPoint(m1.p.x - this.h, m1.p.y, 8, 1, true);
let m4 = new MassPoint(m1.p.x + this.h, m1.p.y, 8, 1, true);
this.world.add(m3);
this.world.add(m4);
let rl = 1;
this.world.add_c(new StickC(m2, m3, m2.p.dist(m3.p) * rl));
this.world.add_c(new StickC(m2, m4, m2.p.dist(m4.p) * rl));
}
show() {
// stroke(0, this.c, 0)
strokeWeight(map(this.L, 50, 200, 1, 2));
for(let i = 0; i < this.points.length - 2; ++i) {
line(this.points[i].p.x, this.points[i].p.y, this.points[i+1].p.x, this.points[i+1].p.y);
}
// fill("green")
beginShape()
vertex(this.x0, this.y0);
for(let i = 1; i < this.points.length - 2; ++i) {
let e = p5.Vector.sub(this.points[i+1].p, this.points[i].p);
e.rotate(PI/2);
e.normalize().mult(10.0/(i+1));
let x1 = (this.points[i].p.x + this.points[i+1].p.x) / 2;
let y1 = (this.points[i].p.y + this.points[i+1].p.y) / 2;
// line(x1, y1, x1 + e.x, y1 + e.y)
vertex(x1 + e.x, y1 + e.y);
// vertex(x1, y1, x1 - e.x, y1 - e.y);
}
vertex(this.points[this.points.length-2].p.x, this.points[this.points.length-2].p.y)
for(let i = this.points.length - 3; i >= 0; i--) {
let e = p5.Vector.sub(this.points[i+1].p, this.points[i].p);
e.rotate(PI/2);
e.normalize().mult(9.0/(i*i+1));
let x1 = (this.points[i].p.x + this.points[i+1].p.x) / 2;
let y1 = (this.points[i].p.y + this.points[i+1].p.y) / 2;
vertex(x1 - e.x, y1 - e.y);
}
vertex(this.x0, this.y0)
endShape()
}
copyPoints() {
for(let p of this.points) {
this.gpoints.push(p)
}
}
}
let points = [];
let plants = [];
let frame = 0;
function setup() {
createCanvas(400, 400);
img.loadPixels();
world = new World();
// randomSeed(1);
// Walls
world.add_gc(new WallC(0, 400, 400, 400));
world.add_gc(new WallC(0, 0, 400, 0));
world.add_gc(new WallC(0, 0, 0, 400));
world.add_gc(new WallC(400, 0, 400, 400));
for(let i = 0; i < grassN; ++i) {
plants.push(new Plant(world, points, 6, randomGaussian(150, 50), 450 * random() - 25, 380));
}
// for(let p1 of points) {
// for(let p2 of points) {
// if(p1 != p2) {
// world.add_c(new PointPointC(p1, p2));
// }
// }
// }
}
let particles = [];
function draw() {
background("skyblue");
W = randomGaussian() * W_C + 10;
if(particles.length < N) {
for(let i = 0; i < 5; ++i) {
let m = new MassPoint(30 * random(), 100 * random());
world.add(m);
particles.push(m);
// if(points.length > 1) {
// world.add_c(new StickC(m, points[points.length-2], 30 + random() * 20));
// }
for(let j = 0; j < points.length; ++j) {
world.add_c(new PointPointC(m, points[j]));
}
}
}
// else {
// console.log("finished")
// }
let i = 0;
for(let p of plants) {
let c = map(i, 0, grassN, 150, 200)
stroke(0, c - 20, 0);
fill(0, c, 0);
p.show();
i += 1;
}
world.update();
noStroke();
fill(0, 150, 0)
rect(0, 350, 400, 400)
fill("yellow")
circle(320, 10, 100)
// world.show();
// world.show_c();
// image(img, 0, 0);
}
// function mousePressed() {
// let json = {};
// for(let ol of world.objects) {
// ol.getColor();
// json[ol.id] = ol.c;
// }
// saveJSON(json, 'test.json');
// }