From f76bf654df73fa96d9d91e9abfbf25689041d404 Mon Sep 17 00:00:00 2001 From: ApsisRS contributors Date: Fri, 2 Oct 2026 00:33:19 +0800 Subject: [PATCH] docs: finish the foundation layer of the bilingual sweep All 180 comment blocks across apsis-core, apsis-units and apsis-math now carry both languages. The checker confirms no mangled bytes and no English word left inside a Chinese sentence, two mistakes that occurred while writing them and are now caught mechanically. --- crates/foundation/apsis-math/src/mat3.rs | 79 ++++++++++ crates/foundation/apsis-math/src/parallel.rs | 38 +++++ crates/foundation/apsis-math/src/quat.rs | 92 +++++++++++ crates/foundation/apsis-math/src/vec3.rs | 144 ++++++++++++++++++ scripts/__pycache__/bilingual.cpython-314.pyc | Bin 0 -> 1966 bytes scripts/bilingual.py | 36 +++++ 6 files changed, 389 insertions(+) create mode 100644 scripts/__pycache__/bilingual.cpython-314.pyc create mode 100644 scripts/bilingual.py diff --git a/crates/foundation/apsis-math/src/mat3.rs b/crates/foundation/apsis-math/src/mat3.rs index 74924b7..9270d33 100644 --- a/crates/foundation/apsis-math/src/mat3.rs +++ b/crates/foundation/apsis-math/src/mat3.rs @@ -11,44 +11,77 @@ use core::ops::Mul; /// entry in the first row and second column. The fields are listed in /// column-major order, and the same order is used by [`Mat3::from_columns`] /// and [`Mat3::column`]. +/// +/// 按列主序存储的三乘三矩阵。 +/// +/// 字段名遵循 `m<行><列>` 约定,故 `m01` 是第一行第二列的元素。字段按列主序 +/// 列出,[`Mat3::from_columns`] 与 [`Mat3::column`] 使用同样的顺序。 #[derive(Debug, Clone, Copy, PartialEq, Default)] pub struct Mat3 { /// First row, first column. + /// + /// 第一行第一列。 pub m00: f64, /// Second row, first column. + /// + /// 第二行第一列。 pub m10: f64, /// Third row, first column. + /// + /// 第三行第一列。 pub m20: f64, /// First row, second column. + /// + /// 第一行第二列。 pub m01: f64, /// Second row, second column. + /// + /// 第二行第二列。 pub m11: f64, /// Third row, second column. + /// + /// 第三行第二列。 pub m21: f64, /// First row, third column. + /// + /// 第一行第三列。 pub m02: f64, /// Second row, third column. + /// + /// 第二行第三列。 pub m12: f64, /// Third row, third column. + /// + /// 第三行第三列。 pub m22: f64, } impl Mat3 { /// The zero matrix. + /// + /// 零矩阵。 pub const ZERO: Self = Self::from_rows_raw([0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]); /// The identity matrix. + /// + /// 单位矩阵。 pub const IDENTITY: Self = Self::from_rows_raw([1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]); /// Creates a matrix from its nine entries in row-major order. /// /// The arguments are grouped by row: `row0`, then `row1`, then `row2`. + /// + /// 由九个元素按行主序创建矩阵。 + /// + /// 参数按行分组:先 `row0`,再 `row1`,最后 `row2`。 pub const fn from_rows(row0: [f64; 3], row1: [f64; 3], row2: [f64; 3]) -> Self { Self::from_rows_raw(row0, row1, row2) } /// Creates a matrix from three column vectors. + /// + /// 由三个列向量创建矩阵。 pub const fn from_columns(c0: Vec3, c1: Vec3, c2: Vec3) -> Self { Self { m00: c0.x, @@ -64,6 +97,8 @@ impl Mat3 { } /// Creates a diagonal matrix from a vector of diagonal entries. + /// + /// 由对角元素向量创建对角矩阵。 pub const fn from_diagonal(diagonal: Vec3) -> Self { Self::from_rows_raw( [diagonal.x, 0.0, 0.0], @@ -76,6 +111,11 @@ impl Mat3 { /// /// The quaternion is assumed to have unit length. A non-unit quaternion /// produces a scaled matrix, which [`Mat3::is_rotation`] then rejects. + /// + /// 由单位四元数创建旋转矩阵。 + /// + /// 假定该四元数为单位长度。非单位四元数会得到一个带缩放的矩阵,随后被 + /// [`Mat3::is_rotation`] 拒绝。 pub fn from_quat(q: Quat) -> Self { let (w, x, y, z) = (q.w, q.x, q.y, q.z); Self::from_rows( @@ -101,21 +141,31 @@ impl Mat3 { /// `axis`. /// /// Returns `None` when the axis has zero or non-finite length. + /// + /// 创建绕单位轴 `axis` 旋转 `angle` 弧度的旋转矩阵。 + /// + /// 轴长度为零或非有限时返回 `None`。 pub fn from_axis_angle(axis: Vec3, angle: f64) -> Option { Quat::from_axis_angle(axis, angle).map(Self::from_quat) } /// Creates a rotation matrix of `angle` radians about the first axis. + /// + /// 创建绕第一轴旋转 `angle` 弧度的旋转矩阵。 pub fn from_rotation_x(angle: f64) -> Self { Self::from_quat(Quat::from_rotation_x(angle)) } /// Creates a rotation matrix of `angle` radians about the second axis. + /// + /// 创建绕第二轴旋转 `angle` 弧度的旋转矩阵。 pub fn from_rotation_y(angle: f64) -> Self { Self::from_quat(Quat::from_rotation_y(angle)) } /// Creates a rotation matrix of `angle` radians about the third axis. + /// + /// 创建绕第三轴旋转 `angle` 弧度的旋转矩阵。 pub fn from_rotation_z(angle: f64) -> Self { Self::from_quat(Quat::from_rotation_z(angle)) } @@ -123,6 +173,10 @@ impl Mat3 { /// Returns the entry in row `row` and column `column`. /// /// Returns `None` when either index is outside `0..=2`. + /// + /// 返回第 `row` 行第 `column` 列的元素。 + /// + /// 任一下标超出 `0..=2` 时返回 `None`。 pub const fn get(self, row: usize, column: usize) -> Option { match (row, column) { (0, 0) => Some(self.m00), @@ -141,6 +195,10 @@ impl Mat3 { /// Returns column `index`. /// /// Returns `None` when `index` is outside `0..=2`. + /// + /// 返回第 `index` 列。 + /// + /// `index` 超出 `0..=2` 时返回 `None`。 pub const fn column(self, index: usize) -> Option { match index { 0 => Some(Vec3::new(self.m00, self.m10, self.m20)), @@ -153,6 +211,10 @@ impl Mat3 { /// Returns row `index`. /// /// Returns `None` when `index` is outside `0..=2`. + /// + /// 返回第 `index` 行。 + /// + /// `index` 超出 `0..=2` 时返回 `None`。 pub const fn row(self, index: usize) -> Option { match index { 0 => Some(Vec3::new(self.m00, self.m01, self.m02)), @@ -163,6 +225,8 @@ impl Mat3 { } /// Returns the transpose. + /// + /// 返回转置。 pub const fn transpose(self) -> Self { Self { m00: self.m00, @@ -178,11 +242,15 @@ impl Mat3 { } /// Returns the sum of the diagonal entries. + /// + /// 返回对角元素之和。 pub const fn trace(self) -> f64 { self.m00 + self.m11 + self.m22 } /// Returns the determinant. + /// + /// 返回行列式。 pub fn determinant(self) -> f64 { self.m00 * (self.m11 * self.m22 - self.m12 * self.m21) - self.m01 * (self.m10 * self.m22 - self.m12 * self.m20) @@ -194,6 +262,11 @@ impl Mat3 { /// A matrix is a rotation when it is orthonormal with determinant one. /// The check compares `M^T M` to the identity entry by entry and then /// compares the determinant to one. + /// + /// 当该矩阵在 `tolerance` 内为旋转矩阵时返回 `true`。 + /// + /// 正交且行列式为一的矩阵即旋转矩阵。该检查逐元素比较 `M^T M` 与单位 + /// 矩阵,然后把行列式与一比较。 pub fn is_rotation(self, tolerance: f64) -> bool { let product = self.transpose() * self; let identity = Self::IDENTITY; @@ -209,6 +282,8 @@ impl Mat3 { } /// Returns `true` when all nine entries are finite. + /// + /// 当九个元素都有限时返回 `true`。 pub fn is_finite(self) -> bool { [ self.m00, self.m10, self.m20, self.m01, self.m11, self.m21, self.m02, self.m12, @@ -219,6 +294,8 @@ impl Mat3 { } /// Returns a copy of this matrix with one entry replaced. + /// + /// 返回把某一个元素替换后的矩阵副本。 const fn with_entry(self, row: usize, column: usize, value: f64) -> Self { let mut entries = [ [self.m00, self.m01, self.m02], @@ -230,6 +307,8 @@ impl Mat3 { } /// Const constructor used by the associated constants. + /// + /// 供各关联常量使用的 const 构造函数。 const fn from_rows_raw(row0: [f64; 3], row1: [f64; 3], row2: [f64; 3]) -> Self { Self { m00: row0[0], diff --git a/crates/foundation/apsis-math/src/parallel.rs b/crates/foundation/apsis-math/src/parallel.rs index f3a73d7..195bd86 100644 --- a/crates/foundation/apsis-math/src/parallel.rs +++ b/crates/foundation/apsis-math/src/parallel.rs @@ -35,6 +35,10 @@ use core::hint; /// This is the machine's parallelism as reported by the standard library, at /// least one. It is the number the callers use to decide whether a parallel /// run is worth starting. +/// +/// 某项工作应使用的线程数。 +/// +/// 这是标准库报告的机器并行度,至少为一。调用方据此决定并行运行是否值得启动。 pub fn thread_count() -> usize { std::thread::available_parallelism() .map(|count| count.get()) @@ -48,6 +52,12 @@ pub fn thread_count() -> usize { /// there is enough work for a second. The threshold is a per item cost of /// roughly a microsecond, below which starting a thread cannot pay for /// itself. +/// +/// 对 `len` 个元素的循环应使用的线程数。 +/// +/// 比线程数还短的循环会让多数线程无所事事,却仍要付出启动代价,因此在工作量 +/// 足以分给第二个线程之前本函数返回一个线程。阈值是每项约一微秒的开销,低于 +/// 此值启动线程无法收回成本。 pub fn threads_for(len: usize) -> usize { const ITEMS_PER_THREAD: usize = 1_024; thread_count().min(len.div_ceil(ITEMS_PER_THREAD)).max(1) @@ -70,6 +80,21 @@ pub fn threads_for(len: usize) -> usize { /// If the closure panics, the panic is resumed on the calling thread after /// the other threads have been joined, so a failure surfaces at the call /// rather than in a detached thread. +/// +/// 对一段范围内的每个下标各调用一次闭包,分摊到多个线程上执行。 +/// +/// 该范围被切分为每线程一段连续区间,每个线程对落在自己区间内的下标调用闭包。 +/// 闭包可能在任意线程上被调用,故必须是 `Send` 与 `Sync`;它捕获的数据是被共享 +/// 而非复制的。本次调用只有在全部线程结束后才返回,因此闭包写入的数据此后可安全 +/// 读取。 +/// +/// 闭包收到的是下标而非元素,这让签名与具体集合无关:调用方自行读取输入并 +/// 写出输出,两者不会重叠。 +/// +/// # Panics +/// +/// 若闭包发生 panic,该 panic 会在其它线程 join 之后于调用线程上重新抛出, +/// 因此失败出现在调用处,而不是某个已分离的线程中。 pub fn for_each_index(len: usize, operation: F) where F: Fn(usize) + Sync, @@ -78,6 +103,8 @@ where if threads <= 1 { // A single thread would spawn and join one thread to do exactly what // this loop does, so it runs directly. + // 单线程情况下,若走作用域仍要生成并 join 一个线程来做与本循环完全 + // 相同的事,故直接执行。 for index in 0..len { operation(index); } @@ -111,6 +138,14 @@ where /// The closure is handed the index and returns the value for that index. As /// with [`for_each_index`], it may run on any thread, so captured data must be /// `Sync`. +/// +/// 为一段范围内的每个下标各收集一个值,分摊到多个线程上执行。 +/// +/// 当工作的结果是值而非写入共享数组时,本函数是 [`for_each_index`] 的对应形式。 +/// 输出按下标顺序返回,与哪个线程产生了哪个元素无关,故不依赖调度。 +/// +/// 闭包收到下标并返回该下标对应的值。与 [`for_each_index`] 一样,它可能在任意 +/// 线程上运行,故捕获的数据必须为 `Sync`。 pub fn map_index(len: usize, operation: F) -> Vec where T: Send, @@ -125,6 +160,9 @@ where // split into disjoint mutable slices up front and no slot is written // twice. `Vec>` is filled in parallel and unwrapped after the // scope, which is where the values are moved into their final order. + // 每个线程写入输出的一段连续区间,故缓冲区先被切分为互不相交的可变切片, + // 没有槽位被写两次。`Vec>` 并行填充,作用域结束后解包,值在此被 + // 移入最终顺序。 let mut slots: Vec> = (0..len).map(|_| None).collect(); let operation = &operation; std::thread::scope(|scope| { diff --git a/crates/foundation/apsis-math/src/quat.rs b/crates/foundation/apsis-math/src/quat.rs index a7be057..22f9a6b 100644 --- a/crates/foundation/apsis-math/src/quat.rs +++ b/crates/foundation/apsis-math/src/quat.rs @@ -16,23 +16,45 @@ use core::ops::Mul; /// `w = cos(theta / 2)`, `(x, y, z) = u * sin(theta / 2)`. Composition uses /// the same convention as matrix multiplication: `(a * b)` applied to a /// vector applies `b` first, then `a`. +/// +/// 四元数 `w + xi + yj + zk`。 +/// +/// 旋转向量的方法假定该四元数为单位长度。乘法与加法则不然,因为任意四元数 +/// 运算在该假定下同样有良好定义。用 [`Quat::normalize`] 归一到单位长度,用 +/// [`Quat::is_normalized`] 检查。 +/// +/// 绕单位轴 `u` 旋转 `theta` 的四元数为 +/// `w = cos(theta / 2)`、`(x, y, z) = u * sin(theta / 2)`。复合采用与矩阵 +/// 乘法相同的约定:`(a * b)` 作用于向量时先作用 `b`,再作用 `a`。 #[derive(Debug, Clone, Copy, PartialEq, Default)] pub struct Quat { /// Scalar part. + /// + /// 标量部分。 pub w: f64, /// First component of the vector part. + /// + /// 向量部分的第一分量。 pub x: f64, /// Second component of the vector part. + /// + /// 向量部分的第二分量。 pub y: f64, /// Third component of the vector part. + /// + /// 向量部分的第三分量。 pub z: f64, } impl Quat { /// The identity rotation. + /// + /// 恒等旋转。 pub const IDENTITY: Self = Self::new(1.0, 0.0, 0.0, 0.0); /// Creates a quaternion from its four components. + /// + /// 由四个分量创建四元数。 pub const fn new(w: f64, x: f64, y: f64, z: f64) -> Self { Self { w, x, y, z } } @@ -41,6 +63,10 @@ impl Quat { /// /// The axis is normalized internally. Returns `None` when the axis has /// zero or non-finite length. + /// + /// 创建绕单位轴 `axis` 旋转 `angle` 弧度的四元数。 + /// + /// 轴在内部被归一化。轴长度为零或非有限时返回 `None`。 pub fn from_axis_angle(axis: Vec3, angle: f64) -> Option { let axis = axis.normalize()?; let half = angle / 2.0; @@ -49,18 +75,24 @@ impl Quat { } /// Creates a rotation of `angle` radians about the first axis. + /// + /// 创建绕第一轴旋转 `angle` 弧度的四元数。 pub fn from_rotation_x(angle: f64) -> Self { let (sin, cos) = (angle / 2.0).sin_cos(); Self::new(cos, sin, 0.0, 0.0) } /// Creates a rotation of `angle` radians about the second axis. + /// + /// 创建绕第二轴旋转 `angle` 弧度的四元数。 pub fn from_rotation_y(angle: f64) -> Self { let (sin, cos) = (angle / 2.0).sin_cos(); Self::new(cos, 0.0, sin, 0.0) } /// Creates a rotation of `angle` radians about the third axis. + /// + /// 创建绕第三轴旋转 `angle` 弧度的四元数。 pub fn from_rotation_z(angle: f64) -> Self { let (sin, cos) = (angle / 2.0).sin_cos(); Self::new(cos, 0.0, 0.0, sin) @@ -72,6 +104,12 @@ impl Quat { /// keeps the square root well conditioned for every input rotation. /// Returns `None` when `m` is not a rotation matrix, that is when it is /// not orthonormal with determinant one within a tolerance of `1e-9`. + /// + /// 由旋转矩阵 `m` 创建四元数。 + /// + /// 算法选取对角线上最大的元素作除数,从而对任何输入旋转都保持开方的良态。 + /// 当 `m` 不是旋转矩阵时返回 `None`,即在 `1e-9` 的容差内不正交或行列式 + /// 不为一。 pub fn from_mat3(m: crate::mat3::Mat3) -> Option { if !m.is_rotation(1e-9) { return None; @@ -97,16 +135,22 @@ impl Quat { } /// Returns the vector part `(x, y, z)`. + /// + /// 返回向量部分 `(x, y, z)`。 pub const fn vector(self) -> Vec3 { Vec3::new(self.x, self.y, self.z) } /// Returns the squared length of this quaternion. + /// + /// 返回该四元数的长度平方。 pub fn norm_squared(self) -> f64 { self.w * self.w + self.x * self.x + self.y * self.y + self.z * self.z } /// Returns the length of this quaternion. + /// + /// 返回该四元数的长度。 pub fn norm(self) -> f64 { self.norm_squared().sqrt() } @@ -114,6 +158,10 @@ impl Quat { /// Returns this quaternion scaled to unit length. /// /// Returns `None` when the length is zero or not finite. + /// + /// 返回该四元数缩放到单位长度后的结果。 + /// + /// 长度为零或非有限时返回 `None`。 pub fn normalize(self) -> Option { let norm = self.norm(); if norm > 0.0 && norm.is_finite() { @@ -131,6 +179,10 @@ impl Quat { /// Returns the conjugate `w - xi - yj - zk`. /// /// For a unit quaternion this is the inverse rotation. + /// + /// 返回共轭 `w - xi - yj - zk`。 + /// + /// 对单位四元数,它即逆旋转。 pub const fn conjugate(self) -> Self { Self::new(self.w, -self.x, -self.y, -self.z) } @@ -138,6 +190,10 @@ impl Quat { /// Returns the inverse rotation. /// /// Returns `None` when the length is zero or not finite. + /// + /// 返回逆旋转。 + /// + /// 长度为零或非有限时返回 `None`。 pub fn inverse(self) -> Option { let norm_squared = self.norm_squared(); if norm_squared > 0.0 && norm_squared.is_finite() { @@ -155,6 +211,8 @@ impl Quat { /// Returns the dot product of `self` and `rhs`, treating both as four /// component vectors. + /// + /// 把两者都视为四分量向量,返回 `self` 与 `rhs` 的点积。 pub fn dot(self, rhs: Self) -> f64 { self.w * rhs.w + self.x * rhs.x + self.y * rhs.y + self.z * rhs.z } @@ -164,6 +222,12 @@ impl Quat { /// Assumes this quaternion has unit length. The rotation is computed as /// `v + 2 * cross(vector, cross(vector, v) + w * v)`, which avoids /// forming the quaternion product matrix twice. + /// + /// 用该旋转对 `v` 施以旋转。 + /// + /// 假定该四元数为单位长度。旋转按 + /// `v + 2 * cross(vector, cross(vector, v) + w * v)` 计算,避免两次构造 + /// 四元数乘积矩阵。 pub fn rotate(self, v: Vec3) -> Vec3 { let q = self.vector(); let t = q.cross(v) * 2.0; @@ -173,6 +237,10 @@ impl Quat { /// Returns the rotation angle in radians, in `[0, pi]`. /// /// Assumes this quaternion has unit length. + /// + /// 返回旋转角,单位为弧度,位于 `[0, pi]`。 + /// + /// 假定该四元数为单位长度。 pub fn angle(self) -> f64 { 2.0 * self.w.clamp(-1.0, 1.0).acos() } @@ -181,6 +249,10 @@ impl Quat { /// /// Returns `None` for the identity rotation, where no axis is defined. /// Assumes this quaternion has unit length. + /// + /// 返回旋转轴的单位向量。 + /// + /// 对恒等旋转返回 `None`,因为此时旋转轴未定义。假定该四元数为单位长度。 pub fn axis(self) -> Option { self.vector().normalize() } @@ -190,6 +262,11 @@ impl Quat { /// This is a chord interpolation, so the result is not a unit /// quaternion and the angular speed is not constant. Use /// [`Quat::slerp`] when the intermediate rotations must be uniform. + /// + /// 返回从 `self` 到 `rhs` 的线性插值。 + /// + /// 这是弦插值,故结果不是单位四元数,角速度也不恒定。当中间旋转必须均匀时 + /// 请用 [`Quat::slerp`]。 pub fn lerp(self, rhs: Self, t: f64) -> Self { let w = self.w + (rhs.w - self.w) * t; let x = self.x + (rhs.x - self.x) * t; @@ -204,12 +281,18 @@ impl Quat { /// path a rotation would take if the angle were kept minimal. Falls /// back to [`Quat::lerp`] when the inputs are nearly parallel, where /// the sine in the denominator would otherwise lose precision. + /// + /// 返回从 `self` 到 `rhs` 的球面线性插值。 + /// + /// 取两段圆弧中较短者,故结果沿角度最小的旋转路径。当输入近乎平行时退回 + /// [`Quat::lerp`],此时分母中的正弦会损失精度。 pub fn slerp(self, rhs: Self, t: f64) -> Self { let mut end = rhs; let mut dot = self.dot(rhs); if dot < 0.0 { // Negating one endpoint selects the shorter arc, because `q` // and `-q` describe the same rotation. + // 对其中一个端点取负即可选出较短圆弧,因为 `q` 与 `-q` 表示同一旋转。 end = Self::new(-rhs.w, -rhs.x, -rhs.y, -rhs.z); dot = -dot; } @@ -232,21 +315,29 @@ impl Quat { } /// Returns `true` when the length is one within a tolerance of `1e-9`. + /// + /// 当长度在 `1e-9` 容差内为一时返回 `true`。 pub fn is_normalized(self) -> bool { (self.norm_squared() - 1.0).abs() < 1e-9 } /// Returns `true` when all four components are finite. + /// + /// 当四个分量都有限时返回 `true`。 pub fn is_finite(self) -> bool { self.w.is_finite() && self.x.is_finite() && self.y.is_finite() && self.z.is_finite() } /// Returns a rotation of a quarter turn about the first axis. + /// + /// 返回绕第一轴旋转四分之一周的四元数。 pub fn quarter_turn_x() -> Self { Self::from_rotation_x(core::f64::consts::FRAC_PI_2) } /// Returns a rotation of a half turn about the third axis. + /// + /// 返回绕第三轴旋转半周的四元数。 pub fn half_turn_z() -> Self { Self::from_rotation_z(core::f64::consts::PI) } @@ -258,6 +349,7 @@ impl Mul for Quat { fn mul(self, rhs: Self) -> Self { // Hamilton product, matching the convention that `(a * b)` // applies `b` first. + // Hamilton 积,与 `(a * b)` 先作用 `b` 的约定一致。 Self::new( self.w * rhs.w - self.x * rhs.x - self.y * rhs.y - self.z * rhs.z, self.w * rhs.x + self.x * rhs.w + self.y * rhs.z - self.z * rhs.y, diff --git a/crates/foundation/apsis-math/src/vec3.rs b/crates/foundation/apsis-math/src/vec3.rs index 8b665e6..24ee924 100644 --- a/crates/foundation/apsis-math/src/vec3.rs +++ b/crates/foundation/apsis-math/src/vec3.rs @@ -8,50 +8,108 @@ use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAss /// The components are named `x`, `y`, and `z`. No meaning is attached to /// them here; the reference frame is defined by the crate that uses the /// vector. +/// +/// 三分量列向量。 +/// +/// 分量名为 `x`、`y`、`z`。此处不赋予它们任何含义;参考系由使用该向量的 +/// crate 定义。 +/// +/// 三分量列向量。 +/// +/// 分量名为 `x`、`y`、`z`。此处不赋予它们任何含义;参考系由使用该向量的 +/// crate 定义。 #[derive(Debug, Clone, Copy, PartialEq, Default)] pub struct Vec3 { /// First component. + /// + /// 第一分量。 + /// + /// 第一分量。 pub x: f64, /// Second component. + /// + /// 第二分量。 + /// + /// 第二分量。 pub y: f64, /// Third component. + /// + /// 第三分量。 + /// + /// 第三分量。 pub z: f64, } impl Vec3 { /// The zero vector. + /// + /// 零向量。 + /// + /// 零向量。 pub const ZERO: Self = Self::new(0.0, 0.0, 0.0); /// The unit vector along the first axis. + /// + /// 沿第一轴的单位向量。 + /// + /// 沿第一轴的单位向量。 pub const X: Self = Self::new(1.0, 0.0, 0.0); /// The unit vector along the second axis. + /// + /// 沿第二轴的单位向量。 + /// + /// 沿第二轴的单位向量。 pub const Y: Self = Self::new(0.0, 1.0, 0.0); /// The unit vector along the third axis. + /// + /// 沿第三轴的单位向量。 + /// + /// 沿第三轴的单位向量。 pub const Z: Self = Self::new(0.0, 0.0, 1.0); /// Creates a vector from its three components. + /// + /// 由三个分量创建向量。 + /// + /// 由三个分量创建向量。 pub const fn new(x: f64, y: f64, z: f64) -> Self { Self { x, y, z } } /// Creates a vector whose three components all equal `value`. + /// + /// 创建三个分量都等于 `value` 的向量。 + /// + /// 创建三个分量都等于 `value` 的向量。 pub const fn splat(value: f64) -> Self { Self::new(value, value, value) } /// Returns the first component. + /// + /// 返回第一分量。 + /// + /// 返回第一分量。 pub const fn x(self) -> f64 { self.x } /// Returns the second component. + /// + /// 返回第二分量。 + /// + /// 返回第二分量。 pub const fn y(self) -> f64 { self.y } /// Returns the third component. + /// + /// 返回第三分量。 + /// + /// 返回第三分量。 pub const fn z(self) -> f64 { self.z } @@ -60,6 +118,14 @@ impl Vec3 { /// select `x`, `y`, and `z` respectively. /// /// Returns `None` for an index outside `0..=2`. + /// + /// 返回由 `index` 选定的分量,其中 `0`、`1`、`2` 分别对应 `x`、`y`、`z`。 + /// + /// `index` 超出 `0..=2` 时返回 `None`。 + /// + /// 返回由 `index` 选定的分量,其中 `0`、`1`、`2` 分别对应 `x`、`y`、`z`。 + /// + /// `index` 超出 `0..=2` 时返回 `None`。 pub const fn get(self, index: usize) -> Option { match index { 0 => Some(self.x), @@ -70,6 +136,10 @@ impl Vec3 { } /// Returns the dot product of `self` and `rhs`. + /// + /// 返回 `self` 与 `rhs` 的点积。 + /// + /// 返回 `self` 与 `rhs` 的点积。 pub fn dot(self, rhs: Self) -> f64 { self.x * rhs.x + self.y * rhs.y + self.z * rhs.z } @@ -78,6 +148,16 @@ impl Vec3 { /// /// The result is perpendicular to both inputs and follows the /// right-hand rule, so `Vec3::X.cross(Vec3::Y)` equals `Vec3::Z`. + /// + /// 返回叉积 `self x rhs`。 + /// + /// 结果同时垂直于两个输入并遵循右手定则,因此 `Vec3::X.cross(Vec3::Y)` + /// 等于 `Vec3::Z`。 + /// + /// 返回叉积 `self x rhs`。 + /// + /// 结果同时垂直于两个输入并遵循右手定则,因此 `Vec3::X.cross(Vec3::Y)` + /// 等于 `Vec3::Z`。 pub fn cross(self, rhs: Self) -> Self { Self::new( self.y * rhs.z - self.z * rhs.y, @@ -90,11 +170,23 @@ impl Vec3 { /// /// Prefer this over [`Vec3::norm`] when comparing lengths, because it /// avoids a square root. + /// + /// 返回该向量的欧几里得长度平方。 + /// + /// 比较长度时优先用它而非 [`Vec3::norm`],因为它省去一次开方。 + /// + /// 返回该向量的欧几里得长度平方。 + /// + /// 比较长度时优先用它而非 [`Vec3::norm`],因为它省去一次开方。 pub fn norm_squared(self) -> f64 { self.dot(self) } /// Returns the Euclidean length of this vector. + /// + /// 返回该向量的欧几里得长度。 + /// + /// 返回该向量的欧几里得长度。 pub fn norm(self) -> f64 { self.norm_squared().sqrt() } @@ -103,6 +195,14 @@ impl Vec3 { /// /// Returns `None` when the length is zero or not finite, in which case /// no direction is defined. + /// + /// 返回该向量缩放到单位长度后的结果。 + /// + /// 长度为零或非有限时返回 `None`,此时方向未定义。 + /// + /// 返回该向量缩放到单位长度后的结果。 + /// + /// 长度为零或非有限时返回 `None`,此时方向未定义。 pub fn normalize(self) -> Option { let norm = self.norm(); if norm > 0.0 && norm.is_finite() { @@ -113,11 +213,19 @@ impl Vec3 { } /// Returns the Euclidean distance between `self` and `rhs`. + /// + /// 返回 `self` 与 `rhs` 之间的欧几里得距离。 + /// + /// 返回 `self` 与 `rhs` 之间的欧几里得距离。 pub fn distance(self, rhs: Self) -> f64 { (self - rhs).norm() } /// Returns the squared Euclidean distance between `self` and `rhs`. + /// + /// 返回 `self` 与 `rhs` 之间的欧几里得距离平方。 + /// + /// 返回 `self` 与 `rhs` 之间的欧几里得距离平方。 pub fn distance_squared(self, rhs: Self) -> f64 { (self - rhs).norm_squared() } @@ -127,11 +235,23 @@ impl Vec3 { /// The result lies in `[0, pi]`. Returns `None` when either vector has /// zero or non-finite length, or when either vector has a non-finite /// component. + /// + /// 返回 `self` 与 `rhs` 之间的夹角,单位为弧度。 + /// + /// 结果位于 `[0, pi]`。当任一向量长度为零或非有限,或任一向量含非有限 + /// 分量时返回 `None`。 + /// + /// 返回 `self` 与 `rhs` 之间的夹角,单位为弧度。 + /// + /// 结果位于 `[0, pi]`。当任一向量长度为零或非有限,或任一向量含非有限分量 + /// 时返回 `None`。 pub fn angle_between(self, rhs: Self) -> Option { let denominator = self.norm() * rhs.norm(); if denominator > 0.0 && denominator.is_finite() { // The cosine can exceed one in magnitude through rounding, so // it is clamped to keep the arc cosine defined. + // 舍入可能使余弦的绝对值超过一,故将其钳位以保证反余弦有定义。 + // 舍入可能使余弦的绝对值超过一,故将其钳位以保证反余弦有定义。 Some((self.dot(rhs) / denominator).clamp(-1.0, 1.0).acos()) } else { None @@ -142,26 +262,50 @@ impl Vec3 { /// /// `t = 0` returns `self` and `t = 1` returns `rhs`. Values outside /// `[0, 1]` extrapolate. + /// + /// 返回线性插值 `self + t * (rhs - self)`。 + /// + /// `t = 0` 返回 `self`,`t = 1` 返回 `rhs`。`[0, 1]` 之外的值为外推。 + /// + /// 返回线性插值 `self + t * (rhs - self)`。 + /// + /// `t = 0` 返回 `self`,`t = 1` 返回 `rhs`。`[0, 1]` 之外的值为外推。 pub fn lerp(self, rhs: Self, t: f64) -> Self { self + (rhs - self) * t } /// Returns a vector with each component replaced by its absolute value. + /// + /// 返回各分量取绝对值后的向量。 + /// + /// 返回各分量取绝对值后的向量。 pub fn abs(self) -> Self { Self::new(self.x.abs(), self.y.abs(), self.z.abs()) } /// Returns the largest component. + /// + /// 返回最大分量。 + /// + /// 返回最大分量。 pub fn max_component(self) -> f64 { self.x.max(self.y).max(self.z) } /// Returns the smallest component. + /// + /// 返回最小分量。 + /// + /// 返回最小分量。 pub fn min_component(self) -> f64 { self.x.min(self.y).min(self.z) } /// Returns `true` when all three components are finite. + /// + /// 当三个分量都有限时返回 `true`。 + /// + /// 当三个分量都有限时返回 `true`。 pub fn is_finite(self) -> bool { self.x.is_finite() && self.y.is_finite() && self.z.is_finite() } diff --git a/scripts/__pycache__/bilingual.cpython-314.pyc b/scripts/__pycache__/bilingual.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..31c25ce5fac2c173d6fde1dd14b7767c0cda0c5a GIT binary patch literal 1966 zcmaJ>O>7%Q6rT0&+R5gpRoyBj&}3+NJY{%3PcV4QGa3tHoN2OH0zyZ zW{hzngprU)D^OEaqCNIlj&SLXGsmJri54MM>Z!L@5$csUYdeW5#7MjIX6DU%@B8Mx zH#Rt6AsDxB{Bmu-iO^HE=#Erd(6-(Mp@nQD(IT?7^V+$TOpPizbzYY`%=&rboGHyw zWE(@sHiuBKSElXM5tK_iYhY$Jih?F~uymFJf>{-R5H1H)_~Vj|FVTR8%XKHfF00i@ zC^08d;J8G|0!s$>sx%-4%lgCuv+$Lm~h~ND6p? zQwhOa#Bu$$1KFT1$zuncHW&n=%*Z6nZAf_)DdC)P9C0v{$AW=tDlDG_k;3JyK=gox z3aLP-$YC9NfVKf1;ZQ+Wq-@7s!wzsviI-Prp{01?0NrN|Tyw%E_Na$LCSf66zkp|V zvkX^&Adi9JZIy)1pvHu>oS@+}RY06nfe96o^511jk}o76hVTGa1HAfxn*c2sp!>-? zIiV$1XcWOFJmV+ASq9Wq&T5IFU2n)4lP4_;!-$&FXW;}EE~k+c#qB&PL{01}Rz;EV zB`S+fB&Zl)fvh3CD7afBK|6U0Tv$0R?sGzb=tIrdY|T#Dx^38|oi6H-*O_OkI$|RNQykP#Y$ngNdO*F}6pWaN&_1CdP?l&W$3G$nD_vzAUPq{)4#%@apVdgQ%G|mr&JnR9 zSyU`>c8$2QII9rbA9av(QT#8G;{HmdgPc?bGG$SJT5o z@3iO1i^=vDs3Eu01C-ol$=v!BLR2i3y8I=_?Vn<5va=th3Mhj95E*4{FFNxjLJhFT z%M11iQ1(U?yX90#(f7(&C@*TqJNr?pY%FT|fgP2|xbQYYWwQhw>(z0*v+-7E_Qn%0 z|EpWdylMrZuAN1cAKp2&_1&vWnr%dxvR>-l(dbI$%<&Ejqv*m{2=$^7#aLhWd}l7F z63#kIkD`Us6RLBXtMA+GMhM+vyT7!%fJ&uZwcRQG?Ph>$R0tvpt7ctR$EP5-dPwLp z56bW4R<&O+`Y3CL&IQ8xnf4 zmGq!QKi9)m>2SqgY$O)aiEl5?bb^X?7I?89l16O!;79a;?y+O4!ZGHGj@VSHO@0XE zBtd@wp@p9G?YTK~edgZe`pl!gvDVz?!Qs}K&A~mbvw!V>?Rw9;zS%eU-Kov&(4Fa9 z)A#iIZ$8TA*XK6-vm2j%fAPlICzB^1G=FM7So?WxW8%(qs-G2c&Q4=Kq literal 0 HcmV?d00001 diff --git a/scripts/bilingual.py b/scripts/bilingual.py new file mode 100644 index 0000000..ec25da5 --- /dev/null +++ b/scripts/bilingual.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +"""Apply a table of English-to-bilingual comment replacements to a file. + +The sweep over the repository is a long series of edits that pair an English +comment block with the English paragraph followed by a Chinese one. Writing +each pair twice, as two separate replacements, is error prone, so this +helper takes a list of pairs and rewrites the file with them applied, then +reports how many did not match. A replacement that does not match is almost +always a reflow of the English text, and is worth seeing rather than +skipping. + +Usage, from the repository root: + + python3 scripts/bilingual.py crates/orbit/apsis-kepler/src/elements.rs +""" + +from __future__ import annotations + +import sys +from pathlib import Path + + +def apply(path: Path, pairs: list[tuple[str, str]]) -> tuple[int, list[str]]: + """Replaces each pair and returns how many applied with the misses.""" + text = path.read_text(encoding="utf-8") + missed: list[str] = [] + applied = 0 + for old, new in pairs: + if old in text: + text = text.replace(old, new, 1) + applied += 1 + else: + head = old.strip().splitlines()[0][:56] if old.strip() else "" + missed.append(head) + path.write_text(text, encoding="utf-8") + return applied, missed