The old ids live only in crates/engine/src/legacy_ids.rs (the legacy migration table): find_command maps them, so old scripts, recipes and control calls keep working, and saved shortcuts, recent and pinned commands are migrated on load (designs store no command ids). Parity maps the observed catalog ids to ours through xtask/data/fusion-ids.tsv. The agent rule now reads: our own dotted id, never another product's. Cargo.toml's repository points at github.com/bherbruck/solvecraft. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
49 lines
2.1 KiB
Rust
49 lines
2.1 KiB
Rust
//! Section Analysis: a view-only cut through the model by a plane (what is on the plane's
|
|
//! positive side is hidden). It changes no geometry and is not an undo step.
|
|
|
|
use serde_json::{Value, json};
|
|
use solvecraft_geom::{Plane, Vec3};
|
|
|
|
use super::CommandSpec;
|
|
use crate::params::{bad, bool_, expr, vec3};
|
|
use crate::{Result, Session};
|
|
|
|
pub static COMMANDS: &[CommandSpec] = &[CommandSpec::new("inspect.section", "Section Analysis", section)
|
|
.at("SOLID", "INSPECT")
|
|
.icon("section")
|
|
.noundo()
|
|
.params("plane: XY|XZ|YZ | {origin, normal}; offset?: expr along the normal; flip?: bool; or clear: true")];
|
|
|
|
fn section(s: &mut Session, p: &Value) -> Result<Value> {
|
|
let cmd = "inspect.section";
|
|
if bool_(p, "clear").unwrap_or(false) {
|
|
s.section = None;
|
|
s.revision += 1;
|
|
return Ok(json!({"section": null}));
|
|
}
|
|
let (origin, normal) = match p.get("plane") {
|
|
Some(Value::String(n)) => {
|
|
let pl = Plane::named(n).ok_or_else(|| bad(cmd, format!("unknown plane `{n}` (XY, XZ, YZ)")))?;
|
|
(pl.origin, pl.normal())
|
|
}
|
|
Some(o @ Value::Object(_)) => {
|
|
let origin = o.get("origin").and_then(vec3).unwrap_or(Vec3::ZERO);
|
|
let n = o.get("normal").and_then(vec3).and_then(|n| n.normalized()).ok_or_else(|| bad(cmd, "the plane needs a non-zero `normal`"))?;
|
|
(origin, n)
|
|
}
|
|
_ => return Err(bad(cmd, "`plane` must be XY, XZ, YZ or {origin, normal}")),
|
|
};
|
|
let offset = match expr(p, "offset") {
|
|
Some(e) => s.doc.eval(&e, solvecraft_doc::expr::Kind::Length).map_err(|e| bad(cmd, format!("offset: {e}")))?,
|
|
None => 0.0,
|
|
};
|
|
if !origin.is_finite() || !offset.is_finite() {
|
|
return Err(bad(cmd, "the plane must be finite"));
|
|
}
|
|
let normal = if bool_(p, "flip").unwrap_or(false) { -normal } else { normal };
|
|
let origin = origin + normal * offset * if bool_(p, "flip").unwrap_or(false) { -1.0 } else { 1.0 };
|
|
s.section = Some((origin, normal));
|
|
s.revision += 1;
|
|
Ok(json!({"section": {"origin": origin, "normal": normal}}))
|
|
}
|