Skip to main content

oxihuman_morph/
scar_tissue_morph.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5//! Scar/keloid surface morph stub.
6
7/// Type of scar.
8#[derive(Debug, Clone, Copy, PartialEq)]
9pub enum ScarType {
10    Atrophic,
11    Hypertrophic,
12    Keloid,
13    Contracture,
14}
15
16/// A single scar region entry.
17#[derive(Debug, Clone)]
18pub struct ScarRegion {
19    pub scar_type: ScarType,
20    pub position: [f32; 3],
21    pub intensity: f32,
22    pub radius: f32,
23}
24
25/// Scar tissue morph controller.
26#[derive(Debug, Clone)]
27pub struct ScarTissueMorph {
28    pub scars: Vec<ScarRegion>,
29    pub global_intensity: f32,
30    pub morph_count: usize,
31    pub enabled: bool,
32}
33
34impl ScarTissueMorph {
35    pub fn new(morph_count: usize) -> Self {
36        ScarTissueMorph {
37            scars: Vec::new(),
38            global_intensity: 1.0,
39            morph_count,
40            enabled: true,
41        }
42    }
43}
44
45/// Create a new scar tissue morph.
46pub fn new_scar_tissue_morph(morph_count: usize) -> ScarTissueMorph {
47    ScarTissueMorph::new(morph_count)
48}
49
50/// Add a scar region.
51pub fn scm_add_scar(morph: &mut ScarTissueMorph, region: ScarRegion) {
52    morph.scars.push(region);
53}
54
55/// Set global intensity.
56pub fn scm_set_intensity(morph: &mut ScarTissueMorph, intensity: f32) {
57    morph.global_intensity = intensity.clamp(0.0, 1.0);
58}
59
60/// Remove all scars.
61pub fn scm_clear(morph: &mut ScarTissueMorph) {
62    morph.scars.clear();
63}
64
65/// Evaluate morph weights (stub: uniform from global_intensity).
66pub fn scm_evaluate(morph: &ScarTissueMorph) -> Vec<f32> {
67    /* Stub: uniform weight from global_intensity */
68    if !morph.enabled || morph.morph_count == 0 {
69        return vec![];
70    }
71    vec![morph.global_intensity; morph.morph_count]
72}
73
74/// Enable or disable.
75pub fn scm_set_enabled(morph: &mut ScarTissueMorph, enabled: bool) {
76    morph.enabled = enabled;
77}
78
79/// Return scar count.
80pub fn scm_scar_count(morph: &ScarTissueMorph) -> usize {
81    morph.scars.len()
82}
83
84/// Serialize to JSON-like string.
85pub fn scm_to_json(morph: &ScarTissueMorph) -> String {
86    format!(
87        r#"{{"scar_count":{},"global_intensity":{},"morph_count":{},"enabled":{}}}"#,
88        morph.scars.len(),
89        morph.global_intensity,
90        morph.morph_count,
91        morph.enabled
92    )
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98
99    fn make_scar(t: ScarType) -> ScarRegion {
100        ScarRegion {
101            scar_type: t,
102            position: [0.0, 0.0, 0.0],
103            intensity: 0.5,
104            radius: 0.1,
105        }
106    }
107
108    #[test]
109    fn test_initial_scar_count() {
110        let m = new_scar_tissue_morph(4);
111        assert_eq!(scm_scar_count(&m), 0 /* no scars initially */);
112    }
113
114    #[test]
115    fn test_add_scar() {
116        let mut m = new_scar_tissue_morph(4);
117        scm_add_scar(&mut m, make_scar(ScarType::Keloid));
118        assert_eq!(scm_scar_count(&m), 1 /* one scar after add */);
119    }
120
121    #[test]
122    fn test_clear_scars() {
123        let mut m = new_scar_tissue_morph(4);
124        scm_add_scar(&mut m, make_scar(ScarType::Atrophic));
125        scm_clear(&mut m);
126        assert_eq!(scm_scar_count(&m), 0 /* scars cleared */);
127    }
128
129    #[test]
130    fn test_set_intensity_clamps() {
131        let mut m = new_scar_tissue_morph(4);
132        scm_set_intensity(&mut m, 1.5);
133        assert!((m.global_intensity - 1.0).abs() < 1e-6 /* intensity clamped to 1.0 */);
134    }
135
136    #[test]
137    fn test_evaluate_length() {
138        let m = new_scar_tissue_morph(5);
139        assert_eq!(
140            scm_evaluate(&m).len(),
141            5 /* output must match morph_count */
142        );
143    }
144
145    #[test]
146    fn test_evaluate_disabled() {
147        let mut m = new_scar_tissue_morph(4);
148        scm_set_enabled(&mut m, false);
149        assert!(scm_evaluate(&m).is_empty() /* disabled must return empty */);
150    }
151
152    #[test]
153    fn test_to_json_has_scar_count() {
154        let m = new_scar_tissue_morph(4);
155        let j = scm_to_json(&m);
156        assert!(j.contains("\"scar_count\"") /* JSON must have scar_count */);
157    }
158
159    #[test]
160    fn test_enabled_default() {
161        let m = new_scar_tissue_morph(4);
162        assert!(m.enabled /* must be enabled by default */);
163    }
164
165    #[test]
166    fn test_evaluate_matches_intensity() {
167        let mut m = new_scar_tissue_morph(3);
168        scm_set_intensity(&mut m, 0.6);
169        let out = scm_evaluate(&m);
170        assert!((out[0] - 0.6).abs() < 1e-5 /* evaluate must match global_intensity */);
171    }
172}