def validateMirrorNode(node): """ Ensure the node still has a valid mirroring counterpart. If it does not, remove the mirror data from the node. Return: True if the node is a valid mirror node """ if not isMirrorNode(node): return False data = meta.getMetaData(node, MIRROR_METACLASS) otherNode = data['otherNode'] if otherNode is None: LOG.debug("{0} paired node not found, " "removing mirroring data".format(node)) meta.removeMetaData(node, MIRROR_METACLASS) return False else: othersOther = getPairedNode(otherNode, False) if othersOther != node: LOG.debug("{0} pairing is unreciprocated, " "removing mirror data".format(node)) meta.removeMetaData(node, MIRROR_METACLASS) return False return True
def test_removeLockedData(self): meta.setMetaData(self.node, 'myMetaClass', 'myTestData') self.node.attr(meta.core.METADATA_ATTR).setLocked(True) result = meta.removeMetaData(self.node) self.assertFalse(result) data = meta.getMetaData(self.node) self.assertEqual(data, {'myMetaClass': 'myTestData'})
def load(self, node=None): if not node: node = self.getNode() if node: data = meta.getMetaData(node, META_CLASSNAME) self.name = getCollectionNameFromNode(node) self.sets = [QuickSelectSet(**kwargs) for kwargs in data.get('sets', [])]
def switchSpace(ctl: pm.PyNode, space: str) -> bool: """ Switch a control into a new space Args: ctl: A node with space switching meta data space: The name of the space to switch to Returns: True if the space was changed, false otherwise """ meta_data = meta.getMetaData(ctl, pulse.spaces.SPACECONSTRAINT_METACLASS) space_data = [ s for s in meta_data.get('spaces', []) if s['name'] == space ] if not space_data: return False space_data = space_data[0] index = space_data['index'] # remember world matrix wm = ctl.wm.get() # change space ctl.attr('space').set(index) # restore world matrix pulse.nodes.setWorldMatrix(ctl, wm) return True
def _createSpaceConstraint(node, spaceNodesByName): """ Connect all spaces defined in the node's space data to the space constraint utility nodes. Args: node (PyNode): The space constraint node spaceNodesByName (dict): A dict of the space nodes index by name. """ data = meta.getMetaData(node, SPACECONSTRAINT_METACLASS) didConnectAny = False for spaceData in data['spaces']: index = spaceData['index'] # ensure the switch is not already created if not spaceData['switch']: spaceNode = spaceNodesByName.get(spaceData['name'], None) if spaceNode: _connectSpaceToConstraint(node, data, index, spaceNode) didConnectAny = True else: LOG.warning("Space node not found: {0}".format( spaceData['name'])) if didConnectAny: # connect space constraint output now that at least one space is setup # TODO: make sure the space 0 is setup, or whatever the attrs value is decomp = data['decompose'] follower = data['follower'] decomp.outputTranslate >> follower.translate decomp.outputRotate >> follower.rotate decomp.outputScale >> follower.scale
def getRigMetaData(self): """ Return all meta data on the rig being built """ if not self.rig: self.log.error('Cannot get rig meta data, no rig is set') return return meta.getMetaData(self.rig, RIG_METACLASS)
def getLinkMetaData(node): """ Return all link metadata for a node """ result = meta.getMetaData(node, className=LINK_METACLASS) if not result: return {} return result
def getAllSpacesIndexedByName(): """ Return all space nodes in a dict indexed by their space name """ allSpaceNodes = getAllSpaces() result = {} for spaceNode in allSpaceNodes: spaceData = meta.getMetaData(spaceNode, SPACE_METACLASS) result[spaceData['name']] = spaceNode return result
def getFootControl(ctl: pm.PyNode): """ Return the main foot control for a foot control system Args: ctl: A control with foot control meta data """ if meta.hasMetaClass(ctl, FOOT_CTL_METACLASSNAME): return meta.getMetaData(ctl, FOOT_CTL_METACLASSNAME).get('foot_ctl')
def loadFromNode(self, node): """ Load Blueprint data from a node. Args: node: A PyNode or node name """ if not Blueprint.isBlueprintNode(node): raise ValueError( "Node does not contain Blueprint data: {0}".format(node)) data = meta.getMetaData(node, BLUEPRINT_METACLASS) self.deserialize(data)
def debugOpenBlueprintScene(self): rigs = pulse.getAllRigs() if not rigs: print('No rig in the scene') return rigdata = meta.getMetaData(rigs[0], pulse.RIG_METACLASS) blueprintFile = rigdata.get('blueprintFile') if not blueprintFile: print('No blueprintFile set on the rig') return print('Opening blueprint: ' + blueprintFile) pm.openFile(blueprintFile, f=True) self.model.reloadBlueprint()
def getAllRigsByName(names): """ Return a list of all rigs in the scene that have a specific rig name Args: names: A list of string rig names """ rigs = getAllRigs() matches = [] for r in rigs: data = meta.getMetaData(r, RIG_METACLASS) if data.get('name') in names: matches.append(r) return matches
def getBlueprintFilepath(self): """ Return the filepath for the Blueprint being edited """ sceneName = None if self.rigExists: # get filepath from rig rig = pulse.getAllRigs()[0] rigdata = meta.getMetaData(rig, pulse.RIG_METACLASS) sceneName = rigdata.get('blueprintFile') else: sceneName = pm.sceneName() if sceneName: filepath = os.path.splitext(sceneName)[0] + '.yaml' return filepath
def getBlueprintFilepath(self) -> str: """ Return the full path to the Blueprint file being edited. """ sceneName = None allRigs = rigs.getAllRigs() if len(allRigs) > 0: # get filepath from rig rig = allRigs[0] rigdata = meta.getMetaData(rig, rigs.RIG_METACLASS) sceneName = rigdata.get('blueprintFile') else: sceneName = pm.sceneName() if sceneName: baseName = os.path.splitext(sceneName)[0] filepath = '%s.%s' % (baseName, BLUEPRINT_FILE_EXT) return filepath
def openRigBlueprint(rig): """ Open the Blueprint source file that was used to build a rig. Args: rig: A rig node """ rigdata = meta.getMetaData(rig, RIG_METACLASS) blueprintFile = rigdata.get('blueprintFile') if not blueprintFile: LOG.warning('No blueprintFile set on the rig') return LOG.info('Opening blueprint: ' + blueprintFile) saveCameras() pm.openFile(blueprintFile, f=True) restoreCameras()
def _connectSpaceConstraint(node, spaceNodesByName): """ Connect all spaces defined in the node's space data to the space constraint utility nodes. Args: node (PyNode): The space constraint node spaceNodesByName (dict): A dict of the space nodes index by name. """ data = meta.getMetaData(node, SPACECONSTRAINT_METACLASS) didConnectAny = False for spaceData in data['spaces']: index = spaceData['index'] # ensure the switch is not already created if not spaceData['switch']: spaceNode = spaceNodesByName.get(spaceData['name'], None) if spaceNode: _connectSpaceToConstraint(data, index, spaceNode) didConnectAny = True else: LOG.warning("Space node not found: {0}".format( spaceData['name'])) if didConnectAny: # connect final output now that at least one space is connected # TODO: make sure the space 0 is setup, or whatever the attrs value is follower = data['follower'] useOffsetMatrix = data['useOffsetMatrix'] if useOffsetMatrix: multMatrix = data['multMatrix'] nodes.connectMatrix(multMatrix.matrixSum, follower, nodes.ConnectMatrixMethod.CONNECT_ONLY) else: # TODO: support joint matrix constraints that don't disable inheritsTransform, # or just remove this path altogether decomp = data['decompose'] decomp.outputTranslate >> follower.translate decomp.outputRotate >> follower.rotate decomp.outputScale >> follower.scale # no longer need to inherit transform follower.inheritsTransform.set(False)
def buildMenuItems(self): ctl = self.getSelectedNodesWithMetaClass( pulse.spaces.SPACECONSTRAINT_METACLASS)[0] meta_data = meta.getMetaData(ctl, pulse.spaces.SPACECONSTRAINT_METACLASS) spaces = meta_data.get('spaces', []) if spaces: pm.menuItem(l="Spaces", enable=False) for space in spaces: index = space['index'] is_current = ctl.attr('space').get() == index title = pulse.names.toTitle(space['name']) suffix = ' (Default)' if index == 0 else '' prefix = '> ' if is_current else ' ' display_name = f"{prefix}{title}{suffix}" pm.menuItem(l=display_name, c=pm.Callback(SpaceSwitchUtils.switchSpace, ctl, space['name']))
def getPairedNode(node, validate=True): """ For a node with mirroring data, return the other node. Args: node: A node with mirroring data that references another node validate (bool): When true, ensures that the pairing is reciprocated by the other node """ if isMirrorNode(node): data = meta.getMetaData(node, MIRROR_METACLASS) if validate: otherNode = data['otherNode'] if otherNode and validate: if getPairedNode(otherNode, False) == node: return otherNode else: LOG.debug('{0} pairing not reciprocated'.format(node)) else: return data['otherNode']
def _createSpaceConstraint(node, spaceNodesByName): """ Create the actual constraints for each defined space in a space constraint node. Args: node (PyNode): The space constraint node spaceNodesByName (dict): A dict of the space nodes index by name. """ data = meta.getMetaData(node, SPACECONSTRAINT_METACLASS) for spaceData in data['spaces']: # ensure the switch is not already created if not spaceData['switch']: spaceNode = spaceNodesByName.get(spaceData['name'], None) if spaceNode: _createConstraintSwitchForSpace( node, data, spaceData, spaceNode) else: LOG.warning( "Space node not found: {0}".format(spaceData['name']))
def test_setAndGetData(self): setData = ['myData', {'a': 1, 'b': 2}, ('x', 'y', 'z')] className = 'myMetaClass' meta.setMetaData(self.node, className, setData) self.assertEqual(meta.getMetaData(self.node, className), setData)
def getLink(node): """ Return the leader that a node is linked to """ return meta.getMetaData(node, className=LINK_METACLASS)
def getDelegateControl(node): ctl_delegate_data = meta.getMetaData(node, 'pulse_ctl_delegate') if ctl_delegate_data: return ctl_delegate_data['delegate_ctl'] return node
def getIKFKData(ctl): return meta.getMetaData(ctl, IKFK_CONTROL_METACLASS)
def metaData(self): if self._metaData is None: self._metaData = meta.getMetaData(self.node, RIG_METACLASS) return self._metaData if self._metaData else {}
def test_multiClassData(self): cls1 = 'myMetaClass1' cls2 = 'myMetaClass2' meta.setMetaData(self.node, cls1, None) meta.setMetaData(self.node, cls2, None) self.assertEqual(meta.getMetaData(self.node), {cls1: None, cls2: None})
def getMirrorSettings(sourceNode, destNode=None, useNodeSettings=True, excludedNodeSettings=None, **kwargs): """ Get mirror settings that represent mirroring from a source node to a target node. Args: sourceNode: A node to get matrix and other settings from destNode: A node that will have mirrored settings applied, necessary when evaluating custom mirroring attributes that need both nodes to compute useNodeSettings: A bool, whether to load custom settings from the node or not excludedNodeSettings: A list of settings to exclude when loading from node kwargs are divided up and used as necessary between 3 mirroring stages: See 'getMirroredMatrices' for a list of kwargs that can be given `mirroredAttrs` -- a list list of custom attribute names that will be included when mirroring `customMirrorAttrExps` -- a dictionary of {attr: expression} that are evaluated using the given sourceNode, destNode to determine custom mirroring behaviour for any attributes """ def filterNodeSettings(settings): if excludedNodeSettings: return { k: v for k, v in settings.items() if k not in excludedNodeSettings } return settings result = {} LOG.debug("Getting Mirror Settings: {0}".format(sourceNode)) if not destNode: destNode = getPairedNode(sourceNode) if not destNode: return # if enabled, pull some custom mirroring settings from the node, # these are stored in a string attr as a python dict if useNodeSettings: data = meta.getMetaData(sourceNode, MIRROR_METACLASS) customSettings = data.get('customSettings') if customSettings is not None: LOG.debug("Custom Mirror Node") # nodeStngs = data['customSettings'] LOG.debug("Settings: {0}".format(customSettings)) kwargs.update(filterNodeSettings(customSettings)) # pull some kwargs used for getMirroredMatrices matrixKwargs = dict([(k, v) for k, v in kwargs.items() if k in ('axis', 'axisMatrix', 'translate', 'rotate', 'mirrorMode')]) result['matrices'] = getMirroredMatrices(sourceNode, **matrixKwargs) # add list of mirrored attributes as designated by kwargs mirAttrKwargs = dict([(a, getattr(sourceNode, a).get()) for a in kwargs.get('mirroredAttrs', [])]) result.setdefault('mirroredAttrs', {}).update(mirAttrKwargs) for attr, exp in kwargs.get('customMirrorAttrExps', {}).items(): if exp: LOG.debug("Attr: {0}".format(attr)) LOG.debug("Exp:\n{0}".format(exp)) val = evalCustomMirrorAttrExp(sourceNode, destNode, attr, exp) LOG.debug("Result: {0}".format(val)) # Eval from the mirror to the dest result['mirroredAttrs'][attr] = val LOG.debug("Mirrored Attrs: {0}".format(result['mirroredAttrs'])) # Save additional variables result['sourceNode'] = sourceNode result['destNode'] = destNode return result
def getFootControlData(ctl): return meta.getMetaData(ctl, FOOT_CTL_METACLASSNAME)