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
use core::ops::{Div, Mul, Sub};
use num_traits::Signed;

use super::point_in_rect;

#[inline]
pub fn line_intersection<T>(
    out: &mut [T; 2],
    a1: &[T; 2],
    a2: &[T; 2],
    b1: &[T; 2],
    b2: &[T; 2],
) -> bool
where
    T: Clone + Signed + PartialEq + PartialOrd,
    for<'a, 'b> &'a T: Div<&'b T, Output = T> + Sub<&'b T, Output = T> + Mul<&'b T, Output = T>,
{
    let dax = &a1[0] - &a2[0];
    let dbx = &b1[0] - &b2[0];
    let day = &a1[1] - &a2[1];
    let dby = &b1[1] - &b2[1];

    let d = &(&dax * &dby) - &(&day * &dbx);
    if &d == &T::zero() {
        false
    } else {
        let ad = &(&a1[0] * &a2[1]) - &(&a1[1] * &a2[0]);
        let bd = &(&b1[0] * &b2[1]) - &(&b1[1] * &b2[0]);

        out[0] = &(&(&ad * &dbx) - &(&dax * &bd)) / &d;
        out[1] = &(&(&ad * &dby) - &(&day * &bd)) / &d;

        if point_in_rect(out, a1, a2) && point_in_rect(out, b1, b2) {
            true
        } else {
            false
        }
    }
}

#[test]
fn test_line_intersection() {
    let mut out = [0.0, 0.0];
    assert!(line_intersection(
        &mut out,
        &[0.0, 0.0],
        &[1.0, 1.0],
        &[1.0, 0.0],
        &[0.0, 1.0],
    ));
    assert_eq!(out, [0.5, 0.5]);

    assert!(!line_intersection(
        &mut [0.0, 0.0],
        &[1.0, 0.0],
        &[1.0, 1.0],
        &[-1.0, 0.0],
        &[-1.0, 1.0],
    ));
    assert!(!line_intersection(
        &mut [0.0, 0.0],
        &[0.0, 0.0],
        &[1.0, 1.0],
        &[2.0, 0.0],
        &[2.0, 1.0],
    ));
}