math_Plane.ts

import {EPS5} from "../math";
import {Vec3} from "./Vec3";
import {Line3} from "./Line3";

const DISJOINT = 0
const COINCIDE = 1;
const INTERSECT = 2;
/**
 * Plane class.
 * @constructor
 * @param {Vec3} [p] - Plane point.
 * @param {Vec3} [n] - Planet normal.
 */
class Plane {
    public p: Vec3;
    public n: Vec3;

    constructor(p: Vec3, n: Vec3) {
        this.p = p ? p.clone() : new Vec3();
        this.n = n ? n.clone() : this.p.normal();
    }

    public set(p: Vec3, n: Vec3) {
        this.p.copy(p);
        this.n.copy(n);
    }

    public getNormal(): Vec3 {
        return this.n.clone();
    }

    public distance(p: Vec3): number {
        let pp = this.getProjection(p);
        return p.distance(pp);
    }

    public getProjection(v: Vec3, def?: Vec3): Vec3 {
        return Vec3.proj_b_to_plane(v, this.n, def);
    }

    public getProjectionPoint(p: Vec3, vh?: Vec3): Vec3 {
        let v = p.sub(this.p),
            n = this.n,
            dist = v.dot(n);

        if (vh) {
            vh.copy(n.scale(dist));
        } else {
            vh = n.scale(dist);
        }
        return p.sub(vh);
    }

    public getIntersection(Pn1: Plane, Pn2: Plane, L: Line3): number {
        let u = Pn1.n.cross(Pn2.n);

        let ax = u.x >= 0 ? u.x : -u.x;
        let ay = u.y >= 0 ? u.y : -u.y;
        let az = u.z >= 0 ? u.z : -u.z;

        // test if the two planes are parallel
        if (ax + ay + az < EPS5) {
            // Pn1 and Pn2 are near parallel
            // test if disjoint or coincide
            let v = Pn2.p.sub(Pn1.p);
            if (Pn1.n.dot(v) == 0) {
                // Pn2.V0 lies in Pn1
                return COINCIDE; // Pn1 and Pn2 coincide
            } else {
                return DISJOINT; // Pn1 and Pn2 are disjoint
            }
        }

        // Pn1 and Pn2 intersect in a line
        // first determine max abs coordinate of cross product
        let maxc; // max coordinate
        if (ax > ay) {
            if (ax > az) {
                maxc = 1;
            } else {
                maxc = 3;
            }
        } else {
            if (ay > az) {
                maxc = 2;
            } else {
                maxc = 3;
            }
        }

        // next, to get a point on the intersect line
        // zero the max coord, and solve for the other two
        let iP = new Vec3(); // intersect point

        let d1, d2; // the constants in the 2 plane equations
        d1 = -Pn1.n.dot(Pn1.p); // note: could be pre-stored  with plane
        d2 = -Pn2.n.dot(Pn2.p); // ditto

        // select max coordinate
        if (maxc === 1) {
            // intersect with x=0
            iP.x = 0;
            iP.y = (d2 * Pn1.n.z - d1 * Pn2.n.z) / u.x;
            iP.z = (d1 * Pn2.n.y - d2 * Pn1.n.y) / u.x;
        } else if (maxc === 2) {
            // intersect with y=0
            iP.x = (d1 * Pn2.n.z - d2 * Pn1.n.z) / u.y;
            iP.y = 0;
            iP.z = (d2 * Pn1.n.x - d1 * Pn2.n.x) / u.y;
        } else if (maxc === 3) {
            // intersect with z=0
            iP.x = (d2 * Pn1.n.y - d1 * Pn2.n.y) / u.z;
            iP.y = (d1 * Pn2.n.x - d2 * Pn1.n.x) / u.z;
            iP.z = 0;
        }
        L.p0.copy(iP);
        L.p1.copy(iP.add(u));
        return INTERSECT;
    }
}

export {Plane};