fix(solver): prevent orientation flips during interactive drag #36
Reference in New Issue
Block a user
Delete Branch "fix/drag-orientation-stability"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
During interactive drag, the solver finds mathematically valid solutions where parts drift through planar/distance constraints while honoring revolute joints. The C++
validateNewPlacements()rejects these as 'flipped orientation' (>91° rotation), causing most drag steps to be rejected (e.g. 17/18 rejected).Root Causes
Missing half-space tracking for compound constraints —
PlanarConstraint,RevoluteConstraint,CylindricalConstraint, etc. all contain parallel-axis or point-in-plane sub-constraints with branch ambiguity, but the preference system only tracked standaloneDistancePointPoint,Parallel,Angle, andPerpendicular.Quaternion hemisphere flips — Newton-Raphson can converge to the -q branch of a quaternion (identical rotation, but the C++ angle measurement sees ~340°).
Changes
preference.py— Half-space tracking for all compound constraintsAdded half-space handlers for every constraint type with branch ambiguity:
solver.py— Quaternion continuity in drag_enforce_quat_continuity(): After each drag solve, checks every non-dragged body's quaternion against its pre-step value. Ifdot(q_prev, q_solved) < 0, negates the quaternion (standard SLERP short-arc correction). Essentially free — 4 multiplies + 4 negations per body.pre_drag()snapshots initial solved quaternions into_DragCache.pre_step_quatsdrag_step()applies continuity enforcement after solving, updates stored quaternions for next stepTesting
All 286 existing tests pass. The fix addresses the symptom shown in logs like:
Expected after fix: near-zero rejections during drag.