vector-traits 0.6.2

Rust traits for 2D and 3D vector types.
Documentation
// SPDX-License-Identifier: MIT OR Apache-2.0
// Copyright (c) 2023, 2025 lacklustr@protonmail.com https://github.com/eadf

// This file is part of vector-traits.

use crate::prelude::*;
use approx::ulps_eq;

#[allow(dead_code)] // this code is used by all the x_impls
/// Helper method for `From<Aabb2>` -> `Vec<GenericVector2>` and `Aabb2::convex_hull()`
/// creates a connected LineString2 from the outlines of the Aabb2
pub(super) fn aabb_to_vec<T>(aabb: T) -> Vec<T::Vector>
where
    T: Aabb2,
    T::Vector: GenericVector2,
{
    if !aabb.is_empty() {
        let min = aabb.min();
        let max = aabb.max();
        vec![
            min,
            T::Vector::new_2d(max.x(), min.y()),
            max,
            T::Vector::new_2d(min.x(), max.y()),
            min,
        ]
    } else {
        Vec::default()
    }
}

#[allow(dead_code)] // this code is used by all the x_impls
/// Helper method for `PartialEq<Aabb2>`
pub(super) fn aabb2_partial_eq<T>(aabb1: &T, aabb2: &T) -> bool
where
    T: Aabb2,
    T::Vector: GenericVector2,
{
    match (aabb1.is_empty(), aabb2.is_empty()) {
        (false, false) => {
            let min1 = aabb1.min();
            let min2 = aabb2.min();
            let max1 = aabb1.max();
            let max2 = aabb2.max();

            ulps_eq!(min1.x(), min2.x())
                && ulps_eq!(min1.y(), min2.y())
                && ulps_eq!(max1.x(), max2.x())
                && ulps_eq!(max1.y(), max2.y())
        }
        (true, true) => true,
        _ => false,
    }
}

#[allow(dead_code)] // this code is used by all the x_impls
/// Helper method for `PartialEq<Aabb3>`
pub(super) fn aabb3_partial_eq<T>(aabb1: &T, aabb2: &T) -> bool
where
    T: Aabb3,
    T::Vector: GenericVector3,
{
    match (aabb1.is_empty(), aabb2.is_empty()) {
        (false, false) => {
            let min1 = aabb1.min();
            let min2 = aabb2.min();
            let max1 = aabb1.max();
            let max2 = aabb2.max();

            ulps_eq!(min1.x(), min2.x())
                && ulps_eq!(min1.y(), min2.y())
                && ulps_eq!(min1.z(), min2.z())
                && ulps_eq!(max1.x(), max2.x())
                && ulps_eq!(max1.y(), max2.y())
                && ulps_eq!(max1.z(), max2.z())
        }
        (true, true) => true,
        _ => false,
    }
}

#[allow(dead_code)] // this code is used by all the x_impls
pub(super) fn from_plane_to_xy<T: GenericVector3>(
    source_plane: Plane,
) -> <T as GenericVector3>::Affine {
    match source_plane {
        Plane::XY => {
            // Identity matrix
            <T as GenericVector3>::Affine::identity()
        }
        Plane::XZ => {
            // Maps X->X, Z->Y, Y->Z
            // This transforms the XZ plane to the XY plane
            <T as GenericVector3>::Affine::from_cols_array(&[
                T::Scalar::ONE,
                T::Scalar::ZERO,
                T::Scalar::ZERO,
                T::Scalar::ZERO, // First column
                T::Scalar::ZERO,
                T::Scalar::ZERO,
                T::Scalar::ONE,
                T::Scalar::ZERO, // Second column
                T::Scalar::ZERO,
                T::Scalar::ONE,
                T::Scalar::ZERO,
                T::Scalar::ZERO, // Third column
                T::Scalar::ZERO,
                T::Scalar::ZERO,
                T::Scalar::ZERO,
                T::Scalar::ONE, // Fourth column
            ])
        }
        Plane::YZ => {
            // Maps Z->X, Y->Y, X->Z
            // This transforms the YZ plane to the YX plane
            <T as GenericVector3>::Affine::from_cols_array(&[
                T::Scalar::ZERO,
                T::Scalar::ZERO,
                T::Scalar::ONE,
                T::Scalar::ZERO, // First column
                T::Scalar::ZERO,
                T::Scalar::ONE,
                T::Scalar::ZERO,
                T::Scalar::ZERO, // Second column
                T::Scalar::ONE,
                T::Scalar::ZERO,
                T::Scalar::ZERO,
                T::Scalar::ZERO, // Third column
                T::Scalar::ZERO,
                T::Scalar::ZERO,
                T::Scalar::ZERO,
                T::Scalar::ONE, // Fourth column
            ])
        }
    }
}

#[allow(dead_code)] // this code is used by all the x_impls
pub(super) fn from_translation<T: GenericVector3>(translation: T) -> T::Affine {
    <T as GenericVector3>::Affine::from_cols_array(&[
        T::Scalar::ONE,
        T::Scalar::ZERO,
        T::Scalar::ZERO,
        T::Scalar::ZERO, // First column
        T::Scalar::ZERO,
        T::Scalar::ZERO,
        T::Scalar::ONE,
        T::Scalar::ZERO, // Second column
        T::Scalar::ZERO,
        T::Scalar::ONE,
        T::Scalar::ZERO,
        T::Scalar::ZERO, // Third column
        translation.x(),
        translation.y(),
        translation.z(),
        T::Scalar::ONE, // Fourth column
    ])
}