Skip to main content

wowlab_engine_gamedata/game_data/
curves.rs

1//! [`ResolvedCurves`]: DBC curves resolved for a sim run.
2
3use wowlab_types::{data::CurvePointFlat, sim::IntMap};
4
5/// DBC curves resolved for a sim run.
6#[derive(Clone, Debug, Default)]
7pub struct ResolvedCurves {
8    points_by_id: IntMap<i32, Vec<(f64, f64)>>,
9}
10
11impl ResolvedCurves {
12    /// Creates an empty curve collection.
13    #[must_use]
14    pub fn new() -> Self {
15        Self::default()
16    }
17
18    #[must_use]
19    pub fn from_scaling(curve_points: &IntMap<i32, Vec<CurvePointFlat>>) -> Self {
20        let mut points_by_id: IntMap<i32, Vec<(f64, f64)>> = IntMap::default();
21
22        for (&curve_id, points) in curve_points {
23            let mut pts: Vec<(f64, f64)> = points.iter().map(|p| (p.pos_0, p.pos_1)).collect();
24
25            pts.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(std::cmp::Ordering::Equal));
26            points_by_id.insert(curve_id, pts);
27        }
28
29        Self { points_by_id }
30    }
31
32    /// Sorts each curve's points by `x` so interpolation callers can rely on ascending order.
33    #[must_use]
34    pub fn from_points(mut points_by_id: IntMap<i32, Vec<(f64, f64)>>) -> Self {
35        for points in points_by_id.values_mut() {
36            points.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(std::cmp::Ordering::Equal));
37        }
38
39        Self { points_by_id }
40    }
41
42    /// Points (ascending by `x`) for `curve_id`; `None` when the curve is absent.
43    pub fn curve_points(&self, curve_id: i32) -> Option<&[(f64, f64)]> {
44        self.points_by_id.get(&curve_id).map(Vec::as_slice)
45    }
46
47    #[must_use]
48    pub fn is_empty(&self) -> bool {
49        self.points_by_id.is_empty()
50    }
51}