Skip to main content

oxihuman_morph/
temporal_region_morph.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5//! Temporal region shape morph — controls temporal fossa hollowing and width.
6
7/// Temporal region morph configuration.
8#[derive(Debug, Clone)]
9pub struct TemporalRegionMorph {
10    pub hollowing: f32,
11    pub width: f32,
12    pub superior_extent: f32,
13    pub muscle_fullness: f32,
14    pub crest_height: f32,
15}
16
17impl TemporalRegionMorph {
18    pub fn new() -> Self {
19        Self {
20            hollowing: 0.3,
21            width: 0.5,
22            superior_extent: 0.5,
23            muscle_fullness: 0.5,
24            crest_height: 0.4,
25        }
26    }
27}
28
29impl Default for TemporalRegionMorph {
30    fn default() -> Self {
31        Self::new()
32    }
33}
34
35/// Create a new temporal region morph.
36pub fn new_temporal_region_morph() -> TemporalRegionMorph {
37    TemporalRegionMorph::new()
38}
39
40/// Set temporal hollowing (0 = full, 1 = deeply hollow).
41pub fn temp_set_hollowing(m: &mut TemporalRegionMorph, v: f32) {
42    m.hollowing = v.clamp(0.0, 1.0);
43}
44
45/// Set temporal width.
46pub fn temp_set_width(m: &mut TemporalRegionMorph, v: f32) {
47    m.width = v.clamp(0.0, 1.0);
48}
49
50/// Set superior extent toward the temporal line.
51pub fn temp_set_superior_extent(m: &mut TemporalRegionMorph, v: f32) {
52    m.superior_extent = v.clamp(0.0, 1.0);
53}
54
55/// Set temporal muscle fullness.
56pub fn temp_set_muscle_fullness(m: &mut TemporalRegionMorph, v: f32) {
57    m.muscle_fullness = v.clamp(0.0, 1.0);
58}
59
60/// Compute effective temporal volume (accounting for hollowing).
61pub fn temp_effective_volume(m: &TemporalRegionMorph) -> f32 {
62    let raw = m.width * m.muscle_fullness;
63    raw * (1.0 - m.hollowing * 0.7)
64}
65
66/// Serialize to JSON-like string.
67pub fn temporal_region_morph_to_json(m: &TemporalRegionMorph) -> String {
68    format!(
69        r#"{{"hollowing":{:.4},"width":{:.4},"superior_extent":{:.4},"muscle_fullness":{:.4},"crest_height":{:.4}}}"#,
70        m.hollowing, m.width, m.superior_extent, m.muscle_fullness, m.crest_height
71    )
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77
78    #[test]
79    fn test_defaults() {
80        let m = new_temporal_region_morph();
81        assert!((m.hollowing - 0.3).abs() < 1e-6);
82        assert!((m.muscle_fullness - 0.5).abs() < 1e-6);
83    }
84
85    #[test]
86    fn test_hollowing_clamp() {
87        let mut m = new_temporal_region_morph();
88        temp_set_hollowing(&mut m, 3.0);
89        assert_eq!(m.hollowing, 1.0);
90    }
91
92    #[test]
93    fn test_hollowing_set() {
94        let mut m = new_temporal_region_morph();
95        temp_set_hollowing(&mut m, 0.6);
96        assert!((m.hollowing - 0.6).abs() < 1e-6);
97    }
98
99    #[test]
100    fn test_width_clamp_low() {
101        let mut m = new_temporal_region_morph();
102        temp_set_width(&mut m, -1.0);
103        assert_eq!(m.width, 0.0);
104    }
105
106    #[test]
107    fn test_superior_extent_set() {
108        let mut m = new_temporal_region_morph();
109        temp_set_superior_extent(&mut m, 0.8);
110        assert!((m.superior_extent - 0.8).abs() < 1e-6);
111    }
112
113    #[test]
114    fn test_muscle_fullness_set() {
115        let mut m = new_temporal_region_morph();
116        temp_set_muscle_fullness(&mut m, 0.9);
117        assert!((m.muscle_fullness - 0.9).abs() < 1e-6);
118    }
119
120    #[test]
121    fn test_effective_volume_positive() {
122        let m = new_temporal_region_morph();
123        assert!(temp_effective_volume(&m) > 0.0);
124    }
125
126    #[test]
127    fn test_effective_volume_reduces_with_hollowing() {
128        let mut m = new_temporal_region_morph();
129        let v0 = temp_effective_volume(&m);
130        temp_set_hollowing(&mut m, 1.0);
131        let v1 = temp_effective_volume(&m);
132        assert!(v1 < v0);
133    }
134
135    #[test]
136    fn test_json_keys() {
137        let m = new_temporal_region_morph();
138        let s = temporal_region_morph_to_json(&m);
139        assert!(s.contains("crest_height"));
140    }
141
142    #[test]
143    fn test_clone() {
144        let m = new_temporal_region_morph();
145        let m2 = m.clone();
146        assert!((m2.hollowing - m.hollowing).abs() < 1e-6);
147    }
148}