use cordial::prelude::*; fn assert_finite(val: f64, label: &str) { assert!(!val.is_nan(), "{label}: got NaN"); assert!(!val.is_infinite(), "{label}: got infinity"); } #[test] fn sphere_through_pipeline() { let s = sphere(2.0); let val_surface = s.eval(2.0, 0.0, 0.0); let val_inside = s.eval(0.0, 0.0, 0.0); let val_outside = s.eval(5.0, 0.0, 0.0); assert_finite(val_surface, "surface"); assert_finite(val_inside, "inside"); assert_finite(val_outside, "outside"); assert!(val_surface.abs() < 1e-6, "surface: expected ~0, got {val_surface}"); assert!(val_inside < 0.0, "inside: expected negative, got {val_inside}"); assert!(val_outside > 0.0, "outside: expected positive, got {val_outside}"); let graph = s.to_trig(); assert!(graph.nodes.len() > 0); let wgsl = s.to_wgsl(); assert!(wgsl.contains("fn scene_sdf")); let cordic = s.to_cordic(); assert!(!cordic.instructions.is_empty()); } #[test] fn complex_csg_through_pipeline() { let body = cube(2.0) .difference(sphere(2.5)) .union(cylinder(0.5, 6.0).rotate_x(90.0)) .translate(1.0, 2.0, 3.0); let test_points: &[(f64, f64, f64)] = &[ (0.0, 0.0, 0.0), (1.0, 2.0, 3.0), (5.0, 5.0, 5.0), (-3.0, -3.0, -3.0), ]; for &(x, y, z) in test_points { let val = body.eval(x, y, z); assert_finite(val, &format!("csg at ({x},{y},{z})")); } let graph = body.to_trig(); assert!(graph.nodes.len() > 10); let wgsl = body.to_wgsl(); assert!(wgsl.contains("fn scene_sdf")); assert!(wgsl.contains("fn fs_main")); let cordic = body.to_cordic(); assert!(!cordic.instructions.is_empty()); } #[test] fn operator_overloads() { let a = sphere(2.0); let b = cube(1.5).translate(1.0, 0.0, 0.0); let union_shape = a.clone() | b.clone(); let inter_shape = a.clone() & b.clone(); let diff_shape = a.clone() - b.clone(); for (label, shape) in [("union", union_shape), ("inter", inter_shape), ("diff", diff_shape)] { let val = shape.eval(0.0, 0.0, 0.0); assert_finite(val, label); let _ = shape.to_wgsl(); let _ = shape.to_cordic(); } } #[test] fn smooth_union_pipeline() { let a = sphere(2.0); let b = sphere(2.0).translate(3.0, 0.0, 0.0); let blended = a.smooth_union(b, 1.0); let midpoint = blended.eval(1.5, 0.0, 0.0); assert_finite(midpoint, "smooth_union midpoint"); assert!(midpoint < 0.0, "smooth_union should blend; midpoint={midpoint}"); let _ = blended.to_wgsl(); let _ = blended.to_cordic(); } #[test] fn variadic_booleans() { let shapes = vec![ sphere(1.0), sphere(1.0).translate(3.0, 0.0, 0.0), sphere(1.0).translate(0.0, 3.0, 0.0), ]; let union_all = Shape::union_all(shapes.clone()); assert!(union_all.eval(0.0, 0.0, 0.0) < 0.0); assert!(union_all.eval(3.0, 0.0, 0.0) < 0.0); assert!(union_all.eval(0.0, 3.0, 0.0) < 0.0); let inter_all = Shape::intersection_all(shapes.clone()); assert!(inter_all.eval(1.5, 1.5, 0.0) > 0.0); let base = sphere(5.0); let diff_all = base.difference_all(shapes); let val = diff_all.eval(0.0, 0.0, 0.0); assert_finite(val, "diff_all origin"); assert!(val > 0.0, "origin should be carved out"); } #[test] fn pattern_linear_array() { let s = sphere(0.5); let arr = pattern::linear_array(&s, 5, [2.0, 0.0, 0.0]); assert!(arr.eval(0.0, 0.0, 0.0) < 0.0); assert!(arr.eval(8.0, 0.0, 0.0) < 0.0); assert!(arr.eval(1.0, 0.0, 0.0) > 0.0); let _ = arr.to_wgsl(); let _ = arr.to_cordic(); } #[test] fn transforms_chain() { let s = sphere(1.0) .rotate_x(45.0) .rotate_y(30.0) .rotate_z(15.0) .scale_uniform(2.0) .translate(5.0, 5.0, 5.0); let val = s.eval(5.0, 5.0, 5.0); assert_finite(val, "center of transformed sphere"); assert!(val < 0.0, "center should be inside; got {val}"); let _ = s.to_wgsl(); let _ = s.to_cordic(); }