Another project
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 3.6 kB View raw
1use std::path::PathBuf; 2 3use bone_document::{EditOutcome, Sketch, SketchEdit, SketchEntity}; 4use bone_render::{ 5 Camera2, PixelDiff, PixelDiffThreshold, SketchRenderer, SketchScene, Style, decode_png, 6 encode_png, 7}; 8use bone_types::{Point2, Point3, SketchEntityId, SketchPlaneBasis, Tolerance, UnitVec3}; 9 10mod common; 11 12use common::{extent_square as extent, make_context}; 13 14const GOLDEN: &str = "tests/goldens/rectangle_256.png"; 15const UPDATE_ENV: &str = "BONE_UPDATE_RECTANGLE_GOLDEN"; 16const DIFF_TOLERANCE: f64 = 16.0 / 255.0; 17 18fn golden_path() -> PathBuf { 19 PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(GOLDEN) 20} 21 22fn plane() -> SketchPlaneBasis { 23 let Ok(basis) = SketchPlaneBasis::new( 24 Point3::origin(), 25 UnitVec3::x_axis(), 26 UnitVec3::y_axis(), 27 Tolerance::new(1e-9), 28 ) else { 29 panic!("xy plane basis is orthogonal"); 30 }; 31 basis 32} 33 34fn add_point(s: Sketch, x: f64, y: f64) -> (Sketch, SketchEntityId) { 35 let Ok((next, EditOutcome::Entity(id))) = s.apply(SketchEdit::AddEntity(SketchEntity::point( 36 Point2::from_mm(x, y), 37 ))) else { 38 panic!("add point"); 39 }; 40 (next, id) 41} 42 43fn add_line(s: Sketch, a: SketchEntityId, b: SketchEntityId) -> Sketch { 44 let Ok((next, _)) = s.apply(SketchEdit::AddEntity(SketchEntity::line(a, b, false))) else { 45 panic!("add line"); 46 }; 47 next 48} 49 50fn rectangle_scene() -> SketchScene { 51 let s = Sketch::new(plane()); 52 let (s, p0) = add_point(s, -8.0, -5.0); 53 let (s, p1) = add_point(s, 8.0, -5.0); 54 let (s, p2) = add_point(s, 8.0, 5.0); 55 let (s, p3) = add_point(s, -8.0, 5.0); 56 let s = add_line(s, p0, p1); 57 let s = add_line(s, p1, p2); 58 let s = add_line(s, p2, p3); 59 let s = add_line(s, p3, p0); 60 let Ok(scene) = SketchScene::extract(&s) else { 61 panic!("scene extract"); 62 }; 63 scene 64} 65 66#[test] 67fn rectangle_sketch_matches_golden() { 68 let size = extent(256); 69 let ctx = make_context(size); 70 let mut renderer = SketchRenderer::new(ctx.gpu(), ctx.color_format()); 71 let scene = rectangle_scene(); 72 let camera = Camera2::new(size); 73 let style = Style::default(); 74 75 let Ok(frame) = renderer.render(&ctx, &scene, camera, &style) else { 76 panic!("SketchRenderer::render failed"); 77 }; 78 79 let path = golden_path(); 80 81 if std::env::var(UPDATE_ENV).is_ok() { 82 let Ok(bytes) = encode_png(&frame) else { 83 panic!("encode_png failed"); 84 }; 85 if let Some(parent) = path.parent() 86 && let Err(e) = std::fs::create_dir_all(parent) 87 { 88 panic!("create goldens dir {}: {e}", parent.display()); 89 } 90 if let Err(e) = std::fs::write(&path, &bytes) { 91 panic!("write golden {}: {e}", path.display()); 92 } 93 return; 94 } 95 96 let Ok(bytes) = std::fs::read(&path) else { 97 panic!( 98 "golden missing at {}: rerun with {UPDATE_ENV}=1 to generate", 99 path.display() 100 ); 101 }; 102 let Ok((golden_extent, golden_rgba)) = decode_png(&bytes) else { 103 panic!("failed to decode golden PNG"); 104 }; 105 assert_eq!(golden_extent, size, "golden extent drift"); 106 let threshold = PixelDiffThreshold::new(DIFF_TOLERANCE); 107 let Ok(report) = PixelDiff::compare(&frame, &golden_rgba, threshold) else { 108 panic!("PixelDiff rejected inputs"); 109 }; 110 assert!( 111 report.is_clean(), 112 "rectangle render drifted from golden: {} mismatches, worst {:?}, backend {}", 113 report.over_threshold(), 114 report.worst(), 115 frame.backend(), 116 ); 117}