rs_math/graphical/triangle.rs
1use crate::graphical::circle::Circle;
2use crate::graphical::point_2d::Point2D;
3
4/// 三角形结构体,由三个顶点组成。
5#[derive(Debug, PartialEq)]
6pub struct Triangle {
7 /// 三角形的第一个顶点
8 pub vertex_a: Point2D,
9 /// 三角形的第二个顶点
10 pub vertex_b: Point2D,
11 /// 三角形的第三个顶点
12 pub vertex_c: Point2D,
13}
14/// 枚举类型,表示三角形的类型。
15#[derive(Debug, PartialEq)]
16pub enum TriangleType {
17 /// 锐角三角形
18 Acute,
19 /// 直角三角形
20 Right,
21 /// 钝角三角形
22 Obtuse,
23}
24#[allow(dead_code)]
25impl Triangle {
26 /// 构造函数,用于创建新的三角形实例。
27 ///
28 /// # 参数
29 ///
30 /// * `vertex_a` - 三角形的顶点 A。
31 /// * `vertex_b` - 三角形的顶点 B。
32 /// * `vertex_c` - 三角形的顶点 C。
33 ///
34 /// # 示例
35 ///
36 /// ```
37 /// use rs_math::graphical::point_2d::Point2D;
38 /// use rs_math::graphical::triangle::Triangle;
39 ///
40 /// let vertex_a = Point2D { x: 0.0, y: 0.0 };
41 /// let vertex_b = Point2D { x: 1.0, y: 0.0 };
42 /// let vertex_c = Point2D { x: 0.0, y: 1.0 };
43 ///
44 /// let triangle = Triangle::new(vertex_a, vertex_b, vertex_c);
45 /// ```
46 pub fn new(vertex_a: Point2D, vertex_b: Point2D, vertex_c: Point2D) -> Self {
47 Triangle {
48 vertex_a,
49 vertex_b,
50 vertex_c,
51 }
52 }
53
54 /// 计算三角形的边长。
55 ///
56 /// # 参数
57 ///
58 /// * `start` - 边的起点。
59 /// * `end` - 边的终点。
60 ///
61 /// # 返回值
62 ///
63 /// 返回边的长度。
64 ///
65 /// # 示例
66 ///
67 /// ```
68 /// use rs_math::graphical::point_2d::Point2D;
69 /// use rs_math::graphical::triangle::Triangle;
70 ///
71 /// let vertex_a = Point2D { x: 0.0, y: 0.0 };
72 /// let vertex_b = Point2D { x: 1.0, y: 0.0 };
73 /// let vertex_c = Point2D { x: 0.0, y: 1.0 };
74 ///
75 /// let triangle = Triangle::new(vertex_a, vertex_b, vertex_c);
76 /// let length = triangle.side_length(&vertex_a, &vertex_b);
77 /// ```
78 pub fn side_length(&self, start: &Point2D, end: &Point2D) -> f64 {
79 ((end.x - start.x).powi(2) + (end.y - start.y).powi(2)).sqrt()
80 }
81
82 /// 计算三角形的周长。
83 ///
84 /// # 返回值
85 ///
86 /// 返回三角形的周长。
87 ///
88 /// # 示例
89 ///
90 /// ```
91 /// use rs_math::graphical::point_2d::Point2D;
92 /// use rs_math::graphical::triangle::{Triangle, TriangleType};
93 ///
94 /// let vertex_a = Point2D { x: 0.0, y: 0.0 };
95 /// let vertex_b = Point2D { x: 1.0, y: 0.0 };
96 /// let vertex_c = Point2D { x: 0.0, y: 1.0 };
97 ///
98 /// let triangle = Triangle::new(vertex_a, vertex_b, vertex_c);
99 /// let perimeter = triangle.perimeter();
100 /// ```
101 pub fn perimeter(&self) -> f64 {
102 let side_ab = self.side_length(&self.vertex_a, &self.vertex_b);
103 let side_bc = self.side_length(&self.vertex_b, &self.vertex_c);
104 let side_ca = self.side_length(&self.vertex_c, &self.vertex_a);
105 side_ab + side_bc + side_ca
106 }
107
108 /// 计算三角形的面积。
109 ///
110 /// # 返回值
111 ///
112 /// 返回三角形的面积。
113 ///
114 /// # 示例
115 ///
116 /// ```
117 /// use rs_math::graphical::point_2d::Point2D;
118 /// use rs_math::graphical::triangle::{Triangle, TriangleType};
119 ///
120 /// let vertex_a = Point2D { x: 0.0, y: 0.0 };
121 /// let vertex_b = Point2D { x: 1.0, y: 0.0 };
122 /// let vertex_c = Point2D { x: 0.0, y: 1.0 };
123 ///
124 /// let triangle = Triangle::new(vertex_a, vertex_b, vertex_c);
125 /// let area = triangle.area();
126 /// ```
127 pub fn area(&self) -> f64 {
128 let side_ab = self.side_length(&self.vertex_a, &self.vertex_b);
129 let side_bc = self.side_length(&self.vertex_b, &self.vertex_c);
130 let side_ca = self.side_length(&self.vertex_c, &self.vertex_a);
131 let s = self.perimeter() / 2.0; // 半周长
132 (s * (s - side_ab) * (s - side_bc) * (s - side_ca)).sqrt()
133 }
134
135
136 /// 计算三角形的半周长。
137 ///
138 /// # 返回值
139 ///
140 /// 返回三角形的半周长。
141 ///
142 /// # 示例
143 ///
144 /// ```
145 /// use rs_math::graphical::point_2d::Point2D;
146 /// use rs_math::graphical::triangle::{Triangle, TriangleType};
147 ///
148 /// let vertex_a = Point2D { x: 0.0, y: 0.0 };
149 /// let vertex_b = Point2D { x: 1.0, y: 0.0 };
150 /// let vertex_c = Point2D { x: 0.0, y: 1.0 };
151 ///
152 /// let triangle = Triangle::new(vertex_a, vertex_b, vertex_c);
153 /// let semi_perimeter = triangle.semi_perimeter();
154 /// ```
155 pub fn semi_perimeter(&self) -> f64 {
156 let side_ab = self.side_length(&self.vertex_a, &self.vertex_b);
157 let side_bc = self.side_length(&self.vertex_b, &self.vertex_c);
158 let side_ca = self.side_length(&self.vertex_c, &self.vertex_a);
159 (side_ab + side_bc + side_ca) / 2.0
160 }
161
162
163 /// 计算三角形的内切圆。
164 ///
165 /// # 返回值
166 ///
167 /// 返回一个 `Circle` 结构体,表示三角形的内切圆。
168 ///
169 /// # 示例
170 ///
171 /// ```
172 /// use rs_math::graphical::point_2d::Point2D;
173 /// use rs_math::graphical::triangle::{Triangle, TriangleType};
174 ///
175 /// let vertex_a = Point2D { x: 0.0, y: 0.0 };
176 /// let vertex_b = Point2D { x: 1.0, y: 0.0 };
177 /// let vertex_c = Point2D { x: 0.0, y: 1.0 };
178 ///
179 /// let triangle = Triangle::new(vertex_a, vertex_b, vertex_c);
180 /// let in_circle = triangle.in_circle();
181 /// ```
182 pub fn in_circle(&self) -> Circle {
183 let s = self.semi_perimeter();
184 let side_ab = self.side_length(&self.vertex_a, &self.vertex_b);
185 let side_bc = self.side_length(&self.vertex_b, &self.vertex_c);
186 let side_ca = self.side_length(&self.vertex_c, &self.vertex_a);
187
188 let radius = self.area() / s;
189
190 // 计算内切圆的中心坐标
191 let center_x = (side_bc * self.vertex_a.x + side_ca * self.vertex_b.x + side_ab * self.vertex_c.x) / (side_ab + side_bc + side_ca);
192 let center_y = (side_bc * self.vertex_a.y + side_ca * self.vertex_b.y + side_ab * self.vertex_c.y) / (side_ab + side_bc + side_ca);
193
194 Circle {
195 x: center_x,
196 y: center_y,
197 radius,
198 }
199 }
200 /// 绕着指定点旋转三角形,返回新的三角形实例。
201 ///
202 /// # 参数
203 ///
204 /// - `center`: 旋转中心点坐标。
205 /// - `angle_degrees`: 旋转角度(度数)。
206 ///
207 /// # 返回值
208 ///
209 /// 返回一个新的 `Triangle` 结构体,表示旋转后的三角形。
210 ///
211 /// # 示例
212 ///
213 /// ```
214 /// use rs_math::graphical::point_2d::Point2D;
215 /// use rs_math::graphical::triangle::{Triangle, TriangleType};
216 ///
217 /// let vertex_a = Point2D { x: 0.0, y: 0.0 };
218 /// let vertex_b = Point2D { x: 1.0, y: 0.0 };
219 /// let vertex_c = Point2D { x: 0.0, y: 1.0 };
220 ///
221 /// let triangle = Triangle::new(vertex_a, vertex_b, vertex_c);
222 /// let center = Point2D { x: 0.5, y: 0.5 };
223 /// let rotated_triangle = triangle.rotate_around_point(¢er, 45.0);
224 /// ```
225 pub fn rotate_around_point(&self, center: &Point2D, angle_degrees: f64) -> Triangle {
226 // 将角度转换为弧度
227 let angle_radians = angle_degrees.to_radians();
228
229 // 定义旋转矩阵
230 let rotation_matrix = [
231 [angle_radians.cos(), -angle_radians.sin()],
232 [angle_radians.sin(), angle_radians.cos()],
233 ];
234
235 // 对每个顶点进行旋转
236 let new_vertex_a = rotate_point(&self.vertex_a, center, rotation_matrix);
237 let new_vertex_b = rotate_point(&self.vertex_b, center, rotation_matrix);
238 let new_vertex_c = rotate_point(&self.vertex_c, center, rotation_matrix);
239
240 Triangle {
241 vertex_a: new_vertex_a,
242 vertex_b: new_vertex_b,
243 vertex_c: new_vertex_c,
244 }
245 }
246
247 /// 判断点是否在三角形内。
248 ///
249 /// # 参数
250 ///
251 /// - `p`: 要判断的点坐标。
252 ///
253 /// # 返回值
254 ///
255 /// 如果点在三角形内,返回 `true`,否则返回 `false`。
256 ///
257 /// # 示例
258 ///
259 /// ```
260 /// use rs_math::graphical::point_2d::Point2D;
261 /// use rs_math::graphical::triangle::{Triangle, TriangleType};
262 ///
263 /// let triangle = Triangle {
264 /// vertex_a: Point2D { x: 0.0, y: 0.0 },
265 /// vertex_b: Point2D { x: 1.0, y: 0.0 },
266 /// vertex_c: Point2D { x: 0.0, y: 1.0 },
267 /// };
268 /// let point_inside = triangle.point_inside_triangle(&Point2D { x: 0.5, y: 0.5 });
269 /// ```
270 pub fn point_inside_triangle(&self, p: &Point2D) -> bool {
271 // 计算重心坐标
272 let barycentric_coords = self.barycentric_coordinates(p);
273
274 // 判断点是否在三角形内
275 barycentric_coords.iter().all(|&coord| coord >= 0.0 && coord <= 1.0)
276 }
277
278 /// 辅助方法,计算点的重心坐标。
279 ///
280 /// # 参数
281 ///
282 /// - `p`: 要计算重心坐标的点。
283 ///
284 /// # 返回值
285 ///
286 /// 返回包含三个元素的数组,表示点的重心坐标。
287 ///
288 /// # 示例
289 ///
290 /// ```
291 /// use rs_math::graphical::point_2d::Point2D;
292 /// use rs_math::graphical::triangle::{Triangle, TriangleType};
293 ///
294 /// let triangle = Triangle {
295 /// vertex_a: Point2D { x: 0.0, y: 0.0 },
296 /// vertex_b: Point2D { x: 1.0, y: 0.0 },
297 /// vertex_c: Point2D { x: 0.0, y: 1.0 },
298 /// };
299 /// let barycentric_coords = triangle.barycentric_coordinates(&Point2D { x: 0.5, y: 0.5 });
300 /// ```
301 pub fn barycentric_coordinates(&self, p: &Point2D) -> [f64; 3] {
302 // 计算三个子三角形的面积
303 let area_triangle = self.area();
304 let area_sub_triangle_a = Triangle::new(p.clone(), self.vertex_b.clone(), self.vertex_c.clone()).area();
305 let area_sub_triangle_b = Triangle::new(self.vertex_a.clone(), p.clone(), self.vertex_c.clone()).area();
306 let area_sub_triangle_c = Triangle::new(self.vertex_a.clone(), self.vertex_b.clone(), p.clone()).area();
307
308 // 计算重心坐标
309 let p1 = area_sub_triangle_a / area_triangle;
310 let p2 = area_sub_triangle_b / area_triangle;
311 let p3 = area_sub_triangle_c / area_triangle;
312
313 [p1, p2, p3]
314 }
315
316 /// 计算垂心。
317 ///
318 /// # 返回值
319 ///
320 /// 返回垂心的坐标。
321 ///
322 /// # 示例
323 ///
324 /// ```
325 /// use rs_math::graphical::point_2d::Point2D;
326 /// use rs_math::graphical::triangle::{Triangle, TriangleType};
327 ///
328 /// let triangle = Triangle {
329 /// vertex_a: Point2D { x: 0.0, y: 0.0 },
330 /// vertex_b: Point2D { x: 1.0, y: 0.0 },
331 /// vertex_c: Point2D { x: 0.0, y: 1.0 },
332 /// };
333 /// let orthocenter = triangle.orthocenter();
334 /// ```
335 pub fn orthocenter(&self) -> Point2D {
336 let x_h = self.vertex_a.x;
337 let y_h = self.vertex_b.y;
338 Point2D { x: x_h, y: y_h }
339 }
340
341 /// 计算重心。
342 ///
343 /// # 返回值
344 ///
345 /// 返回重心的坐标。
346 ///
347 /// # 示例
348 ///
349 /// ```
350 /// use rs_math::graphical::point_2d::Point2D;
351 /// use rs_math::graphical::triangle::{Triangle, TriangleType};
352 ///
353 /// let triangle = Triangle {
354 /// vertex_a: Point2D { x: 0.0, y: 0.0 },
355 /// vertex_b: Point2D { x: 1.0, y: 0.0 },
356 /// vertex_c: Point2D { x: 0.0, y: 1.0 },
357 /// };
358 /// let centroid = triangle.centroid();
359 /// ```
360 pub fn centroid(&self) -> Point2D {
361 let x_g = (self.vertex_a.x + self.vertex_b.x + self.vertex_c.x) / 3.0;
362 let y_g = (self.vertex_a.y + self.vertex_b.y + self.vertex_c.y) / 3.0;
363 Point2D { x: x_g, y: y_g }
364 }
365
366 /// 计算内心。
367 ///
368 /// # 返回值
369 ///
370 /// 返回内心的坐标。
371 ///
372 /// # 示例
373 ///
374 /// ```
375 /// use rs_math::graphical::point_2d::Point2D;
376 /// use rs_math::graphical::triangle::{Triangle, TriangleType};
377 ///
378 /// let triangle = Triangle {
379 /// vertex_a: Point2D { x: 0.0, y: 0.0 },
380 /// vertex_b: Point2D { x: 1.0, y: 0.0 },
381 /// vertex_c: Point2D { x: 0.0, y: 1.0 },
382 /// };
383 /// let incenter = triangle.incenter();
384 /// ```
385 pub fn incenter(&self) -> Point2D {
386 let a = self.vertex_b.distance_to(&self.vertex_c);
387 let b = self.vertex_c.distance_to(&self.vertex_a);
388 let c = self.vertex_a.distance_to(&self.vertex_b);
389
390 let x_i = (a * self.vertex_a.x + b * self.vertex_b.x + c * self.vertex_c.x) / (a + b + c);
391 let y_i = (a * self.vertex_a.y + b * self.vertex_b.y + c * self.vertex_c.y) / (a + b + c);
392
393 Point2D { x: x_i, y: y_i }
394 }
395
396 /// 计算外心。
397 ///
398 /// # 返回值
399 ///
400 /// 返回外心的坐标。
401 ///
402 /// # 示例
403 ///
404 /// ```
405 /// use rs_math::graphical::point_2d::Point2D;
406 /// use rs_math::graphical::triangle::{Triangle, TriangleType};
407 ///
408 /// let triangle = Triangle {
409 /// vertex_a: Point2D { x: 0.0, y: 0.0 },
410 /// vertex_b: Point2D { x: 1.0, y: 0.0 },
411 /// vertex_c: Point2D { x: 0.0, y: 1.0 },
412 /// };
413 /// let circumcenter = triangle.circumcenter();
414 /// ```
415 pub fn circumcenter(&self) -> Point2D {
416 let m_ab = Point2D {
417 x: (self.vertex_a.x + self.vertex_b.x) / 2.0,
418 y: (self.vertex_a.y + self.vertex_b.y) / 2.0,
419 };
420
421 let m_bc = Point2D {
422 x: (self.vertex_b.x + self.vertex_c.x) / 2.0,
423 y: (self.vertex_b.y + self.vertex_c.y) / 2.0,
424 };
425
426 let m_ca = Point2D {
427 x: (self.vertex_c.x + self.vertex_a.x) / 2.0,
428 y: (self.vertex_c.y + self.vertex_a.y) / 2.0,
429 };
430
431 let m_ab_slope = -(self.vertex_b.x - self.vertex_a.x) / (self.vertex_b.y - self.vertex_a.y);
432 let m_bc_slope = -(self.vertex_c.x - self.vertex_b.x) / (self.vertex_c.y - self.vertex_b.y);
433 let m_ca_slope = -(self.vertex_a.x - self.vertex_c.x) / (self.vertex_a.y - self.vertex_c.y);
434
435 let x_o = (m_ab.y - m_ab_slope * m_ab.x + m_bc.y - m_bc_slope * m_bc.x + m_ca.y - m_ca_slope * m_ca.x)
436 / (m_ab_slope + m_bc_slope + m_ca_slope);
437
438 let y_o = m_ab_slope * (x_o - m_ab.x) + m_ab.y;
439
440 Point2D { x: x_o, y: y_o }
441 }
442
443 // 计算三角形的类型
444 pub fn classify_triangle(&self) -> TriangleType {
445 let (angle_a, angle_b, angle_c) = self.classify_angles();
446
447 if angle_a < 90.0 && angle_b < 90.0 && angle_c < 90.0 {
448 TriangleType::Acute
449 } else if angle_a == 90.0 || angle_b == 90.0 || angle_c == 90.0 {
450 TriangleType::Right
451 } else {
452 TriangleType::Obtuse
453 }
454 }
455 /// 计算三角形的类型。
456 ///
457 /// 三角形的类型可以分为三种:锐角三角形、直角三角形和钝角三角形。
458 ///
459 /// # 返回值
460 ///
461 /// 返回三角形的类型。
462 ///
463 /// # 示例
464 ///
465 /// ```rust
466 /// use rs_math::graphical::triangle::{Triangle, TriangleType};
467 /// use rs_math::graphical::point_2d::{ Point2D};
468 ///
469 /// let triangle = Triangle {
470 /// vertex_a: Point2D { x: 0.0, y: 0.0 },
471 /// vertex_b: Point2D { x: 1.0, y: 0.0 },
472 /// vertex_c: Point2D { x: 0.0, y: 1.0 },
473 /// };
474 /// let triangle_type = triangle.classify_triangle();
475 /// ```
476 pub fn classify_angles(&self) -> (f64, f64, f64) {
477 let angle_a = self.angle_between(&self.vertex_b, &self.vertex_c, &self.vertex_a);
478 let angle_b = self.angle_between(&self.vertex_a, &self.vertex_c, &self.vertex_b);
479 let angle_c = self.angle_between(&self.vertex_a, &self.vertex_b, &self.vertex_c);
480
481 (angle_a, angle_b, angle_c)
482 }
483
484 /// 计算两条边之间的角度。
485 ///
486 /// 该函数使用余弦定理计算两条边之间的角度。
487 ///
488 /// # 参数
489 ///
490 /// * `p1`:三角形的第一个顶点。
491 /// * `p2`:三角形的第二个顶点。
492 /// * `p3`:三角形的第三个顶点。
493 ///
494 /// # 返回值
495 ///
496 /// 返回两条边之间的角度,单位为度。
497 ///
498 /// # 示例
499 ///
500 /// ```rust
501 /// use rs_math::graphical::point_2d::Point2D;
502 /// use rs_math::graphical::triangle::{Triangle, TriangleType};
503 ///
504 /// let triangle = Triangle {
505 /// vertex_a: Point2D { x: 0.0, y: 0.0 },
506 /// vertex_b: Point2D { x: 1.0, y: 0.0 },
507 /// vertex_c: Point2D { x: 0.0, y: 1.0 },
508 /// };
509 ///
510 /// let angle = triangle.angle_between(&triangle.vertex_a, &triangle.vertex_b, &triangle.vertex_c);
511 /// ```
512 fn angle_between(&self, p1: &Point2D, p2: &Point2D, p3: &Point2D) -> f64 {
513 let a = p1.distance_to(p2);
514 let b = p2.distance_to(p3);
515 let c = p3.distance_to(p1);
516
517 let cos_angle = (a.powi(2) + b.powi(2) - c.powi(2)) / (2.0 * a * b);
518 let angle_rad = cos_angle.acos();
519
520 // 将弧度转换为角度
521 let angle_deg = angle_rad.to_degrees();
522
523 angle_deg
524 }
525}
526
527/// 旋转单个点。
528///
529/// # 参数
530///
531/// - `point`: 要旋转的点坐标。
532/// - `center`: 旋转中心点坐标。
533/// - `matrix`: 2x2 旋转矩阵。
534///
535/// # 返回值
536///
537/// 返回一个新的 `Point2D` 结构体,表示旋转后的点坐标。
538///
539/// # 示例
540///
541/// ```
542/// use rs_math::graphical::point_2d::Point2D;
543/// use rs_math::graphical::triangle::Triangle;
544///
545/// let point = Point2D { x: 1.0, y: 0.0 };
546/// let center = Point2D { x: 0.0, y: 0.0 };
547/// let matrix = [
548/// [0.0, -1.0],
549/// [1.0, 0.0],
550/// ];
551/// let rotated_point = Triangle::rotate_point(&point, ¢er, matrix);
552/// ```
553fn rotate_point( point: &Point2D, center: &Point2D, matrix: [[f64; 2]; 2]) -> Point2D {
554 let translated_x = point.x - center.x;
555 let translated_y = point.y - center.y;
556
557 let rotated_x = matrix[0][0] * translated_x + matrix[0][1] * translated_y;
558 let rotated_y = matrix[1][0] * translated_x + matrix[1][1] * translated_y;
559
560 Point2D {
561 x: rotated_x + center.x,
562 y: rotated_y + center.y,
563 }
564}