Another project
0

Configure Feed

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

at main 6.2 kB View raw
1use bone_render::PickedItem; 2use bone_types::{SketchDimensionId, SketchEntityId, SketchItemId, SketchRelationId}; 3 4#[derive(Clone, Debug, PartialEq, Eq)] 5pub enum Selection { 6 Entities(Vec<SketchEntityId>), 7 Relation(SketchRelationId), 8 Dimension(SketchDimensionId), 9} 10 11impl Default for Selection { 12 fn default() -> Self { 13 Self::Entities(Vec::new()) 14 } 15} 16 17impl Selection { 18 #[must_use] 19 pub fn entity_ids(&self) -> &[SketchEntityId] { 20 match self { 21 Self::Entities(v) => v, 22 Self::Relation(_) | Self::Dimension(_) => &[], 23 } 24 } 25 26 #[must_use] 27 pub fn is_empty(&self) -> bool { 28 matches!(self, Self::Entities(v) if v.is_empty()) 29 } 30 31 #[must_use] 32 pub fn picked(self, item: Option<SketchItemId>, additive: bool) -> Self { 33 match (item, additive) { 34 (None, false) => Self::default(), 35 (None, true) => self, 36 (Some(SketchItemId::Entity(id)), is_additive) => match self { 37 Self::Entities(v) if is_additive => Self::Entities(toggle(v, id)), 38 _ => Self::Entities(vec![id]), 39 }, 40 (Some(SketchItemId::Relation(id)), _) => Self::Relation(id), 41 (Some(SketchItemId::Dimension(id)), _) => Self::Dimension(id), 42 } 43 } 44} 45 46#[must_use] 47pub fn picked_to_item(picked: PickedItem) -> Option<SketchItemId> { 48 match picked { 49 PickedItem::Point(id) 50 | PickedItem::Line(id) 51 | PickedItem::Arc(id) 52 | PickedItem::Circle(id) => Some(SketchItemId::Entity(id)), 53 PickedItem::Relation(id) => Some(SketchItemId::Relation(id)), 54 PickedItem::Dimension(id) => Some(SketchItemId::Dimension(id)), 55 PickedItem::BrepFace(_) | PickedItem::BrepEdge(_) | PickedItem::BrepVertex(_) => None, 56 } 57} 58 59fn toggle(mut v: Vec<SketchEntityId>, id: SketchEntityId) -> Vec<SketchEntityId> { 60 match v.iter().position(|x| *x == id) { 61 Some(idx) => { 62 v.remove(idx); 63 } 64 None => v.push(id), 65 } 66 v 67} 68 69#[cfg(test)] 70mod tests { 71 use super::*; 72 use crate::sketch_mode::Plane; 73 use crate::tools::add_point; 74 use bone_document::{ 75 DimensionKind, EditOutcome, Sketch, SketchDimension, SketchEdit, SketchRelation, 76 }; 77 use bone_types::{Length, Point2}; 78 use uom::si::length::millimeter; 79 80 fn three_ids() -> (SketchEntityId, SketchEntityId, SketchEntityId) { 81 let s = Sketch::new(Plane::Xy.basis()); 82 let (s, a) = add_point(s, Point2::from_mm(0.0, 0.0)); 83 let (s, b) = add_point(s, Point2::from_mm(1.0, 0.0)); 84 let (_, c) = add_point(s, Point2::from_mm(2.0, 0.0)); 85 (a, b, c) 86 } 87 88 fn rel_id() -> SketchRelationId { 89 let s = Sketch::new(Plane::Xy.basis()); 90 let (s, a) = add_point(s, Point2::from_mm(0.0, 0.0)); 91 let Ok((_, EditOutcome::Relation(id))) = 92 s.apply(SketchEdit::AddRelation(SketchRelation::Fix(a))) 93 else { 94 panic!("expected Relation outcome"); 95 }; 96 id 97 } 98 99 fn dim_id() -> SketchDimensionId { 100 let s = Sketch::new(Plane::Xy.basis()); 101 let (s, a) = add_point(s, Point2::from_mm(0.0, 0.0)); 102 let (s, b) = add_point(s, Point2::from_mm(1.0, 0.0)); 103 let dim = SketchDimension::Linear { 104 a, 105 b, 106 value: Length::new::<millimeter>(1.0), 107 kind: DimensionKind::Driving, 108 }; 109 let Ok((_, EditOutcome::Dimension(id))) = s.apply(SketchEdit::AddDimension(dim)) else { 110 panic!("expected Dimension outcome"); 111 }; 112 id 113 } 114 115 #[test] 116 fn default_selection_is_empty_entities() { 117 assert!(Selection::default().entity_ids().is_empty()); 118 assert!(matches!(Selection::default(), Selection::Entities(_))); 119 } 120 121 #[test] 122 fn pick_replace_entity_overwrites_existing() { 123 let (a, b, _) = three_ids(); 124 let s = Selection::default() 125 .picked(Some(SketchItemId::Entity(a)), false) 126 .picked(Some(SketchItemId::Entity(b)), false); 127 assert_eq!(s.entity_ids(), &[b]); 128 } 129 130 #[test] 131 fn pick_additive_extends_then_toggles_off() { 132 let (a, b, _) = three_ids(); 133 let s = Selection::default() 134 .picked(Some(SketchItemId::Entity(a)), true) 135 .picked(Some(SketchItemId::Entity(b)), true); 136 assert_eq!(s.entity_ids(), &[a, b]); 137 let s = s.picked(Some(SketchItemId::Entity(a)), true); 138 assert_eq!(s.entity_ids(), &[b]); 139 } 140 141 #[test] 142 fn pick_replace_with_none_clears() { 143 let (a, b, _) = three_ids(); 144 let s = Selection::default() 145 .picked(Some(SketchItemId::Entity(a)), true) 146 .picked(Some(SketchItemId::Entity(b)), true) 147 .picked(None, false); 148 assert!(s.entity_ids().is_empty()); 149 } 150 151 #[test] 152 fn pick_additive_with_none_preserves() { 153 let (a, _, _) = three_ids(); 154 let s = Selection::default() 155 .picked(Some(SketchItemId::Entity(a)), true) 156 .picked(None, true); 157 assert_eq!(s.entity_ids(), &[a]); 158 } 159 160 #[test] 161 fn pick_relation_replaces_entities() { 162 let (a, b, _) = three_ids(); 163 let r = rel_id(); 164 let s = Selection::default() 165 .picked(Some(SketchItemId::Entity(a)), true) 166 .picked(Some(SketchItemId::Entity(b)), true) 167 .picked(Some(SketchItemId::Relation(r)), false); 168 assert!(s.entity_ids().is_empty()); 169 assert_eq!(s, Selection::Relation(r)); 170 } 171 172 #[test] 173 fn pick_entity_after_relation_clears_relation() { 174 let (a, _, _) = three_ids(); 175 let r = rel_id(); 176 let s = Selection::default() 177 .picked(Some(SketchItemId::Relation(r)), false) 178 .picked(Some(SketchItemId::Entity(a)), false); 179 assert_eq!(s.entity_ids(), &[a]); 180 } 181 182 #[test] 183 fn pick_dimension_replaces_relation() { 184 let r = rel_id(); 185 let d = dim_id(); 186 let s = Selection::default() 187 .picked(Some(SketchItemId::Relation(r)), false) 188 .picked(Some(SketchItemId::Dimension(d)), false); 189 assert_eq!(s, Selection::Dimension(d)); 190 } 191}