rs_math/graphical/
rectangle.rs

1use crate::graphical::circle::Circle;
2use crate::graphical::point_2d::Point2D;
3
4/// 表示二维平面上的矩形的结构体。
5///
6/// 矩形由左上角顶点 (`x1`, `y1`) 和右下角顶点 (`x2`, `y2`) 定义。
7#[derive(Debug, PartialEq)]
8pub struct Rectangle {
9    /// 左上角顶点的 x 坐标。
10    pub x1: f64,
11    /// 左上角顶点的 y 坐标。
12    pub y1: f64,
13    /// 右下角顶点的 x 坐标。
14    pub x2: f64,
15    /// 右下角顶点的 y 坐标。
16    pub y2: f64,
17}
18
19
20#[allow(dead_code)]
21impl Rectangle {
22    /// 通过给定的左上角顶点坐标、宽度和高度构建矩形。
23    ///
24    /// # 参数
25    ///
26    /// - `x`: 左上角顶点的 x 坐标。
27    /// - `y`: 左上角顶点的 y 坐标。
28    /// - `width`: 矩形的宽度。
29    /// - `height`: 矩形的高度。
30    ///
31    /// # 返回
32    ///
33    /// 返回通过左上角顶点坐标、宽度和高度定义的矩形。
34    ///
35    /// # 注意
36    ///
37    /// 如果提供的参数不合法,将会触发 panic。
38    pub fn new_from_corner(x: f64, y: f64, width: f64, height: f64) -> Self {
39        match (x, y) {
40            (x1, y1) if x1 + width <= x && y1 + height <= y => {
41                // 左上角
42                Rectangle {
43                    x1: x - width,
44                    y1: y - height,
45                    x2: x,
46                    y2: y,
47                }
48            }
49            (x1, y1) if x1 <= x && y1 <= y => {
50                // 左下角
51                Rectangle {
52                    x1: x1,
53                    y1: y1 - height,
54                    x2: x1 + width,
55                    y2: y,
56                }
57            }
58            (x1, y1) if x1 + width >= x && y1 <= y => {
59                // 右上角
60                Rectangle {
61                    x1: x,
62                    y1: y1 - height,
63                    x2: x + width,
64                    y2: y,
65                }
66            }
67            (x1, y1) if x1 <= x && y1 + height >= y => {
68                // 右下角
69                Rectangle {
70                    x1: x1,
71                    y1: y,
72                    x2: x1 + width,
73                    y2: y + height,
74                }
75            }
76            _ => panic!("Invalid corner point"),
77        }
78    }
79
80    /// 缩放矩形。
81    ///
82    /// # 参数
83    ///
84    /// - `sx`: x 方向的缩放比例。
85    /// - `sy`: y 方向的缩放比例。
86    ///
87    /// # 注意
88    ///
89    /// 该方法会修改矩形的右下角顶点坐标,使矩形按照指定的比例进行缩放。
90    pub fn scale(&mut self, sx: f64, sy: f64) {
91        // 计算新的右下角顶点坐标
92        self.x2 = self.x1 + sx * (self.x2 - self.x1);
93        self.y2 = self.y1 + sy * (self.y2 - self.y1);
94    }
95
96    /// 求矩形的四个顶点。
97    ///
98    /// # 参数
99    ///
100    /// - `r`: 给定的矩形。
101    ///
102    /// # 返回
103    ///
104    /// 返回矩形的四个顶点,按照左上角、右上角、左下角、右下角的顺序排列。
105    fn rectangle_corners(r: &Rectangle) -> (Point2D, Point2D, Point2D, Point2D) {
106        (
107            // 左上角
108            Point2D { x: r.x1, y: r.y1 },
109            // 右上角
110            Point2D { x: r.x2, y: r.y1 },
111            // 左下角
112            Point2D { x: r.x1, y: r.y2 },
113            // 右下角
114            Point2D { x: r.x2, y: r.y2 },
115        )
116    }
117
118
119    /// 旋转一个矩形(绕原点)。
120    ///
121    /// # 参数
122    ///
123    /// - `angle`: 旋转角度(弧度)。
124    ///
125    /// # 返回
126    ///
127    /// 返回一个新的矩形,表示原矩形绕原点逆时针旋转一定角度后的状态。
128    pub fn rotate(&self, angle: f64) -> Rectangle {
129        // 计算旋转后的左上角顶点坐标
130        let new_x1 = self.x1 * angle.cos() - self.y1 * angle.sin();
131        let new_y1 = self.x1 * angle.sin() + self.y1 * angle.cos();
132
133        // 计算旋转后的右下角顶点坐标
134        let new_x2 = self.x2 * angle.cos() - self.y2 * angle.sin();
135        let new_y2 = self.x2 * angle.sin() + self.y2 * angle.cos();
136
137        Rectangle {
138            x1: new_x1,
139            y1: new_y1,
140            x2: new_x2,
141            y2: new_y2,
142        }
143    }
144    /// 计算矩形的面积。
145    ///
146    /// # 返回
147    ///
148    /// 返回矩形的面积。
149    pub fn area(&self) -> f64 {
150        (self.x2 - self.x1) * (self.y2 - self.y1)
151    }
152
153
154    /// 计算矩形的周长。
155    ///
156    /// # 返回
157    ///
158    /// 返回矩形的周长。
159    pub fn perimeter(&self) -> f64 {
160        // 计算矩形的宽度和高度
161        let width = self.x2 - self.x1;
162        let height = self.y2 - self.y1;
163
164        // 计算矩形的周长
165        let perimeter = 2.0 * (width + height);
166
167        perimeter.abs() // 确保周长为正数
168    }
169
170    /// 判断点是否在矩形内。
171    ///
172    /// # 参数
173    ///
174    /// - `x`: 点的 x 坐标。
175    /// - `y`: 点的 y 坐标。
176    ///
177    /// # 返回
178    ///
179    /// 如果点在矩形内,返回 `true`,否则返回 `false`。
180    pub fn point_inside(&self, x: f64, y: f64) -> bool {
181        x >= self.x1 && x <= self.x2 && y >= self.y1 && y <= self.y2
182    }
183    /// 根据点旋转矩形。
184    ///
185    /// # 参数
186    ///
187    /// - `angle`: 旋转角度(弧度)。
188    /// - `x_rot`: 旋转点的 x 坐标。
189    /// - `y_rot`: 旋转点的 y 坐标。
190    ///
191    /// # 返回
192    ///
193    /// 旋转后的矩形。
194    pub fn rotate_around_point(&self, angle: f64, x_rot: f64, y_rot: f64) -> Rectangle {
195        // 使用旋转矩阵对矩形进行旋转
196        let x1_prime = (self.x1 - x_rot) * angle.cos() - (self.y1 - y_rot) * angle.sin();
197        let y1_prime = (self.x1 - x_rot) * angle.sin() + (self.y1 - y_rot) * angle.cos();
198        let x2_prime = (self.x2 - x_rot) * angle.cos() - (self.y2 - y_rot) * angle.sin();
199        let y2_prime = (self.x2 - x_rot) * angle.sin() + (self.y2 - y_rot) * angle.cos();
200
201        // 将旋转后的中心点坐标平移到旋转点
202        let x1 = x1_prime + x_rot;
203        let y1 = y1_prime + y_rot;
204        let x2 = x2_prime + x_rot;
205        let y2 = y2_prime + y_rot;
206
207        Rectangle { x1, y1, x2, y2 }
208    }
209
210    /// 判断两个矩形是否相交。
211    ///
212    /// # 参数
213    ///
214    /// - `other`: 另一个矩形。
215    ///
216    /// # 返回
217    ///
218    /// 如果两个矩形相交,则返回 `true`,否则返回 `false`。
219    pub fn intersect(&self, other: &Rectangle) -> bool {
220        self.x1 <= other.x2 && self.x2 >= other.x1 && self.y1 <= other.y2 && self.y2 >= other.y1
221    }
222
223    /// 判断当前矩形是否包含另一个矩形。
224    ///
225    /// # 参数
226    ///
227    /// - `other`: 要检查的矩形。
228    ///
229    /// # 返回
230    ///
231    /// 如果当前矩形包含另一个矩形,则返回 `true`,否则返回 `false`。
232    pub fn contains(&self, other: &Rectangle) -> bool {
233        self.x1 <= other.x1 && self.x2 >= other.x2 && self.y1 <= other.y1 && self.y2 >= other.y2
234    }
235    /// 计算矩形的内切圆。
236    ///
237    /// # 返回
238    ///
239    /// 返回一个包含内切圆信息的 `Circle` 结构体。
240    pub fn inscribed_circle(&self) -> Circle {
241        let (x, y) = &self.center();
242        Circle {
243            x: *x,
244            y: *y,
245            radius: self.inscribed_circle_radius(),
246        }
247    }
248    /// 计算矩形的中心点坐标。
249    ///
250    /// # 返回
251    ///
252    /// 返回一个包含矩形中心点坐标 `(x, y)` 的元组。
253    fn center(&self) -> (f64, f64) {
254        let center_x = (self.x1 + self.x2) / 2.0;
255        let center_y = (self.y1 + self.y2) / 2.0;
256        (center_x, center_y)
257    }
258
259    /// 计算内切圆的半径。
260    ///
261    /// # 返回
262    ///
263    /// 返回内切圆的半径,即矩形宽度和高度中较小值的一半。
264    fn inscribed_circle_radius(&self) -> f64 {
265        let width = self.x2 - self.x1;
266        let height = self.y2 - self.y1;
267
268        f64::min(width, height) / 2.0
269    }
270}
271