Skip to main content

oxihuman_export/
pressure_map_export.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5/// 2D pressure distribution map.
6pub struct PressureMap {
7    pub width: usize,
8    pub height: usize,
9    pub pressures: Vec<f32>,
10}
11
12pub fn new_pressure_map(w: usize, h: usize) -> PressureMap {
13    PressureMap {
14        width: w,
15        height: h,
16        pressures: vec![0.0; w * h],
17    }
18}
19
20pub fn pressure_set(m: &mut PressureMap, x: usize, y: usize, p: f32) {
21    if x < m.width && y < m.height {
22        m.pressures[y * m.width + x] = p;
23    }
24}
25
26pub fn pressure_get(m: &PressureMap, x: usize, y: usize) -> f32 {
27    if x < m.width && y < m.height {
28        m.pressures[y * m.width + x]
29    } else {
30        0.0
31    }
32}
33
34pub fn pressure_total_force(m: &PressureMap, cell_area: f32) -> f32 {
35    m.pressures.iter().sum::<f32>() * cell_area
36}
37
38pub fn pressure_center_of_pressure(m: &PressureMap) -> [f32; 2] {
39    let total: f32 = m.pressures.iter().sum();
40    if total < 1e-9 {
41        return [m.width as f32 * 0.5, m.height as f32 * 0.5];
42    }
43    let mut cx = 0.0f32;
44    let mut cy = 0.0f32;
45    for y in 0..m.height {
46        for x in 0..m.width {
47            let p = m.pressures[y * m.width + x];
48            cx += p * x as f32;
49            cy += p * y as f32;
50        }
51    }
52    [cx / total, cy / total]
53}
54
55pub fn pressure_max(m: &PressureMap) -> f32 {
56    m.pressures
57        .iter()
58        .cloned()
59        .fold(f32::NEG_INFINITY, f32::max)
60}
61
62pub fn pressure_to_bytes(m: &PressureMap) -> Vec<u8> {
63    let mut out = Vec::with_capacity(m.pressures.len() * 4);
64    for &p in &m.pressures {
65        out.extend_from_slice(&p.to_le_bytes());
66    }
67    out
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn test_new_pressure_map_size() {
76        let m = new_pressure_map(5, 5);
77        assert_eq!(m.pressures.len(), 25);
78    }
79
80    #[test]
81    fn test_pressure_set_get() {
82        let mut m = new_pressure_map(4, 4);
83        pressure_set(&mut m, 2, 1, 100.0);
84        assert!((pressure_get(&m, 2, 1) - 100.0).abs() < 1e-4);
85    }
86
87    #[test]
88    fn test_pressure_get_oob() {
89        let m = new_pressure_map(4, 4);
90        assert!((pressure_get(&m, 10, 10) - 0.0).abs() < 1e-6);
91    }
92
93    #[test]
94    fn test_pressure_total_force() {
95        let mut m = new_pressure_map(2, 1);
96        pressure_set(&mut m, 0, 0, 10.0);
97        pressure_set(&mut m, 1, 0, 20.0);
98        assert!((pressure_total_force(&m, 0.01) - 0.3).abs() < 1e-5);
99    }
100
101    #[test]
102    fn test_pressure_center_of_pressure() {
103        let mut m = new_pressure_map(3, 1);
104        pressure_set(&mut m, 0, 0, 0.0);
105        pressure_set(&mut m, 1, 0, 1.0);
106        pressure_set(&mut m, 2, 0, 0.0);
107        let cop = pressure_center_of_pressure(&m);
108        assert!((cop[0] - 1.0).abs() < 1e-4);
109    }
110
111    #[test]
112    fn test_pressure_max() {
113        let mut m = new_pressure_map(3, 1);
114        pressure_set(&mut m, 0, 0, 50.0);
115        pressure_set(&mut m, 1, 0, 200.0);
116        pressure_set(&mut m, 2, 0, 75.0);
117        assert!((pressure_max(&m) - 200.0).abs() < 1e-4);
118    }
119
120    #[test]
121    fn test_pressure_to_bytes_len() {
122        let m = new_pressure_map(4, 4);
123        assert_eq!(pressure_to_bytes(&m).len(), 64);
124    }
125
126    #[test]
127    fn test_pressure_center_empty() {
128        let m = new_pressure_map(4, 4);
129        /* should not panic with all zeros */
130        let _ = pressure_center_of_pressure(&m);
131    }
132}