1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use crate::{Real, Vector2};
/// Holds the result of finding the intersect between a line segment and a circle.
#[derive(Debug, Copy, Clone)]
pub enum CircleCircleIntr<T>
where
T: Real,
{
/// No intersects found.
NoIntersect,
/// One tangent intersect point found.
TangentIntersect {
/// Holds the tangent intersect point.
point: Vector2<T>,
},
/// Simple case of two intersect points found.
TwoIntersects {
/// Holds the first intersect point.
point1: Vector2<T>,
/// Holds the second intersect point.
point2: Vector2<T>,
},
/// Circles overlap each other (same circle).
Overlapping,
}
/// Finds the intersects between two circles.
pub fn circle_circle_intr<T>(
radius1: T,
center1: Vector2<T>,
radius2: T,
center2: Vector2<T>,
) -> CircleCircleIntr<T>
where
T: Real,
{
// Reference algorithm: http://paulbourke.net/geometry/circlesphere/
use CircleCircleIntr::*;
let cv = center2 - center1;
let d2 = cv.dot(cv);
let d = d2.sqrt();
if d.fuzzy_eq_zero() {
// same center position
if radius1.fuzzy_eq(radius2) {
return Overlapping;
}
return NoIntersect;
}
// different center position
if !d.fuzzy_lt(radius1 + radius2) || !d.fuzzy_gt((radius1 - radius2).abs()) {
// distance relative to radii is too large or too small for intersects to occur
return NoIntersect;
}
let rad1_sq = radius1 * radius1;
let a = (rad1_sq - radius2 * radius2 + d2) / (T::two() * d);
let midpoint = center1 + cv.scale(a / d);
let diff = rad1_sq - a * a;
if diff < T::zero() {
return TangentIntersect { point: midpoint };
}
let h = diff.sqrt();
let h_over_d = h / d;
let x_term = h_over_d * cv.y;
let y_term = h_over_d * cv.x;
let pt1 = Vector2::new(midpoint.x + x_term, midpoint.y - y_term);
let pt2 = Vector2::new(midpoint.x - x_term, midpoint.y + y_term);
if pt1.fuzzy_eq(pt2) {
return TangentIntersect { point: pt1 };
}
TwoIntersects {
point1: pt1,
point2: pt2,
}
}