Published
Edited
Aug 27, 2019
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
const context = DOM.context2d(width, width);

console.clear();

const points = [];
const tmp = [];
const c_n = 60;
for (let i = 0; i < c_n; ++i) {
const c = coordsFromDeg(i * (360 / c_n), r, [width / 2, width / 2]);
tmp.push(c);
}
points.push(tmp);

const environment = [];
points.forEach(p => environment.push(new Obstacle(p, context)));

const rays = [];
for (let i = 0; i < n; ++i) {
rays.push(
new Ray([width / 2, width / 2, i * (360 / n)], environment, context)
);
}

while (true) {
yield Promises.delay(1).then(() => {
context.clearRect(0, 0, width, width);

environment.forEach(obsticle => obsticle.draw());
rays.forEach(r => r.run());

return context.canvas;
});
}
}
Insert cell
class Ray {
constructor([x, y, deg], environment, context) {
this.history = [[x, y]];
this.pos = [x, y];
this.r = 3;
this.deg = deg;
this.context = context;
this.environment = environment;
this.stepSize = 2;
}

run() {
this.intersection();
this.step();
this.draw();
}

intersection() {
const { pos, r, environment, history } = this;
for (let obsticle of environment) {
for (let segment of obsticle.lines) {
const intersect = intersectionCL([...pos, 1], segment);
const notOnPoint = dist2D(history[history.length - 1], pos) > 10;

if (intersect && notOnPoint) {
const beam = [history[history.length - 1], pos];
const angle = degBetweenLines(beam, segment);
const segAngle = degBetweenLines(segment, [[0, 0], [width, 0]]);

this.history.push(pos);

this.deg = this.deg + angle * 2;
}
}
}
}

step() {
const { pos, deg, history, stepSize } = this;
const nextPos = coordsFromDeg(deg, stepSize, pos);
this.pos = nextPos;
}

draw() {
const { history, pos, context, r } = this;

const c = "rgba(150, 150, 150, 1)";
if (showTrace) {
line(history[history.length - 1], pos, context, { color: c });
for (let i = history.length - 1; i > 0; --i) {
line(history[i], history[i - 1], context, { color: c });
}
}
circle([...pos, r], context);
}
}
Insert cell
class Obstacle {
constructor(points, context) {
this.points = points;
const pl = points.length;
this.lines = points.map((p, i) => [p, points[(i + 1) % pl]]);
this.context = context;
}

draw() {
const { points, context } = this;
const l = points.length;
for (let i = 0; i < l; ++i) {
circle([...points[i], 1.5], context);
line(points[i], points[(i + 1) % l], context);
}
}
}
Insert cell
function intersectionCL([cx, cy, r], [[x1, y1], [x2, y2]]) {
const d = pointDistFromLine([cx, cy], [[x1, y1], [x2, y2]]);

const inLineSegment =
dist2D([cx, cy], [x1, y1]) + dist2D([cx, cy], [x2, y2]) <=
dist2D([x1, y1], [x2, y2]) + 1;

if (inLineSegment && Math.abs(d) < 1) {
return [cx, cy];
}

return false;
}
Insert cell
function degBetweenLines([s1, e1], [s2, e2]) {
const m1 = slope(s1, e1);
const m2 = slope(s2, e2);
return Math.atan(Math.abs((m2 - m1) / (1 + m1 * m2))) * (180 / Math.PI);
}
Insert cell
function pointDistFromLine([x, y], [[x1, y1], [x2, y2]]) {
return (
((x - x1) * (y2 - y1) - (y - y1) * (x2 - x1)) / dist2D([x1, y1], [x2, y2])
);
}
Insert cell
function slope([x1, y1], [x2, y2]) {
if (x2 - x1 === 0) return 10000000000000000; // should be inifinity but i want to work with it... its ugly i know
return (y2 - y1) / (x2 - x1);
}
Insert cell
import { circle, line, coordsFromDeg, dist2D } from '@timhau/geometry'
Insert cell
import { slider, checkbox } from '@jashkenas/inputs'
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more