vox_geometry_rust 0.1.2

Geometry Tools for Rust
Documentation
/*
 * // Copyright (c) 2021 Feng Yang
 * //
 * // I am making my contributions/submissions to this project solely in my
 * // personal capacity and am not conveying any rights to any intellectual
 * // property of any third parties.
 */

use num::{Float, FromPrimitive};
use crate::constants::{pi, K_EPSILON_D};

///
/// Returns true if \p x and \p y are similar.
///
/// - Parameter  x     The first value.
/// - Parameter  y     The second value.
/// - Parameter  eps   The tolerance.
///
/// - tparam     T     Value type.
///
/// - return     True if similar.
///
#[inline]
pub fn similar<T: Float>(x: T, y: T, eps: Option<T>) -> bool {
    return (x - y).abs() <= eps.unwrap_or(T::epsilon());
}

///
/// Returns the sign of the value.
///
/// - Parameter  x     Input value.
///
/// - tparam     T     Value type.
///
/// - return     The sign.
///
#[inline]
pub fn sign<T: Float>(x: T) -> T {
    return match x >= T::from(0.0).unwrap() {
        true => T::from(1.0).unwrap(),
        false => T::from(-1.0).unwrap()
    };
}

///
/// Returns the minimum value among three inputs.
///
/// - Parameter  x     The first value.
/// - Parameter  y     The second value.
/// - param[in z]     The three value.
///
/// - tparam     T     Value type.
///
/// - return     The minimum value.
///
#[inline]
pub fn min3<T: Float>(x: T, y: T, z: T) -> T {
    return T::min(T::min(x, y), z);
}

///
/// Returns the maximum value among three inputs.
///
/// - Parameter  x     The first value.
/// - Parameter  y     The second value.
/// - Parameter  z     The three value.
///
/// - tparam     T     Value type.
///
/// - return     The maximum value.
///
#[inline]
pub fn max3<T: Float>(x: T, y: T, z: T) -> T {
    return T::max(T::max(x, y), z);
}

/// Returns minimum among n-elements.
#[inline]
pub fn minn<T: Float>(x: &Vec<T>) -> T {
    let mut m = x[0];
    for i in 1..x.len() {
        m = T::min(m, x[i]);
    }
    return m;
}

/// Returns maximum among n-elements.
#[inline]
pub fn maxn<T: Float>(x: &Vec<T>) -> T {
    let mut m = x[0];
    for i in 1..x.len() {
        m = T::max(m, x[i]);
    }
    return m;
}

///
/// \brief      Returns the absolute minimum value among the two inputs.
///
/// \Parameter  x     The first value.
/// \Parameter  y     The second value.
///
/// - tparam     T     Value type.
///
/// \return     The absolute minimum.
///
#[inline]
pub fn absmin<T: Float>(x: T, y: T) -> T {
    return match x * x < y * y {
        true => x,
        false => y
    };
}

///
/// \brief      Returns the absolute maximum value among the two inputs.
///
/// \Parameter  x     The first value.
/// \Parameter  y     The second value.
///
/// - tparam     T     Value type.
///
/// \return     The absolute maximum.
///
#[inline]
pub fn absmax<T: Float>(x: T, y: T) -> T {
    return match x * x > y * y {
        true => x,
        false => y
    };
}

/// Returns absolute minimum among n-elements.
#[inline]
pub fn absminn<T: Float>(x: &Vec<T>) -> T {
    let mut m = x[0];
    for i in 1..x.len() {
        m = absmin(m, x[i]);
    }
    return m;
}

/// Returns absolute maximum among n-elements.
#[inline]
pub fn absmaxn<T: Float>(x: &Vec<T>) -> T {
    let mut m = x[0];
    for i in 1..x.len() {
        m = absmax(m, x[i]);
    }
    return m;
}

#[inline]
pub fn argmin2<T: Float>(x: T, y: T) -> usize {
    return match x < y {
        true => 0,
        false => 1
    };
}

#[inline]
pub fn argmax2<T: Float>(x: T, y: T) -> usize {
    return match x > y {
        true => 0,
        false => 1
    };
}

#[inline]
pub fn argmin3<T: Float>(x: T, y: T, z: T) -> usize {
    return if x < y {
        match x < z {
            true => 0,
            false => 2
        }
    } else {
        match y < z {
            true => 1,
            false => 2
        }
    };
}

#[inline]
pub fn argmax3<T: Float>(x: T, y: T, z: T) -> usize {
    return if x > y {
        match x > z {
            true => 0,
            false => 2
        }
    } else {
        match y > z {
            true => 1,
            false => 2
        }
    };
}

///
/// Returns the square of \p x.
///
/// - Parameter  x     The input.
///
/// - tparam     T     Value type.
///
/// - return     The squared value.
///
#[inline]
pub fn square<T: Float>(x: T) -> T {
    return x * x;
}

///
/// Returns the cubic of \p x.
///
/// - Parameter  x     The input.
///
/// - tparam     T     Value type.
///
/// - return     The cubic of \p x.
///
#[inline]
pub fn cubic<T: Float>(x: T) -> T {
    return x * x * x;
}

///
/// Returns the clamped value.
///
/// - Parameter  val   The value.
/// - Parameter  low   The low value.
/// - Parameter  high  The high value.
///
/// - tparam     T     Value type.
///
/// - return     The clamped value.
///
#[inline]
pub fn clamp<T: Float>(val: T, low: T, high: T) -> T {
    return if val < low {
        low
    } else if val > high {
        high
    } else {
        val
    };
}

///
/// Converts degrees to radians.
///
/// - Parameter  angle_in_degrees The angle in degrees.
///
/// - tparam     T     Value type.
///
/// - return     Angle in radians.
///
#[inline]
pub fn degrees_to_radians<T: Float>(angle_in_degrees: T) -> T {
    return angle_in_degrees * pi::<T>() / T::from(180.0).unwrap();
}

///
/// Converts radians to degrees.
///
/// - Parameter  angle_in_radians The angle in radians.
///
/// - tparam     T              Value type.
///
/// - return     Angle in degrees.
///
#[inline]
pub fn radians_to_degrees<T: Float>(angle_in_radians: T) -> T {
    return angle_in_radians * T::from(180.0).unwrap() / pi::<T>();
}

///
/// Gets the barycentric coordinate.
///
/// - Parameter  x     The input value.
/// - Parameter  i_low  The lowest index.
/// - Parameter  i_high The highest index.
/// - parameter:      i     The output index.
/// - parameter:      t     The offset from \p i.
///
/// - tparam     T     Value type.
///
#[inline]
pub fn get_barycentric<T: Float>(x: T, i_low: isize, i_high: isize, i: &mut isize, f: &mut T) {
    let s = x.floor();
    *i = isize::from_f64(s.to_f64().unwrap()).unwrap();

    let offset = -i_low;
    let i_low = i_low + offset;
    let i_high = i_high + offset;

    if i_low == i_high {
        *i = i_low;
        *f = T::zero();
    } else if *i < i_low {
        *i = i_low;
        *f = T::zero();
    } else if *i > i_high - 1 {
        *i = i_high - 1;
        *f = T::one();
    } else {
        *f = T::from(x - s).unwrap();
    }

    *i -= offset;
}

///
/// Computes linear interpolation.
///
/// - Parameter  f0    The first value.
/// - Parameter  f1    The second value.
/// - Parameter  t     Relative offset [0, 1] from the first value.
///
/// - tparam     T     Offset type.
///
/// - return     The interpolated value.
///
#[inline]
pub fn lerp<T: Float>(value0: T, value1: T, f: T) -> T {
    return (T::from(1.0).unwrap() - f) * value0 + f * value1;
}

/// Computes bilinear interpolation.
#[inline]
pub fn bilerp<T: Float>(f00: T, f10: T, f01: T, f11: T,
                        tx: T, ty: T) -> T {
    return lerp(
        lerp(f00, f10, tx),
        lerp(f01, f11, tx),
        ty);
}

/// Computes trilinear interpolation.
#[inline]
pub fn trilerp<T: Float>(f000: T, f100: T, f010: T, f110: T,
                         f001: T, f101: T, f011: T, f111: T,
                         tx: T, ty: T, tz: T) -> T {
    return lerp(
        bilerp(f000, f100, f010, f110, tx, ty),
        bilerp(f001, f101, f011, f111, tx, ty),
        tz);
}

/// Computes Catmull-Rom interpolation.
#[inline]
pub fn catmull_rom<T: Float>(f0: T, f1: T, f2: T, f3: T, f: T) -> T {
    let d1 = (f2 - f0) / T::from(2.0).unwrap();
    let d2 = (f3 - f1) / T::from(2.0).unwrap();
    let d_diff = f2 - f1;

    let a3 = d1 + d2 - T::from(2.0).unwrap() * d_diff;
    let a2 = T::from(3.0).unwrap() * d_diff - T::from(2.0).unwrap() * d1 - d2;
    let a1 = d1;
    let a0 = f1;

    return a3 * cubic(f) + a2 * square(f) + a1 * f + a0;
}

/// Computes monotonic Catmull-Rom interpolation.
#[inline]
pub fn monotonic_catmull_rom<T: Float>(f0: T, f1: T, f2: T, f3: T,
                                       f: T) -> T {
    let mut d1 = (f2 - f0) / T::from(2.0).unwrap();
    let mut d2 = (f3 - f1) / T::from(2.0).unwrap();
    let d_diff = f2 - f1;

    if d_diff.abs() < T::from(K_EPSILON_D).unwrap() {
        d1 = T::zero();
        d2 = T::zero();
    }

    if sign(d_diff) != sign(d1) {
        d1 = T::zero();
    }

    if sign(d_diff) != sign(d2) {
        d2 = T::zero();
    }

    let a3 = d1 + d2 - T::from(2.0).unwrap() * d_diff;
    let a2 = T::from(3.0).unwrap() * d_diff - T::from(2.0).unwrap() * d1 - d2;
    let a1 = d1;
    let a0 = f1;

    return a3 * cubic(f) + a2 * square(f) + a1 * f + a0;
}