Sketch fillet: never write a failed solve's geometry back, and commit the op

Two P0s in the same gesture. Filleting a corner of a parametric rectangle
produced either nothing at all or a sharp corner with a stray arc floating
above it.

Trigger (snaporca-cq2): the only routes that ever reached confirm_op were
finishing the whole sketch and an unsignposted click on empty space.
set_tool() dropped a ready op, so typing a radius or dragging the arrow and
then touching any other tool threw the value away. Commit a ready op on tool
change (before m_mode is reassigned — op_ready() and confirm_op() both switch
on it), commit on Enter in the radius editor, and drop the pending op before
Esc's tool downgrade so Esc still cancels rather than applies.

Substitution (snaporca-pl5): libslvs writes its last Newton iterate into the
params whether or not it converged, and SketchSolver read them back
unconditionally, so every REJECTED solve deformed the sketch. The fillet
ladder tries a deliberately over-constrained rung first (a tangent on each
leg, against the legs' own H/V); it is correctly rejected, but its wreckage
then failed rungs 2 and 3, which solve cleanly on their own. The arc ended up
with no constraints at all, the rigid loop won, and the corner snapped shut.
Measured: from pristine geometry rung 1 gives result=INCONSISTENT with 3 bad
constraints, rung 2 gives dof=6 with the arc's radius intact.

Read the geometry back only on success. try_add_constraints then needs no
"restore" re-solve — the entities still hold the prior solved state.

Kernel suite 151 cases / 2072 assertions green on both forks; the GUI check
ran on the Snapmaker fork (9d72c4377a).

Ported from the Snapmaker fork. snaporca-pl5 snaporca-cq2
This commit is contained in:
Tommaso Bianchi
2026-07-26 23:33:50 +02:00
parent 50577d66d0
commit 347b83d887
3 changed files with 114 additions and 4 deletions
+9
View File
@@ -333,6 +333,15 @@ static SketchSolveResult solve_impl(std::vector<SketchEntity>& entities,
}
// ---- Read solved geometry back --------------------------------------------------
// ONLY on success. A failed solve leaves libslvs' params holding its last Newton
// iterate — geometry that satisfies nothing and is usually wildly deformed. Writing
// that back made every rejected attempt destructive: the caller rolls the constraints
// back, but the sketch it rolls back to is already wreckage, so the next attempt starts
// from the corpse. The fillet degrade ladder hit this on every corner — rung 1 (a
// tangent on each leg) is legitimately over-constrained against the legs' own H/V, and
// its wreckage then failed rungs 2 and 3, which solve cleanly on their own. The arc
// ended up with no constraints at all and the solver snapped the corner shut. snaporca-pl5.
if (!out.ok) return out;
for (size_t i = 0; i < entities.size(); ++i) {
SketchEntity& e = entities[i];
const Slots& s = slot[i];