Contained lines
長方形内部を斜線で塗りつぶしたくて作り始めたが、長方形の辺と交点の計算や、交点がどこに現れるかの場合分けなどで想像以上に複雑なコードとなってしまった。
const dang = 0.01;
let shapes = []
class Shape {
constructor(n, x, y, w, h, ang, dir) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.ang = ang;
this.dir = dir;
this.n = n
}
update() {
this.ang += this.dir * dang;
if (this.ang >= TWO_PI) this.ang -= TWO_PI;
}
draw() {
push();
stroke(0);
noFill();
translate(this.x, this.y);
drawLines(this.n, this.w, this.h, this.ang);
pop();
}
}
function setup() {
createCanvas(windowWidth, windowHeight);
background(255);
ang = PI/4;
const M = 300
const N = 20;
for (let i = 0; i < M; i++) {
const x = random(-width/2, width + width/2);
const y = random(-height/2, height + height/2);
const w = random(0, width);
const h = random(0, height);
const ang = random(0, TWO_PI);
const dir = random([-1, 1]);
shapes.push(new Shape(N, x, y, w, h, ang, dir))
}
}
function draw() {
background(255);
for (const shape of shapes) {
shape.update();
shape.draw();
}
}
const drawLines = (N, W, H, ang) => {
const xsp = abs(tan(ang) / H);
for (let i = 0; i < N; i++) {
const x = map(i, 0, N, -xsp, W + xsp);
drawLineInRect(W, H, x, ang);
}
}
const drawLineInRect = (W, H, x, ang) => {
const p = createVector(x, 0);
const v0 = createVector(W - p.x, 0 - p.y);
const v1 = createVector(W - p.x, H - p.y);
const v2 = createVector(0 - p.x, H - p.y);
const v = p5.Vector.fromAngle(ang);
if (0 <= x && x <= W) {
const t = solve_intersect_wrapper_inner(W, H, p, v, v0, v1, v2, ang);
if (t === null) return;
const n0 = p5.Vector.fromAngle(ang);
n0.setMag(t)
line(p.x, p.y, p.x + n0.x, p.y + n0.y);
} else if (x < 0) {
const [t0, t1] = solve_intersect_wrapper_left(W, H, p, v, v0, v1, v2, ang);
if (t0 === null || t1 === null) return;
const n0 = p5.Vector.fromAngle(ang);
n0.setMag(t0)
const n1 = p5.Vector.fromAngle(ang);
n1.setMag(t1)
line(p.x + n0.x, p.y + n0.y, p.x + n1.x, p.y + n1.y);
} else if (x > W) {
const [t0, t1] = solve_intersect_wrapper_right(W, H, p, v, v0, v1, v2, ang);
if (t0 === null || t1 === null) return;
const n0 = p5.Vector.fromAngle(ang);
n0.setMag(t0)
const n1 = p5.Vector.fromAngle(ang);
n1.setMag(t1)
line(p.x + n0.x, p.y + n0.y, p.x + n1.x, p.y + n1.y);
}
};
const solve_intersect_wrapper_inner = (W, H, p, v, v0, v1, v2, ang) => {
const ang1 = v0.angleBetween(v1);
const ang2 = v0.angleBetween(v2);
if (0 <= ang && ang <= ang1) {
return solve_intersect(v, p.x, p.y, W, 0, W, H);
} else if (ang1 <= ang && ang <= ang2) {
return solve_intersect(v, p.x, p.y, 0, H, W, H);
} else if (ang2 <= ang && ang <= PI) {
return solve_intersect(v, p.x, p.y, 0, 0, 0, H);
} else {
return null;
}
}
const solve_intersect_wrapper_left = (W, H, p, v, v0, v1, v2, ang) => {
const ang1 = v0.angleBetween(v1);
const ang2 = v0.angleBetween(v2);
if (0 <= ang && ang <= ang1) {
return [solve_intersect(v, p.x, p.y, 0, 0, 0, H),
solve_intersect(v, p.x, p.y, W, 0, W, H)]
} else if (ang1 <= ang && ang <= ang2) {
return [solve_intersect(v, p.x, p.y, 0, 0, 0, H),
solve_intersect(v, p.x, p.y, 0, H, W, H)]
} else {
return [null, null];
}
}
const solve_intersect_wrapper_right = (W, H, p, v, v0, v1, v2, ang) => {
const ang1 = v0.angleBetween(v1) + PI;
const ang2 = v0.angleBetween(v2) + PI;
if (0 <= ang && ang <= ang1) {
return [null, null];
} else if (ang1 <= ang && ang <= ang2) {
return [solve_intersect(v, p.x, p.y, W, 0, W, H),
solve_intersect(v, p.x, p.y, 0, H, W, H)]
} else if (ang2 <= ang && ang <= PI) {
return [solve_intersect(v, p.x, p.y, W, 0, W, H),
solve_intersect(v, p.x, p.y, 0, 0, 0, H)]
} else {
return [null, null];
}
}
// 直線 (x, y) = (x0, y0) + t*vと
// 直線 (x, y) = (x1, y1) + s*u
// の交点を求める
const solve_intersect = (v, x0, y0, x1, y1, x2, y2) => {
const u = createVector(x2 - x1, y2 - y1);
return (u.y*(x1 - x0) - u.x*(y1 - y0)) / (v.x*u.y - v.y*u.x);
};