rs_math/graphical/circle.rs
1use std::f64::consts::PI;
2use crate::graphical::point_2d::Point2D;
3use crate::graphical::rectangle::Rectangle;
4
5/// 表示一个圆的结构体。
6#[derive(Debug, PartialEq)]
7pub struct Circle {
8 /// 圆的中心坐标
9 pub x: f64,
10 pub y: f64,
11 /// 圆的半径
12 pub radius: f64,
13}
14
15#[allow(dead_code)]
16impl Circle {
17 /// 通过两点和半径创建圆。
18 ///
19 /// # 参数
20 ///
21 /// * `point1` - 圆上的第一个点。
22 /// * `point2` - 圆上的第二个点。
23 /// * `radius` - 圆的半径。
24 ///
25 /// # 返回值
26 ///
27 /// 如果给定半径有效,返回一个包含圆心和半径的 `Circle` 结构体实例;否则返回 `None`。
28 ///
29 /// # 示例
30 ///
31 /// ```
32 /// use rs_math::graphical::point_2d::Point2D;
33 /// use rs_math::graphical::circle::Circle;
34 ///
35 /// let point1 = Point2D { x: 0.0, y: 0.0 };
36 /// let point2 = Point2D { x: 1.0, y: 0.0 };
37 /// let radius = 0.5;
38 /// let circle = Circle::from_points_and_radius(&point1, &point2, radius);
39 /// ```
40 pub fn from_points_and_radius(point1: &Point2D, point2: &Point2D, radius: f64) -> Option<Circle> {
41 // 计算圆心的中点坐标
42 let center_x = (point1.x + point2.x) / 2.0;
43 let center_y = (point1.y + point2.y) / 2.0;
44
45 // 计算两点间的距离
46 let distance = ((point2.x - point1.x).powi(2) + (point2.y - point1.y).powi(2)).sqrt();
47
48 // 验证半径是否有效
49 if (radius - distance / 2.0).abs() < std::f64::EPSILON {
50 Some(Circle {
51 x: center_x,
52 y: center_y,
53 radius,
54 })
55 } else {
56 None
57 }
58 }
59 /// 通过三个点创建圆。
60 ///
61 /// # 参数
62 ///
63 /// * `p1` - 圆上的第一个点。
64 /// * `p2` - 圆上的第二个点。
65 /// * `p3` - 圆上的第三个点。
66 ///
67 /// # 返回值
68 ///
69 /// 如果给定三个点共线,返回 `None`;否则返回一个包含圆心和半径的 `Circle` 结构体实例。
70 ///
71 /// # 示例
72 ///
73 /// ```
74 /// use rs_math::graphical::point_2d::Point2D;
75 /// use rs_math::graphical::circle::Circle;
76 ///
77 /// let p1 = Point2D { x: 0.0, y: 0.0 };
78 /// let p2 = Point2D { x: 1.0, y: 0.0 };
79 /// let p3 = Point2D { x: 0.0, y: 1.0 };
80 /// let circle = Circle::from_points(&p1, &p2, &p3);
81 /// ```
82 pub fn from_points(p1: &Point2D, p2: &Point2D, p3: &Point2D) -> Option<Circle> {
83 // 计算圆心坐标 (h, k)
84 let h = (p1.x + p2.x) / 2.0;
85 let k = (p1.y + p2.y) / 2.0;
86
87 // 计算半径 r
88 let r = ((p1.x - h).powi(2) + (p1.y - k).powi(2)).sqrt();
89
90 // 检查第三个点是否在圆上
91 let distance_to_center_squared = (p3.x - h).powi(2) + (p3.y - k).powi(2);
92 let epsilon = 1e-6; // 设置一个小的误差范围
93
94 // 如果给定三个点共线,返回 None;否则返回包含圆心和半径的 Circle 结构体实例。
95 if (distance_to_center_squared - r.powi(2)).abs() < epsilon {
96 Some(Circle { x: h, y: k, radius: r })
97 } else {
98 None
99 }
100 }
101 /// 创建一个新的圆实例。
102 ///
103 /// # 参数
104 ///
105 /// * `x` - 圆的中心横坐标。
106 /// * `y` - 圆的中心纵坐标。
107 /// * `radius` - 圆的半径。
108 ///
109 /// # 返回值
110 ///
111 /// 返回一个包含给定圆心和半径的 `Circle` 结构体实例。
112 ///
113 /// # 示例
114 ///
115 /// ```
116 /// use rs_math::graphical::circle::Circle;
117 ///
118 /// let circle = Circle::new(0.0, 0.0, 1.0);
119 /// ```
120 pub fn new(x: f64, y: f64, radius: f64) -> Circle {
121 Circle { x, y, radius }
122 }
123
124 /// 计算圆的面积。
125 ///
126 /// # 返回值
127 ///
128 /// 返回圆的面积,使用标准的 π(pi) 值。
129 ///
130 /// # 示例
131 ///
132 /// ```
133 /// use rs_math::graphical::circle::Circle;
134 ///
135 /// let circle = Circle::new(0.0, 0.0, 1.0);
136 /// let area = circle.area();
137 /// ```
138 pub fn area(&self) -> f64 {
139 std::f64::consts::PI * self.radius * self.radius
140 }
141
142 /// 判断给定点是否在圆内。
143 ///
144 /// # 参数
145 ///
146 /// * `point_x` - 待判断点的横坐标。
147 /// * `point_y` - 待判断点的纵坐标。
148 ///
149 /// # 返回值
150 ///
151 /// 如果给定点在圆内或在圆上,返回 `true`;否则返回 `false`。
152 ///
153 /// # 示例
154 ///
155 /// ```
156 /// use rs_math::graphical::circle::Circle;
157 ///
158 /// let circle = Circle::new(0.0, 0.0, 1.0);
159 /// let is_inside = circle.is_point_inside(0.5, 0.5);
160 /// ```
161 pub fn is_point_inside(&self, point_x: f64, point_y: f64) -> bool {
162 let distance_squared = (point_x - self.x).powi(2) + (point_y - self.y).powi(2);
163 distance_squared <= self.radius.powi(2)
164 }
165 /// 生成圆上的点。
166 ///
167 /// # 参数
168 ///
169 /// * `num_points` - 要生成的点的数量。
170 ///
171 /// # 返回值
172 ///
173 /// 返回一个包含圆上生成点的 `Vec<Point2D>`。
174 ///
175 /// # 示例
176 ///
177 /// ```
178 /// use rs_math::graphical::circle::Circle;
179 /// use rs_math::graphical::point_2d::Point2D;
180 ///
181 /// let circle = Circle::new(0.0, 0.0, 1.0);
182 /// let points = circle.generate_points(10);
183 /// ```
184 pub fn generate_points(&self, num_points: usize) -> Vec<Point2D> {
185 generate_points_on_circle(self.x, self.y, self.radius, num_points)
186 }
187 /// 判断点是否在圆弧上。
188 ///
189 /// # 参数
190 ///
191 /// * `start_angle` - 圆弧的起始角度。
192 /// * `end_angle` - 圆弧的结束角度。
193 /// * `point` - 待判断的点。
194 ///
195 /// # 返回值
196 ///
197 /// 如果给定点在圆弧上,返回 `true`;否则返回 `false`。
198 ///
199 /// # 示例
200 ///
201 /// ```
202 /// use rs_math::graphical::circle::Circle;
203 /// use rs_math::graphical::point_2d::Point2D;
204 ///
205 /// let circle = Circle::new(0.0, 0.0, 1.0);
206 /// let start_angle = 0.0;
207 /// let end_angle = std::f64::consts::PI;
208 /// let point = Point2D { x: 1.0, y: 0.0 };
209 /// let is_on_arc = circle.is_point_on_arc(start_angle, end_angle, &point);
210 /// ```
211 pub fn is_point_on_arc(&self, start_angle: f64, end_angle: f64, point: &Point2D) -> bool {
212 let distance_squared = (point.x - self.x).powi(2) + (point.y - self.y).powi(2);
213 let distance = distance_squared.sqrt();
214
215 distance == self.radius && self.is_angle_in_range(start_angle, end_angle, point)
216 }
217
218 /// 判断夹角是否在指定范围内的辅助函数。
219 ///
220 /// # 参数
221 ///
222 /// * `start_angle` - 范围的起始角度。
223 /// * `end_angle` - 范围的结束角度。
224 /// * `point` - 待判断的点。
225 ///
226 /// # 返回值
227 ///
228 /// 如果给定点的夹角在指定范围内,返回 `true`;否则返回 `false`。
229 ///
230 /// # 示例
231 ///
232 /// ```
233 /// use rs_math::graphical::circle::Circle;
234 /// use rs_math::graphical::point_2d::Point2D;
235 ///
236 /// let circle = Circle::new(0.0, 0.0, 1.0);
237 /// let start_angle = 0.0;
238 /// let end_angle = std::f64::consts::PI;
239 /// let point = Point2D { x: 1.0, y: 0.0 };
240 /// let is_in_range = circle.is_angle_in_range(start_angle, end_angle, &point);
241 /// ```
242 pub fn is_angle_in_range(&self, start_angle: f64, end_angle: f64, point: &Point2D) -> bool {
243 let angle = (point.y - self.x).atan2(point.x - self.y);
244 let positive_angle = if angle < 0.0 {
245 2.0 * std::f64::consts::PI + angle
246 } else {
247 angle
248 };
249 positive_angle >= start_angle && positive_angle <= end_angle
250 }
251
252 /// 判断点是否在圆边界上。
253 ///
254 /// # 参数
255 ///
256 /// * `point` - 待判断的点。
257 ///
258 /// # 返回值
259 ///
260 /// 如果给定点在圆边界上,返回 `true`;否则返回 `false`。
261 ///
262 /// # 示例
263 ///
264 /// ```
265 /// use rs_math::graphical::circle::Circle;
266 /// use rs_math::graphical::point_2d::Point2D;
267 ///
268 /// let circle = Circle::new(0.0, 0.0, 1.0);
269 /// let point = Point2D { x: 1.0, y: 0.0 };
270 /// let is_on_boundary = circle.is_point_on_circle_boundary(&point);
271 /// ```
272 pub fn is_point_on_circle_boundary(&self, point: &Point2D) -> bool {
273 let distance = distance_between_points(point.x, point.y, self.x, self.y);
274 distance == self.radius
275 }
276
277 /// 寻找与直线的交点。
278 ///
279 /// # 参数
280 ///
281 /// * `p1` - 直线上的第一个点。
282 /// * `p2` - 直线上的第二个点。
283 ///
284 /// # 返回值
285 ///
286 /// 返回一个包含交点的 `Vec<Point2D>`。
287 ///
288 /// # 示例
289 ///
290 /// ```
291 /// use rs_math::graphical::circle::Circle;
292 /// use rs_math::graphical::point_2d::Point2D;
293 ///
294 /// let circle = Circle::new(0.0, 0.0, 1.0);
295 /// let point1 = Point2D { x: -2.0, y: 0.0 };
296 /// let point2 = Point2D { x: 2.0, y: 0.0 };
297 /// let intersections = circle.find_line_intersection(&point1, &point2);
298 /// ```
299 pub fn find_line_intersection(&self, p1: &Point2D, p2: &Point2D) -> Vec<Point2D> {
300 let dx = p2.x - p1.x;
301 let dy = p2.y - p1.y;
302
303 let a = dx * dx + dy * dy;
304 let b = 2.0 * (dx * (p1.x - self.x) + dy * (p1.y - self.y));
305 let c = (p1.x - self.x) * (p1.x - self.x) + (p1.y - self.y) * (p1.y - self.y) - self.radius * self.radius;
306
307 let discriminant = b * b - 4.0 * a * c;
308
309 if discriminant < 0.0 {
310 // 无实数解(无交点)
311 return Vec::new();
312 }
313
314 let t1 = (-b + discriminant.sqrt()) / (2.0 * a);
315 let t2 = (-b - discriminant.sqrt()) / (2.0 * a);
316
317 let mut intersections = Vec::new();
318
319 if t1 >= 0.0 && t1 <= 1.0 {
320 intersections.push(Point2D {
321 x: p1.x + t1 * dx,
322 y: p1.y + t1 * dy,
323 });
324 }
325
326 if t2 >= 0.0 && t2 <= 1.0 {
327 intersections.push(Point2D {
328 x: p1.x + t2 * dx,
329 y: p1.y + t2 * dy,
330 });
331 }
332
333 intersections
334 }
335 /// 判断两个圆是否相交。
336 ///
337 /// # 参数
338 ///
339 /// * `other` - 另一个圆的实例。
340 ///
341 /// # 返回值
342 ///
343 /// 如果两个圆相交,返回 `true`;否则返回 `false`。
344 ///
345 /// # 示例
346 ///
347 /// ```
348 /// use rs_math::graphical::circle::Circle;
349 ///
350 /// let circle1 = Circle::new(0.0, 0.0, 1.0);
351 /// let circle2 = Circle::new(2.0, 0.0, 1.0);
352 /// let do_intersect = circle1.circles_intersect(&circle2);
353 /// ```
354 pub fn circles_intersect(&self, other: &Circle) -> bool {
355 let distance_between_centers = ((self.x - other.x).powi(2) + (self.y - other.y).powi(2)).sqrt();
356 let sum_of_radii = self.radius + other.radius;
357
358 distance_between_centers < sum_of_radii
359 }
360
361 /// 判断两个圆是否相切。
362 ///
363 /// # 参数
364 ///
365 /// * `other` - 另一个圆的实例。
366 ///
367 /// # 返回值
368 ///
369 /// 如果两个圆相切,返回 `true`;否则返回 `false`。
370 ///
371 /// # 示例
372 ///
373 /// ```
374 /// use rs_math::graphical::circle::Circle;
375 ///
376 /// let circle1 = Circle::new(0.0, 0.0, 1.0);
377 /// let circle2 = Circle::new(2.0, 0.0, 1.0);
378 /// let do_touch = circle1.circles_touch(&circle2);
379 /// ```
380 pub fn circles_touch(&self, other: &Circle) -> bool {
381 let distance_between_centers = ((self.x - other.x).powi(2) + (self.y - other.y).powi(2)).sqrt();
382 let sum_of_radii = self.radius + other.radius;
383
384 (distance_between_centers - sum_of_radii).abs() < f64::EPSILON
385 }
386
387 /// 判断一个圆是否完全包含另一个圆。
388 ///
389 /// # 参数
390 ///
391 /// * `other` - 另一个圆的实例。
392 ///
393 /// # 返回值
394 ///
395 /// 如果一个圆完全包含另一个圆,返回 `true`;否则返回 `false`。
396 ///
397 /// # 示例
398 ///
399 /// ```
400 /// use rs_math::graphical::circle::Circle;
401 ///
402 /// let large_circle = Circle::new(0.0, 0.0, 2.0);
403 /// let small_circle = Circle::new(0.0, 0.0, 1.0);
404 /// let does_contain = large_circle.circle_contains(&small_circle);
405 /// ```
406 pub fn circle_contains(&self, other: &Circle) -> bool {
407 let distance_between_centers = ((self.x - other.x).powi(2) + (self.y - other.y).powi(2)).sqrt();
408 distance_between_centers + other.radius <= self.radius
409 }
410
411 /// 判断圆心是否在矩形内。
412 ///
413 /// 公式:`circle_x >= rect.x1 && circle_x <= rect.x2 && circle_y >= rect.y1 && circle_y <= rect.y2`
414 ///
415 /// 圆心的 x 坐标在矩形的 x 范围内,且圆心的 y 坐标在矩形的 y 范围内。
416 ///
417 /// # 参数
418 ///
419 /// * `rect` - 包含矩形的实例。
420 ///
421 /// # 返回值
422 ///
423 /// 如果圆心在矩形内,返回 `true`;否则返回 `false`。
424 ///
425 /// # 示例
426 ///
427 /// ```
428 /// use rs_math::graphical::circle::Circle;
429 /// use rs_math::graphical::rectangle::Rectangle;
430 ///
431 /// let circle = Circle::new(1.0, 1.0, 2.0);
432 /// let rectangle = Rectangle::new(0.0, 0.0, 3.0, 3.0);
433 /// let is_inside = circle.circle_inside_rectangle(&rectangle);
434 /// ```
435 pub fn circle_inside_rectangle(&self, rect: &Rectangle) -> bool {
436 self.x >= rect.x1 && self.x <= rect.x2 && self.y >= rect.y1 && self.y <= rect.y2
437 }
438
439 /// 判断圆心是否在矩形的某个边上。
440 ///
441 /// 公式:
442 /// - `(circle_x == rect.x1 || circle_x == rect.x2) && circle_y >= rect.y1 && circle_y <= rect.y2`
443 /// 或
444 /// - `circle_x >= rect.x1 && circle_x <= rect.x2 && (circle_y == rect.y1 || circle_y == rect.y2)`
445 ///
446 /// 圆心在矩形的 x 或 y 范围的一个边界上,但不在矩形内部。
447 ///
448 /// # 参数
449 ///
450 /// * `rect` - 包含矩形的实例。
451 ///
452 /// # 返回值
453 ///
454 /// 如果圆心在矩形的边上,返回 `true`;否则返回 `false`。
455 ///
456 /// # 示例
457 ///
458 /// ```
459 /// use rs_math::graphical::circle::Circle;
460 /// use rs_math::graphical::rectangle::Rectangle;
461 ///
462 /// let circle = Circle::new(2.0, 2.0, 1.0);
463 /// let rectangle = Rectangle::new(1.0, 1.0, 3.0, 3.0);
464 /// let on_edge = circle.circle_on_rectangle_edge(&rectangle);
465 /// ```
466 pub fn circle_on_rectangle_edge(&self, rect: &Rectangle) -> bool {
467 (self.x == rect.x1 || self.x == rect.x2) && self.y >= rect.y1 && self.y <= rect.y2 || self.x >= rect.x1 && self.x <= rect.x2 && (self.y == rect.y1 || self.y == rect.y2)
468 }
469
470 /// 判断圆心是否在矩形的角上。
471 ///
472 /// 公式:
473 /// - `(circle_x == rect.x1 && circle_y == rect.y1)`
474 /// 或
475 /// - `(circle_x == rect.x1 && circle_y == rect.y2)`
476 /// 或
477 /// - `(circle_x == rect.x2 && circle_y == rect.y1)`
478 /// 或
479 /// - `(circle_x == rect.x2 && circle_y == rect.y2)`
480 ///
481 /// 圆心在矩形的 x 或 y 范围的一个边界上,并且与另一个边界相交。
482 ///
483 /// # 参数
484 ///
485 /// * `rect` - 包含矩形的实例。
486 ///
487 /// # 返回值
488 ///
489 /// 如果圆心在矩形的角上,返回 `true`;否则返回 `false`。
490 ///
491 /// # 示例
492 ///
493 /// ```
494 /// use rs_math::graphical::circle::Circle;
495 /// use rs_math::graphical::rectangle::Rectangle;
496 ///
497 /// let circle = Circle::new(1.0, 1.0, 0.5);
498 /// let rectangle = Rectangle::new(0.0, 0.0, 2.0, 2.0);
499 /// let on_corner = circle.circle_on_rectangle_corner(&rectangle);
500 /// ```
501 pub fn circle_on_rectangle_corner(&self, rect: &Rectangle) -> bool {
502 (self.x == rect.x1 && self.y == rect.y1) || (self.x == rect.x1 && self.y == rect.y2) || (self.x == rect.x2 && self.y == rect.y1) || (self.x == rect.x2 && self.y == rect.y2)
503 }
504
505 /// 获取圆的外接矩形。
506 ///
507 /// 外接矩形的左上角坐标为 `(circle_x - radius, circle_y - radius)`,
508 /// 右下角坐标为 `(circle_x + radius, circle_y + radius)`。
509 ///
510 /// # 返回值
511 ///
512 /// 返回一个包含外接矩形坐标的 `Rectangle` 结构体实例。
513 ///
514 /// # 示例
515 ///
516 /// ```
517 /// use rs_math::graphical::circle::Circle;
518 /// use rs_math::graphical::rectangle::Rectangle;
519 ///
520 /// let circle = Circle::new(3.0, 4.0, 2.0);
521 /// let bounding_box = circle.bounding_box();
522 /// ```
523
524 pub fn bounding_box(&self) -> Rectangle {
525 Rectangle {
526 x1: self.x - self.radius,
527 y1: self.y - self.radius,
528 x2: self.x + self.radius,
529 y2: self.y + self.radius,
530 }
531 }
532}
533/// 计算两点之间的欧几里德距离。
534///
535/// 公式:sqrt((x2 - x1)^2 + (y2 - y1)^2)
536///
537/// # 参数
538///
539/// * `x1` - 第一个点的 x 坐标。
540/// * `y1` - 第一个点的 y 坐标。
541/// * `x2` - 第二个点的 x 坐标。
542/// * `y2` - 第二个点的 y 坐标。
543///
544/// # 返回值
545///
546/// 返回两点之间的欧几里德距离。
547///
548/// # 示例
549///
550/// ```
551/// use rs_math::graphical::circle::distance_between_points;
552///
553/// let distance = distance_between_points(1.0, 2.0, 4.0, 6.0);
554/// ```
555pub fn distance_between_points(x1: f64, y1: f64, x2: f64, y2: f64) -> f64 {
556 ((x2 - x1).powi(2) + (y2 - y1).powi(2)).sqrt()
557}
558
559/// 生成圆上的均匀分布的点集合。
560///
561/// # 参数
562///
563/// * `center_x` - 圆心的 x 坐标。
564/// * `center_y` - 圆心的 y 坐标。
565/// * `radius` - 圆的半径。
566/// * `num_points` - 生成的点的数量。
567///
568/// # 返回值
569///
570/// 返回一个包含生成的点坐标的 `Vec<Point2D>` 实例。
571///
572/// # 示例
573///
574/// ```
575/// use rs_math::graphical::circle::generate_points_on_circle;
576///
577/// let points = generate_points_on_circle(0.0, 0.0, 1.0, 8);
578/// ```
579
580pub fn generate_points_on_circle(center_x: f64, center_y: f64, radius: f64, num_points: usize) -> Vec<Point2D> {
581 // 存储生成的点的容器
582 let mut points = Vec::with_capacity(num_points);
583
584 // 计算角度步长,确保点在圆上均匀分布
585 let angle_step = 2.0 * PI / num_points as f64;
586
587 // 生成点的坐标
588 for i in 0..num_points {
589 let angle = i as f64 * angle_step;
590 let x = center_x + radius * angle.cos();
591 let y = center_y + radius * angle.sin();
592 points.push(Point2D { x, y });
593 }
594
595 points
596}