#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub enum AxisScale {
#[default]
Linear,
Log {
base: f64,
},
}
impl AxisScale {
pub(crate) fn data_to_plot(self, value: f64) -> Option<f64> {
match self {
Self::Linear => value.is_finite().then_some(value),
Self::Log { base } => (value.is_finite() && value > 0.0)
.then(|| value.log(base))
.filter(|v| v.is_finite()),
}
}
pub(crate) fn plot_to_data(self, value: f64) -> Option<f64> {
match self {
Self::Linear => value.is_finite().then_some(value),
Self::Log { base } => {
if !value.is_finite() {
return None;
}
let out = base.powf(value);
(out.is_finite() && out > 0.0).then_some(out)
}
}
}
}
pub(crate) fn data_point_to_plot(
point: [f64; 2],
x_scale: AxisScale,
y_scale: AxisScale,
) -> Option<[f64; 2]> {
Some([
x_scale.data_to_plot(point[0])?,
y_scale.data_to_plot(point[1])?,
])
}
pub(crate) fn plot_point_to_data(
point: [f64; 2],
x_scale: AxisScale,
y_scale: AxisScale,
) -> Option<[f64; 2]> {
Some([
x_scale.plot_to_data(point[0])?,
y_scale.plot_to_data(point[1])?,
])
}