6 齐次坐标模块(homogen.rs)

server/2025/2/2 6:06:43/

homogen.rs代码定义了一个名为 HomogeneousVector 的结构体,它是用于表示三维空间中的齐次向量。齐次向量常用于计算机图形学和几何学中,特别是在处理投影和变换时。下面是对这段代码的详细解释和一些关键的代码片段分析:

一、homogen.rs文件源码

rust">use crate::point::{Point2D, Point3D};
use crate::vector::{Vector2D, Vector3D};use crate::num::{One, Zero};#[cfg(feature = "bytemuck")]
use bytemuck::{Pod, Zeroable};
use core::cmp::{Eq, PartialEq};
use core::fmt;
use core::hash::Hash;
use core::marker::PhantomData;
use core::ops::Div;
#[cfg(feature = "serde")]
use serde;/// Homogeneous vector in 3D space.
#[repr(C)]
pub struct HomogeneousVector<T, U> {pub x: T,pub y: T,pub z: T,pub w: T,#[doc(hidden)]pub _unit: PhantomData<U>,
}impl<T: Copy, U> Copy for HomogeneousVector<T, U> {}impl<T: Clone, U> Clone for HomogeneousVector<T, U> {fn clone(&self) -> Self {HomogeneousVector {x: self.x.clone(),y: self.y.clone(),z: self.z.clone(),w: self.w.clone(),_unit: PhantomData,}}
}#[cfg(feature = "serde")]
impl<'de, T, U> serde::Deserialize<'de> for HomogeneousVector<T, U>
whereT: serde::Deserialize<'de>,
{fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>whereD: serde::Deserializer<'de>,{let (x, y, z, w) = serde::Deserialize::deserialize(deserializer)?;Ok(HomogeneousVector {x,y,z,w,_unit: PhantomData,})}
}#[cfg(feature = "serde")]
impl<T, U> serde::Serialize for HomogeneousVector<T, U>
whereT: serde::Serialize,
{fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>whereS: serde::Serializer,{(&self.x, &self.y, &self.z, &self.w).serialize(serializer)}
}#[cfg(feature = "arbitrary")]
impl<'a, T, U> arbitrary::Arbitrary<'a> for HomogeneousVector<T, U>
whereT: arbitrary::Arbitrary<'a>,
{fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {let (x, y, z, w) = arbitrary::Arbitrary::arbitrary(u)?;Ok(HomogeneousVector {x,y,z,w,_unit: PhantomData,})}
}#[cfg(feature = "bytemuck")]
unsafe impl<T: Zeroable, U> Zeroable for HomogeneousVector<T, U> {}#[cfg(feature = "bytemuck")]
unsafe impl<T: Pod, U: 'static> Pod for HomogeneousVector<T, U> {}impl<T, U> Eq for HomogeneousVector<T, U> where T: Eq {}impl<T, U> PartialEq for HomogeneousVector<T, U>
whereT: PartialEq,
{fn eq(&self, other: &Self) -> bool {self.x == other.x && self.y == other.y && self.z == other.z && self.w == other.w}
}impl<T, U> Hash for HomogeneousVector<T, U>
whereT: Hash,
{fn hash<H: core::hash::Hasher>(&self, h: &mut H) {self.x.hash(h);self.y.hash(h);self.z.hash(h);self.w.hash(h);}
}impl<T, U> HomogeneousVector<T, U> {/// Constructor taking scalar values directly.#[inline]pub const fn new(x: T, y: T, z: T, w: T) -> Self {HomogeneousVector {x,y,z,w,_unit: PhantomData,}}
}impl<T: Copy + Div<T, Output = T> + Zero + PartialOrd, U> HomogeneousVector<T, U> {/// Convert into Cartesian 2D point.////// Returns `None` if the point is on or behind the W=0 hemisphere.#[inline]pub fn to_point2d(self) -> Option<Point2D<T, U>> {if self.w > T::zero() {Some(Point2D::new(self.x / self.w, self.y / self.w))} else {None}}/// Convert into Cartesian 3D point.////// Returns `None` if the point is on or behind the W=0 hemisphere.#[inline]pub fn to_point3d(self) -> Option<Point3D<T, U>> {if self.w > T::zero() {Some(Point3D::new(self.x / self.w,self.y / self.w,self.z / self.w,))} else {None}}
}impl<T: Zero, U> From<Vector2D<T, U>> for HomogeneousVector<T, U> {#[inline]fn from(v: Vector2D<T, U>) -> Self {HomogeneousVector::new(v.x, v.y, T::zero(), T::zero())}
}impl<T: Zero, U> From<Vector3D<T, U>> for HomogeneousVector<T, U> {#[inline]fn from(v: Vector3D<T, U>) -> Self {HomogeneousVector::new(v.x, v.y, v.z, T::zero())}
}impl<T: Zero + One, U> From<Point2D<T, U>> for HomogeneousVector<T, U> {#[inline]fn from(p: Point2D<T, U>) -> Self {HomogeneousVector::new(p.x, p.y, T::zero(), T::one())}
}impl<T: One, U> From<Point3D<T, U>> for HomogeneousVector<T, U> {#[inline]fn from(p: Point3D<T, U>) -> Self {HomogeneousVector::new(p.x, p.y, p.z, T::one())}
}impl<T: fmt::Debug, U> fmt::Debug for HomogeneousVector<T, U> {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {f.debug_tuple("").field(&self.x).field(&self.y).field(&self.z).field(&self.w).finish()}
}#[cfg(test)]
mod homogeneous {use super::HomogeneousVector;use crate::default::{Point2D, Point3D};#[test]fn roundtrip() {assert_eq!(Some(Point2D::new(1.0, 2.0)),HomogeneousVector::from(Point2D::new(1.0, 2.0)).to_point2d());assert_eq!(Some(Point3D::new(1.0, -2.0, 0.1)),HomogeneousVector::from(Point3D::new(1.0, -2.0, 0.1)).to_point3d());}#[test]fn negative() {assert_eq!(None,HomogeneousVector::<f32, ()>::new(1.0, 2.0, 3.0, 0.0).to_point2d());assert_eq!(None,HomogeneousVector::<f32, ()>::new(1.0, -2.0, -3.0, -2.0).to_point3d());}
}

二、结构体定义

rust">#[repr(C)]
pub struct HomogeneousVector<T, U> {pub x: T,pub y: T,pub z: T,pub w: T,#[doc(hidden)]pub _unit: PhantomData<U>,
}
  • #[repr©] 属性确保了结构体在内存中的布局是连续的,这对于与C语言接口或者特定的内存对齐需求很有用。
  • T 是向量的坐标类型,它可以是任何数值类型,比如 f32 或 f64。
  • U 是一个类型参数,通过 PhantomData 被引入,通常用于表示一些与结构体相关的额外信息,比如单位或维度,但不占用实际的内存空间。
  • _unit 字段被标记为文档隐藏,意味着在生成的文档中不会显示这个字段。

三、实现特性

  • Copy 和 Clone:由于 HomogeneousVector 持有的是泛型 T,只有当 T 实现 Copy 或 Clone 时,HomogeneousVector 才能相应地实现 Copy 或 Clone。
  • serde 序列化/反序列化:当启用了 serde 功能时,HomogeneousVector 可以被序列化和反序列化,前提是它的类型参数 T 也支持 serde。
  • From 实现:提供了从 Vector2D、Vector3D、Point2D 和 Point3D 到 HomogeneousVector 的转换方法。这些转换方法将源数据转换为齐次坐标形式,例如,二维点转换为齐次坐标时,w 分量被设置为 1,而 z 分量(对于2D点来说不存在)被设置为 0。

四、示例代码片段分析

从 Vector2D 转换到 HomogeneousVector

rust">impl<T: Zero, U> From<Vector2D<T, U>> for HomogeneousVector<T, U> {#[inline]fn from(v: Vector2D<T, U>) -> Self {HomogeneousVector::new(v.x, v.y, T::zero(), T::zero())}
}

这里假设 Vector2D 是一个二维向量结构体,T::zero() 返回类型 T 的零值。此实现将二维向量的 x 和 y 分量转换为齐次向量的前两个分量,并将 z 和 w 分量都设置为零。

调试输出

rust">impl<T: fmt::Debug, U> fmt::Debug for HomogeneousVector<T, U> {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {f.debug_tuple("").field(&self.x).field(&self.y).field(&self.z).field(&self.w).finish()}
}

当 T 实现了 fmt::Debug 时,HomogeneousVector 也可以被格式化输出,这通常用于调试目的。

五、总结

homogen.rs代码展示了如何在 Rust 中定义和实现一个泛型结构体,以及如何利用 Rust 的类型系统和特性(如 PhantomData、条件编译 #[cfg()]、特性标志等)来增强代码的功能性和灵活性。HomogeneousVector 的设计使其能够灵活地与不同的数值类型和额外的类型信息一起工作,同时支持序列化和从其他几何类型转换。


http://www.ppmy.cn/server/164262.html

相关文章

PyCharm接入DeepSeek实现AI编程

目录 效果演示 创建API key 在PyCharm中下载CodeGPT插件 配置Continue DeepSeek 是一家专注于人工智能技术研发的公司&#xff0c;致力于开发高性能、低成本的 AI 模型。DeepSeek-V3 是 DeepSeek 公司推出的最新一代 AI 模型。其前身是 DeepSeek-V2.5&#xff0c;经过持续的…

微服务学习-服务调用组件 OpenFeign 实战

1. OpenFeign 接口方法编写规范 1.1. 在编写 OpenFeign 接口方法时&#xff0c;需要遵循以下规范 1.1.1.1. 接口中的方法必须使用 RequestMapping、GetMapping、PostMapping 等注解声明 HTTP 请求的类型。 1.1.1.2. 方法的参数可以使用 RequestParam、RequestHeader、PathVa…

31. C语言 命令行参数

本章目录: 前言&#xff1a;什么是命令行参数&#xff1f;一个简单的示例运行结果 命令行参数的常见使用场景带空格的参数 高级命令行参数解析使用 getopt_long 的示例示例运行 注意事项进一步的实践&#xff1a;实现多功能程序总结 前言&#xff1a; 在 C 语言中&#xff0c;…

C语言初阶牛客网刷题—— HJ97 记负均正【难度:简单】

1. 题目描述 牛客网在线OJ题 1、首先输入要输入的整数个数 n &#xff0c;然后输入 n 个整数。输出为 n 个整数中负数的个数&#xff0c;和所有正整数的平均值&#xff0c; 结果保留一位小数。 注意&#xff1a; 0 即不是正整数&#xff0c;也不是负数&#xff0c;不计入计算&…

自制一个入门STM32 四足机器人具体开发顺序

0 前期准备 1. 知识储备 学习 STM32 微控制器的基础知识&#xff0c;包括 GPIO、定时器、串口通信等外设的使用&#xff0c;可通过官方文档、教程和视频课程进行学习。了解舵机控制原理&#xff0c;因为四足机器人通常使用舵机来实现关节运动。掌握基本的机械结构设计知识&am…

C 语言实现计算一年中指定日期是第几天 题】

引言 在编程的世界里&#xff0c;处理日期和时间相关的问题是非常常见的。比如在日历应用、任务管理系统、数据分析等场景中&#xff0c;经常需要计算某个日期在一年中是第几天。本文将详细介绍如何使用 C 语言来实现这一功能&#xff0c;通过分析代码的结构、逻辑以及可能存在…

文明的基因:在传承中破茧重生

敦煌莫高窟的壁画历经千年风雨&#xff0c;至今仍在向世界讲述着东方美学的密码。那些斑驳的壁画上&#xff0c;既有北魏时期的天竺梵音&#xff0c;也留存着盛唐气象的长安余韵。文明的基因从未停止生长&#xff0c;就像莫高窟的壁画师们在临摹前朝壁画时&#xff0c;总会在衣…

机器学习6-全连接神经网络2

机器学习6-全连接神经网络2-梯度算法改进 梯度下降算法存在的问题动量法与自适应梯度动量法一、动量法的核心思想二、动量法的数学表示三、动量法的作用四、动量法的应用五、示例 自适应梯度与RMSProp 权值初始化随机权值初始化Xavier初始化HE初始化(MSRA) ![在这里插入图片描述…