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