From ebd9dd8a686f16957f29d7a81896ac13b8d43f16 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Wed, 4 Mar 2020 16:36:17 +0800 Subject: [PATCH] assembly: fix element offset/flip menu action --- freecad/asm3/assembly.py | 79 +++++++++++++++++++++++++--------------- freecad/asm3/mover.py | 25 ++++++++----- 2 files changed, 64 insertions(+), 40 deletions(-) diff --git a/freecad/asm3/assembly.py b/freecad/asm3/assembly.py index a07b9ca..5e762ee 100644 --- a/freecad/asm3/assembly.py +++ b/freecad/asm3/assembly.py @@ -1259,7 +1259,7 @@ class ViewProviderAsmElement(ViewProviderAsmOnTop): menu.addAction(action) action = QtGui.QAction(QtGui.QIcon(), - "Attach" if obj.Detach else "Detach", menu) + "Attach element" if obj.Detach else "Detach element", menu) if obj.Detach: action.setToolTip('Attach this element to its linked geometry,\n' 'so that it will auto update on change.') @@ -1271,38 +1271,44 @@ class ViewProviderAsmElement(ViewProviderAsmOnTop): menu.addAction(action) if obj.Proxy.isBroken(): - action = QtGui.QAction(QtGui.QIcon(), "Fix", menu) + action = QtGui.QAction(QtGui.QIcon(), "Fix element", menu) action.setToolTip('Auto fix broken element') QtCore.QObject.connect(action,QtCore.SIGNAL("triggered()"),vobj.Proxy.fix) menu.addAction(action) - action = QtGui.QAction(QtGui.QIcon(), 'Offset', menu) + action = QtGui.QAction(QtGui.QIcon(), 'Offset element', menu) action.setToolTip('Activate dragger to offset this element') menu.addAction(action) QtCore.QObject.connect(action,QtCore.SIGNAL("triggered()"),vobj2.Proxy.offset) - - def setupContextMenu(self,vobj,menu): - ViewProviderAsmElement.setupMenu(menu, vobj, vobj) + if vobj2.Object.Offset != FreeCAD.Placement(): + action = QtGui.QAction(QtGui.QIcon(), 'Reset offset', menu) + action.setToolTip('Clear offset of this element') + menu.addAction(action) + QtCore.QObject.connect(action,QtCore.SIGNAL("triggered()"),vobj2.Proxy.resetOffset) action = QtGui.QAction(QtGui.QIcon(), 'Flip element', menu) action.setToolTip('Flip this element\' Z normal by rotating 180 degree\n' 'along the X axis (or Y axis by holding the CTRL key).\n\n' - 'Note that this is only effective when for elements\n' - 'used in "Attachment" constraint. For others, please\n' - 'try "Flip part" instead.') + 'Note that depending on the type of constraint and the\n' + 'order of the selected element, flipping element may not\n' + 'be effective. You can try "Flip part" instead.') menu.addAction(action) - QtCore.QObject.connect(action,QtCore.SIGNAL("triggered()"),self.flip) + QtCore.QObject.connect(action,QtCore.SIGNAL("triggered()"),vobj2.Proxy.flip) action = QtGui.QAction(QtGui.QIcon(), 'Flip part', menu) - action.setToolTip('Flip the owner part using this element Z normal as\n' - 'reference, which is done by rotating 180 degree along\n' + action.setToolTip('Flip the owner part using this element Z normal as\n' \ + 'reference, which is done by rotating 180 degree along\n' \ 'the element\'s X axis (or Y axis by holding the CTRL key).\n\n' - 'Note that this won\'t work for elements in "Attachment"\n' - 'constraint. Please try "Flip element" instead.') + 'Note that depending on the type of constraint and the\n' + 'order of the selected element, flipping part may not\n' + 'be effective. You can try "Flip element" instead.') menu.addAction(action) - QtCore.QObject.connect(action,QtCore.SIGNAL("triggered()"),self.flipPart) + QtCore.QObject.connect(action,QtCore.SIGNAL("triggered()"),vobj2.Proxy.flipPart) + + def setupContextMenu(self,vobj,menu): + ViewProviderAsmElement.setupMenu(menu, vobj, vobj) return True def fix(self): @@ -1331,7 +1337,18 @@ class ViewProviderAsmElement(ViewProviderAsmOnTop): return mover.movePart(element=self.ViewObject.Object, moveElement=True) @staticmethod - def doFlip(obj, info, flipElement=False): + def doResetOffset(obj): + FreeCAD.setActiveTransaction('Reset offset') + obj.Offset = FreeCAD.Placement() + obj.recompute(True) + FreeCAD.closeActiveTransaction() + + def resetOffset(self): + obj = self.ViewObject.Object + ViewProviderAsmElement.doResetOffset(obj) + + @staticmethod + def doFlip(obj, info, flipElement): if QtGui.QApplication.keyboardModifiers()==QtCore.Qt.ControlModifier: rot = FreeCAD.Rotation(FreeCAD.Vector(0,1,0),180) else: @@ -1345,8 +1362,9 @@ class ViewProviderAsmElement(ViewProviderAsmOnTop): obj.Offset = rot.multiply(obj.Offset) else: offset = utils.getElementPlacement(obj.getSubObject('')) - offset = offset.inverse().multiply(rot).multiply(offset) - setPlacement(info.Part, info.Placement.multiply(offset)) + offset = offset.multiply(rot).multiply(offset.inverse()) + setPlacement(info.Part, offset.multiply(info.Placement)) + obj.recompute(True) FreeCAD.closeActiveTransaction() except Exception: FreeCAD.closeActiveTransaction(True) @@ -1354,7 +1372,7 @@ class ViewProviderAsmElement(ViewProviderAsmOnTop): def flip(self): obj = self.ViewObject.Object - ViewProviderAsmElement.doFlip(obj, obj.Proxy.getInfo()) + ViewProviderAsmElement.doFlip(obj, obj.Proxy.getInfo(), True) def flipPart(self): obj = self.ViewObject.Object @@ -2052,25 +2070,23 @@ class ViewProviderAsmElementLink(ViewProviderAsmOnTop): return; ViewProviderAsmElement.setupMenu(menu, element.ViewObject, vobj) - - action = QtGui.QAction(QtGui.QIcon(), 'Flip', menu) - action.setToolTip('For element link inside an "Attachment" constraint,\n' - 'flip the element\'s Z normal by rotating 180 degree along\n' - 'its X axis (or Y axis by holding the CTRL key). For other\n' - 'constraint, flip the owner part instead.') - menu.addAction(action) - QtCore.QObject.connect(action,QtCore.SIGNAL("triggered()"),self.flip) - return True def offset(self): from . import mover return mover.movePart(element=self.ViewObject.Object, moveElement=True) + def resetOffset(self): + obj = self.ViewObject.Object + ViewProviderAsmElement.doResetOffset(obj) + def flip(self): obj = self.ViewObject.Object - ViewProviderAsmElement.doFlip(obj, obj.Proxy.getInfo(), - Constraint.isAttachment(obj.Proxy.parent.Object)) + ViewProviderAsmElement.doFlip(obj, obj.Proxy.getInfo(), True) + + def flipPart(self): + obj = self.ViewObject.Object + ViewProviderAsmElement.doFlip(obj, obj.Proxy.getInfo(), False) class AsmConstraint(AsmGroup): @@ -4295,6 +4311,9 @@ class ViewProviderAssembly(ViewProviderAsmGroup): def onDragEnd(self): try: if getattr(self,'_movingPart',None): + pla = self._movingPart.dragEnd() + if pla: + self.ViewObject.DraggingPlacement = pla FreeCAD.closeActiveTransaction() return True finally: diff --git a/freecad/asm3/mover.py b/freecad/asm3/mover.py index e43c827..8a27aff 100644 --- a/freecad/asm3/mover.py +++ b/freecad/asm3/mover.py @@ -49,11 +49,6 @@ class AsmMovingPart(object): # Place the dragger at element's current (maybe offseted) shape # center point in assembly coordinate self.draggerPlacement = utils.getElementPlacement(shape) - # calculate the placement of an unoffseted element in assembly coordinate - self.offset = utils.getElementPlacement(element.getSubObject('',transform=False)) - # Calculate the placement to transform the unoffseted element - # shape to the origin of its own coordinate space - self.offsetInv = self.offset.inverse() return # if we are not moving the element, but its owner part, transform @@ -135,9 +130,7 @@ class AsmMovingPart(object): shape = self.element.getSubObject('') pla = utils.getElementPlacement(shape) elif utils.isDraftObject(info.Part): - pos = utils.getElementPos(info.Shape) - rot = utils.getElementRotation(info.Shape) - pla = info.Placement.multiply(FreeCAD.Placement(pos,rot)) + pla = utils.getElementPlacement(info.Shape) else: pla = info.Placement.multiply(self.offset) logger.trace('part move update {}: {}',objName(info.Parent),pla) @@ -158,6 +151,15 @@ class AsmMovingPart(object): mat = FreeCADGui.editDocument().EditingTransform return mat.multiply(self.draggerPlacement.Base) + def dragEnd(self): + if self.moveElement and gui.AsmCmdManager.AutoRecompute: + from . import solver + if not logger.catch('solver exception when moving element', + solver.solve, self.objs): + self.assembly.Object.recompute(True) + else: + return self.update() + def move(self): info = self.info part = info.Part @@ -168,8 +170,11 @@ class AsmMovingPart(object): rollback = [] if self.moveElement: updatePla = False - offset = utils.roundPlacement(self.offsetInv.multiply(pla)) - self.element.Offset = offset + # obtain the placement of an unoffseted element in assembly coordinate + offset = utils.getElementPlacement(self.element.getSubObject('',transform=False)) + self.element.Offset = utils.roundPlacement(offset.inverse().multiply(pla)) + self.element.recompute(True) + return elif not info.Subname.startswith('Face') and utils.isDraftWire(part): updatePla = False if info.Subname.startswith('Vertex'):