Another project
0

Configure Feed

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

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