geop_ops_model/notes.rs
1//! What a step says of a solid it built beyond its shape, kept as the
2//! part's target [`solid_notes`]: a solid only drawn, which is no body (a
3//! harness' swept bundle), the thickness of a sheet-metal body, the wires
4//! ordered in a bundle's place. Whoever weighs, checks or orders a part
5//! reads them here, knowing no step that writes them.
6
7use std::collections::BTreeMap;
8
9use geop_core_math::scalars::Scalar;
10use geop_core_program::{
11 element::{ElementReference, HasElements, Kind, whole},
12 reader::Reader,
13 target::{Target, TargetReference},
14};
15
16/// What a step says of a solid it built beyond its shape (see
17/// [`solid_notes`]).
18#[derive(Clone, Debug, Default, PartialEq)]
19pub struct SolidNote {
20 /// Whether it only shows something that is no body — a harness'
21 /// swept bundle — so that it is neither weighed, checked for
22 /// interference nor ordered as one .
23 pub drawn_only: bool,
24 /// The thickness of the sheet it is bent from (mm), for a sheet-metal
25 /// body or a flat pattern of one.
26 pub thickness: Option<f64>,
27 /// The wires ordered in its place, each cut to length: a harness'.
28 pub wires: Vec<CutWire>,
29}
30
31/// A wire cut to length, as a bill of materials orders it.
32#[derive(Clone, Debug, PartialEq)]
33pub struct CutWire {
34 pub name: String,
35 /// Its colour, `#rrggbb`.
36 pub colour: String,
37 /// Its outer diameter, insulation included.
38 pub diameter: f64,
39 /// Its American wire gauge, if it was given by one.
40 pub gauge: Option<i32>,
41 /// The length to cut it to. An enclosure, as every measured length is.
42 pub cut_length: Scalar,
43}
44
45/// What the steps of a part said of its solids, by the solids' names: the
46/// value of its target [`solid_notes`], which every step that says
47/// something of a solid it built revises.
48#[derive(Clone, Debug, Default, PartialEq)]
49pub struct SolidNotes(BTreeMap<String, SolidNote>);
50
51/// What the steps of the part said of its solids.
52pub fn solid_notes() -> TargetReference<SolidNotes> {
53 TargetReference::new("solid_notes")
54}
55
56impl SolidNotes {
57 /// The note on the solid `solid`, made empty if there is none yet.
58 pub fn note_mut(&mut self, solid: impl Into<String>) -> &mut SolidNote {
59 self.0.entry(solid.into()).or_default()
60 }
61
62 /// Forgets the note on the solid `solid`: one a step consumed.
63 pub fn remove(&mut self, solid: &str) {
64 self.0.remove(solid);
65 }
66
67 /// The note on the solid `solid`, if there is one.
68 pub fn get(&self, solid: &str) -> Option<&SolidNote> {
69 self.0.get(solid)
70 }
71
72 /// Every note, by its solid's name, in the order of the names.
73 pub fn iter(&self) -> impl Iterator<Item = (&str, &SolidNote)> {
74 self.0.iter().map(|(name, note)| (name.as_str(), note))
75 }
76}
77
78/// Every step that says something of a solid adds to them.
79impl Target for SolidNotes {
80 const CHAIN: bool = true;
81}
82
83/// Read whole.
84impl Kind for SolidNotes {
85 const NAME: &'static str = "solid_notes";
86}
87
88impl HasElements<SolidNotes> for SolidNotes {
89 type Element<'a> = &'a SolidNotes;
90 const SINGLETON: Option<&'static str> = Some("solid_notes");
91
92 fn element(&self, name: &str) -> geop_core_math::geop_error::GeopResult<&SolidNotes> {
93 whole(self, name)
94 }
95}
96
97/// What the steps of the part `reader` reads said of its solids: nothing,
98/// if none said anything.
99pub fn notes_of<'a>(reader: &Reader<'a>) -> Option<&'a SolidNotes> {
100 reader.defines(&solid_notes()).then_some(())?;
101 reader
102 .retrieve_element(&ElementReference::<SolidNotes, SolidNotes>::whole(
103 solid_notes(),
104 ))
105 .ok()
106}