brep_kernel/feature_pipeline/pmi/annotations/
mod.rs1pub mod balloon;
8pub mod angle;
9pub mod datum;
10pub mod explode;
11pub mod fcf;
12pub mod hole_callout;
13pub mod leader;
14pub mod linear;
15pub mod note;
16pub mod radial;
17
18use super::{PmiAnnotation, PmiContext, Resolved};
19use crate::feature_pipeline::SelectionProbe;
20use serde_json::{Map, Value};
21
22pub struct PmiTypeDef {
24 pub type_id: &'static str,
26 pub short_name: &'static str,
28 pub icon: &'static str,
32 pub long_name: &'static str,
34 pub label: &'static str,
36 pub applicable: fn(&SelectionProbe) -> bool,
38 pub schema: fn() -> Value,
41 pub resolve: fn(&PmiAnnotation, &PmiContext<'_>) -> Result<Resolved, String>,
43}
44
45pub const PMI_TYPES: [PmiTypeDef; 10] = [
47 linear::DEF,
48 radial::DEF,
49 angle::DEF,
50 leader::DEF,
51 balloon::DEF,
52 note::DEF,
53 hole_callout::DEF,
54 datum::DEF,
55 fcf::DEF,
56 explode::DEF,
57];
58
59pub fn pmi_type(type_id: &str) -> Option<&'static PmiTypeDef> {
61 PMI_TYPES.iter().find(|def| def.type_id == type_id)
62}
63
64pub fn pmi_schema_catalogue() -> Value {
66 Value::Array(PMI_TYPES.iter().map(|def| (def.schema)()).collect())
67}
68
69pub(super) fn id_field() -> Value {
72 serde_json::json!({
73 "type": "string",
74 "default_value": null,
75 "hint": "Unique identifier for the annotation"
76 })
77}
78
79pub(super) fn reference_field(
80 label: &str,
81 filter: &[&str],
82 multiple: bool,
83 min: usize,
84 max: usize,
85 hint: &str,
86) -> Value {
87 serde_json::json!({
88 "type": "reference_selection",
89 "label": label,
90 "selectionFilter": filter,
91 "multiple": multiple,
92 "minSelections": min,
93 "maxSelections": max,
94 "default_value": null,
95 "hint": hint
96 })
97}
98
99pub(super) fn number_field(label: &str, default: f64, step: f64, hint: &str) -> Value {
100 serde_json::json!({
101 "type": "number",
102 "label": label,
103 "default_value": default,
104 "step": step,
105 "hint": hint
106 })
107}
108
109pub(super) fn boolean_field(label: &str, default: bool, hint: &str) -> Value {
110 serde_json::json!({
111 "type": "boolean",
112 "label": label,
113 "default_value": default,
114 "hint": hint
115 })
116}
117
118pub(super) fn string_field(label: &str, default: &str, hint: &str) -> Value {
119 serde_json::json!({
120 "type": "string",
121 "label": label,
122 "default_value": default,
123 "hint": hint
124 })
125}
126
127pub(super) fn options_field(label: &str, options: &[&str], default: &str, hint: &str) -> Value {
128 serde_json::json!({
129 "type": "options",
130 "label": label,
131 "options": options,
132 "default_value": default,
133 "hint": hint
134 })
135}
136
137pub(super) fn dimension_fields(params: &mut Map<String, Value>, decimals_default: u64) {
140 params.insert(
141 "decimals".into(),
142 serde_json::json!({
143 "type": "number",
144 "label": "Decimals",
145 "default_value": decimals_default,
146 "step": 1,
147 "hint": "Decimal places shown (0–8)"
148 }),
149 );
150 params.insert(
151 "isReference".into(),
152 boolean_field("Reference", false, "A reference dimension: shown in parentheses, no tolerance"),
153 );
154 params.insert(
155 "tolMode".into(),
156 options_field(
157 "Tolerance",
158 &["none", "symmetric", "deviation", "limits"],
159 "none",
160 "none · ± symmetric · +upper/−lower deviation · upper/lower limit values",
161 ),
162 );
163 params.insert(
164 "tolUpper".into(),
165 number_field("Upper (+)", 0.0, 0.01, "The upper deviation (the ± value for symmetric)"),
166 );
167 params.insert(
168 "tolLower".into(),
169 number_field("Lower (−)", 0.0, 0.01, "The lower deviation (deviation / limits modes)"),
170 );
171}
172
173pub(super) fn plane_field() -> Value {
177 reference_field(
178 "Annotation plane",
179 &["FACE", "PLANE"],
180 false,
181 0,
182 1,
183 "A planar face or reference plane the annotation lies in — leave empty to align it to the view camera",
184 )
185}
186
187pub(super) fn schema_entry(def: &PmiTypeDef, mut params: Map<String, Value>) -> Value {
188 if def.type_id != "explode" {
189 params.insert("plane".into(), plane_field());
190 }
191 serde_json::json!({
192 "type": def.type_id,
193 "shortName": def.short_name,
194 "longName": def.long_name,
195 "label": def.label,
196 "icon": def.icon,
197 "inputParamsSchema": Value::Object(params),
198 })
199}
200
201pub(super) fn params(entries: Vec<(&str, Value)>) -> Map<String, Value> {
203 let mut map = Map::new();
204 for (key, value) in entries {
205 map.insert(key.to_string(), value);
206 }
207 map
208}
209
210pub(super) fn decimals_of(annotation: &PmiAnnotation, context: &PmiContext<'_>, default: f64) -> usize {
212 annotation
213 .number("decimals", context.env, default)
214 .unwrap_or(default)
215 .round()
216 .clamp(0.0, 8.0) as usize
217}