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