#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Range {
pub min: f64,
pub max: f64,
}
impl Range {
pub fn new(mut min: f64, mut max: f64) -> Self {
if min > max {
std::mem::swap(&mut min, &mut max);
}
Self { min, max }
}
pub fn span(&self) -> f64 {
self.max - self.min
}
pub fn is_finite(&self) -> bool {
self.min.is_finite() && self.max.is_finite()
}
pub fn is_valid(&self) -> bool {
self.is_finite() && self.span() > 0.0
}
pub fn expand_to_include(&mut self, value: f64) {
if !value.is_finite() {
return;
}
if value < self.min {
self.min = value;
}
if value > self.max {
self.max = value;
}
}
pub fn union(a: Self, b: Self) -> Option<Self> {
if !a.is_finite() || !b.is_finite() {
return None;
}
Some(Self {
min: a.min.min(b.min),
max: a.max.max(b.max),
})
}
pub fn clamp(&self, value: f64) -> f64 {
value.max(self.min).min(self.max)
}
pub fn padded(&self, frac: f64, min_padding: f64) -> Self {
let span = self.span().abs();
let padding = (span * frac).max(min_padding);
Self {
min: self.min - padding,
max: self.max + padding,
}
}
pub fn with_min_span(&self, min_span: f64) -> Self {
let span = self.span();
if span >= min_span {
return *self;
}
let center = (self.min + self.max) * 0.5;
let half = min_span * 0.5;
Self {
min: center - half,
max: center + half,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum View {
AutoAll {
auto_x: bool,
auto_y: bool,
},
Manual,
FollowLastN {
points: usize,
},
FollowLastNXY {
points: usize,
},
}
impl Default for View {
fn default() -> Self {
Self::AutoAll {
auto_x: true,
auto_y: true,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Viewport {
pub x: Range,
pub y: Range,
}
impl Viewport {
pub fn new(x: Range, y: Range) -> Self {
Self { x, y }
}
pub fn is_valid(&self) -> bool {
self.x.is_valid() && self.y.is_valid()
}
pub fn padded(&self, frac: f64, min_padding: f64) -> Self {
Self {
x: self.x.padded(frac, min_padding),
y: self.y.padded(frac, min_padding),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn range_with_min_span_expands() {
let range = Range::new(2.0, 2.0);
let expanded = range.with_min_span(1.0);
assert!(expanded.span() >= 1.0);
assert!((expanded.min + expanded.max) * 0.5 - 2.0 < 1e-9);
}
}