use super::funejson::Value; use super::charts_scale_linear_scale::{floats, interpolate, pair}; use super::math_ln::ln; use super::math_round_float::round_float; /// Where `value` lands on a logarithmic axis: equal ratios take equal lengths. /// The base cancels out, so there is none to pass. `ln` is math.ln, not /// `f64::ln`, so every language lands on the same double. /// /// # Panics /// Panics if the domain or range does not have two values, either domain end /// is not positive, the ends are equal, or `value` is not positive. pub fn log_scale(domain: &[f64], range: &[f64], value: f64, clamp: bool) -> f64 { let (d0, d1) = pair(domain, "domain"); let (r0, r1) = pair(range, "range"); if !(d0 > 0.0) || !(d1 > 0.0) { panic!("log scale domain must be positive; got [{}, {}]", d0, d1); } if d0 == d1 { panic!("domain has no width: both ends are {}", d0); } if !(value > 0.0) { panic!("value must be positive for a log scale; got {}", value); } let l0 = ln(d0); let mut t = (ln(value) - l0) / (ln(d1) - l0); if clamp { t = t.max(0.0).min(1.0); } round_float(interpolate(r0, r1, t), 6) } pub fn fune_vector(args: &[Value]) -> Value { Value::Float(log_scale(&floats(&args[0]), &floats(&args[1]), args[2].as_f64(), args[3].as_bool())) }