use std::ops::Range;
use crate::math::{Point, Bounds, Vector};
pub struct PlotFrame {
pt_lim: Bounds<f64>,
px_lim: Bounds<i64>,
px_pt_ratio: Vector,
}
impl PlotFrame {
pub fn new(canvas_bounds: Bounds<i64>, plotting_range: Bounds<f64>) -> PlotFrame {
let pt_lim = plotting_range;
let px_lim = canvas_bounds;
let px_pt_ratio = (1.0, 1.0).into(); let mut frame = PlotFrame { pt_lim, px_lim, px_pt_ratio };
frame.recalculate_scaling();
frame
}
fn recalculate_scaling(&mut self) {
self.px_pt_ratio.x = ((self.px_lim.x.end - self.px_lim.x.start) as f64) / (self.pt_lim.x.end - self.pt_lim.x.start);
self.px_pt_ratio.y = ((self.px_lim.y.end - self.px_lim.y.start) as f64) / (self.pt_lim.y.end - self.pt_lim.y.start);
}
fn x_pt_to_px(&self, x: f64) -> i64 {
((x - self.pt_lim.x.start) * self.px_pt_ratio.x).round() as i64 + self.px_lim.x.start
}
fn y_pt_to_px(&self, y: f64) -> i64 {
((y - self.pt_lim.y.start) * self.px_pt_ratio.y).round() as i64 + self.px_lim.y.start
}
pub fn pt_to_px<T: Into<Point>>(&self, pt: T) -> (i64, i64) {
let p = pt.into();
(self.x_pt_to_px(p.x), self.y_pt_to_px(p.y)).into()
}
pub fn pt_to_px_pt<T: Into<Point>>(&self, pt: T) -> Point {
let p = pt.into();
(
(p.x - self.pt_lim.x.start) * self.px_pt_ratio.x + (self.px_lim.x.start as f64),
(p.y - self.pt_lim.y.start) * self.px_pt_ratio.y + (self.px_lim.y.start as f64)
).into()
}
pub fn set_drawing_bounds<R: Into<Range<i64>>>(&mut self, x_bounds: R, y_bounds: R) {
self.px_lim.x = x_bounds.into();
self.px_lim.y = y_bounds.into();
self.recalculate_scaling();
}
pub fn set_plotting_range<R: Into<Range<f64>>>(&mut self, x_range: R, y_range: R) {
self.pt_lim.x = x_range.into();
self.pt_lim.y = y_range.into();
self.recalculate_scaling();
}
}