#![allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ScalpRegion {
Frontal,
Parietal,
Temporal,
Occipital,
Crown,
}
#[derive(Debug, Clone)]
pub struct HairFollicleDensity {
pub global_density: f32,
pub region_densities: Vec<(ScalpRegion, f32)>,
pub miniaturization: f32,
pub morph_count: usize,
pub enabled: bool,
}
impl HairFollicleDensity {
pub fn new(morph_count: usize) -> Self {
HairFollicleDensity {
global_density: 0.8,
region_densities: Vec::new(),
miniaturization: 0.0,
morph_count,
enabled: true,
}
}
}
pub fn new_hair_follicle_density(morph_count: usize) -> HairFollicleDensity {
HairFollicleDensity::new(morph_count)
}
pub fn hfd_set_density(ctrl: &mut HairFollicleDensity, density: f32) {
ctrl.global_density = density.clamp(0.0, 1.0);
}
pub fn hfd_set_region(ctrl: &mut HairFollicleDensity, region: ScalpRegion, density: f32) {
let v = density.clamp(0.0, 1.0);
if let Some(e) = ctrl.region_densities.iter_mut().find(|(r, _)| *r == region) {
e.1 = v;
} else {
ctrl.region_densities.push((region, v));
}
}
pub fn hfd_set_miniaturization(ctrl: &mut HairFollicleDensity, value: f32) {
ctrl.miniaturization = value.clamp(0.0, 1.0);
}
pub fn hfd_evaluate(ctrl: &HairFollicleDensity) -> Vec<f32> {
if !ctrl.enabled || ctrl.morph_count == 0 {
return vec![];
}
let w = ctrl.global_density * (1.0 - ctrl.miniaturization);
vec![w; ctrl.morph_count]
}
pub fn hfd_set_enabled(ctrl: &mut HairFollicleDensity, enabled: bool) {
ctrl.enabled = enabled;
}
pub fn hfd_region_count(ctrl: &HairFollicleDensity) -> usize {
ctrl.region_densities.len()
}
pub fn hfd_to_json(ctrl: &HairFollicleDensity) -> String {
format!(
r#"{{"global_density":{},"miniaturization":{},"morph_count":{},"enabled":{}}}"#,
ctrl.global_density, ctrl.miniaturization, ctrl.morph_count, ctrl.enabled
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_density() {
let c = new_hair_follicle_density(4);
assert!((c.global_density - 0.8).abs() < 1e-6 );
}
#[test]
fn test_set_density_clamps() {
let mut c = new_hair_follicle_density(4);
hfd_set_density(&mut c, 2.0);
assert!((c.global_density - 1.0).abs() < 1e-6 );
}
#[test]
fn test_region_added() {
let mut c = new_hair_follicle_density(4);
hfd_set_region(&mut c, ScalpRegion::Frontal, 0.5);
assert_eq!(hfd_region_count(&c), 1 );
}
#[test]
fn test_miniaturization_clamped() {
let mut c = new_hair_follicle_density(4);
hfd_set_miniaturization(&mut c, -0.3);
assert!((c.miniaturization).abs() < 1e-6 );
}
#[test]
fn test_evaluate_length() {
let c = new_hair_follicle_density(5);
assert_eq!(
hfd_evaluate(&c).len(),
5
);
}
#[test]
fn test_evaluate_disabled() {
let mut c = new_hair_follicle_density(4);
hfd_set_enabled(&mut c, false);
assert!(hfd_evaluate(&c).is_empty() );
}
#[test]
fn test_evaluate_product() {
let mut c = new_hair_follicle_density(2);
hfd_set_density(&mut c, 0.8);
hfd_set_miniaturization(&mut c, 0.5);
let out = hfd_evaluate(&c);
assert!((out[0] - 0.4).abs() < 1e-5 );
}
#[test]
fn test_to_json_has_fields() {
let c = new_hair_follicle_density(4);
let j = hfd_to_json(&c);
assert!(j.contains("\"global_density\"") );
}
#[test]
fn test_enabled_default() {
let c = new_hair_follicle_density(4);
assert!(c.enabled );
}
#[test]
fn test_no_miniaturization_default() {
let c = new_hair_follicle_density(4);
assert!((c.miniaturization).abs() < 1e-6 );
}
}