block by fogleman 240854789bd3603444a77667514d0f52

Drawing a Butterfly (Motion Planning Algorithm)

Full Screen

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>body {padding: 0; margin: 0; overflow: hidden;}</style>
</head>
<body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.5/p5.min.js"></script>
    <script src="pieces.js"></script>
    <script src="sketch.js"></script>
</body>
</html>

sketch.js

function makePieces(records) {
    var pieces = [];
    for (var i = 0; i < records.length; i++) {
        var r = records[i];
        var x1 = r[0] * 1;
        var y1 = r[1] * 1;
        var x2 = r[2] * 1;
        var y2 = r[3] * 1;
        var j = r[4];
        var t = r[5];
        var num = r[6];
        pieces.push(new Piece(pieces, x1, y1, x2, y2, j, t, num));
    }
    return pieces;
}

var Piece = function(parent, x1, y1, x2, y2, jerk, duration, num) {
    if (Array.isArray(parent)) {
        parent = parent[parent.length - 1];
    }
    this.x1 = x1;
    this.y1 = y1;
    this.x2 = x2;
    this.y2 = y2;
    this.jerk = jerk;
    this.duration = duration;
    this.num = num;
    this.length = dist(x1, y1, x2, y2);
    if (parent) {
        this.t0 = parent.t1;
        this.t1 = this.t0 + duration;
        this.a0 = parent.a(this.t0);
        this.v0 = parent.v(this.t0);
        this.x0 = parent.xf;
    } else {
        this.t0 = 0;
        this.t1 = duration;
        this.a0 = 0;
        this.v0 = 0;
        this.x0 = 0;
    }
    this.xf = this.x0 + this.length;
}

Piece.prototype.hasT = function(t) {
    return t >= this.t0 && t < this.t1;
}

Piece.prototype.j = function(t) {
    return this.jerk;
}

Piece.prototype.a = function(t) {
    t = min(t - this.t0, this.duration);
    return this.a0 + this.jerk * t;
}

Piece.prototype.v = function(t) {
    t = min(t - this.t0, this.duration);
    return this.v0 + this.a0 * t + this.jerk * t * t / 2;
}

Piece.prototype.x = function(t) {
    t = min(t - this.t0, this.duration);
    var x = this.x0 + this.v0 * t + this.a0 * t * t / 2 + this.jerk * t * t * t / 6;
    return min(x, this.xf);
}

function evaluate(pieces, n, t) {
    for (var i = 0; i < pieces.length; i++) {
        if (pieces[i].hasT(t) || i == pieces.length - 1) {
            switch (n) {
                case 0: return pieces[i].x(t);
                case 1: return pieces[i].v(t);
                case 2: return pieces[i].a(t);
                case 3: return pieces[i].j(t);
                default: return 0;
            }
        }
    }
    return 0;
}

function drawPiece(dc, piece) {
    dc.vertex(piece.x1, piece.y1);
    dc.vertex(piece.x2, piece.y2);
}

function drawPieceLength(dc, piece, length) {
    var x1 = piece.x1;
    var y1 = piece.y1;
    var x2 = lerp(piece.x1, piece.x2, length / piece.length);
    var y2 = lerp(piece.y1, piece.y2, length / piece.length);
    dc.vertex(x1, y1);
    dc.vertex(x2, y2);
}

function drawPieces(dc, pieces, length) {
    if (pieces[0].num % 2 == 0) {
        dc.stroke(0);
    } else {
        dc.stroke(0, 32);
    }
    dc.beginShape();
    for (var i = 0; i < pieces.length; i++) {
        if (length <= 0) {
            break;
        }
        var piece = pieces[i];
        if (piece.length < length) {
            drawPiece(dc, piece);
        } else {
            drawPieceLength(dc, piece, length);
        }
        length -= piece.length;
    }
    dc.endShape();
}

function Drawing(pieces) {
    this.pieces = pieces;
    this.x = 0;
    this.y = 0;
    this.w = 300;
    this.h = 300;
}

Drawing.prototype.setTransform = function(dc) {
    var sx = dc.width / (this.w + 40);
    var sy = dc.height / (this.h + 40);
    var s = min(sx, sy);
    var dx = (dc.width - this.w * s) / 2;
    var dy = (dc.height - this.h * s) / 2;
    dc.resetMatrix();
    dc.translate(dx, dy);
    dc.scale(s);
    dc.translate(-this.x, -this.y);
}

Drawing.prototype.draw = function(dc, t) {
    var length = evaluate(this.pieces, 0, t);
    drawPieces(dc, this.pieces, length);
}

Drawing.prototype.done = function(t) {
    var pieces = this.pieces;
    return t > pieces[pieces.length - 1].t1;
}

var buffer;
var drawing;
var index;
var start;

function setup() {
    index = 0;
    start = millis() / 1000;
    drawing = new Drawing(makePieces(PIECES[index]));
    createCanvas(windowWidth, windowHeight);
    restart();
}

function windowResized() {
    resizeCanvas(windowWidth, windowHeight);
    restart();
}

function setStyle(dc) {
    dc.stroke(0);
    dc.strokeWeight(1);
    dc.strokeJoin(ROUND);
    dc.noFill();
}

function restart() {
    background(255);
    buffer = createGraphics(width, height);
    buffer.background(255);
    for (var i = 0; i < index; i++) {
        var d = new Drawing(makePieces(PIECES[i]));
        d.setTransform(buffer);
        d.draw(buffer, 1000000);
    }
}

function draw() {
    resetMatrix();
    var t = millis() / 1000 - start;
    if (drawing.done(t)) {
        setStyle(buffer);
        drawing.setTransform(buffer);
        drawing.draw(buffer, t);
        index++;
        start = millis() / 1000;
        drawing = new Drawing(makePieces(PIECES[index]));
        t = 0;
    }
    image(buffer, 0, 0);
    setStyle(window);
    drawing.setTransform(window);
    drawing.draw(window, t);
}