sketch(fix): preserve rectangle constraints through fillets (#1543)
Thanks @Karl-VonRichter for the fix. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9a07932f20
commit
584bbe923d
4 files changed
+143
-10
No files matched your search
@@ -378,6 +378,34 @@ fn a_fillet_rounds_every_picked_corner_to_one_radius() {
|
||||
assert!((ss.profiles[0].area - (1200.0 - 3.0 * 25.0 * (1.0 - std::f64::consts::PI / 4.0))).abs() < 1e-6, "{}", ss.profiles[0].area);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fully_constrained_center_rectangle_corners_can_be_picked_and_filleted() {
|
||||
let mut h = crate::scenario::Harness::new();
|
||||
h.app.run("sketch.create", json!({"plane":"XY"})).unwrap();
|
||||
h.app.run("sketch.rectangle.center", json!({"center":[0,0],"corner":[20,15]})).unwrap();
|
||||
h.app.run("sketch.constraint.coincident", json!({"a":"p5","b":"origin"})).unwrap();
|
||||
h.app.run("sketch.dimension", json!({"entities":["l1"],"value":40})).unwrap();
|
||||
h.app.run("sketch.dimension", json!({"entities":["l2"],"value":30})).unwrap();
|
||||
h.frames(2);
|
||||
h.step(&json!({"start":"sketch.fillet"})).unwrap();
|
||||
h.frames(2);
|
||||
for corner in [[-20, -15, 0], [20, -15, 0], [20, 15, 0], [-20, 15, 0]] {
|
||||
h.step(&json!({"click":{"world":corner}})).unwrap();
|
||||
h.frames(2);
|
||||
}
|
||||
assert_eq!(h.app.dialog.as_ref().map(|d| d.inputs[0].items.len()), Some(4));
|
||||
set_size(&mut h.app, "3");
|
||||
apply(&mut h);
|
||||
assert!(h.app.dialog.is_none(), "{:?}", h.app.status);
|
||||
let info = h.app.run("sketch.inspect", json!({})).unwrap();
|
||||
assert_eq!(info["dof"], 0, "{info}");
|
||||
assert_eq!(info["status"], "solved", "{info}");
|
||||
let st = h.app.session.world_state();
|
||||
let ss = st.sketch(h.app.session.active_sketch.unwrap()).unwrap();
|
||||
assert_eq!(ss.sketch.curves.iter().filter(|c| matches!(c.kind, CurveKind::Arc { .. })).count(), 4);
|
||||
assert!((ss.profiles[0].area - (1200.0 - 36.0 * (1.0 - std::f64::consts::PI / 4.0))).abs() < 1e-6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ordinary_drawing_keeps_origin_snap_and_real_origin_corners_work() {
|
||||
let mut h = crate::scenario::Harness::new();
|
||||
|
||||
@@ -460,17 +460,18 @@ fn sketch_entity(app: &SolveApp, hits: &[Hit]) -> Option<(String, bool)> {
|
||||
}
|
||||
|
||||
/// The two editable curves that meet at sketch point `pi`, in curve order, which is the order
|
||||
/// the corner commands resolve them in from a `point` parameter. None unless exactly two meet
|
||||
/// there and each is one the command can work on: a line always, an arc only for a fillet.
|
||||
/// the corner commands resolve them in from a `point` parameter. Construction curves are
|
||||
/// ignored when more than two meet. Each side must be a line, or an arc for a fillet.
|
||||
pub(crate) fn corner_curves(sk: &solidcraft_engine::sketch::Sketch, pi: usize, arcs_ok: bool) -> Option<(usize, usize)> {
|
||||
use solidcraft_engine::sketch::CurveKind;
|
||||
let curves: Vec<_> = sk
|
||||
.curves
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(ci, c)| !sk.is_linked_curve(*ci) && c.kind.ends().is_some_and(|(a, b)| a == pi || b == pi))
|
||||
.take(3)
|
||||
.collect();
|
||||
let candidates =
|
||||
sk.curves.iter().enumerate().filter(|(ci, c)| !sk.is_linked_curve(*ci) && c.kind.ends().is_some_and(|(a, b)| a == pi || b == pi));
|
||||
let mut curves: Vec<_> = candidates.clone().take(3).collect();
|
||||
// Center rectangles have construction diagonals at their corners. Match the engine's
|
||||
// corner selection: when more than two curves meet, use the profile sides.
|
||||
if curves.len() > 2 {
|
||||
curves = candidates.filter(|(_, c)| !c.construction).take(3).collect();
|
||||
}
|
||||
if curves.iter().any(|(_, c)| !matches!(c.kind, CurveKind::Line { .. }) && !(arcs_ok && matches!(c.kind, CurveKind::Arc { .. }))) {
|
||||
return None;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user