haar_lib/geom/
intersect_circle_segment.rs

1//! 円と線分の位置関係
2
3use crate::geom::{dist_segment_point::*, *};
4
5/// 円と線分の位置関係
6#[derive(Clone, Copy, Debug, PartialEq)]
7#[allow(non_camel_case_types)]
8pub enum IntersectCircleSegment {
9    /// 線分が円の内部にある
10    INSIDE,
11    /// 線分が円の外部にある
12    OUTSIDE,
13    /// 線分が円に接している
14    TANGENT,
15    /// 線分が円と一つの交点をもつ
16    ONE_CROSSPOINT,
17    /// 線分が円と二つの交点をもつ
18    TWO_CROSSPOINTS,
19}
20
21impl IntersectCircleSegment {
22    /// `INSIDE`かを判定
23    pub fn inside(self) -> bool {
24        self == Self::INSIDE
25    }
26    /// `OUTSIDE`かを判定
27    pub fn outside(self) -> bool {
28        self == Self::OUTSIDE
29    }
30    /// `TANGENT`かを判定
31    pub fn tangent(self) -> bool {
32        self == Self::TANGENT
33    }
34    /// `ONE_CROSSPOINT`かを判定
35    pub fn one_crosspoint(self) -> bool {
36        self == Self::ONE_CROSSPOINT
37    }
38    /// `TWO_CROSSPOINT`かを判定
39    pub fn two_crosspoints(self) -> bool {
40        self == Self::TWO_CROSSPOINTS
41    }
42}
43
44/// 円と線分の位置関係と交点を求める
45pub fn intersect_circle_segment(
46    c: Circle,
47    s: Line,
48    eps: Eps,
49) -> (IntersectCircleSegment, Vec<Vector>) {
50    use self::IntersectCircleSegment::*;
51
52    let Circle {
53        center: c,
54        radius: r,
55    } = c;
56    let d1 = (c - s.from).abs();
57    let d2 = (c - s.to).abs();
58    let v = dist_segment_point(s, c);
59    let m = (r * r - v * v).sqrt();
60    let n = s.normal();
61    let k = s.from + s.diff() * n.cross(c + n - s.from) / n.cross(s.diff());
62
63    if eps.lt(d1, r) && eps.lt(d2, r) {
64        (INSIDE, vec![])
65    } else if eps.eq(v, r) {
66        (TANGENT, vec![k])
67    } else if eps.gt(v, r) {
68        (OUTSIDE, vec![])
69    } else if eps.ge(d1, r) && eps.ge(d2, r) {
70        (TWO_CROSSPOINTS, vec![k - s.unit() * m, k + s.unit() * m])
71    } else {
72        let b = s.unit().dot(s.from - c);
73        let a = (s.from - c).abs_sq() - r * r;
74        let x = (b * b - a).sqrt();
75
76        (
77            ONE_CROSSPOINT,
78            vec![s.from + s.unit() * (if eps.ge(-b, x) { -b - x } else { -b + x })],
79        )
80    }
81}