diff --git a/src/Mod/Assembly/App/AssemblyObject.cpp b/src/Mod/Assembly/App/AssemblyObject.cpp index 3e98a95299..882e1e959d 100644 --- a/src/Mod/Assembly/App/AssemblyObject.cpp +++ b/src/Mod/Assembly/App/AssemblyObject.cpp @@ -80,6 +80,105 @@ namespace PartApp = Part; using namespace Assembly; using namespace MbD; +// ======================================= Utils ====================================== + +Base::Placement getPlacementFromProp(App::DocumentObject* obj, const char* propName) +{ + Base::Placement plc = Base::Placement(); + auto* propPlacement = dynamic_cast(obj->getPropertyByName(propName)); + if (propPlacement) { + plc = propPlacement->getValue(); + } + return plc; +} +/* // Currently unused +Base::Placement* getTargetPlacementRelativeTo( + App::DocumentObject* targetObj, App::DocumentObject* part, App::DocumentObject* container, + bool inContainerBranch, bool ignorePlacement = false) +{ + inContainerBranch = inContainerBranch || (!ignorePlacement && part == container); + + Base::Console().Warning("sub --------------\n"); + if (targetObj == part && inContainerBranch && !ignorePlacement) { + Base::Console().Warning("found0\n"); + return &getPlacementFromProp(targetObj, "Placement"); + } + + if (auto group = dynamic_cast(part)) { + for (auto& obj : group->getOutList()) { + auto foundPlacement = getTargetPlacementRelativeTo( + targetObj, obj, container, inContainerBranch, ignorePlacement + ); + if (foundPlacement != nullptr) { + return foundPlacement; + } + } + } + else if (auto assembly = dynamic_cast(part)) { + Base::Console().Warning("h3\n"); + for (auto& obj : assembly->getOutList()) { + auto foundPlacement = getTargetPlacementRelativeTo( + targetObj, obj, container, inContainerBranch + ); + if (foundPlacement == nullptr) { + continue; + } + + if (!ignorePlacement) { + *foundPlacement = getPlacementFromProp(part, "Placement") * *foundPlacement; + } + + Base::Console().Warning("found\n"); + return foundPlacement; + } + } + else if (auto link = dynamic_cast(part)) { + Base::Console().Warning("h4\n"); + auto linked_obj = link->getLinkedObject(); + + if (dynamic_cast(linked_obj) || dynamic_cast(linked_obj)) { + for (auto& obj : linked_obj->getOutList()) { + auto foundPlacement = getTargetPlacementRelativeTo( + targetObj, obj, container, inContainerBranch + ); + if (foundPlacement == nullptr) { + continue; + } + + *foundPlacement = getPlacementFromProp(link, "Placement") * *foundPlacement; + return foundPlacement; + } + } + + auto foundPlacement = getTargetPlacementRelativeTo( + targetObj, linked_obj, container, inContainerBranch, true + ); + + if (foundPlacement != nullptr && !ignorePlacement) { + *foundPlacement = getPlacementFromProp(link, "Placement") * *foundPlacement; + } + + Base::Console().Warning("found2\n"); + return foundPlacement; + } + + return nullptr; +} + +Base::Placement getGlobalPlacement(App::DocumentObject* targetObj, App::DocumentObject* container = +nullptr) { bool inContainerBranch = container == nullptr; auto rootObjects = +App::GetApplication().getActiveDocument()->getRootObjects(); for (auto& part : rootObjects) { auto +foundPlacement = getTargetPlacementRelativeTo(targetObj, part, container, inContainerBranch); if +(foundPlacement != nullptr) { Base::Placement plc(foundPlacement->toMatrix()); return plc; + } + } + + return Base::Placement(); +} +*/ + +// ================================ Assembly Object ============================ + PROPERTY_SOURCE(Assembly::AssemblyObject, App::Part) AssemblyObject::AssemblyObject() @@ -357,11 +456,7 @@ int AssemblyObject::solve(bool enableRedo) setNewPlacements(); - // The Placement1 and Placement2 of each joint needs to be updated as the parts moved. - // Note calling only recomputeJointPlacements makes a weird illegal storage access - // When solving while moving part. Happens in Py::Callable(attr).apply(); - // it apparently can't access the JointObject 'updateJCSPlacements' function. - getJoints(); + redrawJointPlacements(joints); return 0; } @@ -709,8 +804,8 @@ AssemblyObject::makeMbdJoint(App::DocumentObject* joint) return {}; } - std::string fullMarkerName1 = handleOneSideOfJoint(joint, "Part1", "Placement1"); - std::string fullMarkerName2 = handleOneSideOfJoint(joint, "Part2", "Placement2"); + std::string fullMarkerName1 = handleOneSideOfJoint(joint, "Object1", "Part1", "Placement1"); + std::string fullMarkerName2 = handleOneSideOfJoint(joint, "Object2", "Part2", "Placement2"); mbdJoint->setMarkerI(fullMarkerName1); mbdJoint->setMarkerJ(fullMarkerName2); @@ -719,18 +814,24 @@ AssemblyObject::makeMbdJoint(App::DocumentObject* joint) } std::string AssemblyObject::handleOneSideOfJoint(App::DocumentObject* joint, - const char* propLinkName, + const char* propObjName, + const char* propPartName, const char* propPlcName) { - App::DocumentObject* obj = getLinkObjFromProp(joint, propLinkName); + App::DocumentObject* part = getLinkObjFromProp(joint, propPartName); + App::DocumentObject* obj = getObjFromNameProp(joint, propObjName, propPartName); - std::shared_ptr mbdPart = getMbDPart(obj); + std::shared_ptr mbdPart = getMbDPart(part); + Base::Placement partPlc = getPlacementFromProp(part, "Placement"); Base::Placement objPlc = getPlacementFromProp(obj, "Placement"); Base::Placement plc = getPlacementFromProp(joint, propPlcName); - // Now we have plc which is the JCS placement, but its relative to the doc origin, not to the - // obj. + // Now we have plc which is the JCS placement, but its relative to the Object, not to the + // containing Part. - plc = objPlc.inverse() * plc; + if (obj->getNameInDocument() != part->getNameInDocument()) { + // Make plc relative to the containing part + plc = objPlc * plc; + } std::string markerName = joint->getFullName(); auto mbdMarker = makeMbdMarker(markerName, plc); @@ -964,11 +1065,27 @@ void AssemblyObject::setNewPlacements() } } +void AssemblyObject::redrawJointPlacements(std::vector joints) +{ + // Notify the joint objects that the transform of the coin object changed. + for (auto* joint : joints) { + auto* propPlacement = + dynamic_cast(joint->getPropertyByName("Placement1")); + if (propPlacement) { + propPlacement->setValue(propPlacement->getValue()); + } + propPlacement = + dynamic_cast(joint->getPropertyByName("Placement2")); + if (propPlacement) { + propPlacement->setValue(propPlacement->getValue()); + } + } +} + void AssemblyObject::recomputeJointPlacements(std::vector joints) { // The Placement1 and Placement2 of each joint needs to be updated as the parts moved. for (auto* joint : joints) { - App::PropertyPythonObject* proxy = joint ? dynamic_cast(joint->getPropertyByName("Proxy")) : nullptr; @@ -1135,9 +1252,9 @@ App::DocumentObject* AssemblyObject::getLinkObjFromProp(App::DocumentObject* joi return propObj->getValue(); } -App::DocumentObject* AssemblyObject::getLinkedObjFromNameProp(App::DocumentObject* joint, - const char* pObjName, - const char* pPart) +App::DocumentObject* AssemblyObject::getObjFromNameProp(App::DocumentObject* joint, + const char* pObjName, + const char* pPart) { auto* propObjName = dynamic_cast(joint->getPropertyByName(pObjName)); if (!propObjName) { @@ -1151,13 +1268,13 @@ App::DocumentObject* AssemblyObject::getLinkedObjFromNameProp(App::DocumentObjec } if (objName == containingPart->getNameInDocument()) { - return containingPart->getLinkedObject(true); + return containingPart; } if (containingPart->getTypeId().isDerivedFrom(App::Link::getClassTypeId())) { App::Link* link = dynamic_cast(containingPart); - containingPart = link->getLinkedObject(true); + containingPart = link->getLinkedObject(); if (!containingPart) { return nullptr; } @@ -1165,23 +1282,25 @@ App::DocumentObject* AssemblyObject::getLinkedObjFromNameProp(App::DocumentObjec for (auto obj : containingPart->getOutList()) { if (objName == obj->getNameInDocument()) { - return obj->getLinkedObject(true); + return obj; } } return nullptr; } -Base::Placement AssemblyObject::getPlacementFromProp(App::DocumentObject* obj, const char* propName) +App::DocumentObject* AssemblyObject::getLinkedObjFromNameProp(App::DocumentObject* joint, + const char* pObjName, + const char* pPart) { - Base::Placement plc = Base::Placement(); - auto* propPlacement = dynamic_cast(obj->getPropertyByName(propName)); - if (propPlacement) { - plc = propPlacement->getValue(); + auto* obj = getObjFromNameProp(joint, pObjName, pPart); + if (obj) { + return obj->getLinkedObject(true); } - return plc; + return nullptr; } + /*void Part::handleChangedPropertyType(Base::XMLReader& reader, const char* TypeName, App::Property* prop) { diff --git a/src/Mod/Assembly/App/AssemblyObject.h b/src/Mod/Assembly/App/AssemblyObject.h index 53b550ceda..4cf99e2774 100644 --- a/src/Mod/Assembly/App/AssemblyObject.h +++ b/src/Mod/Assembly/App/AssemblyObject.h @@ -104,6 +104,7 @@ public: std::string handleOneSideOfJoint(App::DocumentObject* joint, const char* propObjLinkName, + const char* propPartName, const char* propPlcName); void jointParts(std::vector joints); std::vector getJoints(); @@ -124,6 +125,7 @@ public: void swapJCS(App::DocumentObject* joint); void setNewPlacements(); + void redrawJointPlacements(std::vector joints); void recomputeJointPlacements(std::vector joints); bool isPartConnected(App::DocumentObject* obj); @@ -141,9 +143,10 @@ public: JointType getJointType(App::DocumentObject* joint); const char* getElementFromProp(App::DocumentObject* obj, const char* propName); std::string getElementTypeFromProp(App::DocumentObject* obj, const char* propName); - Base::Placement getPlacementFromProp(App::DocumentObject* obj, const char* propName); App::DocumentObject* getLinkObjFromProp(App::DocumentObject* joint, const char* propName); App::DocumentObject* + getObjFromNameProp(App::DocumentObject* joint, const char* pObjName, const char* pPart); + App::DocumentObject* getLinkedObjFromNameProp(App::DocumentObject* joint, const char* pObjName, const char* pPart); private: diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp index 9c32514b13..77cc7bb9bd 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp @@ -205,8 +205,6 @@ App::DocumentObject* ViewProviderAssembly::getActivePart() bool ViewProviderAssembly::mouseMove(const SbVec2s& cursorPos, Gui::View3DInventorViewer* viewer) { - // Base::Console().Warning("Mouse move\n"); - // Initialize or end the dragging of parts if (canStartDragging) { canStartDragging = false; diff --git a/src/Mod/Assembly/JointObject.py b/src/Mod/Assembly/JointObject.py index 52514de94a..d29a0f3101 100644 --- a/src/Mod/Assembly/JointObject.py +++ b/src/Mod/Assembly/JointObject.py @@ -428,11 +428,11 @@ class Joint: plc = obj.Placement.inverse() * plc # change plc to be relative to the origin of the document. - global_plc = UtilsAssembly.getGlobalPlacement(obj, part) - plc = global_plc * plc + # global_plc = UtilsAssembly.getGlobalPlacement(obj, part) + # plc = global_plc * plc # change plc to be relative to the assembly. - plc = assembly.Placement.inverse() * plc + # plc = assembly.Placement.inverse() * plc # We apply rotation / reverse / offset it necessary, but only to the second JCS. if isSecond: @@ -621,7 +621,12 @@ class ViewProviderJoint: return camera.height.getValue() / 20 - def set_JCS_placement(self, soTransform, placement): + def set_JCS_placement(self, soTransform, placement, objName, part): + # change plc to be relative to the origin of the document. + obj = UtilsAssembly.getObjectInPart(objName, part) + global_plc = UtilsAssembly.getGlobalPlacement(obj, part) + placement = global_plc * placement + t = placement.Base soTransform.translation.setValue(t.x, t.y, t.z) @@ -632,20 +637,22 @@ class ViewProviderJoint: """If a property of the handled feature has changed we have the chance to handle this here""" # joint is the handled feature, prop is the name of the property that has changed if prop == "Placement1": - plc = joint.getPropertyByName("Placement1") - if joint.getPropertyByName("Object1"): + if joint.Object1: + plc = joint.Placement1 self.switch_JCS1.whichChild = coin.SO_SWITCH_ALL - self.set_JCS_placement(self.transform1, plc) + + if joint.Part1: # prevent an unwanted call by assembly.isPartConnected + self.set_JCS_placement(self.transform1, plc, joint.Object1, joint.Part1) else: self.switch_JCS1.whichChild = coin.SO_SWITCH_NONE if prop == "Placement2": - plc = joint.getPropertyByName("Placement2") - if joint.getPropertyByName("Object2"): + if joint.Object2: + plc = joint.Placement2 self.switch_JCS2.whichChild = coin.SO_SWITCH_ALL - if self.areJCSReversed(joint): - plc = flipPlacement(plc, App.Vector(1, 0, 0)) - self.set_JCS_placement(self.transform2, plc) + # if self.areJCSReversed(joint): + # plc = flipPlacement(plc, App.Vector(1, 0, 0)) + self.set_JCS_placement(self.transform2, plc, joint.Object2, joint.Part2) else: self.switch_JCS2.whichChild = coin.SO_SWITCH_NONE @@ -656,10 +663,10 @@ class ViewProviderJoint: sameDir = zaxis1.dot(zaxis2) > 0 return not sameDir - def showPreviewJCS(self, visible, placement=None): + def showPreviewJCS(self, visible, placement=None, objName="", part=None): if visible: self.switch_JCS_preview.whichChild = coin.SO_SWITCH_ALL - self.set_JCS_placement(self.transform3, placement) + self.set_JCS_placement(self.transform3, placement, objName, part) else: self.switch_JCS_preview.whichChild = coin.SO_SWITCH_NONE @@ -1110,16 +1117,17 @@ class TaskAssemblyCreateJoint(QtCore.QObject): ) isSecond = len(self.current_selection) == 1 - + objName = self.preselection_dict["object"].Name + part = self.preselection_dict["part"] placement = self.joint.Proxy.findPlacement( self.joint, - self.preselection_dict["object"].Name, - self.preselection_dict["part"], + objName, + part, self.preselection_dict["element_name"], self.preselection_dict["vertex_name"], isSecond, ) - self.joint.ViewObject.Proxy.showPreviewJCS(True, placement) + self.joint.ViewObject.Proxy.showPreviewJCS(True, placement, objName, part) self.previewJCSVisible = True # 3D view keyboard handler @@ -1156,6 +1164,9 @@ class TaskAssemblyCreateJoint(QtCore.QObject): self.current_selection.append(selection_dict) self.updateJoint() + # We hide the preview JCS if we just added to the selection + self.joint.ViewObject.Proxy.showPreviewJCS(False) + def removeSelection(self, doc_name, obj_name, sub_name, mousePos=None): full_element_name = UtilsAssembly.getFullElementName(obj_name, sub_name) selected_object = UtilsAssembly.getObject(full_element_name)