diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp index c18b516725..7bec529a21 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp @@ -503,6 +503,28 @@ bool ViewProviderAssembly::tryMouseMove(const SbVec2s& cursorPos, Gui::View3DInv Base::Placement jcsPlcRelativeToPart = plc.inverse() * jcsGlobalPlc; plc = rotatedGlovalJcsPlc * jcsPlcRelativeToPart.inverse(); } + else if (dragMode == DragMode::Ball) { + Base::Vector3d center = jcsGlobalPlc.getPosition(); + // Vectors from joint center to initial click and current drag position + Base::Vector3d u = initialPosition - center; + Base::Vector3d v = newPos - center; + + // Ensure vectors are valid to prevent singularities + if (u.Length() > Precision::Confusion() && v.Length() > Precision::Confusion()) { + // Calculate rotation that moves vector u to v + Base::Rotation rot; + rot.setValue(u, v); + + // Apply this rotation to the global joint placement (around the joint center) + Base::Placement rotatedGlobalJcsPlc = jcsGlobalPlc; + rotatedGlobalJcsPlc.setRotation(rot * jcsGlobalPlc.getRotation()); + + // Calculate the initial offset of the part relative to the joint + // and apply the new global joint placement to find the new part placement. + Base::Placement jcsPlcRelativeToPart = plc.inverse() * jcsGlobalPlc; + plc = rotatedGlobalJcsPlc * jcsPlcRelativeToPart.inverse(); + } + } else if (dragMode == DragMode::TranslationOnAxis) { Base::Vector3d pos = plc.getPosition() + (newPos - initialPosition); plc.setPosition(pos); @@ -942,7 +964,7 @@ ViewProviderAssembly::DragMode ViewProviderAssembly::findDragMode() return DragMode::TranslationOnAxisAndRotationOnePlane; } else if (jointType == JointType::Ball) { - // return DragMode::Ball; + return DragMode::Ball; } else if (jointType == JointType::Distance) { // depends on the type of distance. For example plane-plane: