#![allow(dead_code)]
use std::f32::consts::PI;
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq)]
pub struct PupilSizeParams {
pub dilation_l: f32,
pub dilation_r: f32,
pub min_radius: f32,
pub max_radius: f32,
}
impl Default for PupilSizeParams {
fn default() -> Self {
Self {
dilation_l: 0.4,
dilation_r: 0.4,
min_radius: 0.15,
max_radius: 0.85,
}
}
}
#[allow(dead_code)]
pub fn default_pupil_size_params() -> PupilSizeParams {
PupilSizeParams::default()
}
#[allow(dead_code)]
pub fn pupil_radius_fraction(dilation: f32, params: &PupilSizeParams) -> f32 {
let d = dilation.clamp(0.0, 1.0);
params.min_radius + (params.max_radius - params.min_radius) * d
}
#[allow(dead_code)]
pub fn set_pupil_dilation_left(params: &mut PupilSizeParams, value: f32) {
params.dilation_l = value.clamp(0.0, 1.0);
}
#[allow(dead_code)]
pub fn set_pupil_dilation_right(params: &mut PupilSizeParams, value: f32) {
params.dilation_r = value.clamp(0.0, 1.0);
}
#[allow(dead_code)]
pub fn set_pupil_dilation_both(params: &mut PupilSizeParams, value: f32) {
let v = value.clamp(0.0, 1.0);
params.dilation_l = v;
params.dilation_r = v;
}
#[allow(dead_code)]
pub fn pupil_from_light(luminance: f32) -> f32 {
let l = luminance.clamp(0.0, 1.0);
let t = 1.0 - l;
t * t * (3.0 - 2.0 * t)
}
#[allow(dead_code)]
pub fn pupil_area_fraction(dilation: f32, params: &PupilSizeParams) -> f32 {
let r = pupil_radius_fraction(dilation, params);
r * r
}
#[allow(dead_code)]
pub fn pupil_asymmetry(params: &PupilSizeParams) -> f32 {
(params.dilation_l - params.dilation_r).abs()
}
#[allow(dead_code)]
pub fn blend_pupil_size(a: &PupilSizeParams, b: &PupilSizeParams, t: f32) -> PupilSizeParams {
let t = t.clamp(0.0, 1.0);
let inv = 1.0 - t;
PupilSizeParams {
dilation_l: a.dilation_l * inv + b.dilation_l * t,
dilation_r: a.dilation_r * inv + b.dilation_r * t,
min_radius: a.min_radius * inv + b.min_radius * t,
max_radius: a.max_radius * inv + b.max_radius * t,
}
}
#[allow(dead_code)]
pub fn reset_pupil_size(params: &mut PupilSizeParams) {
*params = PupilSizeParams::default();
}
#[allow(dead_code)]
pub fn pupil_size_to_json(params: &PupilSizeParams) -> String {
format!(
r#"{{"dilation_l":{:.4},"dilation_r":{:.4},"min_radius":{:.4},"max_radius":{:.4}}}"#,
params.dilation_l, params.dilation_r, params.min_radius, params.max_radius
)
}
#[allow(dead_code)]
pub fn pupil_circumference_ratio(dilation: f32, params: &PupilSizeParams) -> f32 {
let r = pupil_radius_fraction(dilation, params);
2.0 * PI * r
}
#[cfg(test)]
mod tests {
use super::*;
use std::f32::consts::PI;
#[test]
fn test_default_valid() {
let p = PupilSizeParams::default();
assert!((0.0..=1.0).contains(&p.dilation_l));
assert!((0.0..=1.0).contains(&p.dilation_r));
}
#[test]
fn test_radius_fraction_min() {
let p = PupilSizeParams::default();
let r = pupil_radius_fraction(0.0, &p);
assert!((r - p.min_radius).abs() < 1e-6);
}
#[test]
fn test_radius_fraction_max() {
let p = PupilSizeParams::default();
let r = pupil_radius_fraction(1.0, &p);
assert!((r - p.max_radius).abs() < 1e-6);
}
#[test]
fn test_set_dilation_left_clamp() {
let mut p = PupilSizeParams::default();
set_pupil_dilation_left(&mut p, 5.0);
assert!((p.dilation_l - 1.0).abs() < 1e-6);
}
#[test]
fn test_set_dilation_both() {
let mut p = PupilSizeParams::default();
set_pupil_dilation_both(&mut p, 0.7);
assert!((p.dilation_l - 0.7).abs() < 1e-6);
assert!((p.dilation_r - 0.7).abs() < 1e-6);
}
#[test]
fn test_from_light_dark() {
let d = pupil_from_light(0.0);
assert!((d - 1.0).abs() < 1e-6);
}
#[test]
fn test_from_light_bright() {
let d = pupil_from_light(1.0);
assert!(d.abs() < 1e-6);
}
#[test]
fn test_area_fraction_positive() {
let p = PupilSizeParams::default();
let a = pupil_area_fraction(0.5, &p);
assert!(a > 0.0);
}
#[test]
fn test_blend_midpoint() {
let a = PupilSizeParams {
dilation_l: 0.0,
..Default::default()
};
let b = PupilSizeParams {
dilation_l: 1.0,
..Default::default()
};
let r = blend_pupil_size(&a, &b, 0.5);
assert!((r.dilation_l - 0.5).abs() < 1e-6);
}
#[test]
fn test_circumference_uses_pi() {
let p = PupilSizeParams::default();
let c = pupil_circumference_ratio(1.0, &p);
assert!((c - 2.0 * PI * p.max_radius).abs() < 1e-5);
}
}