Another project
0

Configure Feed

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

at main 4.5 kB View raw
1use bone_kernel::{BrepReattach, BrepSolid}; 2use bone_types::SolidKey; 3use serde::{Deserialize, Serialize}; 4 5use super::ron_io::{self, RonError}; 6 7#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] 8#[serde(deny_unknown_fields)] 9pub struct LabelSidecar { 10 solid: SolidKey, 11 reattach: BrepReattach, 12} 13 14impl LabelSidecar { 15 #[must_use] 16 pub fn capture(solid: &BrepSolid) -> Self { 17 Self { 18 solid: solid.content_key(), 19 reattach: solid.reattach_data().clone(), 20 } 21 } 22 23 #[must_use] 24 pub fn solid(&self) -> SolidKey { 25 self.solid 26 } 27 28 #[must_use] 29 pub fn reattach(&self) -> &BrepReattach { 30 &self.reattach 31 } 32 33 #[must_use] 34 pub fn matches(&self, key: SolidKey) -> bool { 35 self.solid == key 36 } 37 38 pub fn to_ron(&self) -> Result<String, RonError> { 39 ron_io::to_string(self) 40 } 41 42 pub fn from_ron(text: &str) -> Result<Self, RonError> { 43 ron_io::from_str(text) 44 } 45} 46 47#[cfg(test)] 48mod tests { 49 use super::LabelSidecar; 50 use bone_types::SolidKey; 51 52 fn cube() -> bone_kernel::BrepSolid { 53 use bone_kernel::{ 54 Curve2Kind, ExtrudeDirection, ExtrudeEndCondition, ExtrudeFeature, ExtrudeProfile, 55 ExtrudeSense, Line2, MergeResult, ProfileEdge, ProfileLoop, evaluate_extrude, 56 }; 57 use bone_types::{ 58 FeatureId, Length, Plane3, Point2, PositiveLength, SketchEntityId, SketchId, Tolerance, 59 UnitVec3, millimeter, 60 }; 61 use slotmap::{Key, SlotMap}; 62 63 let tol = Tolerance::new(1.0e-9); 64 let mut entities: SlotMap<SketchEntityId, ()> = SlotMap::with_key(); 65 let mut features: SlotMap<FeatureId, ()> = SlotMap::with_key(); 66 let point = |x: f64, y: f64| Point2::from_mm(x, y); 67 let line = |a: Point2, b: Point2| { 68 let Ok(segment) = Line2::new(a, b, tol) else { 69 panic!("distinct endpoints"); 70 }; 71 Curve2Kind::Line(segment) 72 }; 73 let corners = [ 74 point(0.0, 0.0), 75 point(2.0, 0.0), 76 point(2.0, 3.0), 77 point(0.0, 3.0), 78 ]; 79 let edges = (0..4) 80 .map(|index| { 81 ProfileEdge::new( 82 line(corners[index], corners[(index + 1) % 4]), 83 entities.insert(()), 84 entities.insert(()), 85 ) 86 }) 87 .collect(); 88 let Ok(plane) = Plane3::new( 89 bone_types::Point3::origin(), 90 UnitVec3::x_axis(), 91 UnitVec3::y_axis(), 92 tol, 93 ) else { 94 panic!("orthonormal axes"); 95 }; 96 let profile = ExtrudeProfile::new(plane, vec![ProfileLoop::Open(edges)]); 97 let Ok(depth) = PositiveLength::new(Length::new::<millimeter>(5.0)) else { 98 panic!("positive depth"); 99 }; 100 let feature = ExtrudeFeature { 101 sketch: SketchId::null(), 102 direction: ExtrudeDirection::Normal { 103 sense: ExtrudeSense::Forward, 104 }, 105 end_condition: ExtrudeEndCondition::Blind { depth }, 106 draft: None, 107 thin_wall: None, 108 merge_result: MergeResult::Merge, 109 }; 110 let Ok(solid) = evaluate_extrude(features.insert(()), &profile, &feature) else { 111 panic!("cube extrudes"); 112 }; 113 solid 114 } 115 116 #[test] 117 fn ron_round_trips() { 118 let solid = cube(); 119 let sidecar = LabelSidecar::capture(&solid); 120 let Ok(text) = sidecar.to_ron() else { 121 panic!("serialize sidecar"); 122 }; 123 let Ok(back) = LabelSidecar::from_ron(&text) else { 124 panic!("deserialize sidecar"); 125 }; 126 assert_eq!(sidecar, back); 127 } 128 129 #[test] 130 fn matches_only_its_own_solid() { 131 let solid = cube(); 132 let sidecar = LabelSidecar::capture(&solid); 133 assert!(sidecar.matches(solid.content_key())); 134 assert!(!sidecar.matches(SolidKey::from_bytes([0u8; 16]))); 135 } 136 137 #[test] 138 fn reattach_payload_round_trips_a_solid() { 139 let solid = cube(); 140 let sidecar = LabelSidecar::capture(&solid); 141 let Ok(blob) = solid.to_blob() else { 142 panic!("blob serializes"); 143 }; 144 let Ok(restored) = bone_kernel::BrepSolid::from_blob(&blob, sidecar.reattach()) else { 145 panic!("sidecar reattaches"); 146 }; 147 assert_eq!(sidecar.solid(), restored.content_key()); 148 } 149}