bug(assembly): planar constraint drifts during interactive drag with combined rotational joints #338
Reference in New Issue
Block a user
Delete Branch "%!s()"
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?
Summary
During interactive drag of a body constrained by a Planar joint + Cylindrical joint (rotation about the assembly origin Z-axis, coplanar on XY), the constrained part drifts away from the constraint plane. The 91-degree orientation validator fires and rejects subsequent drag steps, effectively freezing or "exploding" the part.
This bug persists across both solver backends (OndselSolver and Kindred Newton-Raphson), indicating the root cause is upstream of the solver selection — likely in the drag protocol, constraint formulation, or placement validation layer.
Steps to reproduce
"Assembly: Ignoring bad solve, part (...) flipped orientation (N degrees)"Expected behaviour
The part should remain coplanar with the fixed XY plane throughout the full 360-degree drag rotation, smoothly orbiting the Z-axis while the planar constraint holds.
Actual behaviour
The part progressively drifts off-plane during drag. The C++
validateNewPlacements()91-degree threshold eventually fires, rejecting drag steps. The part appears to freeze or jump erratically.Analysis
Prior fix attempts
9dbb1bcfix/assembly-jcs-visual-drag-robust41c91c4fix/assembly-ondsel-lock3a8f2c1after GCS planar regressionac0d2e8fix/assembly-stabilize-undofa34dc07e2b4f9fix/planar-halfspace-drag-flip(OndselSolver)Architecture context
The drag system uses a three-phase protocol:
The GUI computes absolute placements (not deltas) and passes them to the solver. The solver resolves all non-dragged parts to satisfy constraints, then the C++ validator checks that no part rotated more than 91 degrees from the per-step baseline.
Why both solvers fail
OndselSolver (C++): Uses direction-cosine constraints (
z_I . x_J = 0,z_I . y_J = 0) which are satisfied by bothz_I = +z_Jandz_I = -z_J. The Lagrangian solver has no inherent preference for which branch and converges to the nearest solution from the initial guess. No half-space tracking exists at the C++ level.Kindred Solver (Python): Uses cross-product residuals (
z_I x z_J = 0) plus point-plane distance. After thefa34dc0fix, the half-space correction is disabled for distance=0 planar constraints (to avoid fighting legitimate rotation). But the solver can still converge to the anti-aligned normal branch.Root cause hypothesis
The constraint formulation for Planar + Cylindrical combined is under-determined in normal direction when the dragged body rotates through 90 degrees. At that point
dot(z_body, z_fixed) ~ 0, and both normal orientations are equidistant solutions. The solver picks one arbitrarily. If it picks the anti-aligned branch, the translation constraint(p_i - p_j) . z_j = 0is satisfied on the opposite side of the plane.The key question is whether the initial guess (seeded from the previous accepted drag step) is sufficient to keep the solver in the correct branch, or whether the Jacobian becomes singular/ill-conditioned near the 90-degree crossing and the solver drifts across the branch boundary.
Possible fix directions
z_I perp x_Jandz_I perp y_J, addz_I . z_J > 0(inequality or soft penalty) to break the sign ambiguitydrag_step(), verifydot(z_body_face, z_fixed_plane) > 0and negate the normal if it flipped, before passing tovalidateNewPlacements()z_I . x_J = 0with constraints that distinguish aligned vs anti-aligned normals (e.g.,z_I . z_J = 1instead of relying on two perpendicularity constraints)|dot(z_I, z_J)|is near zero and subdivide the drag step to maintain solver convergence in the correct branchRotationOnPlane, which computes rotation angles. Verify the rotation is applied correctly and the seeded placement does not inadvertently cross the branch boundaryEnvironment
Related issues / PRs
fix/planar-halfspace-drag-flip— latest attempted fix (OndselSolver submodule update)Fixed, next we should investigate more assembly arrangements to understand if there are further quaternion discontinuities in our residuals.