assembly: fix element offset/flip menu action

This commit is contained in:
Zheng, Lei 2020-03-04 16:36:17 +08:00
parent c60a7b7f35
commit ebd9dd8a68
2 changed files with 64 additions and 40 deletions

View File

@ -1259,7 +1259,7 @@ class ViewProviderAsmElement(ViewProviderAsmOnTop):
menu.addAction(action) menu.addAction(action)
action = QtGui.QAction(QtGui.QIcon(), action = QtGui.QAction(QtGui.QIcon(),
"Attach" if obj.Detach else "Detach", menu) "Attach element" if obj.Detach else "Detach element", menu)
if obj.Detach: if obj.Detach:
action.setToolTip('Attach this element to its linked geometry,\n' action.setToolTip('Attach this element to its linked geometry,\n'
'so that it will auto update on change.') 'so that it will auto update on change.')
@ -1271,38 +1271,44 @@ class ViewProviderAsmElement(ViewProviderAsmOnTop):
menu.addAction(action) menu.addAction(action)
if obj.Proxy.isBroken(): 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') action.setToolTip('Auto fix broken element')
QtCore.QObject.connect(action,QtCore.SIGNAL("triggered()"),vobj.Proxy.fix) QtCore.QObject.connect(action,QtCore.SIGNAL("triggered()"),vobj.Proxy.fix)
menu.addAction(action) 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') action.setToolTip('Activate dragger to offset this element')
menu.addAction(action) menu.addAction(action)
QtCore.QObject.connect(action,QtCore.SIGNAL("triggered()"),vobj2.Proxy.offset) QtCore.QObject.connect(action,QtCore.SIGNAL("triggered()"),vobj2.Proxy.offset)
if vobj2.Object.Offset != FreeCAD.Placement():
def setupContextMenu(self,vobj,menu): action = QtGui.QAction(QtGui.QIcon(), 'Reset offset', menu)
ViewProviderAsmElement.setupMenu(menu, vobj, vobj) 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 = QtGui.QAction(QtGui.QIcon(), 'Flip element', menu)
action.setToolTip('Flip this element\' Z normal by rotating 180 degree\n' 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' 'along the X axis (or Y axis by holding the CTRL key).\n\n'
'Note that this is only effective when for elements\n' 'Note that depending on the type of constraint and the\n'
'used in "Attachment" constraint. For others, please\n' 'order of the selected element, flipping element may not\n'
'try "Flip part" instead.') 'be effective. You can try "Flip part" instead.')
menu.addAction(action) 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 = QtGui.QAction(QtGui.QIcon(), 'Flip part', menu)
action.setToolTip('Flip the owner part using this element Z normal as\n' action.setToolTip('Flip the owner part using this element Z normal as\n' \
'reference, which is done by rotating 180 degree along\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' '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' 'Note that depending on the type of constraint and the\n'
'constraint. Please try "Flip element" instead.') 'order of the selected element, flipping part may not\n'
'be effective. You can try "Flip element" instead.')
menu.addAction(action) 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 return True
def fix(self): def fix(self):
@ -1331,7 +1337,18 @@ class ViewProviderAsmElement(ViewProviderAsmOnTop):
return mover.movePart(element=self.ViewObject.Object, moveElement=True) return mover.movePart(element=self.ViewObject.Object, moveElement=True)
@staticmethod @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: if QtGui.QApplication.keyboardModifiers()==QtCore.Qt.ControlModifier:
rot = FreeCAD.Rotation(FreeCAD.Vector(0,1,0),180) rot = FreeCAD.Rotation(FreeCAD.Vector(0,1,0),180)
else: else:
@ -1345,8 +1362,9 @@ class ViewProviderAsmElement(ViewProviderAsmOnTop):
obj.Offset = rot.multiply(obj.Offset) obj.Offset = rot.multiply(obj.Offset)
else: else:
offset = utils.getElementPlacement(obj.getSubObject('')) offset = utils.getElementPlacement(obj.getSubObject(''))
offset = offset.inverse().multiply(rot).multiply(offset) offset = offset.multiply(rot).multiply(offset.inverse())
setPlacement(info.Part, info.Placement.multiply(offset)) setPlacement(info.Part, offset.multiply(info.Placement))
obj.recompute(True)
FreeCAD.closeActiveTransaction() FreeCAD.closeActiveTransaction()
except Exception: except Exception:
FreeCAD.closeActiveTransaction(True) FreeCAD.closeActiveTransaction(True)
@ -1354,7 +1372,7 @@ class ViewProviderAsmElement(ViewProviderAsmOnTop):
def flip(self): def flip(self):
obj = self.ViewObject.Object obj = self.ViewObject.Object
ViewProviderAsmElement.doFlip(obj, obj.Proxy.getInfo()) ViewProviderAsmElement.doFlip(obj, obj.Proxy.getInfo(), True)
def flipPart(self): def flipPart(self):
obj = self.ViewObject.Object obj = self.ViewObject.Object
@ -2052,25 +2070,23 @@ class ViewProviderAsmElementLink(ViewProviderAsmOnTop):
return; return;
ViewProviderAsmElement.setupMenu(menu, element.ViewObject, vobj) 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 return True
def offset(self): def offset(self):
from . import mover from . import mover
return mover.movePart(element=self.ViewObject.Object, moveElement=True) return mover.movePart(element=self.ViewObject.Object, moveElement=True)
def resetOffset(self):
obj = self.ViewObject.Object
ViewProviderAsmElement.doResetOffset(obj)
def flip(self): def flip(self):
obj = self.ViewObject.Object obj = self.ViewObject.Object
ViewProviderAsmElement.doFlip(obj, obj.Proxy.getInfo(), ViewProviderAsmElement.doFlip(obj, obj.Proxy.getInfo(), True)
Constraint.isAttachment(obj.Proxy.parent.Object))
def flipPart(self):
obj = self.ViewObject.Object
ViewProviderAsmElement.doFlip(obj, obj.Proxy.getInfo(), False)
class AsmConstraint(AsmGroup): class AsmConstraint(AsmGroup):
@ -4295,6 +4311,9 @@ class ViewProviderAssembly(ViewProviderAsmGroup):
def onDragEnd(self): def onDragEnd(self):
try: try:
if getattr(self,'_movingPart',None): if getattr(self,'_movingPart',None):
pla = self._movingPart.dragEnd()
if pla:
self.ViewObject.DraggingPlacement = pla
FreeCAD.closeActiveTransaction() FreeCAD.closeActiveTransaction()
return True return True
finally: finally:

View File

@ -49,11 +49,6 @@ class AsmMovingPart(object):
# Place the dragger at element's current (maybe offseted) shape # Place the dragger at element's current (maybe offseted) shape
# center point in assembly coordinate # center point in assembly coordinate
self.draggerPlacement = utils.getElementPlacement(shape) 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 return
# if we are not moving the element, but its owner part, transform # if we are not moving the element, but its owner part, transform
@ -135,9 +130,7 @@ class AsmMovingPart(object):
shape = self.element.getSubObject('') shape = self.element.getSubObject('')
pla = utils.getElementPlacement(shape) pla = utils.getElementPlacement(shape)
elif utils.isDraftObject(info.Part): elif utils.isDraftObject(info.Part):
pos = utils.getElementPos(info.Shape) pla = utils.getElementPlacement(info.Shape)
rot = utils.getElementRotation(info.Shape)
pla = info.Placement.multiply(FreeCAD.Placement(pos,rot))
else: else:
pla = info.Placement.multiply(self.offset) pla = info.Placement.multiply(self.offset)
logger.trace('part move update {}: {}',objName(info.Parent),pla) logger.trace('part move update {}: {}',objName(info.Parent),pla)
@ -158,6 +151,15 @@ class AsmMovingPart(object):
mat = FreeCADGui.editDocument().EditingTransform mat = FreeCADGui.editDocument().EditingTransform
return mat.multiply(self.draggerPlacement.Base) 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): def move(self):
info = self.info info = self.info
part = info.Part part = info.Part
@ -168,8 +170,11 @@ class AsmMovingPart(object):
rollback = [] rollback = []
if self.moveElement: if self.moveElement:
updatePla = False updatePla = False
offset = utils.roundPlacement(self.offsetInv.multiply(pla)) # obtain the placement of an unoffseted element in assembly coordinate
self.element.Offset = offset 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): elif not info.Subname.startswith('Face') and utils.isDraftWire(part):
updatePla = False updatePla = False
if info.Subname.startswith('Vertex'): if info.Subname.startswith('Vertex'):