Line Intersection Test

Working on another game feature, I now need to compute actual line and rectangle intersections rather than just detecting them. This is a quick test:

Click, drag, and release to draw a line. A point will be drawn at the intersection if there is one. Hit ‘S’ to toggle between treating the geometry as line segments or lines.

The demo uses some basic Phaser features for the interaction and drawing. The calculation is taken straight from Phaser’s Arcade Physics math. The full Javascript code is:

var game = new Phaser.Game(530, 300, Phaser.AUTO, 'gamecontainer',
                           { create: create, update: update, render: render });

var linea;
var lineb;

var setting;

var result;

var segment;

function create() {

    linea = new Phaser.Line(game.world.width/4, game.world.height/4,
                            3*game.world.width/4, 3*game.world.height/4);
    lineb = new Phaser.Line(game.world.width/4, 3*game.world.height/4,
                            3*game.world.width/4, game.world.height/4);

    game.input.onDown.add(click, this);
    setting = false;

    result = new Phaser.Point();

    segment = true;

    game.input.keyboard.addKey(Phaser.Keyboard.S)
        .onDown.add(function() {
            segment = !segment;
        }, this);
}


function update() {

    if (setting) {
        lineb.end.set(game.input.activePointer.x,
                      game.input.activePointer.y);

        if (!game.input.activePointer.isDown) {
            setting = false;
        }
    }
}


function click(pointer) {
    setting = true;
    lineb.start.set(pointer.x, pointer.y);
}


function render() {
    game.debug.geom(linea);
    game.debug.geom(lineb);

    if (intersection(linea.start.x, linea.start.y,
                     linea.end.x, linea.end.y,
                     lineb.start.x, lineb.start.y,
                     lineb.end.x, lineb.end.y,
                     segment,
                     result)) {
        result.x--;
        result.y--;
        game.debug.geom(result, '#ff0000');
    }
}

function intersection(ax, ay, bx, by, ex, ey, fx, fy, asSegment, result) {

    var a1 = by - ay;
    var a2 = fy - ey;
    var b1 = ax - bx;
    var b2 = ex - fx;
    var c1 = (bx * ay) - (ax * by);
    var c2 = (fx * ey) - (ex * fy);
    var denom = (a1 * b2) - (a2 * b1);

    if (denom === 0) {
        return false;
    }

    result.x = ((b1 * c2) - (b2 * c1)) / denom;
    result.y = ((a2 * c1) - (a1 * c2)) / denom;

    if (asSegment) {
        if ( result.x < Math.min(ax, bx) || result.x > Math.max(ax, bx) ||
             result.y < Math.min(ay, by) || result.y > Math.max(ay, by) ||
             result.x < Math.min(ex, fx) || result.x > Math.max(ex, fx) ||
             result.y < Math.min(ey, fy) || result.y > Math.max(ey, fy) ) {
            return false;
        }
    }

    return true;

}