raw Software
RAW Software Graphics Computational Geometry

Point Orientation Relative to a Directed Line

Robert Eisele

The sign of the 2D perp product determines on which side of a directed line a point lies. Let the line point from A to B, and let P be the test point.

The orientation predicate is

orient2d(A, B, P) =
    (B.x - A.x) * (P.y - A.y)
  - (B.y - A.y) * (P.x - A.x)

Its value is twice the signed area of triangle ABP:

Reversing the line direction from A -> B to B -> A reverses the sign and therefore swaps left and right.

JavaScript Implementation

function pointOrientation(A, B, P, relativeTolerance = 8 * Number.EPSILON) {
    const abx = B.x - A.x;
    const aby = B.y - A.y;
    const apx = P.x - A.x;
    const apy = P.y - A.y;

    if (abx === 0 && aby === 0) {
        return "degenerate";
    }

    const signedDoubleArea = abx * apy - aby * apx;
    const scale = Math.abs(abx * apy) + Math.abs(aby * apx);
    const tolerance = relativeTolerance * Math.max(1, scale);

    if (signedDoubleArea > tolerance) return "left";
    if (signedDoubleArea < -tolerance) return "right";
    return "collinear";
}

The explicit degenerate result handles equal coordinates for A and B, where no directed line exists. For exact integer coordinates, pass 0 as the fourth argument. The small default tolerance prevents ordinary floating-point rounding noise from turning a nearly collinear result into an accidental left or right classification.

const A = {x: 0, y: 0};
const B = {x: 4, y: 0};

pointOrientation(A, B, {x: 2, y: 3});   // "left"
pointOrientation(A, B, {x: 2, y: -3});  // "right"
pointOrientation(A, B, {x: 2, y: 0});   // "collinear"
pointOrientation(A, A, {x: 2, y: 3});   // "degenerate"

For very large coordinates or numerically sensitive geometric algorithms, floating-point orientation predicates may require adaptive exact arithmetic rather than a fixed tolerance.