Sierpinski triangle

by alancnet

HTML

<canvas width="400" height="400" id="canvas">
</canvas>

CSS

canvas {
    border: solid 1px black;
}

JavaScript

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
Math.TAO = Math.PI * 2;

function segment(a, b, polarity) {
    return { 
        a: a, 
        b: b, 
        polarity: polarity, 
        children: [],
        vector: vector(b.x - a.x, b.y - a.y),
        normal: vector(b.x - a.x, b.y - a.y).normalize(),
        length: a.length(b)
    }
}
function log(v, text) {
    if (text) {
        console.log(text + ": %o", v);   
    } else {
        console.log(v);
    }
    return v;
}
function vector(x,y) {
    return {
        x: x, 
        y: y,
        multiply: function(v2) {
            if (isFinite(v2)) return vector(this.x * v2, this.y * v2);
            else return vector(this.x * v2.x, this.y * v2.y);
        },
        add: function(v2) {
            if (isFinite(v2)) return vector(this.x + v2, this.y + v2);
            else return vector(this.x + v2.x, this.y + v2.y);
        },
        rotate: function(r) {
            var length = this.length(vector(0,0));
            var normal = this.normalize();
            var radian = normal.radial();
            
            r -= radian;
            return vector(
                Math.cos(r),
                Math.sin(r)
            ).multiply(length);
        },
        length: function(v2) {
            return Math.sqrt(Math.pow(v2.x - this.x, 2) + Math.pow(v2.y - this.y, 2)); 
        },
        normalize: function() {
            var correction = 1 / this.length(vector(0,0));
            return vector(this.x * correction, this.y * correction);
        },
        radial: function() {
            return Math.atan2(this.x, this.y);
        }
    }
}

function rotation(f) {
    return (Math.TAO / 4) + Math.TAO * f;
}

function fractal(s) {
    // If this segment has been fractaled, fractal the children instead.
    if (s.children.length) s.children.forEach(fractal);
    else {
        var seg1 = segment(
            s.a,
            s.a.add(s.vector.rotate(rotation(-.166666666666666...