Skip to main content

oxihuman_export/
scar_map_export.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5pub struct ScarMap {
6    pub width: u32,
7    pub height: u32,
8    pub elevation: Vec<f32>,
9    pub maturity: Vec<f32>,
10}
11
12pub fn new_scar_map(w: u32, h: u32) -> ScarMap {
13    let n = (w * h) as usize;
14    ScarMap {
15        width: w,
16        height: h,
17        elevation: vec![0.0; n],
18        maturity: vec![0.0; n],
19    }
20}
21
22fn idx(m: &ScarMap, x: u32, y: u32) -> usize {
23    (y * m.width + x) as usize
24}
25
26pub fn scar_set(m: &mut ScarMap, x: u32, y: u32, elev: f32, maturity: f32) {
27    let i = idx(m, x, y);
28    m.elevation[i] = elev;
29    m.maturity[i] = maturity;
30}
31
32pub fn scar_get(m: &ScarMap, x: u32, y: u32) -> (f32, f32) {
33    let i = idx(m, x, y);
34    (m.elevation[i], m.maturity[i])
35}
36
37pub fn scar_coverage(m: &ScarMap) -> f32 {
38    let total = m.elevation.len();
39    if total == 0 {
40        return 0.0;
41    }
42    let scar = m.elevation.iter().filter(|&&v| v > 0.0).count();
43    scar as f32 / total as f32
44}
45
46pub fn scar_mean_elevation(m: &ScarMap) -> f32 {
47    if m.elevation.is_empty() {
48        return 0.0;
49    }
50    m.elevation.iter().sum::<f32>() / m.elevation.len() as f32
51}
52
53pub fn scar_to_bytes(m: &ScarMap) -> Vec<u8> {
54    m.elevation
55        .iter()
56        .zip(m.maturity.iter())
57        .flat_map(|(&e, &mt)| {
58            let eb = (e.clamp(0.0, 1.0) * 255.0) as u8;
59            let mb = (mt.clamp(0.0, 1.0) * 255.0) as u8;
60            [eb, mb, 0u8, 255u8]
61        })
62        .collect()
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn test_new_scar_map() {
71        /* zeroed */
72        let m = new_scar_map(4, 4);
73        assert_eq!(m.elevation.len(), 16);
74    }
75
76    #[test]
77    fn test_set_get() {
78        /* round-trip */
79        let mut m = new_scar_map(3, 3);
80        scar_set(&mut m, 1, 1, 0.5, 0.8);
81        let (e, mt) = scar_get(&m, 1, 1);
82        assert!((e - 0.5).abs() < 1e-6);
83        assert!((mt - 0.8).abs() < 1e-6);
84    }
85
86    #[test]
87    fn test_coverage_zero() {
88        /* no scars => 0 */
89        let m = new_scar_map(4, 4);
90        assert!((scar_coverage(&m)).abs() < 1e-6);
91    }
92
93    #[test]
94    fn test_coverage_half() {
95        /* half pixels elevated */
96        let mut m = new_scar_map(2, 1);
97        scar_set(&mut m, 0, 0, 0.5, 0.0);
98        assert!((scar_coverage(&m) - 0.5).abs() < 1e-6);
99    }
100
101    #[test]
102    fn test_mean_elevation() {
103        /* mean */
104        let mut m = new_scar_map(2, 1);
105        scar_set(&mut m, 0, 0, 0.0, 0.0);
106        scar_set(&mut m, 1, 0, 1.0, 0.0);
107        assert!((scar_mean_elevation(&m) - 0.5).abs() < 1e-6);
108    }
109
110    #[test]
111    fn test_to_bytes_length() {
112        /* 4 bytes per pixel */
113        let m = new_scar_map(3, 3);
114        let bytes = scar_to_bytes(&m);
115        assert_eq!(bytes.len(), 3 * 3 * 4);
116    }
117}