Circular light source + multiple rays per point
Log in to post a comment.
const light_Y = 25; // min=0, max=35, step=1 const light_R = 20; // min=1, max=25, step=1 const N_points = 1000000; const stroke_len = 1; const N_rays = 16; // min=1, max=64, step=1 const fade = 1; // min=0, max=1, step=1 (False, True) const max_D = 170; // min=100, max=250, step= 1 const show_light = 1; // min=0, max=1, step=1 (True circle source, Candle) let R = light_R; let R2 = R * R; Canvas.setpenopacity(-0.5); const t = new Turtle(); const light = [0, -light_Y]; const walls = [[[-75, -25], [-75, 25]], [[-80, -25], [-75, -25]], [[75, -25], [75, 25]], [[75, -25], [80, -25]], [[-25, -75], [25, -75]], [[-25, 50], [25, 50]], [[-75, 75], [-50, 75]], [[-50, 75], [-50, 100]], [[75, 75], [50, 75]], [[50, 75], [50, 100]]]; for (let i = 0; i < walls.length; i++) { if (walls[i][0][0] == walls[i][1][0]) { [walls[i][0][1], walls[i][1][1]] = [Math.min(walls[i][0][1], walls[i][1][1]), Math.max(walls[i][0][1], walls[i][1][1])] } else { [walls[i][0][0], walls[i][1][0]] = [Math.min(walls[i][0][0], walls[i][1][0]), Math.max(walls[i][0][0], walls[i][1][0])] } } if (show_light == 0) { // draw true light circle for (let r = 0.1; r <= R; r += 0.05) { t.jump(light[0] - r, light[1]); t.seth(-90); t.circle(r); } } else { // draw candle let fire_r = Math.max(2, light_R / 5); for (let r = 0.1; r <= fire_r; r += 0.05) { t.jump(light[0] - r, light[1]); t.seth(-90); t.circle(r); } let fire_h = 2.5 * fire_r; for (let dy = 0; dy <= fire_h; dy += 0.05) { let dx = fire_r * (1 - dy / fire_h)**0.6; let y = light[1] - dy - 1; let dy1 = light[1] - y; if (dy1 <= fire_r) { let dr = Math.sqrt(fire_r**2 - dy1**2); t.jump(-dx, y); t.goto(-dr, y); t.jump(+dr, y); t.goto(+dx, y); } else { t.jump(-dx, y); t.goto(+dx, y); } } let candle_r = 4; let candle_y = light[1] + fire_r + 1 for (let y = candle_y; y < 50; y += 0.05) { t.jump(-candle_r, y); t.goto(+candle_r, y); } for (let x = -0.5; x <= 0.5; x += 0.05) { t.jump(x, candle_y); t.goto(x, light[1] + fire_r); } } function intersects(p1, p2, w1, w2) { if (w1[0] == w2[0]) { if (((p1[0] < w1[0]) && (p2[0] < w1[0])) || ((p1[0] > w1[0]) && (p2[0] > w1[0]))) { return false; } else { let y = p1[1] + (p2[1] - p1[1]) / (p2[0]- p1[0]) * (w1[0] - p1[0]); return (w1[1] < y) && (y < w2[1]); } } else { if (((p1[1] < w1[1]) && (p2[1] < w1[1])) || ((p1[1] > w1[1]) && (p2[1] > w1[1]))) { return false; } else { let x = p1[0] + (p2[0] - p1[0]) / (p2[1]- p1[1]) * (w1[1] - p1[1]); return (w1[0] < x) && (x < w2[0]); } } } function walk(frame) { let x = -100 + 200 * Math.random(); let y = -100 + 200 * Math.random(); let p = [x, y]; let dx = light[0] - x, dy = light[1] - y; let d2 = dx * dx + dy * dy; let n = 0; for (let i = 0; i < N_rays; i++) { let phi = 2 * Math.PI * Math.random(); let light_p = [light[0] + R * Math.cos(phi), light[1] + R * Math.sin(phi)]; let ok = true; for (let w of walls) { if (intersects(light_p, p, w[0], w[1])) { ok = false; break; } } if (ok) { n++; } } if (n > 0) { let d = Math.sqrt(d2); let s = stroke_len / d * (n / N_rays); if (fade == 1) { s *= Math.max(0.0, (1 - d / max_D))**2; } [dx, dy] = [dx * s, dy * s]; t.jump(x, y); t.goto(x + dx, y + dy); } return frame < N_points; }