zmatrix 0.4.2

Compile-time dimensional analysis & physics-aware linear algebra for aerospace and robotics
Documentation
use crate::physics::basic::{Coef, Momentum, MomentumType, Vector3};
use crate::utils::float;

impl Vector3<Momentum> {
    pub fn limit_float(&self, threshold: f64, momentum_type: MomentumType) -> Self {
        let (x, y, z) = match momentum_type {
            MomentumType::KgMperSecond => (
                float::limit_float(self.x.as_kg_m_s(), threshold),
                float::limit_float(self.y.as_kg_m_s(), threshold),
                float::limit_float(self.z.as_kg_m_s(), threshold),
            ),
            MomentumType::KgKmperSecond => (
                float::limit_float(self.x.as_kg_km_s(), threshold),
                float::limit_float(self.y.as_kg_km_s(), threshold),
                float::limit_float(self.z.as_kg_km_s(), threshold),
            ),
        };
        Self {
            x: Momentum { v: x, default_type: momentum_type },
            y: Momentum { v: y, default_type: momentum_type },
            z: Momentum { v: z, default_type: momentum_type },
        }
    }

    pub fn to_vector3_coef(&self, momentum_type: MomentumType) -> Vector3<Coef> {
        match momentum_type {
            MomentumType::KgMperSecond => {
                let (x, y, z) = (self.x.as_kg_m_s(), self.y.as_kg_m_s(), self.z.as_kg_m_s());
                Vector3::<Coef>::from_array([x, y, z])
            }
            MomentumType::KgKmperSecond => {
                let (x, y, z) = (self.x.as_kg_km_s(), self.y.as_kg_km_s(), self.z.as_kg_km_s());
                Vector3::<Coef>::from_array([x, y, z])
            }
        }
    }

    pub fn from_vector_coef(coef: Vector3<Coef>, momentum_type: MomentumType) -> Vector3<Momentum> {
        let x = Momentum {
            v: coef.x.v,
            default_type: momentum_type,
        };
        let y = Momentum {
            v: coef.y.v,
            default_type: momentum_type,
        };
        let z = Momentum {
            v: coef.z.v,
            default_type: momentum_type,
        };
        Vector3::new(x, y, z)
    }

    pub fn from_array_with_unit(array: [f64; 3], momentum_type: MomentumType) -> Vector3<Momentum> {
        let [x, y, z] = array;
        let x = Momentum {
            v: x,
            default_type: momentum_type,
        };
        let y = Momentum {
            v: y,
            default_type: momentum_type,
        };
        let z = Momentum {
            v: z,
            default_type: momentum_type,
        };
        Vector3::new(x, y, z)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use approx::assert_relative_eq;

    #[test]
    fn test_limit_float() {
        let v = Vector3::new(
            Momentum::from_kg_m_s(1.0),
            Momentum::from_kg_m_s(-5.0),
            Momentum::from_kg_m_s(3.0),
        );
        let result = v.limit_float(3.0, MomentumType::KgMperSecond);
        assert_relative_eq!(result.x.as_kg_m_s(), 1.0);
        assert_relative_eq!(result.y.as_kg_m_s(), -3.0);
        assert_relative_eq!(result.z.as_kg_m_s(), 3.0);

        let result = v.limit_float(1e10, MomentumType::KgKmperSecond);
        assert_relative_eq!(result.x.as_kg_km_s(), 0.001);
        assert_relative_eq!(result.y.as_kg_km_s(), -0.005);
        assert_relative_eq!(result.z.as_kg_km_s(), 0.003);
    }

    #[test]
    fn test_to_vector3_coef_kg_m_s() {
        let momentum_vec = Vector3::new(
            Momentum::from_kg_m_s(10.0),
            Momentum::from_kg_m_s(20.0),
            Momentum::from_kg_m_s(30.0),
        );
        
        let coef_vec = momentum_vec.to_vector3_coef(MomentumType::KgMperSecond);
        
        assert_relative_eq!(coef_vec.x, 10.0);
        assert_relative_eq!(coef_vec.y, 20.0);
        assert_relative_eq!(coef_vec.z, 30.0);
    }

    #[test]
    fn test_to_vector3_coef_kg_km_s() {
        let momentum_vec = Vector3::new(
            Momentum::from_kg_m_s(1000.0),  // 1000 kg⋅m/s = 1 kg⋅km/s
            Momentum::from_kg_m_s(2000.0),  // 2000 kg⋅m/s = 2 kg⋅km/s
            Momentum::from_kg_m_s(3000.0),  // 3000 kg⋅m/s = 3 kg⋅km/s
        );
        
        let coef_vec = momentum_vec.to_vector3_coef(MomentumType::KgKmperSecond);
        
        assert_relative_eq!(coef_vec.x, 1.0);
        assert_relative_eq!(coef_vec.y, 2.0);
        assert_relative_eq!(coef_vec.z, 3.0);
    }

    #[test]
    fn test_from_vector_coef_kg_m_s() {
        let coef_vec = Vector3::new(
            Coef::new(10.0),
            Coef::new(20.0),
            Coef::new(30.0),
        );

        let momentum_vec = Vector3::<Momentum>::from_vector_coef(coef_vec, MomentumType::KgMperSecond);

        assert_relative_eq!(momentum_vec.x.as_kg_m_s(), 10.0);
        assert_relative_eq!(momentum_vec.y.as_kg_m_s(), 20.0);
        assert_relative_eq!(momentum_vec.z.as_kg_m_s(), 30.0);
    }

    #[test]
    fn test_from_vector_coef_kg_km_s() {
        let coef_vec = Vector3::new(
            Coef::new(1.0),
            Coef::new(2.0),
            Coef::new(3.0),
        );

        let momentum_vec = Vector3::<Momentum>::from_vector_coef(coef_vec, MomentumType::KgKmperSecond);

        assert_relative_eq!(momentum_vec.x.as_kg_km_s(), 1.0);
        assert_relative_eq!(momentum_vec.y.as_kg_km_s(), 2.0);
        assert_relative_eq!(momentum_vec.z.as_kg_km_s(), 3.0);
    }

    #[test]
    fn test_from_vector_coef_roundtrip() {
        let original_momentum_vec = Vector3::new(
            Momentum::from_kg_m_s(10.0),
            Momentum::from_kg_m_s(20.0),
            Momentum::from_kg_m_s(30.0),
        );

        let coef_vec = original_momentum_vec.to_vector3_coef(MomentumType::KgMperSecond);
        let reconstructed_momentum_vec = Vector3::<Momentum>::from_vector_coef(coef_vec, MomentumType::KgMperSecond);

        assert_relative_eq!(original_momentum_vec.x.as_kg_m_s(), reconstructed_momentum_vec.x.as_kg_m_s());
        assert_relative_eq!(original_momentum_vec.y.as_kg_m_s(), reconstructed_momentum_vec.y.as_kg_m_s());
        assert_relative_eq!(original_momentum_vec.z.as_kg_m_s(), reconstructed_momentum_vec.z.as_kg_m_s());
    }

    #[test]
    fn test_from_array_with_unit() {
        // 测试从数组和单位类型创建动量向量
        let array = [10.0, 20.0, 30.0];
        let momentum_vec = Vector3::<Momentum>::from_array_with_unit(array, MomentumType::KgMperSecond);
        
        assert_relative_eq!(momentum_vec.x.as_kg_m_s(), 10.0);
        assert_relative_eq!(momentum_vec.y.as_kg_m_s(), 20.0);
        assert_relative_eq!(momentum_vec.z.as_kg_m_s(), 30.0);
        
        // 测试不同单位类型
        let array = [1.0, 2.0, 3.0];
        let momentum_vec = Vector3::<Momentum>::from_array_with_unit(array, MomentumType::KgKmperSecond);
        
        assert_relative_eq!(momentum_vec.x.as_kg_km_s(), 1.0);
        assert_relative_eq!(momentum_vec.y.as_kg_km_s(), 2.0);
        assert_relative_eq!(momentum_vec.z.as_kg_km_s(), 3.0);
    }
}