Assembly: Enable ungrounded connected parts to move as one item.

This commit is contained in:
PaddleStroke
2024-08-05 08:21:08 +02:00
committed by Yorik van Havre
parent 8fb3b26704
commit 79b9d45726
5 changed files with 131 additions and 64 deletions

View File

@@ -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<DocumentObject*> 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*>(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<App::DocumentObject*> AssemblyObject::getJoints(bool updateJCS, bool delBadJoints)
std::vector<App::DocumentObject*>
AssemblyObject::getJoints(bool updateJCS, bool delBadJoints, bool subJoints)
{
std::vector<App::DocumentObject*> joints = {};
@@ -528,9 +534,11 @@ std::vector<App::DocumentObject*> 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<ObjRef> 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<App::DocumentObject*> joints = getJoints(false);
@@ -1533,7 +1544,9 @@ std::vector<ObjRef> 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<std::string> names = getSubAsList(prop);
App::Document* doc = obj->getDocument();
std::vector<std::string> 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<App::DocumentObjectGroup>()) {
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<std::string> 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<App::PropertyXLinkSub*>(joint->getPropertyByName(pName));

View File

@@ -168,8 +168,8 @@ public:
Base::Placement getMbdPlacement(std::shared_ptr<MbD::ASMTPart> mbdPart);
bool validateNewPlacements();
void setNewPlacements();
void recomputeJointPlacements(std::vector<App::DocumentObject*> joints);
void redrawJointPlacements(std::vector<App::DocumentObject*> joints);
static void recomputeJointPlacements(std::vector<App::DocumentObject*> joints);
static void redrawJointPlacements(std::vector<App::DocumentObject*> joints);
// Ondsel Solver interface
@@ -193,7 +193,8 @@ public:
void jointParts(std::vector<App::DocumentObject*> joints);
JointGroup* getJointGroup();
ViewGroup* getExplodedViewGroup();
std::vector<App::DocumentObject*> getJoints(bool updateJCS = true, bool delBadJoints = false);
std::vector<App::DocumentObject*>
getJoints(bool updateJCS = true, bool delBadJoints = false, bool subJoints = true);
std::vector<App::DocumentObject*> getGroundedJoints();
std::vector<App::DocumentObject*> getJointsOfObj(App::DocumentObject* obj);
std::vector<App::DocumentObject*> getJointsOfPart(App::DocumentObject* part);
@@ -217,7 +218,8 @@ public:
bool isPartGrounded(App::DocumentObject* part);
bool isPartConnected(App::DocumentObject* part);
std::vector<ObjRef> getDownstreamParts(App::DocumentObject* part, App::DocumentObject* joint);
std::vector<ObjRef> getDownstreamParts(App::DocumentObject* part,
App::DocumentObject* joint = nullptr);
std::vector<App::DocumentObject*> 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);

View File

@@ -1,23 +1,24 @@
/***************************************************************************
* Copyright (c) 2014 Jürgen Riegel <juergen.riegel@web.de> *
* *
* 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 <development@ondsel.com> *
* *
* 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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/

View File

@@ -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<AssemblyObject*>(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<AssemblyObject*>(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<App::PropertyPlacement*>(obj->getPropertyByName("Placement"));
dynamic_cast<App::PropertyPlacement*>(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<Assembly::ObjRef>& refs) {
for (auto& partRef : refs) {
auto* pPlc =
dynamic_cast<App::PropertyPlacement*>(partRef.obj->getPropertyByName("Placement"));
if (pPlc) {
App::DocumentObject* selRoot = partRef.ref->getValue();
if (!selRoot) {
continue;
}
std::vector<std::string> 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<AssemblyObject*>(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<Assembly::ObjRef> 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<Assembly::ObjRef> downstreamParts =
assemblyPart->getDownstreamParts(docsToMove[0].obj, movingJoint);
for (auto& partRef : downstreamParts) {
auto* pPlc =
dynamic_cast<App::PropertyPlacement*>(partRef.obj->getPropertyByName("Placement"));
if (pPlc) {
App::DocumentObject* selRoot = partRef.ref->getValue();
if (!selRoot) {
return DragMode::None;
}
std::vector<std::string> 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<AssemblyObject*>(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<AssemblyObject*>(getObject());
assemblyPart->setObjMasses(objectMasses);
std::vector<App::DocumentObject*> 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()

View File

@@ -85,6 +85,7 @@ class AssemblyGuiExport ViewProviderAssembly: public Gui::ViewProviderPart,
enum class DragMode
{
Translation,
TranslationNoSolve,
TranslationOnAxis,
TranslationOnPlane,
Rotation,