use crate::span::Span;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Rule {
Clearance,
Separation,
Contact,
Crossing,
Impossible,
}
impl Rule {
pub fn id(self) -> &'static str {
match self {
Rule::Clearance => "clearance",
Rule::Separation => "separation",
Rule::Contact => "contact",
Rule::Crossing => "crossing",
Rule::Impossible => "impossible",
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Severity {
Warning,
Info,
}
#[derive(Clone, Debug)]
pub struct Violation {
pub rule: Rule,
pub severity: Severity,
pub links: Vec<String>,
pub detail: String,
pub span: Span,
}
pub(crate) fn cross(a: &[(f64, f64)], b: &[(f64, f64)]) -> Option<(f64, f64)> {
let (h, v) = if a[0].1 == a[1].1 && b[0].0 == b[1].0 {
(a, b)
} else if a[0].0 == a[1].0 && b[0].1 == b[1].1 {
(b, a)
} else {
return None;
};
let (x, y) = (v[0].0, h[0].1);
let (hx0, hx1) = (h[0].0.min(h[1].0), h[0].0.max(h[1].0));
let (vy0, vy1) = (v[0].1.min(v[1].1), v[0].1.max(v[1].1));
(hx0 < x && x < hx1 && vy0 < y && y < vy1).then_some((x, y))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn transversal_pairs_cross_at_the_meet() {
let h = [(0.0, 5.0), (10.0, 5.0)];
let v = [(4.0, 0.0), (4.0, 10.0)];
assert_eq!(cross(&h, &v), Some((4.0, 5.0)));
assert_eq!(cross(&v, &h), Some((4.0, 5.0)));
}
#[test]
fn touches_and_parallels_are_not_crossings() {
let h = [(0.0, 5.0), (10.0, 5.0)];
assert_eq!(cross(&h, &[(10.0, 0.0), (10.0, 10.0)]), None);
assert_eq!(cross(&h, &[(4.0, 5.0), (4.0, 10.0)]), None);
assert_eq!(cross(&h, &[(0.0, 7.0), (10.0, 7.0)]), None);
assert_eq!(cross(&h, &[(5.0, 5.0), (20.0, 5.0)]), None);
}
}