use std::f64::consts::PI;
use crate::{GaugeGeometry, GaugeLayout, PieRadius};
pub fn resolve_gauge_layout(
plot_width: f64,
plot_height: f64,
geometry: &GaugeGeometry,
value: Option<f64>,
value_min: f64,
value_max: f64,
) -> GaugeLayout {
let max_radius = plot_width.min(plot_height) / 2.0;
let cx = geometry.cx.resolve_center(plot_width, plot_height, true);
let cy = geometry.cy.resolve_center(plot_width, plot_height, false);
let inner_radius = geometry.inner_radius.resolve(plot_width, plot_height, true);
let outer_radius = geometry.outer_radius.resolve(plot_width, plot_height, true);
let start_rad = deg_to_rad(geometry.start_angle);
let end_rad = deg_to_rad(geometry.end_angle);
let value_rad = value.map(|v| {
let frac = value_fraction(v, value_min, value_max);
start_rad + frac * (end_rad - start_rad)
});
GaugeLayout {
cx,
cy,
inner_radius,
outer_radius,
max_radius,
start_rad,
end_rad,
value_rad,
value_min,
value_max,
value,
}
}
pub fn parse_gauge_radius(s: &str, default: PieRadius) -> PieRadius {
if s.is_empty() {
return default;
}
PieRadius::parse(s)
}
pub fn value_fraction(value: f64, value_min: f64, value_max: f64) -> f64 {
if (value_max - value_min).abs() < f64::EPSILON {
return 0.0;
}
((value - value_min) / (value_max - value_min)).clamp(0.0, 1.0)
}
fn deg_to_rad(deg: f64) -> f64 {
deg * PI / 180.0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn value_fraction_clamps() {
assert_eq!(value_fraction(50.0, 0.0, 100.0), 0.5);
assert_eq!(value_fraction(-10.0, 0.0, 100.0), 0.0);
assert_eq!(value_fraction(150.0, 0.0, 100.0), 1.0);
}
#[test]
fn resolve_gauge_layout_value_angle() {
let geom = GaugeGeometry::default();
let layout = resolve_gauge_layout(200.0, 200.0, &geom, Some(75.0), 0.0, 100.0);
assert!(layout.value_rad.is_some());
let value_rad = layout.value_rad.unwrap();
assert!(value_rad > layout.start_rad);
assert!(value_rad <= layout.end_rad + 1e-9);
}
}