#![allow(dead_code)]
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq)]
pub struct ToothShapeParams {
pub width: f32,
pub height: f32,
pub rounding: f32,
pub overbite: f32,
pub crowding: f32,
pub whiteness: f32,
pub translucency: f32,
}
impl Default for ToothShapeParams {
fn default() -> Self {
Self {
width: 0.5,
height: 0.5,
rounding: 0.4,
overbite: 0.2,
crowding: 0.0,
whiteness: 0.8,
translucency: 0.2,
}
}
}
#[allow(dead_code)]
pub fn default_tooth_shape_params() -> ToothShapeParams {
ToothShapeParams::default()
}
#[allow(dead_code)]
pub fn set_tooth_width(params: &mut ToothShapeParams, value: f32) {
params.width = value.clamp(0.0, 1.0);
}
#[allow(dead_code)]
pub fn set_tooth_height(params: &mut ToothShapeParams, value: f32) {
params.height = value.clamp(0.0, 1.0);
}
#[allow(dead_code)]
pub fn set_tooth_rounding(params: &mut ToothShapeParams, value: f32) {
params.rounding = value.clamp(0.0, 1.0);
}
#[allow(dead_code)]
pub fn set_tooth_overbite(params: &mut ToothShapeParams, value: f32) {
params.overbite = value.clamp(0.0, 1.0);
}
#[allow(dead_code)]
pub fn set_tooth_crowding(params: &mut ToothShapeParams, value: f32) {
params.crowding = value.clamp(0.0, 1.0);
}
#[allow(dead_code)]
pub fn set_tooth_whiteness(params: &mut ToothShapeParams, value: f32) {
params.whiteness = value.clamp(0.0, 1.0);
}
#[allow(dead_code)]
pub fn tooth_color_rgb(params: &ToothShapeParams) -> [f32; 3] {
let w = params.whiteness.clamp(0.0, 1.0);
let t = params.translucency.clamp(0.0, 1.0);
let r = 0.85 + w * 0.12;
let g = 0.80 + w * 0.10 - t * 0.03;
let b = 0.70 + w * 0.08 - t * 0.05;
[r.clamp(0.0, 1.0), g.clamp(0.0, 1.0), b.clamp(0.0, 1.0)]
}
#[allow(dead_code)]
pub fn blend_tooth_shape(a: &ToothShapeParams, b: &ToothShapeParams, t: f32) -> ToothShapeParams {
let t = t.clamp(0.0, 1.0);
let inv = 1.0 - t;
ToothShapeParams {
width: a.width * inv + b.width * t,
height: a.height * inv + b.height * t,
rounding: a.rounding * inv + b.rounding * t,
overbite: a.overbite * inv + b.overbite * t,
crowding: a.crowding * inv + b.crowding * t,
whiteness: a.whiteness * inv + b.whiteness * t,
translucency: a.translucency * inv + b.translucency * t,
}
}
#[allow(dead_code)]
pub fn reset_tooth_shape(params: &mut ToothShapeParams) {
*params = ToothShapeParams::default();
}
#[allow(dead_code)]
pub fn tooth_shape_to_json(params: &ToothShapeParams) -> String {
format!(
r#"{{"width":{:.4},"height":{:.4},"rounding":{:.4},"overbite":{:.4},"crowding":{:.4},"whiteness":{:.4}}}"#,
params.width,
params.height,
params.rounding,
params.overbite,
params.crowding,
params.whiteness
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default() {
let p = ToothShapeParams::default();
assert!((0.0..=1.0).contains(&p.width));
}
#[test]
fn test_set_width_clamp() {
let mut p = ToothShapeParams::default();
set_tooth_width(&mut p, 5.0);
assert!((p.width - 1.0).abs() < 1e-6);
}
#[test]
fn test_set_height_clamp() {
let mut p = ToothShapeParams::default();
set_tooth_height(&mut p, -1.0);
assert!(p.height.abs() < 1e-6);
}
#[test]
fn test_set_rounding() {
let mut p = ToothShapeParams::default();
set_tooth_rounding(&mut p, 0.9);
assert!((p.rounding - 0.9).abs() < 1e-6);
}
#[test]
fn test_set_whiteness() {
let mut p = ToothShapeParams::default();
set_tooth_whiteness(&mut p, 0.3);
assert!((p.whiteness - 0.3).abs() < 1e-6);
}
#[test]
fn test_tooth_color_bright() {
let p = ToothShapeParams {
whiteness: 1.0,
translucency: 0.0,
..Default::default()
};
let c = tooth_color_rgb(&p);
assert!(c[0] > 0.9);
}
#[test]
fn test_tooth_color_range() {
let p = ToothShapeParams::default();
let c = tooth_color_rgb(&p);
for ch in c {
assert!((0.0..=1.0).contains(&ch));
}
}
#[test]
fn test_blend_midpoint() {
let a = ToothShapeParams {
width: 0.0,
..Default::default()
};
let b = ToothShapeParams {
width: 1.0,
..Default::default()
};
let r = blend_tooth_shape(&a, &b, 0.5);
assert!((r.width - 0.5).abs() < 1e-6);
}
#[test]
fn test_reset() {
let mut p = ToothShapeParams {
whiteness: 0.1,
..Default::default()
};
reset_tooth_shape(&mut p);
assert!((p.whiteness - 0.8).abs() < 1e-6);
}
#[test]
fn test_to_json() {
let j = tooth_shape_to_json(&ToothShapeParams::default());
assert!(j.contains("whiteness"));
assert!(j.contains("crowding"));
}
}