pub fn minimum_blank_size(
effective_diameter_mm: f64,
eyesize_mm: f64,
bridge_mm: f64,
ipd_mm: f64,
) -> f64 {
debug_assert!(effective_diameter_mm >= 0.0, "effective_diameter_mm must be non-negative");
debug_assert!(eyesize_mm >= 0.0, "eyesize_mm must be non-negative");
debug_assert!(bridge_mm >= 0.0, "bridge_mm must be non-negative");
debug_assert!(ipd_mm >= 0.0, "ipd_mm must be non-negative");
effective_diameter_mm + (eyesize_mm + bridge_mm - ipd_mm)
}
pub fn recommended_blank_size(
effective_diameter_mm: f64,
eyesize_mm: f64,
bridge_mm: f64,
ipd_mm: f64,
) -> f64 {
minimum_blank_size(effective_diameter_mm, eyesize_mm, bridge_mm, ipd_mm) + 2.0
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_abs_diff_eq;
const EPS: f64 = 1e-9;
#[test]
fn minimum_blank_size_standard_example() {
let result = minimum_blank_size(55.0, 50.0, 15.0, 53.0);
assert_abs_diff_eq!(result, 67.0, epsilon = EPS);
}
#[test]
fn minimum_blank_size_formula_verification() {
let effective_diameter = 60.0;
let eyesize = 48.0;
let bridge = 18.0;
let ipd = 62.0;
let result = minimum_blank_size(effective_diameter, eyesize, bridge, ipd);
let expected = effective_diameter + (eyesize + bridge - ipd);
assert_abs_diff_eq!(result, expected, epsilon = EPS);
assert_abs_diff_eq!(result, 64.0, epsilon = EPS); }
#[test]
fn minimum_blank_size_large_frame() {
let result = minimum_blank_size(70.0, 60.0, 20.0, 65.0);
assert_abs_diff_eq!(result, 85.0, epsilon = EPS); }
#[test]
fn minimum_blank_size_small_frame() {
let result = minimum_blank_size(45.0, 40.0, 12.0, 50.0);
assert_abs_diff_eq!(result, 47.0, epsilon = EPS); }
#[test]
fn minimum_blank_size_zero_components() {
let result = minimum_blank_size(0.0, 50.0, 15.0, 53.0);
assert_abs_diff_eq!(result, 12.0, epsilon = EPS); }
#[test]
fn minimum_blank_size_negative_decentration() {
let result = minimum_blank_size(55.0, 45.0, 10.0, 60.0);
assert_abs_diff_eq!(result, 50.0, epsilon = EPS); }
#[test]
fn recommended_blank_size_adds_working_edge() {
let min_size = minimum_blank_size(55.0, 50.0, 15.0, 53.0);
let recommended = recommended_blank_size(55.0, 50.0, 15.0, 53.0);
assert_abs_diff_eq!(recommended, min_size + 2.0, epsilon = EPS);
assert_abs_diff_eq!(recommended, 69.0, epsilon = EPS);
}
#[test]
fn recommended_blank_size_consistency() {
let effective_diameter = 60.0;
let eyesize = 48.0;
let bridge = 18.0;
let ipd = 62.0;
let recommended = recommended_blank_size(effective_diameter, eyesize, bridge, ipd);
let manual = minimum_blank_size(effective_diameter, eyesize, bridge, ipd) + 2.0;
assert_abs_diff_eq!(recommended, manual, epsilon = EPS);
}
#[test]
fn minimum_blank_size_precision() {
let result = minimum_blank_size(55.5, 50.25, 15.75, 53.5);
let expected = 55.5 + (50.25 + 15.75 - 53.5);
assert_abs_diff_eq!(result, expected, epsilon = EPS);
assert_abs_diff_eq!(result, 68.0, epsilon = EPS);
}
#[test]
#[should_panic(expected = "effective_diameter_mm must be non-negative")]
fn minimum_blank_size_panics_negative_effective_diameter() {
let _ = minimum_blank_size(-1.0, 50.0, 15.0, 53.0);
}
#[test]
#[should_panic(expected = "eyesize_mm must be non-negative")]
fn minimum_blank_size_panics_negative_eyesize() {
let _ = minimum_blank_size(55.0, -1.0, 15.0, 53.0);
}
#[test]
#[should_panic(expected = "bridge_mm must be non-negative")]
fn minimum_blank_size_panics_negative_bridge() {
let _ = minimum_blank_size(55.0, 50.0, -1.0, 53.0);
}
#[test]
#[should_panic(expected = "ipd_mm must be non-negative")]
fn minimum_blank_size_panics_negative_ipd() {
let _ = minimum_blank_size(55.0, 50.0, 15.0, -1.0);
}
#[test]
fn minimum_blank_size_edge_case_zero_ipd() {
let result = minimum_blank_size(55.0, 50.0, 15.0, 0.0);
assert_abs_diff_eq!(result, 120.0, epsilon = EPS); }
#[test]
fn minimum_blank_size_edge_case_zero_eyesize_and_bridge() {
let result = minimum_blank_size(55.0, 0.0, 0.0, 53.0);
assert_abs_diff_eq!(result, 2.0, epsilon = EPS); }
}