"use strict" const Vec2 = { add({x:x1, y:y1}, {x:x2, y:y2}) { return Object.freeze({x:x1+x2, y:y1+y2}) }, avg({x:x1, y:y1}, {x:x2, y:y2}) { return Object.freeze({x:(x1+x2)/2, y:(y1+y2)/2}) }, fromPolar({x,y}, radius, angle) { return Object.freeze({x: x + radius * Math.cos(angle), y: y + radius * Math.sin(angle)}) }, sub({x:x1, y:y1}, {x:x2, y:y2}) { return Object.freeze({x:x1-x2, y: y1-y2}) }, angle({x, y}) { return Math.atan2(y, x) }, len({x, y}) { return Math.sqrt((x*x) + (y*y)) }, dist(a, b) { return Vec2.len(Vec2.sub(a, b)) }, distLess(a, b, radius) { const {x, y} = Vec2.sub(a, b) return ((x*x) + (y*y)) < (radius * radius) }, zero: Object.freeze({x:0, y:0}) }; function drawVertices(context, vertices, draw=true, close=true) { if (draw) context.beginPath(); context.moveTo(vertices[0].x, vertices[0].y); vertices.slice(1).forEach(({x, y}) => context.lineTo(x, y)) if (close) context.lineTo(vertices[0].x, vertices[0].y); if (draw) context.stroke(); } function convrgb(values) { return 'rgb(' + values.map(x=>x|0).join(', ') + ')'; }; // apply mild noise on the sensor reading, and clamp between valid values function gaussNoise(sigma=1) { const x0 = 1.0 - Math.random(); const x1 = 1.0 - Math.random(); return sigma * Math.sqrt(-2 * Math.log(x0)) * Math.cos(2 * Math.PI * x1); }; const zip = (arr, ...arrs) => { return arr.map((val, i) => arrs.reduce((a, arr) => [...a, arr[i]], [val])); } const sum = (arr) => arr.reduce((a,b) => a+b)