1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
//! Higher-order channel-interpolator factory.
//!
//! Mirrors culori 4.0.2's `interpolatorPiecewise` (defined in
//! `node_modules/culori/src/interpolate/piecewise.js`). Given a per-segment
//! interpolator `f(a, b, t)`, returns a factory that builds a sampler over
//! a stop slice. The built sampler partitions `[0, 1]` evenly across the
//! segments, then calls `f` on the active segment with a local `t`.
//!
//! Missing stops (encoded as `NaN`) follow culori's `[a, a]` / `[b, b]`
//! propagation rule: a class with one missing endpoint repeats the present
//! endpoint, a class with both missing returns `NaN`.
use ;
/// Build a [`ChannelInterpFactory`] from a per-segment interpolator
/// `f(a, b, t)`. The returned factory takes a stop slice and produces a
/// sampler that, given `t` in `[0, 1]`, picks the active segment and
/// returns `f(stops[i], stops[i+1], local_t)`.
///
/// Mirrors culori's `interpolatorPiecewise(interpolator)`: the partition
/// logic is identical (`idx = floor(t * (n - 1))` clamped to `[0, n - 2]`),
/// and the missing-endpoint rule (`[a, a]` if only `a` is defined,
/// `[b, b]` if only `b` is, `None` if neither) is preserved bit-for-bit.
///
/// Slot the resulting factory into
/// [`crate::InterpolateOptions::channel_interpolator`] to use a custom
/// per-channel interpolator, exactly as culori's
/// `interpolate(stops, mode, { interpolator })` does.
///
/// # Example
///
/// ```rust
/// use culors::interpolator_piecewise;
///
/// // Quadratic ease per segment.
/// let factory = interpolator_piecewise(|a: f64, b: f64, t: f64| {
/// a + (b - a) * t * t
/// });
/// let sampler = factory(&[0.0, 10.0]);
/// assert!((sampler(0.5) - 2.5).abs() < 1e-12);
/// ```
// Shared with `lerp.rs` — duplicated here to avoid a module-private
// dependency edge. The two are byte-for-byte identical because they both
// mirror culori's `get_classes`.