use crate::bound_type::{Left, Right};
use crate::traits::{BoundaryOf, Flip, IntoGeneral};
use crate::{Bound, Exclusive, Inclusive, LeftBounded, RightBounded};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct IntervalUnion<T, L: Flip, R: Flip> {
pub span: Interval<T, L, R>,
pub gap: Option<Interval<T, R::Flip, L::Flip>>,
}
impl<T, L: Flip, R: Flip> IntervalUnion<T, L, R> {
pub fn into_vec(self) -> Vec<Interval<T, L, R>> {
self.into_iter().collect()
}
}
impl<T, L: Flip, R: Flip> IntoIterator for IntervalUnion<T, L, R> {
type Item = Interval<T, L, R>;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
if let Some(gap) = self.gap {
let first = Interval {
left: self.span.left,
right: gap.left.flip(),
};
let second = Interval {
left: gap.right.flip(),
right: self.span.right,
};
vec![first, second].into_iter()
} else {
vec![self.span].into_iter()
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct IntervalDifference<T, L: Flip, R: Flip> {
pub lower: Option<Interval<T, L, L::Flip>>,
pub upper: Option<Interval<T, R::Flip, R>>,
}
impl<T, L: Flip<Flip = R>, R: Flip<Flip = L>> IntervalDifference<T, L, R> {
pub fn into_vec(self) -> Vec<Interval<T, L, R>> {
self.into_iter().collect()
}
}
impl<T, L: Flip<Flip = R>, R: Flip<Flip = L>> IntoIterator for IntervalDifference<T, L, R> {
type Item = Interval<T, L, R>;
type IntoIter =
std::iter::Chain<std::option::IntoIter<Self::Item>, std::option::IntoIter<Self::Item>>;
fn into_iter(self) -> Self::IntoIter {
self.lower.into_iter().chain(self.upper)
}
}
fn is_valid_interval<T, L, R>(left: &LeftBounded<T, L>, right: &RightBounded<T, R>) -> bool
where
T: PartialOrd,
L: BoundaryOf<Left>,
R: BoundaryOf<Right>,
{
left.contains(&right.limit) && right.contains(&left.limit)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Interval<T, L = Inclusive, R = L> {
pub(crate) left: LeftBounded<T, L>,
pub(crate) right: RightBounded<T, R>,
}
impl<T, L, R> Interval<T, L, R> {
pub fn left(&self) -> &LeftBounded<T, L> {
&self.left
}
pub fn right(&self) -> &RightBounded<T, R> {
&self.right
}
}
impl<T: PartialOrd, L: BoundaryOf<Left>, R: BoundaryOf<Right>> Interval<T, L, R> {
fn new_(left: LeftBounded<T, L>, right: RightBounded<T, R>) -> Option<Self> {
is_valid_interval(&left, &right).then_some(Self { left, right })
}
pub fn try_new(left: Bound<T, L>, right: Bound<T, R>) -> Option<Self> {
Self::new_(left.into(), right.into())
}
pub fn new(left: Bound<T, L>, right: Bound<T, R>) -> Self {
Self::try_new(left, right).expect("Invalid interval: left must be less than right.")
}
pub fn try_between(a: T, b: T) -> Option<Self>
where
T: Into<Bound<T, L>> + Into<Bound<T, R>>,
{
if a < b {
Self::try_new(a.into(), b.into())
} else {
Self::try_new(b.into(), a.into())
}
}
pub fn between(a: T, b: T) -> Self
where
T: Into<Bound<T, L>> + Into<Bound<T, R>>,
{
Self::try_between(a, b).unwrap()
}
pub fn inf(&self) -> &T {
self.left.inf()
}
pub fn sup(&self) -> &T {
self.right.sup()
}
pub fn closure(self) -> Interval<T, Inclusive> {
Interval {
left: self.left.closure(),
right: self.right.closure(),
}
}
pub fn interior(self) -> Option<Interval<T, Exclusive>> {
Interval::<_, Exclusive>::new_(self.left.interior(), self.right.interior())
}
pub fn contains(&self, t: &T) -> bool {
self.left.contains(t) && self.right.contains(t)
}
pub fn dilate(self, delta: T) -> Self
where
T: Clone + std::ops::Add<Output = T> + std::ops::Sub<Output = T>,
{
Self::new_(self.left.dilate(delta.clone()), self.right.dilate(delta)).unwrap()
}
pub fn includes(&self, other: &Self) -> bool {
self.left.includes(&other.left) && self.right.includes(&other.right)
}
pub fn overlaps(&self, other: &Self) -> bool {
let left = crate::half::partial_max(&self.left, &other.left);
let right = crate::half::partial_min(&self.right, &other.right);
is_valid_interval(left, right)
}
pub fn intersection(&self, other: &Self) -> Option<Self>
where
T: Clone,
{
Self::new_(
self.left.intersection(&other.left).clone(),
self.right.intersection(&other.right).clone(),
)
}
pub fn span(&self, other: &Self) -> Self
where
T: Clone,
{
Self {
left: self.left.union(&other.left).clone(),
right: self.right.union(&other.right).clone(),
}
}
pub fn hull(self, t: T) -> Self
where
T: Clone,
{
Self {
left: self.left.hull(t.clone()),
right: self.right.hull(t),
}
}
pub fn gap(&self, other: &Self) -> Option<Interval<T, R::Flip, L::Flip>>
where
T: Clone,
L::Flip: BoundaryOf<Right>,
R::Flip: BoundaryOf<Left>,
{
Interval::new_(self.right.clone().flip(), other.left.clone().flip())
.or_else(|| Interval::new_(other.right.clone().flip(), self.left.clone().flip()))
}
pub fn union(&self, other: &Self) -> IntervalUnion<T, L, R>
where
T: Clone,
L::Flip: BoundaryOf<Right>,
R::Flip: BoundaryOf<Left>,
{
IntervalUnion {
gap: self.gap(other),
span: self.span(other),
}
}
pub fn lower_bound(&self) -> RightBounded<T, L::Flip>
where
T: Clone,
{
self.left.clone().flip()
}
pub fn upper_bound(&self) -> LeftBounded<T, R::Flip>
where
T: Clone,
{
self.right.clone().flip()
}
pub fn measure(&self) -> T
where
T: Clone + std::ops::Sub<Output = T>,
{
self.sup().clone() - self.inf().clone()
}
pub fn step_by(&self, step: T) -> impl Iterator<Item = T> + '_
where
T: Clone,
for<'a> T: std::ops::AddAssign<&'a T>,
{
self.left
.step_by(step)
.take_while(|t| self.right.contains(t))
}
pub fn step_rev_by(&self, step: T) -> impl Iterator<Item = T> + '_
where
T: Clone,
for<'a> T: std::ops::SubAssign<&'a T>,
{
self.right
.step_rev_by(step)
.take_while(|t| self.left.contains(t))
}
pub fn span_many<A: std::borrow::Borrow<Self>>(
items: impl IntoIterator<Item = A>,
) -> Option<Self>
where
T: Clone,
{
let mut items = items.into_iter();
let first = items.next()?.borrow().clone();
Some(items.fold(first, |acc, item| acc.span(item.borrow())))
}
pub fn hull_many(items: impl IntoIterator<Item = T>) -> Option<Self>
where
T: Clone + Into<Bound<T, L>> + Into<Bound<T, R>>,
{
let mut items = items.into_iter();
let mut left = items.next()?;
let mut right = left.clone();
for x in items {
if x < left {
left = x;
} else if right < x {
right = x;
}
}
Self::try_new(left.into(), right.into())
}
}
impl<T: PartialOrd, L: BoundaryOf<Left, Flip = R>, R: BoundaryOf<Right, Flip = L>>
Interval<T, L, R>
{
pub fn difference(&self, other: &Self) -> IntervalDifference<T, L, R>
where
T: Clone,
{
IntervalDifference {
lower: Self::new_(self.left.clone(), other.lower_bound()),
upper: Self::new_(other.upper_bound(), self.right.clone()),
}
}
}
impl<T: PartialOrd + Clone> Interval<T, Inclusive, Exclusive> {
pub fn try_split_at(&self, t: T) -> (Option<Self>, Option<Self>) {
if !self.left.contains(&t) {
return (None, Some(self.clone()));
}
if !self.right.contains(&t) {
return (Some(self.clone()), None);
}
let lower = Self::new_(self.left.clone(), Exclusive.at(t.clone()).into());
let upper = Self::new_(Inclusive.at(t).into(), self.right.clone());
(lower, upper)
}
pub fn split_at(&self, t: T) -> (Self, Self) {
assert!(self.contains(&t));
let lower = Self::new_(self.left.clone(), Exclusive.at(t.clone()).into());
let upper = Self::new_(Inclusive.at(t).into(), self.right.clone());
(lower.unwrap(), upper.unwrap())
}
}
impl<T: num::Float, L: BoundaryOf<Left>, R: BoundaryOf<Right>> Interval<T, L, R> {
pub fn center(&self) -> T {
(self.left.limit + self.right.limit) / (T::one() + T::one())
}
pub fn iou(&self, other: &Self) -> T {
self.intersection(other)
.map(|intersection| {
let union = self.span(other);
intersection.measure() / union.measure()
})
.unwrap_or(T::zero())
}
pub fn lerp(&self, ratio: T) -> T {
(T::one() - ratio) * *self.inf() + ratio * *self.sup()
}
pub fn step_uniform(&self, n: usize) -> impl Iterator<Item = T> + '_ {
let step = self.measure() / T::from(n).unwrap();
let (mut i, mut t) = if self.left.bound_type.is_inclusive() {
(0, *self.inf())
} else {
(1, *self.inf() + step)
};
let last = if self.right.bound_type.is_inclusive() {
n
} else {
n - 1
};
std::iter::from_fn(move || {
let ret = (i <= last).then_some(t);
t = if i == n { *self.sup() } else { t + step };
i += 1;
ret
})
}
}
impl<T, L, R> Interval<T, L, R> {
pub fn cast<U: From<T>>(self) -> Interval<U, L, R> {
Interval {
left: self.left.cast(),
right: self.right.cast(),
}
}
}
impl<T: num::NumCast, L, R> Interval<T, L, R> {
pub fn try_cast<U: num::NumCast>(self) -> Option<Interval<U, L, R>> {
Some(Interval {
left: self.left.try_cast()?,
right: self.right.try_cast()?,
})
}
}
impl<T, L: IntoGeneral, R: IntoGeneral> IntoGeneral for Interval<T, L, R> {
type General = Interval<T, L::General, R::General>;
fn into_general(self) -> Self::General {
Interval {
left: self.left.into_general(),
right: self.right.into_general(),
}
}
}
impl<T, L, R> IntoIterator for Interval<T, L, R>
where
std::ops::RangeInclusive<T>: Iterator<Item = T>,
T: num::Integer + Clone,
L: BoundaryOf<Left>,
R: BoundaryOf<Right>,
for<'a> T: std::ops::AddAssign<&'a T> + std::ops::SubAssign<&'a T>,
{
type Item = T;
type IntoIter = std::ops::RangeInclusive<T>;
fn into_iter(self) -> Self::IntoIter {
let first = self.left.step_by(T::one()).next().unwrap();
let last = self.right.step_rev_by(T::one()).next().unwrap();
first..=last
}
}