Skip to content

Koch Curve ​

The Koch curve: each segment is replaced by four, with a bump in the middle, computed with vectors. Three curves around a triangle make the snowflake. After The Nature of Code.

js
const shape = Inputs.radio(["Curve", "Snowflake"], {label: "Shape", value: "Snowflake"});
js
const levels = Inputs.range([0, 5], {label: "Levels", step: 1, value: 4});
js
const width = 640;
const height = shape === "Curve" ? 200 : 640;
const padding = 10;
const points = [];

if (shape === "Curve") {
  points.push(cm.vec(padding, height - padding), cm.vec(width - padding, height - padding));
} else {
  const d = width - padding * 2;
  const y2 = height - padding;
  const y1 = y2 - d * 0.75;
  const dx = (d * Math.sqrt(3)) / 4;
  points.push(cm.vec(width / 2 - dx, y1), cm.vec(width / 2 + dx, y1), cm.vec(width / 2, y2));
}

// Replace the segment from point i to point j with four segments.
function koch(i, j, level) {
  if (level >= levels) return;
  const n = points.length;
  const start = points[i % n];
  const end = points[j % n];
  const dir = cm.vecSub(end, start).div(3);
  const p0 = cm.vecAdd(start, dir);
  const p1 = cm.vecAdd(p0, cm.vecFromAngle(dir.angle() - Math.PI / 3).mult(dir.mag()));
  const p2 = cm.vecAdd(p0, dir);
  points.splice(i + 1, 0, p0, p1, p2);
  for (let k = i + 4; k > i; k--) koch(k - 1, k, level + 1);
}

if (shape === "Curve") koch(0, 1, 0);
else for (let i = 2; i >= 0; i--) koch(i, i + 1, 0);

const renderer = cm.canvas({width, height});
const root = cm.flow().renderer(renderer);

root.data(points).append(cm.line, {
  x: (d) => d.x,
  y: (d) => d.y,
  stroke: "black",
  strokeWidth: 2,
  close: shape === "Snowflake",
});

root.render();

document.body.append(renderer.node());