use crate::gui::editor::state::material_name_from_index;
use indicatrix_cut_core::{FreshDesignSpec, MaterialSelection, PreformSpec};
pub(in crate::gui::editor) fn parse_preform_form(
shape_index: i32,
half_width: &str,
length_over_width: &str,
depth: &str,
cylinder_sides: usize,
) -> Result<PreformSpec, String> {
let half_width: f64 = half_width
.trim()
.parse()
.map_err(|_| format!("Half-width '{}' is not a number.", half_width.trim()))?;
let length_over_width: f64 = length_over_width.trim().parse().map_err(|_| {
format!(
"Length/width '{}' is not a number.",
length_over_width.trim()
)
})?;
let depth: f64 = depth
.trim()
.parse()
.map_err(|_| format!("Depth '{}' is not a number.", depth.trim()))?;
if !(half_width.is_finite() && length_over_width.is_finite() && depth.is_finite())
|| half_width <= 0.0
|| length_over_width <= 0.0
|| depth <= 0.0
{
return Err("Preform dimensions must be positive, finite numbers.".to_string());
}
Ok(if shape_index == 0 {
PreformSpec::block(half_width, length_over_width, depth)
} else {
PreformSpec::cylinder(cylinder_sides, half_width, length_over_width, depth)
})
}
pub(in crate::gui::editor) fn parse_new_design_form(
gear_teeth: i32,
preform: PreformSpec,
symmetry_order_text: &str,
mirror: bool,
material_index: i32,
) -> Result<FreshDesignSpec, String> {
let symmetry_order: u32 = symmetry_order_text.trim().parse().map_err(|_| {
format!(
"Symmetry order '{}' is not a whole number.",
symmetry_order_text.trim()
)
})?;
if symmetry_order < 1 {
return Err("Symmetry order must be a positive whole number.".to_string());
}
Ok(FreshDesignSpec {
gear_teeth,
symmetry_order,
mirror,
material: MaterialSelection {
name: material_name_from_index(material_index),
specific_gravity_override: None,
refractive_index_override: None,
},
preform,
})
}
#[cfg(test)]
mod tests {
use super::*;
use indicatrix_cut_core::PreformShape;
#[test]
fn parse_preform_form_builds_a_block_at_index_zero() {
let preform = parse_preform_form(0, "1.2", "1.5", "0.8", 96).unwrap();
assert_eq!(preform.shape, PreformShape::Block);
assert_eq!(preform.half_width, 1.2);
assert_eq!(preform.length_over_width, 1.5);
assert_eq!(preform.depth, 0.8);
}
#[test]
fn parse_preform_form_builds_a_cylinder_with_the_given_side_count() {
let preform = parse_preform_form(1, "1.0", "1.0", "0.8", 64).unwrap();
assert_eq!(preform.shape, PreformShape::Cylinder { sides: 64 });
}
#[test]
fn parse_preform_form_rejects_zero_or_negative_dimensions() {
assert!(parse_preform_form(0, "0.0", "1.0", "0.8", 96).is_err());
assert!(parse_preform_form(0, "1.0", "-1.0", "0.8", 96).is_err());
assert!(parse_preform_form(0, "1.0", "1.0", "0.0", 96).is_err());
}
#[test]
fn parse_preform_form_rejects_unparseable_text() {
assert!(parse_preform_form(0, "wide", "1.0", "0.8", 96).is_err());
}
#[test]
fn parse_new_design_form_round_trips_gear_symmetry_mirror_and_material() {
let preform = PreformSpec::cylinder(80, 1.5, 1.0, 1.5);
let spec = parse_new_design_form(80, preform, "6", false, 9).unwrap();
assert_eq!(spec.gear_teeth, 80);
assert_eq!(spec.symmetry_order, 6);
assert!(!spec.mirror);
assert_eq!(spec.material.name.as_deref(), Some("Quartz")); assert_eq!(spec.preform.half_width, 1.5);
}
#[test]
fn parse_new_design_form_none_material_index_means_no_material_selected() {
let preform = PreformSpec::cylinder(50, 1.0, 1.0, 1.0);
let spec = parse_new_design_form(50, preform, "8", true, 0).unwrap();
assert_eq!(spec.gear_teeth, 50);
assert_eq!(spec.material.name, None);
}
#[test]
fn parse_new_design_form_rejects_a_non_positive_symmetry_order() {
let preform = PreformSpec::cylinder(96, 1.0, 1.0, 1.0);
assert!(parse_new_design_form(96, preform, "0", true, 0).is_err());
assert!(parse_new_design_form(96, preform, "wide", true, 0).is_err());
}
}