• Options

Hilbert Curve

The Hilbert Curve is one of many space-filling curves. As such it is related to other Peano Curves. With infinitely many iterations it would perfectly fill out a complete plane. Hilbert Curves are used in a lot of different places, like the Blender rendering algorithm, to step over each point in a plane only once and preserving locality. This means that points on a Hilbert Curve that are close to each other in the 2D plane would also be close to each other, in terms of distance traveled along the 1D path of the curve.

Hilbert Curves are constructed by drawing a small shape that looks a bit like a rotated u, for small tiles in the plane, and then connecting them up into one continuous curve.

There is a wonderful video by 3Blue1Brown diving into the topic of Hilbert Curves, which has a pretty animation as to how they are constructed, which you should check out!

What you see here is an L-System Implementation, which is generated by the L-System Algorithm with the following settings:

const hilbertCurve: Ruleset = {
    color: "#fc79ff",
    minIterations: 1,
    maxIterations: 9,
    axiom: "W",
    replace: {
      V: "-WF+VFV+FW-",
      W: "+VF-WFW-FV+",
    },
    angle: 90,
    initLength: (sizes) => Math.min(sizes.width, sizes.height) * 0.7,
    initTranslation: (sizes, initialLength) => [
      sizes.width / 2 - initialLength / 2,
      sizes.height / 2 + initialLength / 2,
    ],
    divideFactor: 2,
  };

Because this is an L-System, the generation works a little differently, namely, on each iteration, we produce a new string of letters, that we then map into drawing commands. Draw a line and move forward, rotate right, draw a line and move forward, rotate right again... and so on. The L-System's axiom (the letter sequence we start with) and its replacement rules are set up in such a way, that with every iteration of replacements, we get the next iteration of a Hilbert Curve!

This fractal, by its nature as an L-System, is related to all the other L-System Fractals. A few you can check out: Sierpinski Curve, Fern 1, and the Lévy Curve.

The alphabet to instructions set used to draw this fractal are the same as for the other L-Systems:

const drawRules: Record<string, () => void> = {
    V: () => {},
    W: () => {},
    X: () => {},
    Y: () => {},
    Z: () => {},
    G: drawForward,
    F: drawForward,
    f: () => ctx.translate(0, -len),
    "+": () => ctx.rotate(angle * rotationDirection),
    "-": () => ctx.rotate(angle * -rotationDirection),
    "|": () => ctx.rotate(180),
    "[": () => ctx.push(),
    "]": () => ctx.pop(),
    "#": () => (ctx.lineWidth = weight += weightIncrement) ,
    "!": () => (ctx.lineWidth = weight -= weightIncrement) ,
    ">": () => (len *= scale),
    "<": () => (len /= scale),
    "&": () => (rotationDirection = -rotationDirection),
    "(": () => (angle += angleIncrement),
    ")": () => (angle -= angleIncrement),
};