diff --git a/src/Mod/Assembly/App/AssemblyObject.cpp b/src/Mod/Assembly/App/AssemblyObject.cpp index f9fe2066e9..c5cce33416 100644 --- a/src/Mod/Assembly/App/AssemblyObject.cpp +++ b/src/Mod/Assembly/App/AssemblyObject.cpp @@ -659,19 +659,26 @@ bool AssemblyObject::validateNewPlacements() // Get the relative rotation: how much did the part rotate? Base::Rotation relativeRot = newRot * oldRot.inverse(); - // Get the angle of this rotation + // Ensure we measure the short-arc angle. Rotation stores + // angle = 2*acos(w) which gives [0, 2*pi]. When the + // quaternion w component is negative (opposite hemisphere), + // the angle exceeds pi even though q and -q represent the + // same rotation. Map to [0, pi] for a correct comparison. Base::Vector3d axis; double angle; relativeRot.getRawValue(axis, angle); + if (angle > M_PI) { + angle = 2.0 * M_PI - angle; + } // If the part rotated more than 90 degrees, consider it a flip // Use 91 degrees to allow for small numerical errors constexpr double maxAngle = 91.0 * M_PI / 180.0; - if (std::abs(angle) > maxAngle) { + if (angle > maxAngle) { Base::Console().warning( "Assembly : Ignoring bad solve, part (%s) flipped orientation (%.1f degrees).\n", obj->getFullLabel(), - std::abs(angle) * 180.0 / M_PI + angle * 180.0 / M_PI ); return false; }