diff --git a/assembly.py b/assembly.py index d30c384..a25bcd3 100644 --- a/assembly.py +++ b/assembly.py @@ -1553,6 +1553,77 @@ class AsmRelationGroup(AsmBase): obj.purgeTouched() return obj + @staticmethod + def gotoRelationOfConstraint(obj,subname): + sub = Part.splitSubname(subname)[0].split('.') + sobj = obj.getSubObject(subname,retType=1) + if isTypeOf(sobj,AsmElementLink): + sobj = sobj.parent.Object + sub = sub[:-2] + else: + sub = sub[:-1] + if not isTypeOf(sobj,AsmConstraint): + return + sub[-2] = '3' + sub[-1] = '' + sub = '.'.join(sub) + subs = [] + relationGroup = sobj.Proxy.getAssembly().getRelationGroup(True) + for relation in relationGroup.Proxy.getRelations().values(): + for o in relation.Group: + if isTypeOf(o,AsmRelation): + found = False + for child in o.Group: + if child == sobj: + subs.append('{}{}.{}.{}.'.format( + sub,relation.Name,o.Name,child.Name)) + found = True + break + if found: + continue + elif o == sobj: + subs.append('{}{}.{}.'.format(sub,relation.Name,o.Name)) + + if subs: + FreeCADGui.Selection.pushSelStack() + FreeCADGui.Selection.clearSelection() + FreeCADGui.Selection.addSelection(obj,subs) + FreeCADGui.Selection.pushSelStack() + FreeCADGui.runCommand('Std_TreeSelection') + + @staticmethod + def gotoRelation(moveInfo): + if not moveInfo: + return + info = moveInfo.ElementInfo + if info.Subname: + subs = moveInfo.SelSubname[:-len(info.Subname)] + else: + subs = moveInfo.SelSubname + subs = subs.split('.') + relationGroup = resolveAssembly(info.Parent).getRelationGroup() + if isinstance(info.Part,tuple): + part = info.Part[0] + else: + part = info.Part + relation = relationGroup.Proxy.findRelation(part) + if not relation: + return + if isinstance(info.Part,tuple): + if len(subs)<4: + subs.append('') + subs[-4] = '3' + subs[-3] = relation.Name + subs[-2] = relation.Group[info.Part[1]].Name + else: + subs[-3] = '3' + subs[-2] = relation.Name + FreeCADGui.Selection.pushSelStack() + FreeCADGui.Selection.clearSelection() + FreeCADGui.Selection.addSelection(moveInfo.SelObj,'.'.join(subs)) + FreeCADGui.Selection.pushSelStack() + FreeCADGui.runCommand('Std_TreeSelection') + class ViewProviderAsmRelationGroup(ViewProviderAsmBase): _iconName = 'Assembly_Assembly_Relation_Tree.svg' @@ -1587,6 +1658,18 @@ class AsmRelation(AsmBase): obj.setPropertyStatus('Group','Hidden') super(AsmRelation,self).attach(obj) + def getSubObject(self,obj,subname,retType,mat,transform,depth): + if not subname or subname[0]==';': + return False + idx = subname.find('.') + if idx<0: + return False + name = subname[:idx] + for o in obj.Group: + if o.Name == name: + return o.getSubObject(subname[idx+1:], + retType,mat,transform,depth+1) + def getAssembly(self): return self.parent.getAssembly() diff --git a/gui.py b/gui.py index 9bee924..2153c92 100644 --- a/gui.py +++ b/gui.py @@ -231,31 +231,48 @@ class AsmCmdMove(AsmCmdBase): _id = 2 _menuText = 'Move part' _iconName = 'Assembly_Move.svg' - _useCenterballDragger = True _accel = 'A, M' + _moveInfo = None @classmethod def Activated(cls): from . import mover - mover.movePart(cls._useCenterballDragger) + mover.movePart(True,cls._moveInfo) + + @classmethod + def canMove(cls): + from . import mover + cls._moveInfo = None + cls._moveInfo = mover.getMovingElementInfo() + mover.checkFixedPart(cls._moveInfo.ElementInfo) + return True @classmethod def checkActive(cls): - from . import mover - cls._active = mover.canMovePart() + cls._active = logger.catchTrace('',cls.canMove) @classmethod def onClearSelection(cls): cls._active = False + cls._moveInfo = None -class AsmCmdAxialMove(AsmCmdMove): +class AsmCmdAxialMove(AsmCmdBase): _id = 3 _menuText = 'Axial move part' _iconName = 'Assembly_AxialMove.svg' _useCenterballDragger = False _accel = 'A, A' -class AsmCmdQuickMove(AsmCmdBase): + @classmethod + def IsActive(cls): + return AsmCmdMove.IsActive() + + @classmethod + def Activated(cls): + from . import mover + mover.movePart(False,AsmCmdMove._moveInfo) + +class AsmCmdQuickMove(AsmCmdAxialMove): _id = 13 _menuText = 'Quick move' _tooltip = 'Bring an object contained in an assembly to where the mouse\n'\ @@ -269,15 +286,6 @@ class AsmCmdQuickMove(AsmCmdBase): from . import mover mover.quickMove() - @classmethod - def checkActive(cls): - from . import mover - cls._active = mover.canMovePart() - - @classmethod - def onClearSelection(cls): - cls._active = False - class AsmCmdCheckable(AsmCmdBase): _id = -2 _saveParam = False @@ -465,6 +473,45 @@ class AsmCmdAddWorkplaneGroup(AsmCmdAddWorkplane): def Activated(cls,idx=0): FreeCADGui.runCommand(cls._cmds[idx]) +class AsmCmdGotoRelation(AsmCmdBase): + _id = 16 + _menuText = 'Go to relation' + _tooltip = 'Select the corresponding part object in the relation group' + _iconName = 'Assembly_GotoRelation.svg' + _accel = 'A, R' + + @classmethod + def Activated(cls): + from .assembly import AsmRelationGroup + if AsmCmdMove._moveInfo: + AsmRelationGroup.gotoRelation(AsmCmdMove._moveInfo) + return + sels = FreeCADGui.Selection.getSelectionEx('',0,True) + if sels and len(sels[0].SubElementNames)==1: + AsmRelationGroup.gotoRelationOfConstraint( + sels[0].Object,sels[0].SubElementNames[0]) + + @classmethod + def IsActive(cls): + if AsmCmdMove._moveInfo: + return True + if cls._active is None: + cls.checkActive() + return cls._active + + @classmethod + def checkActive(cls): + from .assembly import isTypeOf, AsmConstraint, AsmElementLink + sels = FreeCADGui.Selection.getSelection('',1,True) + if sels and isTypeOf(sels[0],(AsmConstraint,AsmElementLink)): + cls._active = True + else: + cls._active = False + + @classmethod + def onSelectionChange(cls,hasSelection): + cls._active = None if hasSelection else False + class AsmCmdUp(AsmCmdBase): _id = 6 diff --git a/mover.py b/mover.py index c22a785..fbb6aa1 100644 --- a/mover.py +++ b/mover.py @@ -210,13 +210,10 @@ class AsmMovingPart(object): # AsmMovingPart.update() return self.draggerPlacement -def _checkFixedPart(info): +def checkFixedPart(info): if not gui.AsmCmdManager.LockMover: return - if isTypeOf(info.Parent,Assembly,True): - assembly = info.Parent.getLinkedObject(True).Proxy - else: - assembly = info.Parent.getAssembly() + assembly = resolveAssembly(info.Parent) cstrs = assembly.getConstraints() parts = assembly.getPartGroup().Group if info.Part in Constraint.getFixedParts(None,cstrs,parts): @@ -258,7 +255,6 @@ def getMovingElementInfo(): if len(sels[0].SubElementNames)==1: info = getElementInfo(ret[0].Assembly, ret[0].Subname, checkPlacement=True) - _checkFixedPart(info) return MovingPartInfo(SelObj=selObj, SelSubname=selSub, Hierarchy=ret, @@ -283,22 +279,19 @@ def getMovingElementInfo(): for r in ret2: if assembly == r.Assembly: info = getElementInfo(r.Assembly,r.Subname,checkPlacement=True) - _checkFixedPart(info) return MovingPartInfo(SelObj=selObj, SelSubname=selSub, Hierarchy=ret2, ElementInfo=info) raise RuntimeError('not child parent selection') -def canMovePart(): - return logger.catchTrace('',getMovingElementInfo) is not None - -def movePart(useCenterballDragger=None): - ret = logger.catch('exception when moving part', getMovingElementInfo) - if not ret: - return False - - info = ret.ElementInfo +def movePart(useCenterballDragger=None,moveInfo=None): + if not moveInfo: + moveInfo = logger.catch( + 'exception when moving part', getMovingElementInfo) + if not moveInfo: + return False + info = moveInfo.ElementInfo doc = FreeCADGui.editDocument() if doc: doc.resetEdit() @@ -306,7 +299,7 @@ def movePart(useCenterballDragger=None): doc = info.Parent.ViewObject.Document if useCenterballDragger is not None: vobj.UseCenterballDragger = useCenterballDragger - vobj.Proxy._movingPart = AsmMovingPart(ret.Hierarchy,info) + vobj.Proxy._movingPart = AsmMovingPart(moveInfo.Hierarchy,info) FreeCADGui.Selection.clearSelection() return doc.setEdit(vobj,1)