From e572625de3af271a5e6c3ad7093bca6f10e2bbab Mon Sep 17 00:00:00 2001 From: ramox81 <184937705+ramox81@users.noreply.github.com> Date: Fri, 18 Sep 2026 18:58:35 +0300 Subject: [PATCH] Refuse an edit the constraints can only satisfy by collapsing the entity 9) When an edit contradicts a fixed point together with another constraint so that the only solution collapses the entity (a rotated line with a fixed start and a Vertical relation), the entity returns to its pre-edit shape instead of degenerating, as the reference does. Co-Authored-By: Claude Fable 5.1 --- src/scene/parametric_solve.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/scene/parametric_solve.rs b/src/scene/parametric_solve.rs index 39dd09618..4d52fe8b4 100644 --- a/src/scene/parametric_solve.rs +++ b/src/scene/parametric_solve.rs @@ -1038,6 +1038,18 @@ fn retained_tangent_side( Some(dx * (center[1] - y1) - dy * (center[0] - x1) >= 0.0) } +/// A solve result with no extent left — the only way the solver could +/// honour every constraint after an edit that contradicted them. +fn collapsed_by_solve(entity: &EntityType) -> bool { + const EPS: f64 = 1.0e-9; + match entity { + EntityType::Line(line) => (line.end - line.start).length() <= EPS, + EntityType::Circle(circle) => circle.radius <= EPS, + EntityType::Arc(arc) => arc.radius <= EPS, + _ => false, + } +} + /// The kernel parameters a `Fixed` constraint on `r` holds in place: a /// polyline segment's endpoints (plus center/radius for an arc segment), one /// addressable point, or every intrinsic parameter of a whole entity. Arc @@ -3613,6 +3625,19 @@ impl Scene { self.parametric_constraints[i].conflicts.clear(); } for (handle, new_entity) in solved { + // An edit the constraints can only satisfy by collapsing the + // entity (a rotated line whose start is fixed and direction + // constrained) is refused: the entity goes back to its + // pre-edit shape, as the reference does. + let new_entity = match originals.get(&handle) { + Some(original) + if collapsed_by_solve(&new_entity) + && !collapsed_by_solve(original.as_ref()) => + { + original.as_ref().clone() + } + _ => new_entity, + }; if let Some(before) = self.document.get_entity_arc(handle) { self.record_undo_before(handle, Some(before)); }