wowlab_parsers/parsers/scaling/
curve.rs1use wowlab_types::{data::ItemScalingData, numeric::interpolate_sorted};
4
5#[must_use]
7pub fn interpolate_curve(scaling_data: &ItemScalingData, curve_id: i32, x: f64) -> Option<f64> {
8 let points = scaling_data.curve_points.get(&curve_id)?;
9 let mut sorted_points: Vec<_> = points
11 .iter()
12 .map(|point| (point.pos_0, point.pos_1))
13 .collect();
14
15 sorted_points.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(std::cmp::Ordering::Equal));
16
17 interpolate_sorted(&sorted_points, x).or_else(|| sorted_points.last().map(|(_, value)| *value))
18}
19
20#[cfg(test)]
21mod tests {
22 use googletest::prelude::*;
23 use wowlab_types::data::CurvePointFlat;
24
25 use super::*;
26
27 fn make_scaling_data(data: &[(f64, f64)]) -> Result<ItemScalingData> {
28 let points = data
29 .iter()
30 .enumerate()
31 .map(|(i, (x, y))| -> Result<_> {
32 let index = i32::try_from(i).or_fail()?;
33
34 Ok(CurvePointFlat {
35 id: index,
36 curve_id: 1,
37 order_index: index,
38 pos_0: *x,
39 pos_1: *y,
40 pos_pre_squish_0: *x,
41 pos_pre_squish_1: *y,
42 })
43 })
44 .collect::<Result<Vec<_>>>()?;
45 let mut scaling_data = ItemScalingData::default();
46
47 scaling_data.curve_points.insert(1, points);
48
49 Ok(scaling_data)
50 }
51
52 #[gtest]
53 fn test_interpolate_exact_point() -> Result<()> {
54 let data = make_scaling_data(&[(100.0, 50.0), (200.0, 100.0), (300.0, 150.0)])?;
55
56 verify_that!(interpolate_curve(&data, 1, 100.0), eq(Some(50.0)))?;
57 verify_that!(interpolate_curve(&data, 1, 200.0), eq(Some(100.0)))?;
58 verify_that!(interpolate_curve(&data, 1, 300.0), eq(Some(150.0)))?;
59
60 Ok(())
61 }
62
63 #[gtest]
64 fn test_interpolate_between_points() -> Result<()> {
65 let data = make_scaling_data(&[(100.0, 50.0), (200.0, 100.0)])?;
66
67 verify_that!(interpolate_curve(&data, 1, 150.0), eq(Some(75.0)))?;
68
69 Ok(())
70 }
71
72 #[gtest]
73 fn test_interpolate_clamp_below() -> Result<()> {
74 let data = make_scaling_data(&[(100.0, 50.0), (200.0, 100.0)])?;
75
76 verify_that!(interpolate_curve(&data, 1, 50.0), eq(Some(50.0)))?;
77
78 Ok(())
79 }
80
81 #[gtest]
82 fn test_interpolate_clamp_above() -> Result<()> {
83 let data = make_scaling_data(&[(100.0, 50.0), (200.0, 100.0)])?;
84
85 verify_that!(interpolate_curve(&data, 1, 250.0), eq(Some(100.0)))?;
86
87 Ok(())
88 }
89
90 #[gtest]
91 fn test_interpolate_empty() -> Result<()> {
92 let data = make_scaling_data(&[])?;
93
94 verify_that!(interpolate_curve(&data, 1, 100.0), eq(None))?;
95
96 Ok(())
97 }
98
99 #[gtest]
100 fn test_interpolate_nan_falls_back_to_last_point() -> Result<()> {
101 let data = make_scaling_data(&[(100.0, 50.0), (200.0, 100.0)])?;
102
103 verify_that!(interpolate_curve(&data, 1, f64::NAN), eq(Some(100.0)))?;
104
105 Ok(())
106 }
107}