haar_lib/geom/
intersect_segments.rs

1//! 2つの線分の位置関係
2
3use crate::geom::{ccw::*, *};
4
5/// 2つの線分の位置関係
6#[derive(Clone, Copy, Debug, PartialEq)]
7#[allow(non_camel_case_types)]
8pub enum IntersectSegments {
9    /// 2つの線分が交差している
10    INTERSECTED,
11    /// 2つの線分が重なっている
12    OVERLAPPED,
13    /// 2つの線分が交差していない
14    NOT_INTERSECTED,
15    /// 2つの線分が同一である
16    SAME,
17}
18
19impl IntersectSegments {
20    /// `INTERSECTED`かを判定
21    pub fn intersected(self) -> bool {
22        self == Self::INTERSECTED
23    }
24    /// `OVERLAPPED`かを判定
25    pub fn overlapped(self) -> bool {
26        self == Self::OVERLAPPED
27    }
28    /// `NOT_INTERSECTED`かを判定
29    pub fn not_intersected(self) -> bool {
30        self == Self::NOT_INTERSECTED
31    }
32    /// `SAME`かを判定
33    pub fn same(self) -> bool {
34        self == Self::SAME
35    }
36}
37
38/// 2つの線分の位置関係と交点を求める
39pub fn intersect_segments(a: Line, b: Line, eps: Eps) -> (IntersectSegments, Option<Vector>) {
40    use self::IntersectSegments::*;
41
42    let cr = a.cross(b);
43
44    if eps.eq(cr.abs(), 0.0) {
45        return if ccw(a.from, a.to, b.from, eps).to_value()
46            * ccw(a.from, a.to, b.to, eps).to_value()
47            <= 0
48            && ccw(b.from, b.to, a.from, eps).to_value() * ccw(b.from, b.to, a.to, eps).to_value()
49                <= 0
50        {
51            (OVERLAPPED, None)
52        } else {
53            (NOT_INTERSECTED, None)
54        };
55    }
56
57    let t1 = (b.from - a.from).cross(b.diff()) / cr;
58    let t2 = (b.from - a.from).cross(a.diff()) / cr;
59
60    if eps.lt(t1, 0.0) || eps.gt(t1, 1.0) || eps.lt(t2, 0.0) || eps.gt(t2, 1.0) {
61        (NOT_INTERSECTED, None)
62    } else {
63        (INTERSECTED, Some(a.from + a.diff() * t1))
64    }
65}