mirror of
https://github.com/storytold/cadcraft.git
synced 2026-10-22 18:22:07 +00:00
Keep Z and elevation of the pieces left by BREAK (#1270)
Found while testing crates/engine/src/cmd/modify.rs:1457 (break_entity; helpers `line()`/`arc()`/`lwpoly()` in crates/engine/src/cmd/helpers.rs:10-23) Co-authored-by: Claude Haiku 5.5 <[email protected]> Co-authored-by: Brandon Thomas <[email protected]>
This commit is contained in:
2 files changed
+92
-8
No files matched your search
@@ -1437,6 +1437,16 @@ fn run_explode(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
Ok(json!({ "handles": r.iter().map(|h| h.hex()).collect::<Vec<_>>() }))
|
||||
}
|
||||
|
||||
/// Gives a rebuilt arc piece its source centre Z, or a rebuilt polyline piece its source elevation.
|
||||
fn with_z(mut k: EntityKind, z: f64) -> EntityKind {
|
||||
match &mut k {
|
||||
EntityKind::Arc(a) => a.center.z = z,
|
||||
EntityKind::LwPolyline(p) => p.elevation = z,
|
||||
_ => {}
|
||||
}
|
||||
k
|
||||
}
|
||||
|
||||
/// Break `h` between two points (or at one point when p1 == p2).
|
||||
pub(crate) fn break_entity(s: &mut Session, h: Handle, p1: Vec2, p2: Vec2) -> Result<Vec<Handle>> {
|
||||
if super::curves::is_locked(s, h) {
|
||||
@@ -1450,12 +1460,13 @@ pub(crate) fn break_entity(s: &mut Session, h: Handle, p1: Vec2, p2: Vec2) -> Re
|
||||
if t1 > t2 {
|
||||
std::mem::swap(&mut t1, &mut t2);
|
||||
}
|
||||
let at3 = |t: f64| ln.at(t).to3(l.a.z + (l.b.z - l.a.z) * t);
|
||||
let mut v = Vec::new();
|
||||
if t1 > 1e-12 {
|
||||
v.push(line(ln.a, ln.at(t1)));
|
||||
v.push(EntityKind::Line(cadcraft_doc::Line { a: l.a, b: at3(t1) }));
|
||||
}
|
||||
if t2 < 1.0 - 1e-12 {
|
||||
v.push(line(ln.at(t2), ln.b));
|
||||
v.push(EntityKind::Line(cadcraft_doc::Line { a: at3(t2), b: l.b }));
|
||||
}
|
||||
v
|
||||
}
|
||||
@@ -1466,7 +1477,7 @@ pub(crate) fn break_entity(s: &mut Session, h: Handle, p1: Vec2, p2: Vec2) -> Re
|
||||
let a1 = c.center.xy().angle_to(p1);
|
||||
let a2 = c.center.xy().angle_to(p2);
|
||||
// AutoCAD removes the CCW portion from the first to the second point.
|
||||
vec![arc(&Arc::new(c.center.xy(), c.radius, a2, a1))]
|
||||
vec![with_z(arc(&Arc::new(c.center.xy(), c.radius, a2, a1)), c.center.z)]
|
||||
}
|
||||
EntityKind::Arc(a) => {
|
||||
let ga = Arc::new(a.center.xy(), a.radius, a.start, a.end);
|
||||
@@ -1477,10 +1488,10 @@ pub(crate) fn break_entity(s: &mut Session, h: Handle, p1: Vec2, p2: Vec2) -> Re
|
||||
}
|
||||
let mut v = Vec::new();
|
||||
if t1 > 1e-12 {
|
||||
v.push(arc(&Arc::new(ga.center, ga.radius, ga.start, ga.start + t1)));
|
||||
v.push(with_z(arc(&Arc::new(ga.center, ga.radius, ga.start, ga.start + t1)), a.center.z));
|
||||
}
|
||||
if t2 < ga.sweep() - 1e-12 {
|
||||
v.push(arc(&Arc::new(ga.center, ga.radius, ga.start + t2, ga.end)));
|
||||
v.push(with_z(arc(&Arc::new(ga.center, ga.radius, ga.start + t2, ga.end)), a.center.z));
|
||||
}
|
||||
v
|
||||
}
|
||||
@@ -1510,17 +1521,17 @@ pub(crate) fn break_entity(s: &mut Session, h: Handle, p1: Vec2, p2: Vec2) -> Re
|
||||
// vertices, goes; what is left runs from the second point round to the first.
|
||||
let doubled: Vec<Segment> = segs.iter().chain(segs.iter()).copied().collect();
|
||||
let end = if t1 > t2 { t1 } else { t1 + total };
|
||||
vec![lwpoly(sub_polyline(&doubled, t2, end), false)]
|
||||
vec![with_z(lwpoly(sub_polyline(&doubled, t2, end), false), p.elevation)]
|
||||
} else {
|
||||
if t1 > t2 {
|
||||
std::mem::swap(&mut t1, &mut t2);
|
||||
}
|
||||
let mut v = Vec::new();
|
||||
if t1 > 1e-12 {
|
||||
v.push(lwpoly(sub_polyline(&segs, 0.0, t1), false));
|
||||
v.push(with_z(lwpoly(sub_polyline(&segs, 0.0, t1), false), p.elevation));
|
||||
}
|
||||
if t2 < total - 1e-12 {
|
||||
v.push(lwpoly(sub_polyline(&segs, t2, total), false));
|
||||
v.push(with_z(lwpoly(sub_polyline(&segs, t2, total), false), p.elevation));
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
//! BREAK and BREAKATPOINT keep the Z / elevation of the pieces they leave.
|
||||
|
||||
use cadcraft_engine::Session;
|
||||
use cadcraft_engine::doc::{Arc, Common, Entity, EntityKind, Handle, Line, LwPolyline};
|
||||
use cadcraft_engine::geom::{PolyVertex, Vec2, Vec3};
|
||||
use serde_json::{Value, json};
|
||||
|
||||
fn add(s: &mut Session, kind: EntityKind) -> String {
|
||||
let space = s.space();
|
||||
let d = s.doc_mut().unwrap();
|
||||
let handle = d.new_handle();
|
||||
d.space_mut(&space).unwrap().push(Entity { handle, common: Common::default(), kind });
|
||||
handle.hex()
|
||||
}
|
||||
|
||||
fn pieces(s: &Session, r: &Value) -> Vec<EntityKind> {
|
||||
let d = s.doc().unwrap();
|
||||
r["handles"].as_array().unwrap().iter().map(|h| d.entity(Handle::parse_hex(h.as_str().unwrap()).unwrap()).unwrap().kind.clone()).collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn break_keeps_line_z() {
|
||||
let mut s = Session::new();
|
||||
let h = add(&mut s, EntityKind::Line(Line { a: Vec3::new(0.0, 0.0, 5.0), b: Vec3::new(10.0, 0.0, 5.0) }));
|
||||
let r = s.execute("break", &json!({"handle": h, "p1": [4, 0], "p2": [6, 0]})).unwrap();
|
||||
let ps = pieces(&s, &r);
|
||||
assert_eq!(ps.len(), 2);
|
||||
for p in ps {
|
||||
let EntityKind::Line(l) = p else { panic!("not a line: {p:?}") };
|
||||
assert_eq!((l.a.z, l.b.z), (5.0, 5.0));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn breakatpoint_keeps_line_z() {
|
||||
let mut s = Session::new();
|
||||
let h = add(&mut s, EntityKind::Line(Line { a: Vec3::new(0.0, 0.0, 5.0), b: Vec3::new(10.0, 0.0, 5.0) }));
|
||||
let r = s.execute("breakatpoint", &json!({"handle": h, "at": [4, 0]})).unwrap();
|
||||
let ps = pieces(&s, &r);
|
||||
assert_eq!(ps.len(), 2);
|
||||
for p in ps {
|
||||
let EntityKind::Line(l) = p else { panic!("not a line: {p:?}") };
|
||||
assert_eq!((l.a.z, l.b.z), (5.0, 5.0));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn break_keeps_polyline_elevation() {
|
||||
let mut s = Session::new();
|
||||
let vertices = vec![PolyVertex::new(Vec2::new(0.0, 0.0)), PolyVertex::new(Vec2::new(10.0, 0.0))];
|
||||
let h = add(&mut s, EntityKind::LwPolyline(LwPolyline { vertices, closed: false, const_width: 0.0, elevation: 7.0, plinegen: false }));
|
||||
let r = s.execute("break", &json!({"handle": h, "p1": [4, 0], "p2": [6, 0]})).unwrap();
|
||||
let ps = pieces(&s, &r);
|
||||
assert_eq!(ps.len(), 2);
|
||||
for p in ps {
|
||||
let EntityKind::LwPolyline(pl) = p else { panic!("not a polyline: {p:?}") };
|
||||
assert_eq!(pl.elevation, 7.0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn break_keeps_arc_centre_z() {
|
||||
let mut s = Session::new();
|
||||
let h = add(&mut s, EntityKind::Arc(Arc { center: Vec3::new(0.0, 0.0, 3.0), radius: 5.0, start: 0.0, end: std::f64::consts::PI }));
|
||||
let p1 = [5.0 * 0.5f64.sqrt(), 5.0 * 0.5f64.sqrt()];
|
||||
let r = s.execute("break", &json!({"handle": h, "p1": p1, "p2": [0, 5]})).unwrap();
|
||||
let ps = pieces(&s, &r);
|
||||
assert_eq!(ps.len(), 2);
|
||||
for p in ps {
|
||||
let EntityKind::Arc(a) = p else { panic!("not an arc: {p:?}") };
|
||||
assert_eq!(a.center.z, 3.0);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user