use brep_render::engine_state::EngineState;
use serde_json::{json, Value};
use super::info_windows::num;
#[derive(Default)]
pub struct Cache {
key: Option<(u64, u64, u64, String)>,
value: Value,
}
impl Cache {
pub fn read(&mut self, state: &mut EngineState, document: u64) -> Value {
if state.any_sketch_mode() || state.ref_select_active()
|| crate::workbench::ecad::Target::of_workbench(&state.settings.workbench).is_some()
{
return json!({"shown":false,"text":"","pending":false,"lengthUnit":"mm",
"areaUnit":"mm²","totals":{},"items":[]});
}
let selection = json!({"selection":state.selection_value(),
"vertices":state.emphasis.selected_vertices.iter().map(|v| json!([v.solid, v.position])).collect::<Vec<_>>()}).to_string();
let key = (document, state.applied_generation(), state.scene.exact_revision(), selection);
if self.key.as_ref() != Some(&key) || self.value["pending"] == true {
self.value = readout(state);
self.key = Some(key);
}
self.value.clone()
}
}
pub fn readout(state: &mut EngineState) -> Value {
let faces: Vec<_> = state.emphasis.selected_faces.iter().cloned().collect();
let edges: Vec<_> = state.emphasis.selected_edges.iter().cloned().collect();
let vertices = state.emphasis.selected_vertices.clone();
let mut parts = Vec::new();
let mut items = Vec::new();
let mut totals = serde_json::Map::new();
let mut pending = false;
let mut unavailable = false;
for (names, key, label, unit) in [
(&faces, "area", "Area", "mm²"),
(&edges, "length", "Length", "mm"),
] {
if names.is_empty() { continue; }
let mut total = 0.0;
let mut complete = true;
let mut radius = None;
for name in names {
let info: Value = serde_json::from_str(&state.object_info_json(name)).unwrap_or(Value::Null);
pending |= info["pending"].as_bool().unwrap_or(false);
if let Some(value) = info[key].as_f64().filter(|v| v.is_finite()) {
total += value;
} else {
complete = false;
unavailable |= !info["pending"].as_bool().unwrap_or(false);
}
radius = info["radius"].as_f64();
items.push(info);
}
if complete {
totals.insert(key.into(), json!(total));
let prefix = if names.len() > 1 { "Total " } else { "" };
parts.push(format!("{prefix}{label}: {} {unit}", num(total)));
if names.len() == 1 {
if let Some(r) = radius {
parts.push(format!("Radius: {} mm", num(r)));
if key == "length" { parts.push(format!("Diameter: {} mm", num(2.0 * r))); }
}
}
}
}
for vertex in &vertices {
let [x, y, z] = vertex.position;
parts.push(format!("Vertex: ({}, {}, {}) mm", num(x), num(y), num(z)));
items.push(json!({"kind":"vertex", "solid":vertex.solid, "position":vertex.position}));
}
if pending { parts.push("Measuring…".into()); }
if unavailable { parts.push("Measurement unavailable".into()); }
json!({"shown":!parts.is_empty(), "text":parts.join(" · "), "pending":pending,
"lengthUnit":"mm", "areaUnit":"mm²", "totals":totals, "items":items})
}