use std::cmp::PartialOrd;
use std::ops::{BitAnd, BitOr, Sub};
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct Segment {
pub start: f64,
pub end: f64,
}
impl Segment {
pub fn new(start: f64, end: f64) -> Self {
if start > end {
Segment {
start: end,
end: start,
}
} else {
Segment { start, end }
}
}
pub fn start(&self) -> f64 {
self.start
}
pub fn end(&self) -> f64 {
self.end
}
pub fn contains(&self, other: &Self) -> bool {
self.start <= other.start && other.end <= self.end
}
pub fn is_empty(&self) -> bool {
self.start == self.end
}
}
impl BitAnd for Segment {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
let start = self.start.max(rhs.start);
let end = self.end.min(rhs.end);
if start >= end {
Segment::new(start, start) } else {
Segment::new(start, end)
}
}
}
impl BitOr for Segment {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
let start = self.start.min(rhs.start);
let end = self.end.max(rhs.end);
Segment::new(start, end)
}
}
impl Sub for Segment {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
if self.end <= rhs.start || rhs.end <= self.start {
return self;
}
if rhs.start <= self.start && self.end <= rhs.end {
return Segment::new(self.start, self.start); }
if self.start < rhs.start && rhs.start < self.end {
return Segment::new(self.start, rhs.start);
}
if rhs.start < self.start && self.start < rhs.end && rhs.end < self.end {
return Segment::new(rhs.end, self.end);
}
Segment::new(self.start, self.start) }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_segment() {
assert_eq!(
Segment::new(0.0, 10.0),
Segment {
start: 0.0,
end: 10.0
}
);
assert_eq!(
Segment::new(10.0, 0.0),
Segment {
start: 0.0,
end: 10.0
}
);
assert_eq!(
Segment::new(5.0, 5.0),
Segment {
start: 5.0,
end: 5.0
}
);
}
#[test]
fn test_start_end_properties() {
let s = Segment::new(1.0, 5.0);
assert_eq!(s.start(), 1.0);
assert_eq!(s.end(), 5.0);
}
#[test]
fn test_contains() {
assert!(Segment::new(0.0, 10.0).contains(&Segment::new(1.0, 2.0)));
assert!(!Segment::new(0.0, 10.0).contains(&Segment::new(1.0, 11.0)));
assert!(!Segment::new(0.0, 10.0).contains(&Segment::new(-1.0, 2.0)));
assert!(Segment::new(0.0, 10.0).contains(&Segment::new(0.0, 10.0))); assert!(Segment::new(0.0, 0.0).contains(&Segment::new(0.0, 0.0))); }
#[test]
fn test_is_empty() {
assert!(!Segment::new(0.0, 1.0).is_empty());
assert!(Segment::new(0.0, 0.0).is_empty());
assert!(Segment::new(5.0, 5.0).is_empty());
}
#[test]
fn test_debug_repr() {
let s = Segment::new(1.0, 5.0);
assert_eq!(format!("{:?}", s), "Segment { start: 1.0, end: 5.0 }");
}
#[test]
fn test_bitand_intersection() {
let s1 = Segment::new(0.0, 10.0);
let s2 = Segment::new(5.0, 15.0);
assert_eq!(s1 & s2, Segment::new(5.0, 10.0));
}
#[test]
fn test_bitor_union() {
let s1 = Segment::new(0.0, 10.0);
let s2 = Segment::new(5.0, 15.0);
assert_eq!(s1 | s2, Segment::new(0.0, 15.0));
let s3 = Segment::new(0.0, 5.0);
let s4 = Segment::new(10.0, 15.0);
assert_eq!(s3 | s4, Segment::new(0.0, 15.0));
}
#[test]
fn test_sub_difference() {
assert_eq!(
Segment::new(0.0, 10.0) - Segment::new(5.0, 15.0),
Segment::new(0.0, 5.0)
);
assert_eq!(
Segment::new(5.0, 15.0) - Segment::new(0.0, 10.0),
Segment::new(10.0, 15.0)
);
assert_eq!(
Segment::new(0.0, 10.0) - Segment::new(2.0, 8.0),
Segment::new(0.0, 2.0)
);
assert_eq!(
Segment::new(0.0, 5.0) - Segment::new(10.0, 15.0),
Segment::new(0.0, 5.0)
);
assert_eq!(
Segment::new(10.0, 15.0) - Segment::new(0.0, 5.0),
Segment::new(10.0, 15.0)
);
assert_eq!(
Segment::new(2.0, 8.0) - Segment::new(0.0, 10.0),
Segment::new(2.0, 2.0)
);
assert_eq!(
Segment::new(0.0, 10.0) - Segment::new(2.0, 8.0),
Segment::new(0.0, 2.0)
);
}
#[test]
fn test_partial_ord_less_than() {
assert!(Segment::new(0.0, 10.0) < Segment::new(5.0, 15.0));
assert!(Segment::new(0.0, 10.0) < Segment::new(5.0, 10.0));
assert!(Segment::new(0.0, 10.0) < Segment::new(5.0, 8.0));
assert!(Segment::new(5.0, 10.0) < Segment::new(5.0, 15.0));
assert!(Segment::new(6.0, 10.0) > Segment::new(5.0, 15.0));
assert!(Segment::new(0.0, 10.0) < Segment::new(0.0, 15.0)); assert!(Segment::new(0.0, 10.0) == Segment::new(0.0, 10.0)); }
}