use super::Point2D;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Bounds {
pub x_min: f64,
pub x_max: f64,
pub y_min: f64,
pub y_max: f64,
}
impl Bounds {
#[must_use]
pub const fn new(x_min: f64, x_max: f64, y_min: f64, y_max: f64) -> Self {
Self {
x_min,
x_max,
y_min,
y_max,
}
}
#[must_use]
pub fn width(&self) -> f64 {
self.x_max - self.x_min
}
#[must_use]
pub fn height(&self) -> f64 {
self.y_max - self.y_min
}
#[must_use]
pub fn contains(&self, point: &Point2D) -> bool {
point.x >= self.x_min
&& point.x <= self.x_max
&& point.y >= self.y_min
&& point.y <= self.y_max
}
#[must_use]
pub fn expand(&self, point: &Point2D) -> Self {
Self {
x_min: self.x_min.min(point.x),
x_max: self.x_max.max(point.x),
y_min: self.y_min.min(point.y),
y_max: self.y_max.max(point.y),
}
}
#[must_use]
pub fn with_padding(&self, fraction: f64) -> Self {
let dx = self.width() * fraction;
let dy = self.height() * fraction;
Self {
x_min: self.x_min - dx,
x_max: self.x_max + dx,
y_min: self.y_min - dy,
y_max: self.y_max + dy,
}
}
#[must_use]
pub fn with_padding_top(&self, fraction: f64) -> Self {
let dx = self.width() * fraction;
let dy = self.height() * fraction;
Self {
x_min: self.x_min - dx,
x_max: self.x_max + dx,
y_min: self.y_min, y_max: self.y_max + dy, }
}
#[must_use]
pub fn with_padding_right(&self, fraction: f64) -> Self {
let dx = self.width() * fraction;
let dy = self.height() * fraction;
Self {
x_min: self.x_min, x_max: self.x_max + dx, y_min: self.y_min - dy,
y_max: self.y_max + dy,
}
}
pub fn from_points<I>(points: I) -> Self
where
I: IntoIterator<Item = Point2D>,
{
let mut iter = points.into_iter();
let first = iter
.next()
.expect("Cannot create bounds from empty iterator");
let mut bounds = Self::new(first.x, first.x, first.y, first.y);
for point in iter {
bounds = bounds.expand(&point);
}
bounds
}
#[must_use]
pub fn union(&self, other: &Self) -> Self {
Self {
x_min: self.x_min.min(other.x_min),
x_max: self.x_max.max(other.x_max),
y_min: self.y_min.min(other.y_min),
y_max: self.y_max.max(other.y_max),
}
}
}