Point in triangle test

by ciju

HTML

<pre>Click: place the point.
Double click: random triangle.</pre>

<pre id="result"></pre>

<canvas width="500" height="500"></canvas>

JavaScript

var ctx = $("canvas")[0].getContext("2d");
var W = 500;
var H = 500;

var point = {
    x: W / 2,
    y: H / 2
};
var triangle = randomTriangle();

$("canvas").mousemove(function (evt) {
    point.x = evt.pageX - $(this).offset().left;
    point.y = evt.pageY - $(this).offset().top;
    test();
});

$("canvas").click(function (evt) {
    triangle = randomTriangle();
    test();
});

test();

function test() {
    var slopes = triangleSlopes(triangle.a, triangle.b, triangle.c);
    var result = ptInTriangle(point, triangle.a, triangle.b, triangle.c, slopes);

    showResults(triangle, point, result);
    render(result);
}

function slope(p1, p2) {
    return (p2.y - p1.y) / (p2.x - p1.x);
}

function triangleSlopes(p0, p1, p2) {
    var leftSlope = slope(p0, p2);
    var rightSlope = slope(p1, p2);
    return {
        leftSlope: leftSlope,
        rightSlope: rightSlope
    };
}

function sameSign(a, b) {
    return (a <= 0) === (b <= 0);
}

function ptInTriangle(p, p0, p1, p3, slopes) {
    if (p.y < p0.y && p0.y < p3.y) {
        return false;
    } else if (p.y > p0.y && p0.y > p3.y) {
        return false;
    }
    if (p.x < p3.x) {
        var lSlope = slopes.leftSlope;
        var plSlope = slope(p, p0);

        if (!sameSign(lSlope, plSlope)) {
            return false;
        }
        return Math.abs(plSlope) <= Math.abs(lSlope);
    }
    var rSlope = slopes.rightSlope;
    var prSlope = slope(p, p1);

    if (!sameSign(rSlope, prSlope)) {
        return false;
    }
    return Math.abs(prSlope) <= Math.abs(rSlope);
}


function render(highlight) {
    ctx.fillStyle = "#CCC";
    ctx.fillRect(0, 0, 500, 500);
    drawTriangle(triangle.a, triangle.b, triangle.c, highlight);
    drawPoint(point);
}

function drawTriangle(p0, p1, p2, highlight) {
    ctx.fillStyle = highlight ? "lightgreen" : "#999";
    ctx.beginPath();
    ctx.moveTo(p0.x, p0.y);
    ctx.lineTo(p1.x, p1.y);
    ctx.lineTo(p2.x, p2.y);
    ctx.closePath();
    ctx.fill();
   ...