prima/geom/
line1.rs

1use crate::{core::Axis, geom::Vec2};
2
3use super::{Float, Line2, Intersect};
4
5/// A one dimensional line. Useful for analysing only a single axis
6#[derive(Clone, Copy, Default, Debug, PartialEq)]
7pub struct Line1 {
8    a: Float,
9    b: Float,
10}
11
12impl Line1 {
13    /// Generates a new Line1.
14    pub fn new(a: Float, b: Float) -> Self {
15        Self { a, b }
16    }
17
18    /// Ensures that the line goes from lowest point to highest.
19    pub fn validate(&mut self) {
20        if self.a > self.b {
21            std::mem::swap(&mut self.a, &mut self.b);
22        }
23    }
24
25    /// Returns false is b is less than or equal to a.
26    pub fn is_valid(&self) -> bool {
27        self.a < self.b
28    }
29
30    /// Returns true if point lies on the line. It cannot be equal to an end point.
31    pub fn contains_point(&self, point: Float) -> bool {
32        point > self.a && point < self.b
33    }   
34
35    /// Returns true if other line is contained. It cannot be equal to an end point.
36    pub fn contains(&self, other: &Self) -> bool {
37        self.contains_point(other.a) && self.contains_point(other.b)
38    }
39
40    /// Converts this into a line2, using n as the second (flat) axis.
41    pub fn into_line2(self, axis: Axis, n: Float) -> Line2 {
42        match axis {
43            Axis::Vertical => Line2::new(Vec2::new(n, self.a), Vec2::new(n, self.b)),
44            Axis::Horizontal => Line2::new(Vec2::new(self.a, n), Vec2::new(self.b, n)),
45            _ => panic!("Cannot convert using this kind of axis: {:?}", axis),
46        }
47    }
48
49    /// Gets a line1 from a line2, essentially disgarding a single axis.
50    pub fn from_line2(other: Line2, axis: Axis) -> Self {
51        match axis {
52            Axis::Vertical => Self {a: other.a.y, b: other.b.y},
53            Axis::Horizontal => Self {a: other.a.x, b: other.b.x},
54            _ => panic!("Cannot convert using this kind of axis: {:?}", axis),
55        }
56    }
57
58    /// Subtracts the other line from this one, leaving one or two new lines.
59    pub fn subtract(mut self, other: Self) -> Vec<Self> {
60        self.validate();
61        if !self.intersects(&other) {
62            return vec![self];
63        }
64        if self.contains(&other) {
65            return vec![Line1::new(self.a, other.a), Line1::new(other.b, self.b)];
66        }
67        if self.contains_point(other.a) {
68            return vec![Line1::new(self.a, other.a)];
69        }
70        if self.contains_point(other.b) {
71            return vec![Line1::new(other.b, self.b)];
72        }
73        return vec![self];
74    }
75
76    /// Takes a collection of lines and geometrically subtracts the given line from them.
77    pub fn subtract_collection(old: Vec<Self>, other: Self) -> Vec<Self> {
78        let mut new = Vec::new();
79        for line in old {
80            new.extend(line.subtract(other.clone()));
81        }
82        return new;
83    }
84}
85
86impl Intersect<Self, Self> for Line1 {
87    fn intersection(&self, other: &Self) -> Option<Self> {
88        if !self.intersects(other) {
89            return None;
90        }
91
92        let min = if self.a > other.a { self.a } else { other.a };
93        let max = if self.b < other.b { self.b } else { other.b };
94        Some(Self::new(min, max))
95    }
96
97    fn intersects(&self, other: &Self) -> bool {
98        if self.a > other.b {
99            return false;
100        }
101        if other.a > self.b {
102            return false;
103        }
104        true
105    }
106}