mirror of
https://github.com/storytold/cadcraft.git
synced 2026-10-30 22:06:49 -06:00
Found while testing crates/engine/src/cmd/modify/transform.rs:69 (run_copy) Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
110 lines
3.9 KiB
Rust
110 lines
3.9 KiB
Rust
use super::{Entity, Handle, Mat3, Result, Session, Value, Vec2, bad, bool_or, f64_req, json, point_param, point_req, targets};
|
|
|
|
// ---------------- core operations ----------------
|
|
|
|
pub(crate) fn transform_entities(s: &mut Session, hs: &[Handle], m: &Mat3, copy: bool) -> Result<Vec<Handle>> {
|
|
let d = s.doc_mut()?;
|
|
let mut out = Vec::new();
|
|
for h in hs {
|
|
let Some(sp) = d.space_of(*h) else { continue };
|
|
if copy {
|
|
let Some(e) = d.entity(*h).map(|e| (**e).clone()) else { continue };
|
|
let nh = d.new_handle();
|
|
let mut ne = Entity { handle: nh, ..e };
|
|
ne.kind.transform(m);
|
|
if let Some(st) = d.space_mut(&sp) {
|
|
st.push(ne);
|
|
out.push(nh);
|
|
}
|
|
} else {
|
|
let locked = d.entity(*h).and_then(|e| d.layer(&e.common.layer)).is_some_and(|l| l.locked);
|
|
if locked {
|
|
continue;
|
|
}
|
|
d.modify_entity(*h, |e| e.kind.transform(m))?;
|
|
out.push(*h);
|
|
}
|
|
}
|
|
Ok(out)
|
|
}
|
|
|
|
pub(super) fn erase(s: &mut Session, hs: &[Handle]) -> Result<usize> {
|
|
let d = s.doc_mut()?;
|
|
let mut n = 0;
|
|
for h in hs {
|
|
let locked = d.entity(*h).and_then(|e| d.layer(&e.common.layer)).is_some_and(|l| l.locked);
|
|
if !locked && d.remove_entity(*h).is_some() {
|
|
n += 1;
|
|
}
|
|
}
|
|
s.set_selection(Vec::new());
|
|
Ok(n)
|
|
}
|
|
|
|
pub(super) fn run_erase(s: &mut Session, p: &Value) -> Result<Value> {
|
|
let hs = targets(s, p)?;
|
|
let n = erase(s, &hs)?;
|
|
Ok(json!({ "erased": n }))
|
|
}
|
|
|
|
pub(super) fn delta_of(cmd: &str, p: &Value) -> Result<Vec2> {
|
|
if let Some(d) = point_param(p, "delta") {
|
|
return Ok(d);
|
|
}
|
|
let a = point_req(cmd, p, "from")?;
|
|
let b = point_req(cmd, p, "to")?;
|
|
Ok(b - a)
|
|
}
|
|
|
|
pub(super) fn run_move(s: &mut Session, p: &Value) -> Result<Value> {
|
|
let hs = targets(s, p)?;
|
|
let d = delta_of("move", p)?;
|
|
let moved = transform_entities(s, &hs, &Mat3::translate(d), false)?;
|
|
Ok(json!({ "moved": moved.len() }))
|
|
}
|
|
|
|
pub(super) fn run_copy(s: &mut Session, p: &Value) -> Result<Value> {
|
|
let hs = targets(s, p)?;
|
|
let d = delta_of("copy", p)?;
|
|
let n = match p.get("count") {
|
|
None => 1,
|
|
Some(v) => v.as_u64().filter(|n| (1..=10_000).contains(n)).ok_or_else(|| bad("copy", "`count` must be an integer from 1 to 10000"))?,
|
|
};
|
|
let mut out = Vec::new();
|
|
for k in 1..=n {
|
|
out.extend(transform_entities(s, &hs, &Mat3::translate(d * k as f64), true)?.into_iter().map(|h| h.hex()));
|
|
}
|
|
Ok(json!({ "handles": out }))
|
|
}
|
|
|
|
pub(super) fn run_rotate(s: &mut Session, p: &Value) -> Result<Value> {
|
|
let hs = targets(s, p)?;
|
|
let base = point_req("rotate", p, "base")?;
|
|
let a = f64_req("rotate", p, "angle")?.to_radians();
|
|
let r = transform_entities(s, &hs, &Mat3::rotate_about(base, a), bool_or(p, "copy", false))?;
|
|
Ok(json!({ "handles": r.iter().map(|h| h.hex()).collect::<Vec<_>>() }))
|
|
}
|
|
|
|
pub(super) fn run_scale(s: &mut Session, p: &Value) -> Result<Value> {
|
|
let hs = targets(s, p)?;
|
|
let base = point_req("scale", p, "base")?;
|
|
let f = f64_req("scale", p, "factor")?;
|
|
if f <= 0.0 {
|
|
return Err(bad("scale", "factor must be positive"));
|
|
}
|
|
let r = transform_entities(s, &hs, &Mat3::scale_about(base, f), bool_or(p, "copy", false))?;
|
|
Ok(json!({ "handles": r.iter().map(|h| h.hex()).collect::<Vec<_>>() }))
|
|
}
|
|
|
|
pub(super) fn run_mirror(s: &mut Session, p: &Value) -> Result<Value> {
|
|
let hs = targets(s, p)?;
|
|
let a = point_req("mirror", p, "p1")?;
|
|
let b = point_req("mirror", p, "p2")?;
|
|
if a.near(b, 1e-12) {
|
|
return Err(bad("mirror", "mirror line points coincide"));
|
|
}
|
|
let erase_src = bool_or(p, "erase", false);
|
|
let r = transform_entities(s, &hs, &Mat3::mirror(a, b), !erase_src)?;
|
|
Ok(json!({ "handles": r.iter().map(|h| h.hex()).collect::<Vec<_>>() }))
|
|
}
|