use err::{err_str, Result};
pub const MIN_SPACING: f32 = 0.001;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Period {
begin: f32,
end: f32,
}
impl Period {
pub fn new(begin: f32, end: f32) -> Result<Period> {
if begin < end && begin >= 0.0 && end >= 0.0 {
Ok(Period { begin: begin, end: end })
} else {
Err(err_str(format!("Beginning of range is before end: {}-{}",
begin, end)))
}
}
pub fn from_union_opt(p1: Option<Period>, p2: Option<Period>) ->
Option<Period>
{
match (p1, p2) {
(None, None) => None,
(Some(p), None) => Some(p),
(None, Some(p)) => Some(p),
(Some(p1), Some(p2)) => Some(p1.union(p2)),
}
}
pub fn begin(&self) -> f32 {
self.begin
}
pub fn end(&self) -> f32 {
self.end
}
pub fn duration(&self) -> f32 {
self.end - self.begin
}
pub fn midpoint(&self) -> f32 {
self.begin + self.duration()/2.0
}
pub fn grow(&self, before: f32, after: f32) -> Period {
let mid = self.midpoint();
Period {
begin: (self.begin - before).min(mid).max(0.0),
end: (self.end + after).max(mid + MIN_SPACING),
}
}
pub fn union(&self, other: Period) -> Period {
Period {
begin: self.begin.min(other.begin),
end: self.end.max(other.end),
}
}
pub fn begin_after(&mut self, limit: f32) -> Result<()> {
if limit > self.end - 2.0*MIN_SPACING {
try!(Err(err_str(format!("Cannot begin time period {:?} after {}",
self, limit))));
}
self.begin = self.begin.max(limit + MIN_SPACING);
Ok(())
}
pub fn end_before(&mut self, limit: f32) -> Result<()> {
if limit < self.begin + 2.0*MIN_SPACING {
try!(Err(err_str(format!("Cannot truncate time period {:?} at {}",
self, limit))));
}
self.end = self.end.min(limit - MIN_SPACING);
Ok(())
}
pub fn distance(&self, other: Period) -> Option<f32> {
if self.end <= other.begin {
Some((other.begin - self.end).abs())
} else if other.end <= self.begin {
Some((self.begin - other.end).abs())
} else {
None
}
}
pub fn overlap(&self, other: Period) -> f32 {
(self.end.min(other.end) - self.begin.max(other.begin)).max(0.0)
}
}