-
Notifications
You must be signed in to change notification settings - Fork 110
Expand file tree
/
Copy pathlinear_interpolation.rs
More file actions
40 lines (36 loc) · 1.41 KB
/
linear_interpolation.rs
File metadata and controls
40 lines (36 loc) · 1.41 KB
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
use core::ops::{Add, Div, Mul, Sub};
/// Error returned when `current_in` is outside the `[min_in, max_in]` range.
#[derive(Debug)]
pub struct LinearInterpolationInvalidValuesError;
/// Computes a linearly interpolated output value for a given input within a known range.
///
/// Given an input range `[min_in, max_in]` and a corresponding output range `[min_out, max_out]`,
/// maps `current_in` proportionally to its position in the output range.
///
/// Formula:
/// ```text
/// out = (min_out * (max_in - current_in) + max_out * (current_in - min_in)) / (max_in - min_in)
/// ```
///
/// Returns [`Err(LinearInterpolationInvalidValuesError)`] if `current_in` is outside `[min_in, max_in]`.
///
/// See also: <https://en.wikipedia.org/wiki/Linear_interpolation>
pub fn linear_interpolation<T>(
min_in: T,
max_in: T,
current_in: T,
min_out: T,
max_out: T,
) -> Result<T, LinearInterpolationInvalidValuesError>
where
T: Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T> + PartialOrd + Clone,
{
if min_in > max_in || current_in < min_in || current_in > max_in {
return Err(LinearInterpolationInvalidValuesError);
}
let min_out_weighted = min_out * (max_in.clone() - current_in.clone());
let max_out_weighted = max_out * (current_in - min_in.clone());
let in_diff = max_in - min_in;
let result = (min_out_weighted + max_out_weighted) / in_diff;
Ok(result)
}