Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
use super::funejson::Value; ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
/// Where `value` lands on the range, as a straight-line map from the domain.
/// Outside the domain the line carries on, unless `clamp` stops it at the
/// range's ends.
///
/// # Panics
/// Panics if the domain or range does not have exactly two values, or the
/// domain's ends are equal.
pub fn linear_scale(domain: &[f64], range: &[f64], value: f64, clamp: bool) -> f64 {
let (d0, d1) = pair(domain, "domain");
let (r0, r1) = pair(range, "range");
let mut t = normalise(d0, d1, value, "domain");
if clamp {
t = t.max(0.0).min(1.0);
}
round6(interpolate(r0, r1, t))
}
// The helpers below are shared with invert_linear, which is the same line read
// the other way; they are not part of the group's contract.
pub fn pair(values: &[f64], what: &str) -> (f64, f64) {
if values.len() != 2 {
panic!("{} must have exactly 2 values, [from, to]; got {}", what, values.len());
}
(values[0], values[1])
}
pub fn normalise(from: f64, to: f64, value: f64, what: &str) -> f64 {
// Equal ends would divide by zero and answer NaN or infinity, which then
// draws nothing without saying why.
if from == to {
panic!("{} has no width: both ends are {}", what, from);
}
(value - from) / (to - from)
}
pub fn interpolate(from: f64, to: f64, t: f64) -> f64 {
from + t * (to - from)
}
/// Half up to 6 decimal places, the same way in every language.
pub fn round6(x: f64) -> f64 {
(x * 1e6 + 0.5).floor() / 1e6
}
/// A JSON list of numbers, for the vector adapters.
pub fn floats(value: &Value) -> Vec<f64> {
value.as_arr().iter().map(|v| v.as_f64()).collect()
}
pub fn fune_vector(args: &[Value]) -> Value {
Value::Float(linear_scale(
&floats(&args[0]),
&floats(&args[1]),
args[2].as_f64(),
args[3].as_bool(),
))
}