//! Physical-space mapping helpers for 3-node triangles in 3D.

use crate::math::Scalar;
use crate::math::{cross3, norm3};

/// Map one reference-triangle point `(u, v)` into a physical triangle in 3D.
#[inline]
pub fn map_point<T: Scalar>(n0: [T; 3], n1: [T; 3], n2: [T; 3], uv: [T; 2]) -> [T; 3] {
    let w = T::ONE - uv[0] - uv[1];
    [
        n0[0] * w + n1[0] * uv[0] + n2[0] * uv[1],
        n0[1] * w + n1[1] * uv[0] + n2[1] * uv[1],
        n0[2] * w + n1[2] * uv[0] + n2[2] * uv[1],
    ]
}

/// Physical area of a 3D triangle.
#[inline]
pub fn area<T: Scalar>(n0: [T; 3], n1: [T; 3], n2: [T; 3]) -> T {
    let v01 = [n1[0] - n0[0], n1[1] - n0[1], n1[2] - n0[2]];
    let v02 = [n2[0] - n0[0], n2[1] - n0[1], n2[2] - n0[2]];
    let cross = cross3(v01, v02);
    crate::math::cast::<T>(0.5) * norm3(cross)
}

/// Unit normal of a 3D triangle.
#[inline]
pub fn normal<T: Scalar>(n0: [T; 3], n1: [T; 3], n2: [T; 3]) -> [T; 3] {
    let v01 = [n1[0] - n0[0], n1[1] - n0[1], n1[2] - n0[2]];
    let v02 = [n2[0] - n0[0], n2[1] - n0[1], n2[2] - n0[2]];
    let cross = cross3(v01, v02);
    let norm = norm3(cross);
    [cross[0] / norm, cross[1] / norm, cross[2] / norm]
}
