roundabout
A bit of algorithmic 'art' from 1967. I was working as a vac job for IBM at the Technical University of Denmark in Lyngby, writing a package for the Calcomp plotter. I was asked to prepare a drawing of a super-egg for Piet Hein who had recently popularized the super-egg in a design for a Swedish roundabout. The idea was that a superegg has less sharp ends for cars than those seen in an elliptical roundabout. I liked the idea, but not that it was not continuously differentiable at the points; so I came up with an alternative based on the principle of a driver turning the steering wheel in a regular sine wave. The resulting curve is related to Lissajous figures and hypoid curves, but different. With parameters taken outside the original elongated roundabout it gives nice patterns. The fiddle above is rather more interactive than the 1 day turnaround (if lucky) that I had on runs with the plotter.
by sjpt
HTML
<!DOCTYPE html><html lang="en"><body>
turn offset: <input type="range" min="0" max="2" step="0.001" id="_o" oninput="o=+this.value; draw();">
turn freq: <input type="range" min="0" max="1" step="0.0001" id="_f" oninput="f=+this.value; draw();">
turn scale: <input type="range" min="0" max="1000" step="0.01" id="_s" oninput="s=+this.value; draw();">
<br>
<!--- vel: <input type="range" min="0" max="500" id="_v" oninput="v=+this.value; draw();"> --->
num: <input type="range" min="0" max="2000" id="_n" oninput="n=+this.value; draw();">
dist: <input type="range" min="0.005" max="0.1" step="0.001" id="_d" oninput="d=+this.value; draw();">
<button onclick="roundabout()">roundabout</button>
<p id="msg"></p>
<canvas id="canvas" height="400" width="700" style="background: black"></canvas>
</body></html>
JavaScript
var t, a, v = 84.66, o = 0.118, f = 0.1967, s = 92, d=0.01, n = 500;
function setsliders() {
for (const x in {o, f, s, n, d}) window['_' + x].value = window[x];
}
setsliders();
var {cos, sin, min, max} = Math;
function draw() {
for (const x in {o, f, s, n, d}) window[x] = +window['_' + x].value;
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
if (!ctx) return;
ctx.clearRect(0,0,9999,9999);
// set line stroke and line width
ctx.strokeStyle = 'red';
ctx.lineWidth = 1
var minx, maxx, miny, maxy
for (const ii of [0,1]) {
var x, y;
if (ii === 0) { // find scale
minx = Infinity; maxx = -Infinity; miny = Infinity; maxy = -Infinity;
v = 1;
x = 0; y = 0;
} else { // run using scale
const sc = Math.max((maxx-minx)/canvas.width, (maxy-miny)/canvas.height) * 1.2;
v /= sc; // _v.value = v;
x = (maxx+minx) / sc * -0.5 + canvas.width / 2;
y = (maxy+miny) / sc * -0.5 + canvas.height / 2;
ctx.beginPath();
ctx.moveTo(x, y);
}
for (let t = 0; t < n; t+=d) {
a = o * t - s * sin(f * t);
x += d * v * cos(a);
y += d * v * sin(a);
if (ii === 0) {
minx = min(minx, x); miny = min(miny, y)
maxx = max(maxx, x); maxy = max(maxy, y)
} else {
ctx.lineTo(x, y);
}
}
}
ctx.stroke();
msg.innerHTML = JSON.stringify({v, o, f, s, n, d}).replaceAll('"',' ')
}
draw();
function roundabout() {
o = 0.013; f = 0.0262; s = 0.47; n = 480; d = 0.01;
setsliders();
draw();
}