diff --git a/src/Mod/Assembly/App/AssemblyObject.cpp b/src/Mod/Assembly/App/AssemblyObject.cpp index e3a7b29a26..9695a0dfdd 100644 --- a/src/Mod/Assembly/App/AssemblyObject.cpp +++ b/src/Mod/Assembly/App/AssemblyObject.cpp @@ -454,9 +454,9 @@ App::DocumentObject* AssemblyObject::getJointOfPartConnectingToGround(App::Docum return nullptr; } -JointGroup* AssemblyObject::getJointGroup() +JointGroup* AssemblyObject::getJointGroup(App::Part* part) { - App::Document* doc = getDocument(); + App::Document* doc = part->getDocument(); std::vector jointGroups = doc->getObjectsOfType(Assembly::JointGroup::getClassTypeId()); @@ -464,13 +464,18 @@ JointGroup* AssemblyObject::getJointGroup() return nullptr; } for (auto jointGroup : jointGroups) { - if (hasObject(jointGroup)) { + if (part->hasObject(jointGroup)) { return dynamic_cast(jointGroup); } } return nullptr; } +JointGroup* AssemblyObject::getJointGroup() +{ + return getJointGroup(this); +} + ViewGroup* AssemblyObject::getExplodedViewGroup() { App::Document* doc = getDocument(); @@ -487,7 +492,8 @@ ViewGroup* AssemblyObject::getExplodedViewGroup() return nullptr; } -std::vector AssemblyObject::getJoints(bool updateJCS, bool delBadJoints) +std::vector +AssemblyObject::getJoints(bool updateJCS, bool delBadJoints, bool subJoints) { std::vector joints = {}; @@ -528,9 +534,11 @@ std::vector AssemblyObject::getJoints(bool updateJCS, bool } // add sub assemblies joints. - for (auto& assembly : getSubAssemblies()) { - auto subJoints = assembly->getJoints(updateJCS, delBadJoints); - joints.insert(joints.end(), subJoints.begin(), subJoints.end()); + if (subJoints) { + for (auto& assembly : getSubAssemblies()) { + auto subJoints = assembly->getJoints(); + joints.insert(joints.end(), subJoints.begin(), subJoints.end()); + } } // Make sure the joints are up to date. @@ -1518,8 +1526,11 @@ std::vector AssemblyObject::getDownstreamParts(App::DocumentObject* part App::DocumentObject* joint) { // First we deactivate the joint - bool state = getJointActivated(joint); - setJointActivated(joint, false); + bool state = false; + if (joint) { + state = getJointActivated(joint); + setJointActivated(joint, false); + } std::vector joints = getJoints(false); @@ -1533,7 +1544,9 @@ std::vector AssemblyObject::getDownstreamParts(App::DocumentObject* part } } - AssemblyObject::setJointActivated(joint, state); + if (joint) { + AssemblyObject::setJointActivated(joint, state); + } /*if (limit > 1000) { // Infinite loop protection return {}; } @@ -2177,14 +2190,15 @@ App::DocumentObject* AssemblyObject::getObjFromProp(App::DocumentObject* joint, return propObj->getValue(); } -App::DocumentObject* AssemblyObject::getObjFromRef(App::PropertyXLinkSub* prop) +App::DocumentObject* AssemblyObject::getObjFromRef(App::DocumentObject* obj, std::string& sub) { - if (!prop) { + if (!obj) { return nullptr; } - App::Document* doc = prop->getValue()->getDocument(); - std::vector names = getSubAsList(prop); + App::Document* doc = obj->getDocument(); + + std::vector names = splitSubName(sub); // Lambda function to check if the typeId is a BodySubObject auto isBodySubObject = [](App::DocumentObject* obj) -> bool { @@ -2217,6 +2231,10 @@ App::DocumentObject* AssemblyObject::getObjFromRef(App::PropertyXLinkSub* prop) return nullptr; } + if (obj->isDerivedFrom()) { + continue; + } + // The last but one name should be the selected if (std::next(it) == std::prev(names.end())) { return obj; @@ -2251,6 +2269,25 @@ App::DocumentObject* AssemblyObject::getObjFromRef(App::PropertyXLinkSub* prop) return nullptr; } +App::DocumentObject* AssemblyObject::getObjFromRef(App::PropertyXLinkSub* prop) +{ + if (!prop) { + return nullptr; + } + + App::DocumentObject* obj = prop->getValue(); + if (!obj) { + return nullptr; + } + + std::vector subs = prop->getSubValues(); + if (subs.empty()) { + return nullptr; + } + + return getObjFromRef(obj, subs[0]); +} + App::DocumentObject* AssemblyObject::getObjFromRef(App::DocumentObject* joint, const char* pName) { auto* prop = dynamic_cast(joint->getPropertyByName(pName)); diff --git a/src/Mod/Assembly/App/AssemblyObject.h b/src/Mod/Assembly/App/AssemblyObject.h index 438a0c524d..bb685d76dd 100644 --- a/src/Mod/Assembly/App/AssemblyObject.h +++ b/src/Mod/Assembly/App/AssemblyObject.h @@ -168,8 +168,8 @@ public: Base::Placement getMbdPlacement(std::shared_ptr mbdPart); bool validateNewPlacements(); void setNewPlacements(); - void recomputeJointPlacements(std::vector joints); - void redrawJointPlacements(std::vector joints); + static void recomputeJointPlacements(std::vector joints); + static void redrawJointPlacements(std::vector joints); // Ondsel Solver interface @@ -193,7 +193,8 @@ public: void jointParts(std::vector joints); JointGroup* getJointGroup(); ViewGroup* getExplodedViewGroup(); - std::vector getJoints(bool updateJCS = true, bool delBadJoints = false); + std::vector + getJoints(bool updateJCS = true, bool delBadJoints = false, bool subJoints = true); std::vector getGroundedJoints(); std::vector getJointsOfObj(App::DocumentObject* obj); std::vector getJointsOfPart(App::DocumentObject* part); @@ -217,7 +218,8 @@ public: bool isPartGrounded(App::DocumentObject* part); bool isPartConnected(App::DocumentObject* part); - std::vector getDownstreamParts(App::DocumentObject* part, App::DocumentObject* joint); + std::vector getDownstreamParts(App::DocumentObject* part, + App::DocumentObject* joint = nullptr); std::vector getUpstreamParts(App::DocumentObject* part, int limit = 0); App::DocumentObject* getUpstreamMovingPart(App::DocumentObject* part, App::DocumentObject*& joint, @@ -255,6 +257,8 @@ public: static DistanceType getDistanceType(App::DocumentObject* joint); + static JointGroup* getJointGroup(App::Part* part); + // getters to get from properties static void setJointActivated(App::DocumentObject* joint, bool val); static bool getJointActivated(App::DocumentObject* joint); @@ -264,6 +268,7 @@ public: static std::string getElementFromProp(App::DocumentObject* obj, const char* propName); static std::string getElementTypeFromProp(App::DocumentObject* obj, const char* propName); static App::DocumentObject* getObjFromProp(App::DocumentObject* joint, const char* propName); + static App::DocumentObject* getObjFromRef(App::DocumentObject* obj, std::string& sub); static App::DocumentObject* getObjFromRef(App::PropertyXLinkSub* prop); static App::DocumentObject* getObjFromRef(App::DocumentObject* joint, const char* propName); App::DocumentObject* getMovingPartFromRef(App::DocumentObject* obj, std::string& sub); diff --git a/src/Mod/Assembly/App/AssemblyObjectPyImp.cpp b/src/Mod/Assembly/App/AssemblyObjectPyImp.cpp index 05ba5c20e5..6ec108729f 100644 --- a/src/Mod/Assembly/App/AssemblyObjectPyImp.cpp +++ b/src/Mod/Assembly/App/AssemblyObjectPyImp.cpp @@ -1,23 +1,24 @@ -/*************************************************************************** - * Copyright (c) 2014 Jürgen Riegel * - * * - * This file is part of the FreeCAD CAx development system. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Library General Public * - * License as published by the Free Software Foundation; either * - * version 2 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU Library General Public License for more details. * - * * - * You should have received a copy of the GNU Library General Public * - * License along with this library; see the file COPYING.LIB. If not, * - * write to the Free Software Foundation, Inc., 59 Temple Place, * - * Suite 330, Boston, MA 02111-1307, USA * - * * +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2024 Ondsel * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * ***************************************************************************/ diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp index 1edd205c48..345a816b7e 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp @@ -132,6 +132,7 @@ bool ViewProviderAssembly::doubleClicked() getDocument()->setEdit(this); } + Gui::Selection().clearSelection(); return true; } @@ -443,14 +444,17 @@ bool ViewProviderAssembly::mouseMove(const SbVec2s& cursorPos, Gui::View3DInvent prevPosition = newPos; + auto* assemblyPart = static_cast(getObject()); ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/Mod/Assembly"); bool solveOnMove = hGrp->GetBool("SolveOnMove", true); - if (solveOnMove) { - auto* assemblyPart = static_cast(getObject()); + if (solveOnMove && dragMode != DragMode::TranslationNoSolve) { // assemblyPart->solve(/*enableRedo = */ false, /*updateJCS = */ false); assemblyPart->doDragStep(); } + else { + assemblyPart->redrawJointPlacements(assemblyPart->getJoints()); + } } return false; } @@ -612,16 +616,22 @@ bool ViewProviderAssembly::getSelectedObjectsWithinAssembly(bool addPreselection } App::DocumentObject* selRoot = selObj.getObject(); - App::DocumentObject* obj = assemblyPart->getMovingPartFromRef(selRoot, subNamesStr); + App::DocumentObject* obj = assemblyPart->getObjFromRef(selRoot, subNamesStr); + if (!obj) { + // In case of sub-assembly, the jointgroup would trigger the dragger. + continue; + } + App::DocumentObject* part = + assemblyPart->getMovingPartFromRef(selRoot, subNamesStr); - if (!canDragObjectIn3d(obj)) { + if (!canDragObjectIn3d(part)) { continue; } auto* pPlc = - dynamic_cast(obj->getPropertyByName("Placement")); + dynamic_cast(part->getPropertyByName("Placement")); - MovingObject movingObj(obj, pPlc->getValue(), selRoot, subNamesStr); + MovingObject movingObj(part, pPlc->getValue(), selRoot, subNamesStr); docsToMove.emplace_back(movingObj); } @@ -669,13 +679,39 @@ bool ViewProviderAssembly::getSelectedObjectsWithinAssembly(bool addPreselection ViewProviderAssembly::DragMode ViewProviderAssembly::findDragMode() { + auto addPartsToMove = [&](const std::vector& refs) { + for (auto& partRef : refs) { + auto* pPlc = + dynamic_cast(partRef.obj->getPropertyByName("Placement")); + if (pPlc) { + App::DocumentObject* selRoot = partRef.ref->getValue(); + if (!selRoot) { + continue; + } + std::vector subs = partRef.ref->getSubValues(); + if (subs.empty()) { + continue; + } + + docsToMove.emplace_back(partRef.obj, pPlc->getValue(), selRoot, subs[0]); + } + } + }; + if (docsToMove.size() == 1) { auto* assemblyPart = static_cast(getObject()); std::string pName; movingJoint = assemblyPart->getJointOfPartConnectingToGround(docsToMove[0].obj, pName); if (!movingJoint) { - return DragMode::Translation; + // In this case the user is moving an object that is not grounded + // Then we want to also move other parts that may be connected to it. + // In particular for case of flexible subassemblies or it looks really weird + std::vector connectedParts = + assemblyPart->getDownstreamParts(docsToMove[0].obj, movingJoint); + + addPartsToMove(connectedParts); + return DragMode::TranslationNoSolve; } JointType jointType = AssemblyObject::getJointType(movingJoint); @@ -732,23 +768,7 @@ ViewProviderAssembly::DragMode ViewProviderAssembly::findDragMode() // Add downstream parts so that they move together std::vector downstreamParts = assemblyPart->getDownstreamParts(docsToMove[0].obj, movingJoint); - for (auto& partRef : downstreamParts) { - auto* pPlc = - dynamic_cast(partRef.obj->getPropertyByName("Placement")); - if (pPlc) { - App::DocumentObject* selRoot = partRef.ref->getValue(); - if (!selRoot) { - return DragMode::None; - } - std::vector subs = partRef.ref->getSubValues(); - if (subs.empty()) { - return DragMode::None; - } - - - docsToMove.emplace_back(partRef.obj, pPlc->getValue(), selRoot, subs[0]); - } - } + addPartsToMove(downstreamParts); jointVisibilityBackup = movingJoint->Visibility.getValue(); if (!jointVisibilityBackup) { @@ -827,16 +847,16 @@ void ViewProviderAssembly::initMove(const SbVec2s& cursorPos, Gui::View3DInvento // prevent selection while moving viewer->setSelectionEnabled(false); + auto* assemblyPart = static_cast(getObject()); ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/Mod/Assembly"); bool solveOnMove = hGrp->GetBool("SolveOnMove", true); - if (solveOnMove) { + if (solveOnMove && dragMode != DragMode::TranslationNoSolve) { objectMasses.clear(); for (auto& movingObj : docsToMove) { objectMasses.push_back({movingObj.obj, 10.0}); } - auto* assemblyPart = static_cast(getObject()); assemblyPart->setObjMasses(objectMasses); std::vector dragParts; for (auto& movingObj : docsToMove) { @@ -844,6 +864,9 @@ void ViewProviderAssembly::initMove(const SbVec2s& cursorPos, Gui::View3DInvento } assemblyPart->preDrag(dragParts); } + else { + assemblyPart->redrawJointPlacements(assemblyPart->getJoints()); + } } void ViewProviderAssembly::endMove() diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.h b/src/Mod/Assembly/Gui/ViewProviderAssembly.h index c9152583bd..29295fe341 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.h +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.h @@ -85,6 +85,7 @@ class AssemblyGuiExport ViewProviderAssembly: public Gui::ViewProviderPart, enum class DragMode { Translation, + TranslationNoSolve, TranslationOnAxis, TranslationOnPlane, Rotation,