use crate::compile::fusion::{DecomposedGraph, DecomposedWire, FusedNode};
#[crate::polydat_node(category = Interpolation)]
fn lerp(
t: f64,
#[poly_default(0.0f64)] a: crate::derive_support::Const<f64>,
#[poly_default(1.0f64)] b: crate::derive_support::Const<f64>,
) -> f64 {
*a + t * (*b - *a)
}
#[crate::polydat_node(
category = Interpolation,
jit_constants = scale_range_jit_constants,
)]
fn scale_range(
input: u64,
#[poly_default(0.0f64)] min: crate::derive_support::Const<f64>,
#[poly_default(1.0f64)] max: crate::derive_support::Const<f64>,
) -> f64 {
let t = input as f64 / u64::MAX as f64;
*min + t * (*max - *min)
}
fn scale_range_jit_constants(node: &ScaleRange) -> Vec<u64> {
vec![node.min.to_bits(), (node.max - node.min).to_bits()]
}
impl FusedNode for ScaleRange {
fn decomposed(&self) -> DecomposedGraph {
use crate::library::sampling::icd::UnitInterval;
let mut g = DecomposedGraph::new(1);
let ui = g.add_node(Box::new(UnitInterval::new()), vec![DecomposedWire::Input(0)]);
let lerp = g.add_node(
Box::new(Lerp::new(self.min, self.max)),
vec![DecomposedWire::Node(ui, 0)],
);
g.set_outputs(vec![DecomposedWire::Node(lerp, 0)]);
g
}
}
#[crate::polydat_node(category = Interpolation)]
fn inv_lerp(
input: f64,
#[poly_default(0.0f64)] a: crate::derive_support::Const<f64>,
#[poly_default(1.0f64)] b: crate::derive_support::Const<f64>,
) -> f64 {
let inv_range = 1.0 / (*b - *a);
let t = (input - *a) * inv_range;
t.clamp(0.0, 1.0)
}
#[crate::polydat_node(category = Interpolation)]
fn remap(
input: f64,
#[poly_default(0.0f64)] in_min: crate::derive_support::Const<f64>,
#[poly_default(1.0f64)] in_max: crate::derive_support::Const<f64>,
#[poly_default(0.0f64)] out_min: crate::derive_support::Const<f64>,
#[poly_default(1.0f64)] out_max: crate::derive_support::Const<f64>,
) -> f64 {
let t = (input - *in_min) / (*in_max - *in_min);
*out_min + t * (*out_max - *out_min)
}
#[crate::polydat_node(category = Interpolation)]
fn quantize(
input: f64,
#[poly_default(1.0f64)] step: crate::derive_support::Const<f64>,
) -> f64 {
(input / *step).round() * *step
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ast::{PolydatNode, Value};
#[test]
fn lerp_endpoints() {
let node = Lerp::new(10.0, 20.0);
let mut out = [Value::None];
node.eval(&[Value::F64(0.0)], &mut out);
assert_eq!(out[0].as_f64(), 10.0);
node.eval(&[Value::F64(1.0)], &mut out);
assert_eq!(out[0].as_f64(), 20.0);
}
#[test]
fn lerp_midpoint() {
let node = Lerp::new(0.0, 100.0);
let mut out = [Value::None];
node.eval(&[Value::F64(0.5)], &mut out);
assert_eq!(out[0].as_f64(), 50.0);
}
#[test]
fn scale_range_bounds() {
let node = ScaleRange::new(10.0, 20.0);
let mut out = [Value::None];
node.eval(&[Value::U64(0)], &mut out);
assert!((out[0].as_f64() - 10.0).abs() < 0.001);
node.eval(&[Value::U64(u64::MAX)], &mut out);
assert!((out[0].as_f64() - 20.0).abs() < 0.001);
}
#[test]
fn scale_range_jit_constants_layout() {
let node = ScaleRange::new(10.0, 25.0);
let consts = node.jit_constants();
assert_eq!(consts.len(), 2);
assert_eq!(f64::from_bits(consts[0]), 10.0);
assert_eq!(f64::from_bits(consts[1]), 15.0); }
#[test]
fn inv_lerp_basic() {
let node = InvLerp::new(10.0, 20.0);
let mut out = [Value::None];
node.eval(&[Value::F64(10.0)], &mut out);
assert!((out[0].as_f64() - 0.0).abs() < 0.001);
node.eval(&[Value::F64(15.0)], &mut out);
assert!((out[0].as_f64() - 0.5).abs() < 0.001);
node.eval(&[Value::F64(20.0)], &mut out);
assert!((out[0].as_f64() - 1.0).abs() < 0.001);
}
#[test]
fn inv_lerp_clamps() {
let node = InvLerp::new(0.0, 100.0);
let mut out = [Value::None];
node.eval(&[Value::F64(-50.0)], &mut out);
assert_eq!(out[0].as_f64(), 0.0);
node.eval(&[Value::F64(200.0)], &mut out);
assert_eq!(out[0].as_f64(), 1.0);
}
#[test]
fn remap_basic() {
let node = Remap::new(0.0, 100.0, 0.0, 1.0);
let mut out = [Value::None];
node.eval(&[Value::F64(50.0)], &mut out);
assert!((out[0].as_f64() - 0.5).abs() < 0.001);
}
#[test]
fn remap_different_ranges() {
let node = Remap::new(32.0, 212.0, 0.0, 100.0);
let mut out = [Value::None];
node.eval(&[Value::F64(32.0)], &mut out);
assert!((out[0].as_f64() - 0.0).abs() < 0.001);
node.eval(&[Value::F64(212.0)], &mut out);
assert!((out[0].as_f64() - 100.0).abs() < 0.001);
node.eval(&[Value::F64(72.0)], &mut out);
assert!((out[0].as_f64() - 22.22).abs() < 0.1);
}
#[test]
fn quantize_basic() {
let node = Quantize::new(10.0);
let mut out = [Value::None];
node.eval(&[Value::F64(13.0)], &mut out);
assert_eq!(out[0].as_f64(), 10.0);
node.eval(&[Value::F64(17.0)], &mut out);
assert_eq!(out[0].as_f64(), 20.0);
node.eval(&[Value::F64(15.0)], &mut out);
assert_eq!(out[0].as_f64(), 20.0); }
#[test]
fn quantize_small_step() {
let node = Quantize::new(0.25);
let mut out = [Value::None];
node.eval(&[Value::F64(1.3)], &mut out);
assert!((out[0].as_f64() - 1.25).abs() < 0.001);
}
}