fix(solver): world-anchored reference normal prevents planar axial drift #336
Reference in New Issue
Block a user
Delete Branch "fix/planar-halfspace-drag-flip"
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
When a PlanarConstraint is combined with a CylindricalConstraint on the same body pair, the body drifts along the cylinder axis during drag. The planar distance=0 constraint fails to hold.
Root Cause
PlanarConstraint.residuals() computes its point-in-plane distance using z_j = marker_z_axis(body_j, marker_j_quat) — a body-attached normal that rotates with body_j. The CylindricalConstraint allows rotation about the shared axis, so as the body rotates during Newton iteration, the plane normal tilts. The distance residual (p_i - p_j) · z_j then constrains a rotating plane instead of the original one, allowing the body to drift axially.
Fix
Snapshot the world-frame normal at system-build time (_build_system()) and store it on the PlanarConstraint as reference_normal. The distance residual then uses Const nodes: (p_i - p_j) · z_ref - offset = 0, constraining displacement along the original plane normal regardless of body rotation.
The cross-product (parallelism) residuals still use body-attached normals — correctly enforcing orientation alignment. Only the distance residual needs the fixed reference direction. Works for any offset value.
Changes
All 294 solver tests pass.