首页 > 其他分享 >4 向量结构

4 向量结构

时间:2024-11-18 20:47:53浏览次数:3  
标签:vector self Vector 向量 components Self fn 结构

vector.rs文件定义了一个向量类,用常量泛型实现了1维、2维、3维向量。源码如下:

use std::{fmt, ops};

use crate::Bivector;

use super::{
    coordinates::{Uv, Xyz, T},
    Scalar,
};

/// n维向量
///
/// 向量的维数由常量泛型“D”参数定义。
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd)]
#[repr(C)]
pub struct Vector<const D: usize> {
    /// 矢量分量
    pub components: [Scalar; D], 
}

impl<const D: usize> Vector<D> {
    /// 创建一个分量都相等的向量
    pub fn from_component(scalar: impl Into<Scalar>) -> Self {
        Self {
            components: [scalar.into(); D],
        }
    }

    /// 将向量转换为nalgebra向量
    pub fn to_na(self) -> nalgebra::SVector<f64, D> {
        self.components.map(Scalar::into_f64).into()
    }

    /// Convert to a 1-dimensional vector
    pub fn to_t(self) -> Vector<1> {
        Vector {
            components: [self.components[0]],
        }
    }

    /// Convert the vector into a 2-dimensional vector
    ///
    /// If the vector is 0-, or 1-dimensional, the missing components will be
    /// initialized to zero.
    ///
    /// If the vector has higher dimensionality than two, the superfluous
    /// components will be discarded.
    pub fn to_uv(self) -> Vector<2> {
        let zero = Scalar::ZERO;

        let components = match self.components.as_slice() {
            [] => [zero, zero],
            &[t] => [t, zero],
            &[u, v, ..] => [u, v],
        };

        Vector { components }
    }

    /// Convert the vector into a 3-dimensional vector
    ///
    /// If the vector is 0-, 1-, or 2-dimensional, the missing components will
    /// be initialized to zero.
    ///
    /// If the vector has higher dimensionality than three, the superfluous
    /// components will be discarded.
    pub fn to_xyz(self) -> Vector<3> {
        let zero = Scalar::ZERO;

        let components = match self.components.as_slice() {
            [] => [zero, zero, zero],
            &[t] => [t, zero, zero],
            &[u, v] => [u, v, zero],
            &[x, y, z, ..] => [x, y, z],
        };

        Vector { components }
    }

    /// Compute the magnitude of the vector
    pub fn magnitude(&self) -> Scalar {
        self.to_na().magnitude().into()
    }

    /// Compute a normalized version of the vector
    pub fn normalize(&self) -> Self {
        self.to_na().normalize().into()
    }

    /// 计算这个向量和另一个向量之间的角度
    ///
    /// Returns a zero angle, if the magnitude of `self` or `other` is zero.
    pub fn angle_to(&self, other: &Self) -> Scalar {
        let product = self.magnitude() * other.magnitude();
        if product.is_zero() {
            Scalar::ZERO
        } else {
            (self.dot(other) / product).acos()
        }
    }

    /// 用另一个向量计算点积
    pub fn dot(&self, other: &Self) -> Scalar {
        self.to_na().dot(&other.to_na()).into()
    }

    /// Compute the outer with another vector
    pub fn outer(&self, other: &Self) -> Bivector<D> {
        Bivector {
            a: *self,
            b: *other,
        }
    }

    /// Compute the scalar projection of this vector onto another
    pub fn scalar_projection_onto(&self, other: &Self) -> Scalar {
        if other.magnitude() == Scalar::ZERO {
            return Scalar::ZERO;
        }

        self.dot(&other.normalize())
    }
}

impl Vector<1> {
    /// Construct a `Vector` that represents the t-axis
    pub fn unit_t() -> Self {
        Self::from([1.])
    }
}

impl Vector<2> {
    /// Construct a `Vector` that represents the u-axis
    pub fn unit_u() -> Self {
        Self::from([1., 0.])
    }

    /// Construct a `Vector` that represents the v-axis
    pub fn unit_v() -> Self {
        Self::from([0., 1.])
    }

    /// Compute the 2D cross product with another vector
    pub fn cross2d(&self, other: &Self) -> Scalar {
        (self.u * other.v) - (self.v * other.u)
    }

    /// Determine whether this vector is between two other vectors
    pub fn is_between(&self, others: [impl Into<Self>; 2]) -> bool {
        let [a, b] = others.map(Into::into);
        a.cross2d(self) * b.cross2d(self) < Scalar::ZERO
    }
}

impl Vector<3> {
    /// Construct a `Vector` that represents the x-axis
    pub fn unit_x() -> Self {
        Self::from([1., 0., 0.])
    }

    /// Construct a `Vector` that represents the y-axis
    pub fn unit_y() -> Self {
        Self::from([0., 1., 0.])
    }

    /// Construct a `Vector` that represents the z-axis
    pub fn unit_z() -> Self {
        Self::from([0., 0., 1.])
    }

    /// Compute the cross product with another vector
    pub fn cross(&self, other: &Self) -> Self {
        self.to_na().cross(&other.to_na()).into()
    }

    /// Construct a new vector from this vector's x and y components
    pub fn xy(&self) -> Vector<2> {
        Vector::from([self.x, self.y])
    }
}

impl ops::Deref for Vector<1> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        let ptr = self.components.as_ptr() as *const Self::Target;

        // This is sound. We've created this pointer from a valid instance, that
        // has the same size and layout as the target.
        unsafe { &*ptr }
    }
}

impl ops::Deref for Vector<2> {
    type Target = Uv;

    fn deref(&self) -> &Self::Target {
        let ptr = self.components.as_ptr() as *const Self::Target;

        // This is sound. We've created this pointer from a valid instance, that
        // has the same size and layout as the target.
        unsafe { &*ptr }
    }
}

impl ops::Deref for Vector<3> {
    type Target = Xyz;

    fn deref(&self) -> &Self::Target {
        let ptr = self.components.as_ptr() as *const Self::Target;

        // This is sound. We've created this pointer from a valid instance, that
        // has the same size and layout as the target.
        unsafe { &*ptr }
    }
}

impl ops::DerefMut for Vector<1> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        let ptr = self.components.as_mut_ptr() as *mut Self::Target;

        // This is sound. We've created this pointer from a valid instance, that
        // has the same size and layout as the target.
        unsafe { &mut *ptr }
    }
}

impl ops::DerefMut for Vector<2> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        let ptr = self.components.as_mut_ptr() as *mut Self::Target;

        // This is sound. We've created this pointer from a valid instance, that
        // has the same size and layout as the target.
        unsafe { &mut *ptr }
    }
}

impl ops::DerefMut for Vector<3> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        let ptr = self.components.as_mut_ptr() as *mut Self::Target;

        // This is sound. We've created this pointer from a valid instance, that
        // has the same size and layout as the target.
        unsafe { &mut *ptr }
    }
}

impl<const D: usize> Default for Vector<D> {
    fn default() -> Self {
        let components = [Scalar::default(); D];
        Self { components }
    }
}

impl<S: Into<Scalar>, const D: usize> From<[S; D]> for Vector<D> {
    fn from(components: [S; D]) -> Self {
        Self {
            components: components.map(Into::into),
        }
    }
}

impl<const D: usize> From<nalgebra::SVector<f64, D>> for Vector<D> {
    fn from(vector: nalgebra::SVector<f64, D>) -> Self {
        let components: [f64; D] = vector.into();
        Vector::from(components)
    }
}

impl<const D: usize> From<Vector<D>> for [f32; D] {
    fn from(vector: Vector<D>) -> Self {
        vector.components.map(|scalar| scalar.into_f32())
    }
}

impl<const D: usize> From<Vector<D>> for [f64; D] {
    fn from(vector: Vector<D>) -> Self {
        vector.components.map(|scalar| scalar.into_f64())
    }
}

impl<const D: usize> From<Vector<D>> for [Scalar; D] {
    fn from(vector: Vector<D>) -> Self {
        vector.components
    }
}

impl<const D: usize> From<Vector<D>> for nalgebra::SVector<f64, D> {
    fn from(vector: Vector<D>) -> Self {
        vector.to_na()
    }
}

impl<const D: usize> ops::Neg for Vector<D> {
    type Output = Self;

    fn neg(self) -> Self::Output {
        self.to_na().neg().into()
    }
}

impl<V, const D: usize> ops::Add<V> for Vector<D>
where
    V: Into<Self>,
{
    type Output = Self;

    fn add(self, rhs: V) -> Self::Output {
        self.to_na().add(rhs.into().to_na()).into()
    }
}

impl<V, const D: usize> ops::Sub<V> for Vector<D>
where
    V: Into<Self>,
{
    type Output = Self;

    fn sub(self, rhs: V) -> Self::Output {
        self.to_na().sub(rhs.into().to_na()).into()
    }
}

impl<S, const D: usize> ops::Mul<S> for Vector<D>
where
    S: Into<Scalar>,
{
    type Output = Self;

    fn mul(self, rhs: S) -> Self::Output {
        self.to_na().mul(rhs.into().into_f64()).into()
    }
}

impl<S, const D: usize> ops::MulAssign<S> for Vector<D>
where
    S: Into<Scalar>,
{
    fn mul_assign(&mut self, rhs: S) {
        *self = *self * rhs;
    }
}

impl<S, const D: usize> ops::Div<S> for Vector<D>
where
    S: Into<Scalar>,
{
    type Output = Self;

    fn div(self, rhs: S) -> Self::Output {
        self.to_na().div(rhs.into().into_f64()).into()
    }
}

impl<const D: usize> fmt::Debug for Vector<D> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.components.fmt(f)
    }
}

impl<const D: usize> approx::AbsDiffEq for Vector<D> {
    type Epsilon = <Scalar as approx::AbsDiffEq>::Epsilon;

    fn default_epsilon() -> Self::Epsilon {
        Scalar::default_epsilon()
    }

    fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
        self.components.abs_diff_eq(&other.components, epsilon)
    }
}

#[cfg(test)]
mod tests {
    use crate::{Scalar, Vector};

    #[test]
    fn to_uv() {
        let d0: [f64; 0] = [];
        assert_eq!(Vector::from(d0).to_uv(), Vector::from([0., 0.]));
        assert_eq!(Vector::from([1.]).to_uv(), Vector::from([1., 0.]));
        assert_eq!(Vector::from([1., 2.]).to_uv(), Vector::from([1., 2.]));
        assert_eq!(Vector::from([1., 2., 3.]).to_uv(), Vector::from([1., 2.]),);
    }

    #[test]
    fn to_xyz() {
        let d0: [f64; 0] = [];
        assert_eq!(Vector::from(d0).to_xyz(), Vector::from([0., 0., 0.]));
        assert_eq!(Vector::from([1.]).to_xyz(), Vector::from([1., 0., 0.]));
        assert_eq!(Vector::from([1., 2.]).to_xyz(), Vector::from([1., 2., 0.]));
        assert_eq!(
            Vector::from([1., 2., 3.]).to_xyz(),
            Vector::from([1., 2., 3.]),
        );
    }

    #[test]
    fn scalar_projection_onto() {
        let v = Vector::from([1., 2., 3.]);

        let x = Vector::unit_x() * 3.;
        let y = Vector::unit_y() * 2.;
        let z = Vector::unit_z() * 1.;

        assert_eq!(v.scalar_projection_onto(&x), Scalar::from(1.));
        assert_eq!(v.scalar_projection_onto(&y), Scalar::from(2.));
        assert_eq!(v.scalar_projection_onto(&z), Scalar::from(3.));

        // Zero-length vectors should be handled as well.
        assert_eq!(
            Vector::unit_x()
                .scalar_projection_onto(&Vector::from([0., 0., 0.])),
            Scalar::ZERO
        );
    }

    #[test]
    fn is_between() {
        let v = Vector::from([1., 1.]);

        assert!(v.is_between([[1., 0.], [0., 1.]]));
        assert!(!v.is_between([[1., 0.], [0., -1.]]));
        assert!(!v.is_between([[-1., 0.], [0., 1.]]));
    }
}

标签:vector,self,Vector,向量,components,Self,fn,结构
From: https://blog.csdn.net/weixin_43219667/article/details/143866326

相关文章

  • 数据结构——小小二叉树第一幕(树的认知以及顺序结构二叉树(堆)的实现)超详细!!!!
    文章目录前言一、树1.1树的概念与结构1.2数相关术语1.3树的表示1.4树形结构的实际运用场景二、二叉树2.1概念与结构2.2特殊的二叉树2.2.1满二叉树2.2.2完全二叉树2.3二叉树存储结构2.3.1顺序结构2.3.2链式结构三、实现顺序结构二叉树3.1堆的概念与结构3.......
  • c语言的循环结构
    循环结构在生活中我们常常遇到需要重复处理的问题,我们在编程时解决需要重复处理的问题需要使用循环语句循环语句主要有3种:while()循环;do-while()循环和for()循环while()循环用法:while(循环条件){循环体;……}说明:当程序遇到while()循环的时候,首先会判断while()的......
  • 数据结构(倒排索引)
    倒排索引和正排索引倒排索引是什么?倒排索引也被称作反向索引(invertedindex),是用于提高数据检索速度的一种数据结构,空间消耗比较大。倒排索引首先将检索文档进行分词得到多个词语/词条,然后将词语和文档ID建立关联,从而提高检索效率。分词就是对一段文本,通过规则或者算......
  • 常用代码模板2——数据结构
    单链表——模板题luogu826.单链表//head存储链表头,e[]存储节点的值,ne[]存储节点的next指针,idx表示当前用到了哪个节点inthead,e[N],ne[N],idx;//初始化voidinit(){  head=-1;  idx=0;}//在链表头插入一个数avoidinsert(inta){  e[idx]=a,ne[i......
  • [JavaScript]将数组按照parentId和id整理成树状结构
     JavaScriptfunctionarrayToTree(items){constrootItems=[];constlookup={};for(constitemofitems){constitemId=item.id;lookup[itemId]=item;constparentId=item.parentId;if(parentId===n......
  • 【图像去噪】论文复现:CLIP用于图像去噪提升泛化性!CLIPDenoising的Pytorch源码复现,跑通
    请先看【专栏介绍文章】:【图像去噪(ImageDenoising)】关于【图像去噪】专栏的相关说明,包含适配人群、专栏简介、专栏亮点、阅读方法、定价理由、品质承诺、关于更新、去噪概述、文章目录、资料汇总、问题汇总(更新中)完整代码和训练好的模型权重文件下载链接见本文底部,订阅专......
  • catia零部件装配结构搭建
    catia零部件装配结构搭建ProductCatia的product文件保存装配结构和各个零部件之间的参数关系与约束关系,不保存三维实体本身。装配结构搭建通常在装配结构搭建的时候不考虑零部件之间的约束关系,只保留装配结构与位置关系(零部件的三维坐标与当前的姿态)。程序思路一般情况下,会......
  • leetcode211. 添加与搜索单词 - 数据结构设计
    请你设计一个数据结构,支持添加新单词和查找字符串是否与任何先前添加的字符串匹配。实现词典类 WordDictionary :WordDictionary() 初始化词典对象voidaddWord(word) 将 word 添加到数据结构中,之后可以对它进行匹配boolsearch(word) 如果数据结构中存在字符串与......
  • 编程之路,从0开始:结构体详解
    目录前言正文1、结构体引入2、结构体的声明3、typedef4、结构体的匿名声明5、结构的自引用(1)链表(2)自引用6、结构体内存对齐(1)对齐规则(2)题目(3)为什么存在内存对齐?(4)默认对齐数7、结构体实现位段(1)什么是位段(2)位段的跨平台问题(3)位段的应用总结 前言     ......
  • 数据结构实验三 2024_树与图实验
    数据结构实验三2024_树与图实验7-1根据后序和中序遍历输出前序遍历本题要求根据给定的一棵二叉树的后序遍历和中序遍历结果,输出该树的前序遍历结果。输入格式:第一行给出正整数n(≤30),是树中结点的个数。随后两行,每行给出n个整数,分别对应后序遍历和中序遍历结果,数字间以......