• Options

Lévy Curve

The Lévy Curve, at least to me, is one of the most beautiful fractals in this collection. Parts of it look like the more detailed "leaf" parts of the Pythagoras Tree Fractal and the full curve to me resembles the canopy of the Fractal Canopy.

To construct a Lévy Curve you start with a simple line. That line forms the basis of an isosceles triangle with a right angle at the top. You paint the two same-length sides of the triangle and erase the base (the original line). You then have 2 lines. For both, you repeat the process, giving you 4 lines. And so on.

Recursively building an isosceles triangle on top of a straight line, then deleting the straight line, leaving only the two same-length sides of the created triangle. Then repeat for all the new lines created that way. With each iteration, the amount of line segments doubles. Visually, some of them connect, making long lines though, so it's hard to keep count.

The Lévy Curve is self-similar because each "half" - left and right are complete Lévy Curves again. In the middle, the two overlap, so it's a little bit hard to see.

What you see above is an L-System Implementation of the Lévy Curve which is generated by the L-System Algorithm with the following settings:

const levyCurve: Ruleset = {
    color: "#54bffc",
    minIterations: 1,
    maxIterations: 17,
    axiom: "F",

    replace: {
      F: "-F++F-",
    },
    angle: 45,
    initLength: (sizes) =>
      Math.min(sizes.width, sizes.height) *
      (sizes.width > sizes.height * 1.3 ? 0.7 : 0.45),
    initTranslation: (sizes, initialLength) => [
      sizes.width / 2 - initialLength / 2,
      sizes.height / 2 + initialLength / 2.6,
    ],
    initRotation: (ctx) => ctx.rotate(radians(90)),
    divideFactor: 1.417,
  };

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 Hilbert 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),
};