Skip to main content

smooth_frame/types/
geometry.rs

1use std::ops::{Add, Div, Mul, Neg, Sub};
2
3use crate::utils::{EPSILON, clamp};
4
5/// 二维点。
6#[derive(Debug, Clone, Copy, PartialEq, Default)]
7pub struct Point {
8    /// X 坐标。
9    pub x: f64,
10    /// Y 坐标。
11    pub y: f64,
12}
13
14/// 二维向量。
15#[derive(Debug, Clone, Copy, PartialEq, Default)]
16pub struct Vector {
17    /// X 分量。
18    pub x: f64,
19    /// Y 分量。
20    pub y: f64,
21}
22
23impl Point {
24    /// 创建一个点。
25    #[must_use]
26    pub const fn new(x: f64, y: f64) -> Self {
27        Self { x, y }
28    }
29
30    /// 判断坐标是否都是有限数值。
31    #[must_use]
32    pub fn is_finite(self) -> bool {
33        self.x.is_finite() && self.y.is_finite()
34    }
35}
36
37impl Vector {
38    /// 创建一个二维向量。
39    #[must_use]
40    pub const fn new(x: f64, y: f64) -> Self {
41        Self { x, y }
42    }
43
44    /// 判断分量是否都是有限数值。
45    #[must_use]
46    pub fn is_finite(self) -> bool {
47        self.x.is_finite() && self.y.is_finite()
48    }
49
50    /// 返回向量长度。
51    #[must_use]
52    pub fn length(self) -> f64 {
53        self.length_squared().sqrt()
54    }
55
56    /// 返回向量长度的平方。
57    #[must_use]
58    pub const fn length_squared(self) -> f64 {
59        self.x * self.x + self.y * self.y
60    }
61
62    /// 返回两个向量的点积。
63    #[must_use]
64    pub const fn dot(self, other: Vector) -> f64 {
65        self.x * other.x + self.y * other.y
66    }
67
68    /// 返回两个向量的二维叉积。
69    #[must_use]
70    pub const fn cross(self, other: Vector) -> f64 {
71        self.x * other.y - self.y * other.x
72    }
73
74    /// 返回单位向量;零长度或非有限向量返回 `None`。
75    #[must_use]
76    pub fn normalized(self) -> Option<Vector> {
77        let length = self.length();
78        if !length.is_finite() || length <= EPSILON {
79            return None;
80        }
81        Some(self / length)
82    }
83
84    /// 返回两个向量之间的夹角,单位为弧度。
85    #[must_use]
86    pub fn angle_between(self, other: Vector) -> Option<f64> {
87        let a = self.normalized()?;
88        let b = other.normalized()?;
89        Some(clamp(a.dot(b), -1.0, 1.0).acos())
90    }
91}
92
93/// 点加向量,得到平移后的点
94impl Add<Vector> for Point {
95    type Output = Point;
96
97    // 执行点加向量的平移运算。
98    fn add(self, rhs: Vector) -> Self::Output {
99        Point::new(self.x + rhs.x, self.y + rhs.y)
100    }
101}
102
103/// 两个点相减,得到从右侧点指向左侧点的向量。
104impl Sub<Point> for Point {
105    type Output = Vector;
106
107    // 计算两个点之间的位移向量。
108    fn sub(self, rhs: Point) -> Self::Output {
109        Vector::new(self.x - rhs.x, self.y - rhs.y)
110    }
111}
112
113/// 点减向量,得到反向平移后的点。
114impl Sub<Vector> for Point {
115    type Output = Point;
116
117    // 执行点减向量的反向平移运算。
118    fn sub(self, rhs: Vector) -> Self::Output {
119        Point::new(self.x - rhs.x, self.y - rhs.y)
120    }
121}
122
123/// 两个向量相加,得到叠加后的合成向量。
124impl Add for Vector {
125    type Output = Vector;
126
127    // 按分量相加两个向量。
128    fn add(self, rhs: Vector) -> Self::Output {
129        Vector::new(self.x + rhs.x, self.y + rhs.y)
130    }
131}
132
133/// 两个向量相减,得到左侧向量相对右侧向量的差向量
134impl Sub for Vector {
135    type Output = Vector;
136
137    // 按分量相减两个向量。
138    fn sub(self, rhs: Vector) -> Self::Output {
139        Vector::new(self.x - rhs.x, self.y - rhs.y)
140    }
141}
142
143/// 向量乘以标量,得到按该倍数缩放后的向量。
144impl Mul<f64> for Vector {
145    type Output = Vector;
146
147    // 将向量按标量倍数缩放。
148    fn mul(self, rhs: f64) -> Self::Output {
149        Vector::new(self.x * rhs, self.y * rhs)
150    }
151}
152
153/// 标量乘以向量,得到按该倍数缩放后的向量。
154impl Mul<Vector> for f64 {
155    type Output = Vector;
156
157    // 支持标量在左侧时的向量缩放写法。
158    fn mul(self, rhs: Vector) -> Self::Output {
159        rhs * self
160    }
161}
162
163/// 向量除以标量,得到按该标量倒数缩放后的向量。
164impl Div<f64> for Vector {
165    type Output = Vector;
166
167    // 将向量按标量倒数缩放。
168    fn div(self, rhs: f64) -> Self::Output {
169        Vector::new(self.x / rhs, self.y / rhs)
170    }
171}
172
173/// 对向量取负,得到方向相反、长度相同的向量。
174impl Neg for Vector {
175    type Output = Vector;
176
177    // 翻转向量方向。
178    fn neg(self) -> Self::Output {
179        Vector::new(-self.x, -self.y)
180    }
181}