brep_render/engine_state/
wire_harness_ops.rs1use super::*;
2use brep_kernel::{WireHarnessConnection, WireHarnessReport, WireHarnessState};
3
4#[derive(Debug, Default, Clone, PartialEq)]
7pub struct ConnectionPatch {
8 pub name: Option<String>,
9 pub from: Option<String>,
10 pub to: Option<String>,
11 pub diameter: Option<f64>,
12}
13
14impl EngineState {
15 pub fn wire_harness_report(&self) -> Option<&WireHarnessReport> {
21 self.wire_harness_report.as_ref()
22 }
23
24 pub fn wire_harness_state(&self) -> WireHarnessState {
27 self.history
28 .wire_harness_block()
29 .and_then(|block| serde_json::from_value(block.clone()).ok())
30 .unwrap_or_default()
31 }
32
33 pub fn wire_harness_state_json(&self) -> String {
36 let state = self.wire_harness_state();
37 serde_json::json!({
38 "connections": state.connections,
39 "buildBundles": state.build_bundles,
40 "cutMargin": state.cut_margin,
41 "report": self.wire_harness_report,
42 })
43 .to_string()
44 }
45
46 fn write_wire_harness_state(&mut self, state: WireHarnessState) -> String {
53 let block = if state.connections.is_empty() && state.id_counter == 0 && state.cut_margin == 0.0 {
54 None
55 } else {
56 serde_json::to_value(&state).ok()
57 };
58 self.history.set_wire_harness_block(block);
59 self.rerun_history()
60 }
61
62 pub fn wire_harness_add_connection(&mut self, from: &str, to: &str, diameter: f64) -> String {
65 let mut state = self.wire_harness_state();
66 let id = state.next_id();
67 let name = format!("Wire {}", state.id_counter);
68 state.connections.push(WireHarnessConnection {
69 id: id.clone(),
70 name,
71 from: from.to_string(),
72 to: to.to_string(),
73 diameter: if diameter.is_finite() && diameter > 0.0 { diameter } else { 1.0 },
74 });
75 self.write_wire_harness_state(state);
76 id
77 }
78
79 pub fn wire_harness_update_connection(
82 &mut self,
83 id: &str,
84 patch: &ConnectionPatch,
85 ) -> Result<(), String> {
86 let mut state = self.wire_harness_state();
87 let connection = state
88 .connections
89 .iter_mut()
90 .find(|connection| connection.id == id)
91 .ok_or_else(|| format!("no harness connection '{id}'"))?;
92 if let Some(name) = &patch.name {
93 connection.name = name.trim().to_string();
94 }
95 if let Some(from) = &patch.from {
96 connection.from = from.trim().to_string();
97 }
98 if let Some(to) = &patch.to {
99 connection.to = to.trim().to_string();
100 }
101 if let Some(diameter) = patch.diameter {
102 if !(diameter.is_finite() && diameter > 0.0) {
103 return Err(format!("wire diameter must be positive, got {diameter}"));
104 }
105 connection.diameter = diameter;
106 }
107 self.write_wire_harness_state(state);
108 Ok(())
109 }
110
111 pub fn wire_harness_remove_connection(&mut self, id: &str) -> Result<(), String> {
113 let mut state = self.wire_harness_state();
114 let before = state.connections.len();
115 state.connections.retain(|connection| connection.id != id);
116 if state.connections.len() == before {
117 return Err(format!("no harness connection '{id}'"));
118 }
119 self.write_wire_harness_state(state);
120 Ok(())
121 }
122
123 pub fn wire_harness_set_build_bundles(&mut self, on: bool) {
125 let mut state = self.wire_harness_state();
126 if state.build_bundles == on {
127 return;
128 }
129 state.build_bundles = on;
130 self.write_wire_harness_state(state);
131 }
132
133 pub fn wire_harness_set_cut_margin(&mut self, margin: f64) -> Result<(), String> {
139 if !(margin.is_finite() && margin >= 0.0) {
140 return Err(format!("cut margin must be zero or more, got {margin}"));
141 }
142 let mut state = self.wire_harness_state();
143 if state.cut_margin == margin {
144 return Ok(());
145 }
146 state.cut_margin = margin;
147 self.write_wire_harness_state(state);
148 Ok(())
149 }
150
151 pub fn wire_harness_hover_connection(&mut self, id: &str) {
157 let state = self.wire_harness_state();
158 let mut names: Vec<String> = Vec::new();
159 if let Some(connection) = state.connections.iter().find(|c| c.id == id) {
160 for port in [&connection.from, &connection.to] {
161 if !port.is_empty() && self.scene.solid(port).is_some() {
162 names.push(port.clone());
163 }
164 }
165 }
166 if let Some(report) = &self.wire_harness_report {
167 if let Some(route) = report.routes.iter().find(|route| route.connection_id == id) {
168 for segment in &route.segment_ids {
169 if let Some(bundle) = report.bundles.iter().find(|b| &b.segment_id == segment) {
170 if !bundle.solid_name.is_empty() {
171 names.push(bundle.solid_name.clone());
172 }
173 }
174 }
175 }
176 }
177 self.clear_hover();
178 self.emphasis.hovered_solids.extend(names);
179 self.emphasis.generation = self.emphasis.generation.wrapping_add(1);
180 self.dirty = true;
181 }
182
183 pub fn wire_harness_hover_end(&mut self) {
185 if self.clear_hover() {
186 self.dirty = true;
187 }
188 }
189}
190