#![allow(dead_code)]
use std::f32::consts::PI;
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq)]
pub struct EyelashDensityParams {
pub upper_count: u32,
pub lower_count: u32,
pub length: f32,
pub curl_angle: f32,
pub thickness: f32,
pub darkness: f32,
}
impl Default for EyelashDensityParams {
fn default() -> Self {
Self {
upper_count: 80,
lower_count: 40,
length: 0.5,
curl_angle: PI / 8.0,
thickness: 0.4,
darkness: 0.9,
}
}
}
#[allow(dead_code)]
pub fn default_eyelash_density_params() -> EyelashDensityParams {
EyelashDensityParams::default()
}
#[allow(dead_code)]
pub fn set_upper_lash_count(params: &mut EyelashDensityParams, count: u32) {
params.upper_count = count.clamp(0, 200);
}
#[allow(dead_code)]
pub fn set_lower_lash_count(params: &mut EyelashDensityParams, count: u32) {
params.lower_count = count.clamp(0, 100);
}
#[allow(dead_code)]
pub fn set_lash_length(params: &mut EyelashDensityParams, value: f32) {
params.length = value.clamp(0.0, 1.0);
}
#[allow(dead_code)]
pub fn set_lash_curl(params: &mut EyelashDensityParams, angle_rad: f32) {
params.curl_angle = angle_rad.clamp(0.0, PI / 2.0);
}
#[allow(dead_code)]
pub fn set_lash_thickness(params: &mut EyelashDensityParams, value: f32) {
params.thickness = value.clamp(0.0, 1.0);
}
#[allow(dead_code)]
pub fn set_lash_darkness(params: &mut EyelashDensityParams, value: f32) {
params.darkness = value.clamp(0.0, 1.0);
}
#[allow(dead_code)]
pub fn total_lash_count(params: &EyelashDensityParams) -> u32 {
(params.upper_count + params.lower_count) * 2
}
#[allow(dead_code)]
pub fn curl_tip_offset(params: &EyelashDensityParams) -> [f32; 2] {
let a = params.curl_angle;
[a.sin() * params.length, (1.0 - a.cos()) * params.length]
}
#[allow(dead_code)]
pub fn blend_eyelash_density(
a: &EyelashDensityParams,
b: &EyelashDensityParams,
t: f32,
) -> EyelashDensityParams {
let t = t.clamp(0.0, 1.0);
let inv = 1.0 - t;
let lerp_u32 = |x: u32, y: u32| -> u32 { (x as f32 * inv + y as f32 * t).round() as u32 };
EyelashDensityParams {
upper_count: lerp_u32(a.upper_count, b.upper_count),
lower_count: lerp_u32(a.lower_count, b.lower_count),
length: a.length * inv + b.length * t,
curl_angle: a.curl_angle * inv + b.curl_angle * t,
thickness: a.thickness * inv + b.thickness * t,
darkness: a.darkness * inv + b.darkness * t,
}
}
#[allow(dead_code)]
pub fn reset_eyelash_density(params: &mut EyelashDensityParams) {
*params = EyelashDensityParams::default();
}
#[allow(dead_code)]
pub fn eyelash_density_to_json(params: &EyelashDensityParams) -> String {
format!(
r#"{{"upper_count":{},"lower_count":{},"length":{:.4},"curl_angle":{:.4},"thickness":{:.4},"darkness":{:.4}}}"#,
params.upper_count,
params.lower_count,
params.length,
params.curl_angle,
params.thickness,
params.darkness
)
}
#[cfg(test)]
mod tests {
use super::*;
use std::f32::consts::PI;
#[test]
fn test_default() {
let p = EyelashDensityParams::default();
assert!(p.upper_count > 0);
assert!(p.lower_count > 0);
}
#[test]
fn test_set_upper_count_clamp() {
let mut p = EyelashDensityParams::default();
set_upper_lash_count(&mut p, 999);
assert!(p.upper_count <= 200);
}
#[test]
fn test_set_length_clamp() {
let mut p = EyelashDensityParams::default();
set_lash_length(&mut p, 5.0);
assert!((p.length - 1.0).abs() < 1e-6);
}
#[test]
fn test_set_curl_clamp() {
let mut p = EyelashDensityParams::default();
set_lash_curl(&mut p, PI * 2.0);
assert!(p.curl_angle <= PI / 2.0 + 1e-5);
}
#[test]
fn test_total_count() {
let p = EyelashDensityParams::default();
let total = total_lash_count(&p);
assert_eq!(total, (p.upper_count + p.lower_count) * 2);
}
#[test]
fn test_curl_tip_straight() {
let mut p = EyelashDensityParams::default();
set_lash_curl(&mut p, 0.0);
let tip = curl_tip_offset(&p);
assert!(tip[0].abs() < 1e-6);
assert!(tip[1].abs() < 1e-6);
}
#[test]
fn test_blend_midpoint() {
let a = EyelashDensityParams {
length: 0.0,
..Default::default()
};
let b = EyelashDensityParams {
length: 1.0,
..Default::default()
};
let r = blend_eyelash_density(&a, &b, 0.5);
assert!((r.length - 0.5).abs() < 1e-6);
}
#[test]
fn test_reset() {
let mut p = EyelashDensityParams {
length: 0.0,
..Default::default()
};
reset_eyelash_density(&mut p);
assert!((p.length - 0.5).abs() < 1e-6);
}
#[test]
fn test_to_json() {
let j = eyelash_density_to_json(&EyelashDensityParams::default());
assert!(j.contains("upper_count"));
assert!(j.contains("darkness"));
}
#[test]
fn test_curl_angle_uses_pi() {
let p = EyelashDensityParams::default();
let _pi_ref = PI;
assert!(p.curl_angle < PI);
}
}